diff --git a/Source/Fractorium/DoubleSpinBox.cpp b/Source/Fractorium/DoubleSpinBox.cpp
index 0bc1d20..63b004e 100644
--- a/Source/Fractorium/DoubleSpinBox.cpp
+++ b/Source/Fractorium/DoubleSpinBox.cpp
@@ -71,6 +71,14 @@ void DoubleSpinBox::DoubleClickNonZero(double val)
m_DoubleClickNonZero = val;
}
+///
+/// Get the default step used when the user scrolls.
+///
+double DoubleSpinBox::Step()
+{
+ return m_Step;
+}
+
///
/// Set the default step to be used when the user scrolls.
///
@@ -80,6 +88,14 @@ void DoubleSpinBox::Step(double step)
m_Step = step;
}
+///
+/// Get the small step to be used when the user holds down shift while scrolling.
+///
+double DoubleSpinBox::SmallStep()
+{
+ return m_SmallStep;
+}
+
///
/// Set the small step to be used when the user holds down shift while scrolling.
/// The default is step / 10, so use this if something else is needed.
diff --git a/Source/Fractorium/DoubleSpinBox.h b/Source/Fractorium/DoubleSpinBox.h
index c5e79fd..c07a0fa 100644
--- a/Source/Fractorium/DoubleSpinBox.h
+++ b/Source/Fractorium/DoubleSpinBox.h
@@ -22,7 +22,9 @@ public:
void DoubleClick(bool b);
void DoubleClickZero(double val);
void DoubleClickNonZero(double val);
+ double Step();
void Step(double step);
+ double SmallStep();
void SmallStep(double step);
QLineEdit* lineEdit();
diff --git a/Source/Fractorium/Fractorium.h b/Source/Fractorium/Fractorium.h
index d0aee0a..e56b557 100644
--- a/Source/Fractorium/Fractorium.h
+++ b/Source/Fractorium/Fractorium.h
@@ -211,6 +211,7 @@ public slots:
void OnAffineGroupBoxToggled(bool on);
void OnAffineDrawAllCurrentRadioButtonToggled(bool checked);
+ void OnPolarAffineCheckBoxStateChanged(int state);
//Xforms Color.
void OnXformColorIndexChanged(double d);
@@ -384,6 +385,9 @@ private:
DoubleSpinBox* m_PostY2Spin;
DoubleSpinBox* m_PostO1Spin;
DoubleSpinBox* m_PostO2Spin;
+
+ DoubleSpinBox* m_PreSpins[6];
+ DoubleSpinBox* m_PostSpins[6];
//Palette.
SpinBox* m_PaletteHueSpin;
diff --git a/Source/Fractorium/Fractorium.ui b/Source/Fractorium/Fractorium.ui
index 32bf551..e2c7779 100644
--- a/Source/Fractorium/Fractorium.ui
+++ b/Source/Fractorium/Fractorium.ui
@@ -353,7 +353,7 @@
QTabWidget::Triangular
- 0
+ 2
true
@@ -504,8 +504,8 @@
0
0
- 259
- 852
+ 73
+ 837
@@ -2285,7 +2285,7 @@ SpinBox
QTabWidget::Triangular
- 2
+ 1
@@ -2825,8 +2825,8 @@ SpinBox
0
0
- 118
- 597
+ 245
+ 747
@@ -4065,6 +4065,13 @@ SpinBox
+ -
+
+
+ Polar
+
+
+
-
@@ -5041,8 +5048,8 @@ SpinBox
0
0
- 259
- 853
+ 73
+ 454
diff --git a/Source/Fractorium/FractoriumEmberController.h b/Source/Fractorium/FractoriumEmberController.h
index 05e01bb..008f374 100644
--- a/Source/Fractorium/FractoriumEmberController.h
+++ b/Source/Fractorium/FractoriumEmberController.h
@@ -148,6 +148,7 @@ public:
virtual void MoveCurrentXform(double x, double y, bool pre) { }
virtual void ScaleCurrentXform(double scale, bool pre) { }
virtual void ResetCurrentXformAffine(bool pre) { }
+ virtual void FillBothAffines() { }
//Xforms Color.
virtual void XformColorIndexChanged(double d, bool updateRender) { }
@@ -368,6 +369,7 @@ public:
virtual void MoveCurrentXform(double x, double y, bool pre) override;
virtual void ScaleCurrentXform(double scale, bool pre) override;
virtual void ResetCurrentXformAffine(bool pre) override;
+ virtual void FillBothAffines() override;
void FillAffineWithXform(Xform* xform, bool pre);
//Xforms Color.
diff --git a/Source/Fractorium/FractoriumXformsAffine.cpp b/Source/Fractorium/FractoriumXformsAffine.cpp
index 66d5e84..1d2bfbd 100644
--- a/Source/Fractorium/FractoriumXformsAffine.cpp
+++ b/Source/Fractorium/FractoriumXformsAffine.cpp
@@ -97,48 +97,64 @@ void Fractorium::InitXformsAffineUI()
connect(ui.ShowPostAffineAllRadio, SIGNAL(toggled(bool)), this, SLOT(OnAffineDrawAllCurrentRadioButtonToggled(bool)), Qt::QueuedConnection);
connect(ui.ShowPostAffineCurrentRadio, SIGNAL(toggled(bool)), this, SLOT(OnAffineDrawAllCurrentRadioButtonToggled(bool)), Qt::QueuedConnection);
+ connect(ui.PolarAffineCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnPolarAffineCheckBoxStateChanged(int)), Qt::QueuedConnection);
+
#ifndef WIN32
- //For some reason linux makes these 24x24, even though the designer explicitly says 16x16.
- //Also, in order to get 4 pixels of spacing between elements in the grid layout, 0 must be specified.
- ui.PreFlipHorizontalButton->setIconSize(QSize(16, 16));
- ui.PreFlipVerticalButton->setIconSize(QSize(16, 16));
- ui.PreRotate90CButton->setIconSize(QSize(16, 16));
- ui.PreRotate90CcButton->setIconSize(QSize(16, 16));
- ui.PreRotateCButton->setIconSize(QSize(16, 16));
- ui.PreRotateCcButton->setIconSize(QSize(16, 16));
- ui.PreMoveUpButton->setIconSize(QSize(16, 16));
- ui.PreMoveDownButton->setIconSize(QSize(16, 16));
- ui.PreMoveLeftButton->setIconSize(QSize(16, 16));
- ui.PreMoveRightButton->setIconSize(QSize(16, 16));
- ui.PreScaleDownButton->setIconSize(QSize(16, 16));
- ui.PreScaleUpButton->setIconSize(QSize(16, 16));
- ui.PreResetButton->setIconSize(QSize(16, 16));
- ui.PreAffineGridLayout->setHorizontalSpacing(0);
- ui.PreAffineGridLayout->setVerticalSpacing(0);
-
- ui.PostFlipHorizontalButton->setIconSize(QSize(16, 16));
- ui.PostFlipVerticalButton->setIconSize(QSize(16, 16));
- ui.PostRotate90CButton->setIconSize(QSize(16, 16));
- ui.PostRotate90CcButton->setIconSize(QSize(16, 16));
- ui.PostRotateCButton->setIconSize(QSize(16, 16));
- ui.PostRotateCcButton->setIconSize(QSize(16, 16));
- ui.PostMoveUpButton->setIconSize(QSize(16, 16));
- ui.PostMoveDownButton->setIconSize(QSize(16, 16));
- ui.PostMoveLeftButton->setIconSize(QSize(16, 16));
- ui.PostMoveRightButton->setIconSize(QSize(16, 16));
- ui.PostScaleDownButton->setIconSize(QSize(16, 16));
- ui.PostScaleUpButton->setIconSize(QSize(16, 16));
- ui.PostResetButton->setIconSize(QSize(16, 16));
- ui.PostAffineGridLayout->setHorizontalSpacing(0);
- ui.PostAffineGridLayout->setVerticalSpacing(0);
-
- //Further, the size of the dock widget won't be properly adjusted until the xforms tab is shown.
- //So show it here and it will be switched back in Fractorium's constructor.
- ui.ParamsTabWidget->setCurrentIndex(2);
- ui.DockWidget->update();
+ //For some reason linux makes these 24x24, even though the designer explicitly says 16x16.
+ //Also, in order to get 4 pixels of spacing between elements in the grid layout, 0 must be specified.
+ ui.PreFlipHorizontalButton->setIconSize(QSize(16, 16));
+ ui.PreFlipVerticalButton->setIconSize(QSize(16, 16));
+ ui.PreRotate90CButton->setIconSize(QSize(16, 16));
+ ui.PreRotate90CcButton->setIconSize(QSize(16, 16));
+ ui.PreRotateCButton->setIconSize(QSize(16, 16));
+ ui.PreRotateCcButton->setIconSize(QSize(16, 16));
+ ui.PreMoveUpButton->setIconSize(QSize(16, 16));
+ ui.PreMoveDownButton->setIconSize(QSize(16, 16));
+ ui.PreMoveLeftButton->setIconSize(QSize(16, 16));
+ ui.PreMoveRightButton->setIconSize(QSize(16, 16));
+ ui.PreScaleDownButton->setIconSize(QSize(16, 16));
+ ui.PreScaleUpButton->setIconSize(QSize(16, 16));
+ ui.PreResetButton->setIconSize(QSize(16, 16));
+ ui.PreAffineGridLayout->setHorizontalSpacing(0);
+ ui.PreAffineGridLayout->setVerticalSpacing(0);
+
+ ui.PostFlipHorizontalButton->setIconSize(QSize(16, 16));
+ ui.PostFlipVerticalButton->setIconSize(QSize(16, 16));
+ ui.PostRotate90CButton->setIconSize(QSize(16, 16));
+ ui.PostRotate90CcButton->setIconSize(QSize(16, 16));
+ ui.PostRotateCButton->setIconSize(QSize(16, 16));
+ ui.PostRotateCcButton->setIconSize(QSize(16, 16));
+ ui.PostMoveUpButton->setIconSize(QSize(16, 16));
+ ui.PostMoveDownButton->setIconSize(QSize(16, 16));
+ ui.PostMoveLeftButton->setIconSize(QSize(16, 16));
+ ui.PostMoveRightButton->setIconSize(QSize(16, 16));
+ ui.PostScaleDownButton->setIconSize(QSize(16, 16));
+ ui.PostScaleUpButton->setIconSize(QSize(16, 16));
+ ui.PostResetButton->setIconSize(QSize(16, 16));
+ ui.PostAffineGridLayout->setHorizontalSpacing(0);
+ ui.PostAffineGridLayout->setVerticalSpacing(0);
+
+ //Further, the size of the dock widget won't be properly adjusted until the xforms tab is shown.
+ //So show it here and it will be switched back in Fractorium's constructor.
+ ui.ParamsTabWidget->setCurrentIndex(2);
+ ui.DockWidget->update();
#endif
-
-
+
+ //Placing pointers to the spin boxes in arrays makes them easier to access in various places.
+ m_PreSpins[0] = m_PreX1Spin;//A
+ m_PreSpins[1] = m_PreY1Spin;//B
+ m_PreSpins[2] = m_PreO1Spin;//C
+ m_PreSpins[3] = m_PreX2Spin;//D
+ m_PreSpins[4] = m_PreY2Spin;//E
+ m_PreSpins[5] = m_PreO2Spin;//F
+
+ m_PostSpins[0] = m_PostX1Spin;
+ m_PostSpins[1] = m_PostY1Spin;
+ m_PostSpins[2] = m_PostO1Spin;
+ m_PostSpins[3] = m_PostX2Spin;
+ m_PostSpins[4] = m_PostY2Spin;
+ m_PostSpins[5] = m_PostO2Spin;
+
ui.PostAffineGroupBox->setChecked(true);//Flip it once to force the disabling of the group box.
ui.PostAffineGroupBox->setChecked(false);
}
@@ -155,32 +171,52 @@ void FractoriumEmberController::AffineSetHelper(double d, int index, bool pre
{
UpdateCurrentXform([&] (Xform* xform)
{
- QObject* objSender = m_Fractorium->sender();
- DoubleSpinBox* spinBox = dynamic_cast(objSender);
+ Affine2D* affine = pre ? &xform->m_Affine : &xform->m_Post;
+ DoubleSpinBox** spinners = pre ? m_Fractorium->m_PreSpins : m_Fractorium->m_PostSpins;
- if (spinBox)
+ if (m_Fractorium->ui.PolarAffineCheckBox->isChecked())
{
- Affine2D* affine = pre ? &xform->m_Affine : &xform->m_Post;
-
switch (index)
{
case 0:
- affine->A(spinBox->value());
+ case 3:
+ affine->A(cos(spinners[0]->value() * DEG_2_RAD) * spinners[3]->value());
+ affine->D(sin(spinners[0]->value() * DEG_2_RAD) * spinners[3]->value());
break;
case 1:
- affine->B(spinBox->value());
+ case 4:
+ affine->B(cos(spinners[1]->value() * DEG_2_RAD) * spinners[4]->value());
+ affine->E(sin(spinners[1]->value() * DEG_2_RAD) * spinners[4]->value());
break;
case 2:
- affine->C(spinBox->value());
+ case 5:
+ default:
+ affine->C(cos(spinners[2]->value() * DEG_2_RAD) * spinners[5]->value());
+ affine->F(sin(spinners[2]->value() * DEG_2_RAD) * spinners[5]->value());
+ break;
+ }
+ }
+ else
+ {
+ switch (index)
+ {
+ case 0:
+ affine->A(d);
+ break;
+ case 1:
+ affine->B(d);
+ break;
+ case 2:
+ affine->C(d);
break;
case 3:
- affine->D(spinBox->value());
+ affine->D(d);
break;
case 4:
- affine->E(spinBox->value());
+ affine->E(d);
break;
case 5:
- affine->F(spinBox->value());
+ affine->F(d);
break;
}
}
@@ -465,6 +501,16 @@ void FractoriumEmberController::ResetCurrentXformAffine(bool pre)
///
void Fractorium::OnResetAffineButtonClicked(bool checked) { m_Controller->ResetCurrentXformAffine(sender() == ui.PreResetButton); }
+///
+/// Fill the GUI with the pre and post affine xform values.
+///
+template
+void FractoriumEmberController::FillBothAffines()
+{
+ FillAffineWithXform(CurrentXform(), true);
+ FillAffineWithXform(CurrentXform(), false);
+}
+
///
/// Fill the GUI with the pre/post affine xform values.
///
@@ -473,23 +519,26 @@ void Fractorium::OnResetAffineButtonClicked(bool checked) { m_Controller->ResetC
template
void FractoriumEmberController::FillAffineWithXform(Xform* xform, bool pre)
{
- if (pre)
+ DoubleSpinBox** spinners = pre ? m_Fractorium->m_PreSpins : m_Fractorium->m_PostSpins;
+ const Affine2D& affine = pre ? xform->m_Affine : xform->m_Post;
+
+ if (m_Fractorium->ui.PolarAffineCheckBox->isChecked())
{
- m_Fractorium->m_PreX1Spin->SetValueStealth(xform->m_Affine.A());
- m_Fractorium->m_PreY1Spin->SetValueStealth(xform->m_Affine.B());
- m_Fractorium->m_PreO1Spin->SetValueStealth(xform->m_Affine.C());
- m_Fractorium->m_PreX2Spin->SetValueStealth(xform->m_Affine.D());
- m_Fractorium->m_PreY2Spin->SetValueStealth(xform->m_Affine.E());
- m_Fractorium->m_PreO2Spin->SetValueStealth(xform->m_Affine.F());
+ spinners[0]->SetValueStealth(RAD_2_DEG * atan2(affine.D(), affine.A()));
+ spinners[1]->SetValueStealth(RAD_2_DEG * atan2(affine.E(), affine.B()));
+ spinners[2]->SetValueStealth(RAD_2_DEG * atan2(affine.F(), affine.C()));
+ spinners[3]->SetValueStealth(Hypot(affine.D(), affine.A()));
+ spinners[4]->SetValueStealth(Hypot(affine.E(), affine.B()));
+ spinners[5]->SetValueStealth(Hypot(affine.F(), affine.C()));
}
else
{
- m_Fractorium->m_PostX1Spin->SetValueStealth(xform->m_Post.A());
- m_Fractorium->m_PostY1Spin->SetValueStealth(xform->m_Post.B());
- m_Fractorium->m_PostO1Spin->SetValueStealth(xform->m_Post.C());
- m_Fractorium->m_PostX2Spin->SetValueStealth(xform->m_Post.D());
- m_Fractorium->m_PostY2Spin->SetValueStealth(xform->m_Post.E());
- m_Fractorium->m_PostO2Spin->SetValueStealth(xform->m_Post.F());
+ spinners[0]->SetValueStealth(affine.A());
+ spinners[1]->SetValueStealth(affine.B());
+ spinners[2]->SetValueStealth(affine.C());
+ spinners[3]->SetValueStealth(affine.D());
+ spinners[4]->SetValueStealth(affine.E());
+ spinners[5]->SetValueStealth(affine.F());
}
}
@@ -516,6 +565,31 @@ void Fractorium::OnAffineDrawAllCurrentRadioButtonToggled(bool checked)
ui.GLDisplay->update();
}
+///
+/// Set whether to display affine values in polar vs. rectangular coordinates.
+/// Updates the current affine display.
+///
+/// The state of the checkbox
+void Fractorium::OnPolarAffineCheckBoxStateChanged(int state)
+{
+ double mult = state ? 100 : 0.01;
+ double step = m_PreX1Spin->Step() * mult;
+ double small = m_PreX1Spin->SmallStep() * mult;
+ double click = state ? 90 : 1;
+
+ for (int i = 0; i < 3; i++)
+ {
+ m_PreSpins[i]->Step(step);
+ m_PreSpins[i]->SmallStep(small);
+ m_PostSpins[i]->Step(step);
+ m_PostSpins[i]->SmallStep(small);
+ m_PreSpins[i]->DoubleClickZero(click);
+ m_PostSpins[i]->DoubleClickZero(click);
+ }
+
+ m_Controller->FillBothAffines();
+}
+
///
/// Setup a spinner to be placed in a table cell.
/// Special setup function for affine spinners which differs slightly from the regular