diff --git a/Builds/MSVC/VS2013/Fractorium.vcxproj b/Builds/MSVC/VS2013/Fractorium.vcxproj
index 7ce3a14..d4c16dc 100644
--- a/Builds/MSVC/VS2013/Fractorium.vcxproj
+++ b/Builds/MSVC/VS2013/Fractorium.vcxproj
@@ -326,6 +326,7 @@ xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\flam3-palettes.xml" "$(OutDir)"
+
diff --git a/Builds/MSVC/VS2013/Fractorium.vcxproj.filters b/Builds/MSVC/VS2013/Fractorium.vcxproj.filters
index c96ba9b..853fb83 100644
--- a/Builds/MSVC/VS2013/Fractorium.vcxproj.filters
+++ b/Builds/MSVC/VS2013/Fractorium.vcxproj.filters
@@ -244,6 +244,9 @@
MainWindows
+
+ MainWindows
+
diff --git a/Source/Ember/Ember.h b/Source/Ember/Ember.h
index b361cbc..0a373ea 100644
--- a/Source/Ember/Ember.h
+++ b/Source/Ember/Ember.h
@@ -621,7 +621,7 @@ public:
normalizedWeights.resize(m_Xforms.size());
ForEach(m_Xforms, [&](Xform& xform) { norm += xform.m_Weight; });
- ForEach(normalizedWeights, [&](T& weight) { weight = m_Xforms[i].m_Weight / norm; i++; });
+ ForEach(normalizedWeights, [&](T& weight) { weight = (norm == T(0) ? T(0) : m_Xforms[i].m_Weight / norm); i++; });
}
///
diff --git a/Source/Ember/Isaac.h b/Source/Ember/Isaac.h
index ad5c4fa..887e5bd 100644
--- a/Source/Ember/Isaac.h
+++ b/Source/Ember/Isaac.h
@@ -199,7 +199,7 @@ public:
/// A random 0 or 1
inline uint RandBit()
{
- return Rand() & 1;
+ return RandByte() & 1;
}
///
diff --git a/Source/Fractorium/Fractorium.cpp b/Source/Fractorium/Fractorium.cpp
index 6b752d3..734728a 100644
--- a/Source/Fractorium/Fractorium.cpp
+++ b/Source/Fractorium/Fractorium.cpp
@@ -76,7 +76,8 @@ Fractorium::Fractorium(QWidget* p)
InitXformsColorUI();
InitXformsAffineUI();
InitXformsVariationsUI();
- InitXformsXaosUI();
+ InitXformsSelectUI();
+ InitXaosUI();
InitPaletteUI();
InitLibraryUI();
InitMenusUI();
diff --git a/Source/Fractorium/Fractorium.h b/Source/Fractorium/Fractorium.h
index 70b3ed5..b68c798 100644
--- a/Source/Fractorium/Fractorium.h
+++ b/Source/Fractorium/Fractorium.h
@@ -241,7 +241,11 @@ public slots:
void OnVariationsFilterLineEditTextChanged(const QString& text);
void OnVariationsFilterClearButtonClicked(bool checked);
- //Xforms Xaos.
+ //Xforms Selection.
+ void OnXformsSelectAllButtonClicked(bool checked);
+ void OnXformsSelectNoneButtonClicked(bool checked);
+
+ //Xaos.
void OnXaosChanged(double d);
void OnClearXaosButtonClicked(bool checked);
void OnRandomXaosButtonClicked(bool checked);
@@ -287,7 +291,8 @@ private:
void InitXformsColorUI();
void InitXformsAffineUI();
void InitXformsVariationsUI();
- void InitXformsXaosUI();
+ void InitXformsSelectUI();
+ void InitXaosUI();
void InitPaletteUI();
void InitLibraryUI();
void SetTabOrders();
@@ -301,7 +306,6 @@ private:
//Params.
//Xforms.
- void FillXforms();
//Xforms Color.
@@ -309,7 +313,11 @@ private:
//Xforms Variations.
- //Xforms Xaos.
+ //Xforms Selection.
+ void ClearXformsSelections();
+ void ForEachXformCheckbox(std::function func);
+
+ //Xaos.
void FillXaosTable();
//Palette.
@@ -371,6 +379,8 @@ private:
//Xforms.
DoubleSpinBox* m_XformWeightSpin;
SpinnerButtonWidget* m_XformWeightSpinnerButtonWidget;
+ QFormLayout* m_XformsSelectionLayout;
+ QVector m_XformSelections;
//Xforms Color.
QTableWidgetItem* m_XformColorValueItem;
diff --git a/Source/Fractorium/Fractorium.ui b/Source/Fractorium/Fractorium.ui
index 3f633e4..f279ce6 100644
--- a/Source/Fractorium/Fractorium.ui
+++ b/Source/Fractorium/Fractorium.ui
@@ -74,7 +74,7 @@
0
0
- 923
+ 926
942
@@ -1900,342 +1900,6 @@
4
- -
-
-
-
- 2
- 0
-
-
-
-
- 0
- 45
-
-
-
-
- 16777215
- 45
-
-
-
-
- true
-
-
-
- Qt::StrongFocus
-
-
- false
-
-
- QFrame::Panel
-
-
- QFrame::Plain
-
-
- Qt::ScrollBarAlwaysOff
-
-
- Qt::ScrollBarAlwaysOff
-
-
- false
-
-
- QAbstractItemView::DoubleClicked|QAbstractItemView::SelectedClicked
-
-
- false
-
-
- QAbstractItemView::NoSelection
-
-
- QAbstractItemView::ScrollPerPixel
-
-
- QAbstractItemView::ScrollPerPixel
-
-
- false
-
-
- false
-
-
- 1
-
-
- 2
-
-
- false
-
-
- false
-
-
- 27
-
-
- true
-
-
- false
-
-
- 21
-
-
- false
-
-
- 21
-
-
-
-
- Weight
-
-
-
-
- Name
-
-
- -
-
- AlignLeft|AlignVCenter
-
-
- -
-
- AlignLeft|AlignVCenter
-
-
-
-
- -
-
-
- 2
-
-
-
-
-
-
- 0
- 22
-
-
-
-
- 60
- 22
-
-
-
-
- 60
- 16777215
-
-
-
- Current xform
-
-
- false
-
-
- 12
-
-
-
- 9
- 9
-
-
-
- true
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 25
- 24
-
-
-
-
- 16777215
- 24
-
-
-
- Add xform
-
-
-
-
-
-
- :/Fractorium/Icons/add.png:/Fractorium/Icons/add.png
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 25
- 24
-
-
-
-
- 16777215
- 24
-
-
-
- Duplicate xform
-
-
-
-
-
-
- :/Fractorium/Icons/editraise.png:/Fractorium/Icons/editraise.png
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 25
- 24
-
-
-
-
- 16777215
- 24
-
-
-
- Clear xform variations
-
-
-
-
-
-
- :/Fractorium/Icons/eraser.png:/Fractorium/Icons/eraser.png
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 25
- 24
-
-
-
-
- 16777215
- 24
-
-
-
- Delete xform
-
-
-
-
-
-
- :/Fractorium/Icons/del.png:/Fractorium/Icons/del.png
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 58
- 24
-
-
-
-
- 58
- 24
-
-
-
-
- 0
- 0
-
-
-
- Add final xform
-
-
- Qt::LeftToRight
-
-
- Final
-
-
-
- :/Fractorium/Icons/add.png:/Fractorium/Icons/add.png
-
-
-
-
-
-
@@ -2255,6 +1919,9 @@
MS Shell Dlg 2
+
+
+
true
@@ -2294,6 +1961,9 @@ SpinBox
0
+
+ Color palette index for the current xform, and curve adjustment.
+
Color
@@ -2912,6 +2582,9 @@ SpinBox
0
+
+ Affine transforms for the current xform.
+
true
@@ -4270,12 +3943,12 @@ SpinBox
+
+ Full list of available variations and their weights for the currently selected xform.
+
Variations
-
- Full list of available variations and their weights for the currently selected xform.
-
6
@@ -4326,6 +3999,9 @@ SpinBox
X
+
+ false
+
@@ -4497,218 +4173,701 @@ SpinBox
-
+
+
+ Select multiple xforms to apply operations to.
+
- Xaos
+ Select
-
+
- 4
+ 3
- 6
+ 5
- 6
+ 4
- 6
+ 5
- 6
+ 4
-
-
+
+
+ Select All
+
+
+
+ -
+
+
+ Select None
+
+
+
+ -
+
-
+
0
0
-
-
- 0
- 67
-
+
+ Select Xforms
-
-
- 16777215
- 16777215
-
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
-
-
- true
-
-
-
- Qt::NoFocus
-
-
-
-
-
- QFrame::Panel
-
-
- QFrame::Plain
-
-
- 1
-
-
- Qt::ScrollBarAsNeeded
-
-
- Qt::ScrollBarAsNeeded
-
-
- QAbstractScrollArea::AdjustToContents
-
-
- false
-
-
- QAbstractItemView::NoEditTriggers
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- QAbstractItemView::NoSelection
-
-
- QAbstractItemView::ScrollPerPixel
-
-
- QAbstractItemView::ScrollPerPixel
-
-
- true
-
-
- Qt::SolidLine
-
-
- false
-
-
- false
-
-
- 3
-
-
- false
-
-
- true
-
-
- 40
-
-
- false
-
-
- 15
-
-
- false
-
-
- false
-
-
- true
-
-
- 22
-
-
- false
-
-
- 22
-
-
- false
-
-
-
-
+
+
+ 0
-
-
-
- F1
+
+ 0
-
-
-
- F2
+
+ 0
-
-
-
- F3
+
+ 0
-
- -
-
-
+
+ 0
-
- -
-
-
-
-
- -
-
-
-
-
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QFrame::NoFrame
+
+
+ QFrame::Plain
+
+
+ QAbstractScrollArea::AdjustToContents
+
+
+ true
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
+
+
+
+
+ 0
+ 0
+ 245
+ 682
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+ DeleteMeCheckBox
+
+
+
+ -
+
+
+ CheckBox
+
+
+
+
+
+
+
+
- -
-
-
-
-
-
- Set all xaos values in all xforms to 1
-
-
- Clear Xaos
-
-
-
- -
-
-
- Randomize all xaos values in all xforms
-
-
- Random Xaos
-
-
-
-
-
+ -
+
+
+ 2
+
+
-
+
+
+
+ 0
+ 22
+
+
+
+
+ 60
+ 22
+
+
+
+
+ 60
+ 16777215
+
+
+
+ Current xform
+
+
+ false
+
+
+ 12
+
+
+
+ 9
+ 9
+
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 25
+ 24
+
+
+
+
+ 16777215
+ 24
+
+
+
+ Add xform
+
+
+
+
+
+
+ :/Fractorium/Icons/add.png:/Fractorium/Icons/add.png
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 25
+ 24
+
+
+
+
+ 16777215
+ 24
+
+
+
+ Duplicate selected xforms
+
+
+
+
+
+
+ :/Fractorium/Icons/editraise.png:/Fractorium/Icons/editraise.png
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 25
+ 24
+
+
+
+
+ 16777215
+ 24
+
+
+
+ Clear selected xforms' variations
+
+
+
+
+
+
+ :/Fractorium/Icons/eraser.png:/Fractorium/Icons/eraser.png
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 25
+ 24
+
+
+
+
+ 16777215
+ 24
+
+
+
+ Delete selected xforms
+
+
+
+
+
+
+ :/Fractorium/Icons/del.png:/Fractorium/Icons/del.png
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 58
+ 24
+
+
+
+
+ 58
+ 24
+
+
+
+
+ 0
+ 0
+
+
+
+ Add final xform
+
+
+ Qt::LeftToRight
+
+
+ Final
+
+
+
+ :/Fractorium/Icons/add.png:/Fractorium/Icons/add.png
+
+
+
+
+
+ -
+
+
+
+ 2
+ 0
+
+
+
+
+ 0
+ 45
+
+
+
+
+ 16777215
+ 45
+
+
+
+
+ true
+
+
+
+ Qt::StrongFocus
+
+
+ false
+
+
+ QFrame::Panel
+
+
+ QFrame::Plain
+
+
+ Qt::ScrollBarAlwaysOff
+
+
+ Qt::ScrollBarAlwaysOff
+
+
+ false
+
+
+ QAbstractItemView::DoubleClicked|QAbstractItemView::SelectedClicked
+
+
+ false
+
+
+ QAbstractItemView::NoSelection
+
+
+ QAbstractItemView::ScrollPerPixel
+
+
+ QAbstractItemView::ScrollPerPixel
+
+
+ false
+
+
+ false
+
+
+ 1
+
+
+ 2
+
+
+ false
+
+
+ false
+
+
+ 27
+
+
+ true
+
+
+ false
+
+
+ 21
+
+
+ false
+
+
+ 21
+
+
+
+
+ Weight
+
+
+
+
+ Name
+
+
+ -
+
+ AlignLeft|AlignVCenter
+
+
+ -
+
+ AlignLeft|AlignVCenter
+
+
+
+
+
+
+
+
+ true
+
+
+ Xaos
+
+
+
+ 4
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 4
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 67
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+
+ true
+
+
+
+ Qt::NoFocus
+
+
+
+
+
+ QFrame::Panel
+
+
+ QFrame::Plain
+
+
+ 1
+
+
+ Qt::ScrollBarAsNeeded
+
+
+ Qt::ScrollBarAsNeeded
+
+
+ QAbstractScrollArea::AdjustToContents
+
+
+ false
+
+
+ QAbstractItemView::NoEditTriggers
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+ QAbstractItemView::NoSelection
+
+
+ QAbstractItemView::ScrollPerPixel
+
+
+ QAbstractItemView::ScrollPerPixel
+
+
+ true
+
+
+ Qt::SolidLine
+
+
+ false
+
+
+ false
+
+
+ 3
+
+
+ false
+
+
+ true
+
+
+ 35
+
+
+ false
+
+
+ 35
+
+
+ false
+
+
+ false
+
+
+ true
+
+
+ 22
+
+
+ false
+
+
+ 22
+
+
+ false
+
+
+
+
+
+
+
+
+ F1
+
+
+
+
+ F2
+
+
+
+
+ F3
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Set all xaos values in all xforms to 1
+
+
+ Clear Xaos
+
+
+
+ -
+
+
+ Randomize all xaos values in all xforms
+
+
+ Random Xaos
+
+
+
+
+
@@ -5073,6 +5232,9 @@ SpinBox
24
+
+ Apply a random adjustment to the current palette
+
Random Adjustment
@@ -6022,7 +6184,6 @@ SpinBox
VariationsFilterLineEdit
VariationsFilterClearButton
VariationsTree
- XaosTable
PaletteAdjustTable
PaletteListTable
scrollArea_5
diff --git a/Source/Fractorium/FractoriumEmberController.cpp b/Source/Fractorium/FractoriumEmberController.cpp
index 4fb3b8b..8185357 100644
--- a/Source/Fractorium/FractoriumEmberController.cpp
+++ b/Source/Fractorium/FractoriumEmberController.cpp
@@ -224,21 +224,79 @@ void FractoriumEmberController::Update(std::function func, bool
}
///
-/// Wrapper to call a function on the current xform, then optionally add the requested action to the rendering queue.
+/// Wrapper to call a function on the specified xforms, then optionally add the requested action to the rendering queue.
+/// If no xforms are selected via the checkboxes, and the update type is UPDATE_SELECTED, then the function will be called only on the currently selected xform.
///
/// The function to call
+/// Whether to apply this update operation on the current, all or selected xforms. Default: UPDATE_CURRENT.
/// True to update renderer, else false. Default: true.
/// The action to add to the rendering queue. Default: FULL_RENDER.
template
-void FractoriumEmberController::UpdateCurrentXform(std::function*)> func, bool updateRender, eProcessAction action)
+void FractoriumEmberController::UpdateXform(std::function*)> func, eXformUpdate updateType, bool updateRender, eProcessAction action)
{
- if (Xform* xform = CurrentXform())
- {
- func(xform);
+ size_t i = 0;
+ bool isCurrentFinal = m_Ember.IsFinalXform(CurrentXform());
+ bool doFinal = updateType != eXformUpdate::UPDATE_SELECTED_EXCEPT_FINAL && updateType != eXformUpdate::UPDATE_ALL_EXCEPT_FINAL;
- if (updateRender)
- UpdateRender(action);
+ switch (updateType)
+ {
+ case eXformUpdate::UPDATE_CURRENT:
+ {
+ if (Xform* xform = CurrentXform())
+ func(xform);
+ }
+ break;
+
+ case eXformUpdate::UPDATE_SELECTED:
+ case eXformUpdate::UPDATE_SELECTED_EXCEPT_FINAL:
+ {
+ bool anyUpdated = false;
+
+ while (Xform* xform = (doFinal ? m_Ember.GetTotalXform(i) : m_Ember.GetXform(i)))
+ {
+ if (QLayoutItem* child = m_Fractorium->m_XformsSelectionLayout->itemAt(i))
+ {
+ if (auto* w = dynamic_cast(child->widget()))
+ {
+ if (w->isChecked())
+ {
+ func(xform);
+ anyUpdated = true;
+ }
+ }
+ }
+
+ i++;
+ }
+
+ if (!anyUpdated)//None were selected, so just apply to the current.
+ if (doFinal || !isCurrentFinal)//If do final, call func regardless. If not, only call if current is not final.
+ if (Xform* xform = CurrentXform())
+ func(xform);
+ }
+
+ break;
+
+ case eXformUpdate::UPDATE_ALL:
+ {
+ while (Xform* xform = m_Ember.GetTotalXform(i++))
+ func(xform);
+ }
+
+ break;
+
+ case eXformUpdate::UPDATE_ALL_EXCEPT_FINAL:
+ default:
+ {
+ while (Xform* xform = m_Ember.GetXform(i++))
+ func(xform);
+ }
+
+ break;
}
+
+ if (updateRender)
+ UpdateRender(action);
}
///
@@ -276,7 +334,7 @@ void FractoriumEmberController::SetEmberPrivate(const Ember& ember, bool v
#endif
m_GLController->ResetMouseState();
- m_Fractorium->FillXforms();//Must do this first because the palette setup in FillParamTablesAndPalette() uses the xforms combo.
+ FillXforms();//Must do this first because the palette setup in FillParamTablesAndPalette() uses the xforms combo.
FillParamTablesAndPalette();
//If a resize happened, this won't do anything because the new size is not reflected in the scroll area yet.
diff --git a/Source/Fractorium/FractoriumEmberController.h b/Source/Fractorium/FractoriumEmberController.h
index 937936a..db9dd5a 100644
--- a/Source/Fractorium/FractoriumEmberController.h
+++ b/Source/Fractorium/FractoriumEmberController.h
@@ -11,7 +11,12 @@
///
/// An enum representing the type of edit being done.
///
-enum eEditUndoState : uint { REGULAR_EDIT = 0, UNDO_REDO = 1, EDIT_UNDO = 2 };
+enum eEditUndoState : uint { REGULAR_EDIT, UNDO_REDO, EDIT_UNDO };
+
+///
+/// An enum representing which xforms an update should be applied to.
+///
+enum eXformUpdate : uint { UPDATE_CURRENT, UPDATE_SELECTED, UPDATE_SELECTED_EXCEPT_FINAL, UPDATE_ALL, UPDATE_ALL_EXCEPT_FINAL };
///
/// FractoriumEmberController and Fractorium need each other, but each can't include the other.
@@ -58,8 +63,8 @@ public:
//virtual void Clear() { }
virtual void AddXform() { }
virtual void DuplicateXform() { }
- virtual void ClearCurrentXform() { }
- virtual void DeleteCurrentXform() { }
+ virtual void ClearXform() { }
+ virtual void DeleteXforms() { }
virtual void AddFinalXform() { }
virtual bool UseFinalXform() { return false; }
virtual size_t XformCount() const { return 0; }
@@ -145,20 +150,23 @@ public:
virtual void AffineInterpTypeChanged(int i) { }
virtual void InterpTypeChanged(int i) { }
virtual void BackgroundChanged(const QColor& color) { }
-
+ virtual void ClearColorCurves() { }
+ virtual void ColorCurveChanged(int curveIndex, int pointInxed, const QPointF& point) { }
+
//Xforms.
virtual void CurrentXformComboChanged(int index) { }
virtual void XformWeightChanged(double d) { }
virtual void EqualizeWeights() { }
virtual void XformNameChanged(int row, int col) { }
+ virtual void FillXforms() { }
//Xforms Affine.
virtual void AffineSetHelper(double d, int index, bool pre) { }
- virtual void FlipCurrentXform(bool horizontal, bool vertical, bool pre) { }
- virtual void RotateCurrentXformByAngle(double angle, bool pre) { }
- virtual void MoveCurrentXform(double x, double y, bool pre) { }
- virtual void ScaleCurrentXform(double scale, bool pre) { }
- virtual void ResetCurrentXformAffine(bool pre) { }
+ virtual void FlipXforms(bool horizontal, bool vertical, bool pre) { }
+ virtual void RotateXformsByAngle(double angle, bool pre) { }
+ virtual void MoveXforms(double x, double y, bool pre) { }
+ virtual void ScaleXforms(double scale, bool pre) { }
+ virtual void ResetXformsAffine(bool pre) { }
virtual void FillBothAffines() { }
//Xforms Color.
@@ -167,8 +175,6 @@ public:
virtual void XformColorSpeedChanged(double d) { }
virtual void XformOpacityChanged(double d) { }
virtual void XformDirectColorChanged(double d) { }
- virtual void ClearColorCurves() { }
- virtual void ColorCurveChanged(int curveIndex, int pointInxed, const QPointF& point) { }//need to put this in a different section because it's not xform specific.//TODO
void SetPaletteRefTable(QPixmap* pixmap);
//Xforms Variations.
@@ -176,7 +182,9 @@ public:
virtual void ClearVariationsTree() { }
virtual void VariationSpinBoxValueChanged(double d) { }
- //Xforms Xaos.
+ //Xforms Selection.
+
+ //Xaos.
virtual void FillXaos() { }
virtual QString MakeXaosNameString(uint i) { return ""; }
virtual void XaosChanged(DoubleSpinBox* sender) { }
@@ -281,8 +289,8 @@ public:
//virtual void Clear() override { }
virtual void AddXform() override;
virtual void DuplicateXform() override;
- virtual void ClearCurrentXform() override;
- virtual void DeleteCurrentXform() override;
+ virtual void ClearXform() override;
+ virtual void DeleteXforms() override;
virtual void AddFinalXform() override;
virtual bool UseFinalXform() override { return m_Ember.UseFinalXform(); }
//virtual bool IsFinal(uint i) { return false; }
@@ -371,22 +379,25 @@ public:
virtual void AffineInterpTypeChanged(int index) override;
virtual void InterpTypeChanged(int index) override;
virtual void BackgroundChanged(const QColor& col) override;
+ virtual void ClearColorCurves() override;
+ virtual void ColorCurveChanged(int curveIndex, int pointInxed, const QPointF& point) override;
//Xforms.
virtual void CurrentXformComboChanged(int index) override;
virtual void XformWeightChanged(double d) override;
virtual void EqualizeWeights() override;
virtual void XformNameChanged(int row, int col) override;
+ virtual void FillXforms() override;
void FillWithXform(Xform* xform);
Xform* CurrentXform();
//Xforms Affine.
virtual void AffineSetHelper(double d, int index, bool pre) override;
- virtual void FlipCurrentXform(bool horizontal, bool vertical, bool pre) override;
- virtual void RotateCurrentXformByAngle(double angle, bool pre) override;
- 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 FlipXforms(bool horizontal, bool vertical, bool pre) override;
+ virtual void RotateXformsByAngle(double angle, bool pre) override;
+ virtual void MoveXforms(double x, double y, bool pre) override;
+ virtual void ScaleXforms(double scale, bool pre) override;
+ virtual void ResetXformsAffine(bool pre) override;
virtual void FillBothAffines() override;
void FillAffineWithXform(Xform* xform, bool pre);
@@ -396,8 +407,6 @@ public:
virtual void XformColorSpeedChanged(double d) override;
virtual void XformOpacityChanged(double d) override;
virtual void XformDirectColorChanged(double d) override;
- virtual void ClearColorCurves() override;
- virtual void ColorCurveChanged(int curveIndex, int pointInxed, const QPointF& point) override;
void FillColorWithXform(Xform* xform);
//Xforms Variations.
@@ -444,15 +453,20 @@ private:
bool IsFinal(Xform* xform);
//Xforms Color.
- void SetCurrentXformColorIndex(double d);
+ void SetCurrentXformColorIndex(double d, bool updateRender);
void FillCurvesControl();
+ //Xforms Selection.
+ QString MakeXformCaption(size_t i);
+ bool XformCheckboxAt(int i, std::function func);
+ bool XformCheckboxAt(Xform* xform, std::function func);
+ void UpdateXform(std::function*)> func, eXformUpdate updateType = eXformUpdate::UPDATE_CURRENT, bool updateRender = true, eProcessAction action = FULL_RENDER);
+
//Palette.
void UpdateAdjustedPaletteGUI(Palette& palette);
//Rendering/progress.
void Update(std::function func, bool updateRender = true, eProcessAction action = FULL_RENDER);
- void UpdateCurrentXform(std::function*)> func, bool updateRender = true, eProcessAction action = FULL_RENDER);
bool SyncSizes();
//Templated members.
diff --git a/Source/Fractorium/FractoriumMenus.cpp b/Source/Fractorium/FractoriumMenus.cpp
index d97b960..8ae234a 100644
--- a/Source/Fractorium/FractoriumMenus.cpp
+++ b/Source/Fractorium/FractoriumMenus.cpp
@@ -618,10 +618,12 @@ void FractoriumEmberController::AddReflectiveSymmetry()
{
QComboBox* combo = m_Fractorium->ui.CurrentXformCombo;
- m_Ember.AddSymmetry(-1, m_Rand);
- m_Fractorium->FillXforms();
- combo->setCurrentIndex(combo->count() - (m_Fractorium->HaveFinal() ? 2 : 1));//Set index to the last item before final.
- UpdateRender();
+ Update([&]()
+ {
+ m_Ember.AddSymmetry(-1, m_Rand);
+ FillXforms();
+ combo->setCurrentIndex(combo->count() - (m_Fractorium->HaveFinal() ? 2 : 1));//Set index to the last item before final.
+ });
}
void Fractorium::OnActionAddReflectiveSymmetry(bool checked) { m_Controller->AddReflectiveSymmetry(); }
@@ -635,10 +637,12 @@ void FractoriumEmberController::AddRotationalSymmetry()
{
QComboBox* combo = m_Fractorium->ui.CurrentXformCombo;
- m_Ember.AddSymmetry(2, m_Rand);
- m_Fractorium->FillXforms();
- combo->setCurrentIndex(combo->count() - (m_Fractorium->HaveFinal() ? 2 : 1));//Set index to the last item before final.
- UpdateRender();
+ Update([&]()
+ {
+ m_Ember.AddSymmetry(2, m_Rand);
+ FillXforms();
+ combo->setCurrentIndex(combo->count() - (m_Fractorium->HaveFinal() ? 2 : 1));//Set index to the last item before final.
+ });
}
void Fractorium::OnActionAddRotationalSymmetry(bool checked) { m_Controller->AddRotationalSymmetry(); }
@@ -652,10 +656,12 @@ void FractoriumEmberController::AddBothSymmetry()
{
QComboBox* combo = m_Fractorium->ui.CurrentXformCombo;
- m_Ember.AddSymmetry(-2, m_Rand);
- m_Fractorium->FillXforms();
- combo->setCurrentIndex(combo->count() - (m_Fractorium->HaveFinal() ? 2 : 1));//Set index to the last item before final.
- UpdateRender();
+ Update([&]()
+ {
+ m_Ember.AddSymmetry(-2, m_Rand);
+ FillXforms();
+ combo->setCurrentIndex(combo->count() - (m_Fractorium->HaveFinal() ? 2 : 1));//Set index to the last item before final.
+ });
}
void Fractorium::OnActionAddBothSymmetry(bool checked) { m_Controller->AddBothSymmetry(); }
@@ -665,7 +671,7 @@ void Fractorium::OnActionAddBothSymmetry(bool checked) { m_Controller->AddBothSy
/// Resets the rendering process.
///
template
-void FractoriumEmberController::Flatten() { UpdateCurrentXform([&] (Xform* xform) { m_Ember.Flatten(XmlToEmber::m_FlattenNames); FillVariationTreeWithXform(xform); }); }
+void FractoriumEmberController::Flatten() { UpdateXform([&] (Xform* xform) { m_Ember.Flatten(XmlToEmber::m_FlattenNames); FillVariationTreeWithXform(xform); }); }
void Fractorium::OnActionFlatten(bool checked) { m_Controller->Flatten(); }
///
@@ -673,7 +679,7 @@ void Fractorium::OnActionFlatten(bool checked) { m_Controller->Flatten(); }
/// Resets the rendering process.
///
template
-void FractoriumEmberController::Unflatten() { UpdateCurrentXform([&] (Xform* xform) { m_Ember.Unflatten(); FillVariationTreeWithXform(xform); }); }
+void FractoriumEmberController::Unflatten() { UpdateXform([&] (Xform* xform) { m_Ember.Unflatten(); FillVariationTreeWithXform(xform); }); }
void Fractorium::OnActionUnflatten(bool checked) { m_Controller->Unflatten(); }
///
@@ -684,21 +690,23 @@ void Fractorium::OnActionUnflatten(bool checked) { m_Controller->Unflatten(); }
template
void FractoriumEmberController::ClearFlame()
{
- while (m_Ember.TotalXformCount() > 1)
- m_Ember.DeleteTotalXform(m_Ember.TotalXformCount() - 1);
-
- if (m_Ember.XformCount() == 1)
+ Update([&]()
{
- if (Xform* xform = m_Ember.GetXform(0))
- {
- xform->Clear();
- xform->ParentEmber(&m_Ember);
- }
- }
+ while (m_Ember.TotalXformCount() > 1)
+ m_Ember.DeleteTotalXform(m_Ember.TotalXformCount() - 1);
- m_Fractorium->FillXforms();
- m_Fractorium->ui.CurrentXformCombo->setCurrentIndex(0);
- UpdateRender();
+ if (m_Ember.XformCount() == 1)
+ {
+ if (Xform* xform = m_Ember.GetXform(0))
+ {
+ xform->Clear();
+ xform->ParentEmber(&m_Ember);
+ }
+ }
+
+ FillXforms();
+ m_Fractorium->ui.CurrentXformCombo->setCurrentIndex(0);
+ });
}
void Fractorium::OnActionClearFlame(bool checked) { m_Controller->ClearFlame(); }
diff --git a/Source/Fractorium/FractoriumPalette.cpp b/Source/Fractorium/FractoriumPalette.cpp
index fa1c7ac..697990f 100644
--- a/Source/Fractorium/FractoriumPalette.cpp
+++ b/Source/Fractorium/FractoriumPalette.cpp
@@ -202,7 +202,7 @@ void FractoriumEmberController::UpdateAdjustedPaletteGUI(Palette& palette)
template
void FractoriumEmberController::PaletteAdjust()
{
- UpdateCurrentXform([&] (Xform* xform)
+ Update([&]()
{
ApplyPaletteToEmber();
UpdateAdjustedPaletteGUI(m_Ember.m_Palette);
diff --git a/Source/Fractorium/FractoriumXaos.cpp b/Source/Fractorium/FractoriumXaos.cpp
index 848f6d7..d72f278 100644
--- a/Source/Fractorium/FractoriumXaos.cpp
+++ b/Source/Fractorium/FractoriumXaos.cpp
@@ -4,7 +4,7 @@
///
/// Initialize the xforms xaos UI.
///
-void Fractorium::InitXformsXaosUI()
+void Fractorium::InitXaosUI()
{
connect(ui.ClearXaosButton, SIGNAL(clicked(bool)), this, SLOT(OnClearXaosButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.RandomXaosButton, SIGNAL(clicked(bool)), this, SLOT(OnRandomXaosButtonClicked(bool)), Qt::QueuedConnection);
@@ -88,6 +88,7 @@ void Fractorium::FillXaosTable()
QWidget* w = nullptr;
QString lbl("lbl");
+ ui.XaosTable->blockSignals(true);
ui.XaosTable->setRowCount(count);//This will grow or shrink the number of rows and call the destructor for previous DoubleSpinBoxes.
ui.XaosTable->setColumnCount(count);
@@ -137,6 +138,7 @@ void Fractorium::FillXaosTable()
w = SetTabOrder(this, w, ui.ClearXaosButton);
w = SetTabOrder(this, w, ui.RandomXaosButton);
+ ui.XaosTable->blockSignals(false);
}
///
diff --git a/Source/Fractorium/FractoriumXforms.cpp b/Source/Fractorium/FractoriumXforms.cpp
index 3381fca..4b3e1e8 100644
--- a/Source/Fractorium/FractoriumXforms.cpp
+++ b/Source/Fractorium/FractoriumXforms.cpp
@@ -30,7 +30,7 @@ void Fractorium::InitXformsUI()
connect(ui.XformWeightNameTable, SIGNAL(cellChanged(int, int)), this, SLOT(OnXformNameChanged(int, int)), Qt::QueuedConnection);
ui.CurrentXformCombo->setProperty("soloxform", -1);
-
+
#ifndef WIN32
//For some reason linux makes these 24x24, even though the designer explicitly says 16x16.
ui.AddXformButton->setIconSize(QSize(16, 16));
@@ -101,7 +101,7 @@ void Fractorium::OnCurrentXformComboChanged(int index) { m_Controller->CurrentXf
template
void FractoriumEmberController::AddXform()
{
- UpdateCurrentXform([&] (Xform* xform)
+ Update([&]()
{
Xform newXform;
QComboBox* combo = m_Fractorium->ui.CurrentXformCombo;
@@ -109,7 +109,7 @@ void FractoriumEmberController::AddXform()
newXform.m_Weight = 0.25;
newXform.m_ColorX = m_Rand.Frand01();
m_Ember.AddXform(newXform);
- m_Fractorium->FillXforms();
+ FillXforms();
combo->setCurrentIndex(combo->count() - (m_Fractorium->HaveFinal() ? 2 : 1));//Set index to the last item before final.
});
}
@@ -117,7 +117,7 @@ void FractoriumEmberController::AddXform()
void Fractorium::OnAddXformButtonClicked(bool checked) { m_Controller->AddXform(); }
///
-/// Duplicate the current xform in the current ember, and set it as the current xform.
+/// Duplicate the specified xforms in the current ember, and set the last one as the current xform.
/// Called when the duplicate xform button is clicked.
/// Resets the rendering process.
///
@@ -125,71 +125,112 @@ void Fractorium::OnAddXformButtonClicked(bool checked) { m_Controller->AddXform(
template
void FractoriumEmberController::DuplicateXform()
{
- UpdateCurrentXform([&] (Xform* xform)
+ vector> vec;
+
+ vec.reserve(m_Ember.XformCount());
+
+ UpdateXform([&] (Xform* xform)
+ {
+ vec.push_back(*xform);
+ }, eXformUpdate::UPDATE_SELECTED_EXCEPT_FINAL, false);
+
+ Update([&]()
{
QComboBox* combo = m_Fractorium->ui.CurrentXformCombo;
- if (xform && !IsFinal(xform))
- {
- m_Ember.AddXform(*xform);
- m_Fractorium->FillXforms();
- combo->setCurrentIndex(combo->count() - (m_Fractorium->HaveFinal() ? 2 : 1));//Set index to the last item before final.
- }
+ for (auto& it : vec)
+ m_Ember.AddXform(it);
+
+ FillXforms();//Handles xaos.
+ combo->setCurrentIndex(combo->count() - (m_Fractorium->HaveFinal() ? 2 : 1));//Set index to the last item before final.
});
}
void Fractorium::OnDuplicateXformButtonClicked(bool checked) { m_Controller->DuplicateXform(); }
///
-/// Clear all variations from the current xform, affine, palette and xaos are left untouched.
+/// Clear all variations from the selected xforms. Affine, palette and xaos are left untouched.
/// Called when the clear xform button is clicked.
/// Resets the rendering process.
///
/// Ignored
template
-void FractoriumEmberController::ClearCurrentXform()
+void FractoriumEmberController::ClearXform()
{
- UpdateCurrentXform([&] (Xform* xform)
+ UpdateXform([&] (Xform* xform)
{
- xform->ClearAndDeleteVariations();
- //Note xaos is left alone.
- FillVariationTreeWithXform(xform);
- });
+ xform->ClearAndDeleteVariations();//Note xaos is left alone.
+ }, eXformUpdate::UPDATE_SELECTED);
+
+ FillVariationTreeWithXform(CurrentXform());
}
-void Fractorium::OnClearXformButtonClicked(bool checked) { m_Controller->ClearCurrentXform(); }
+void Fractorium::OnClearXformButtonClicked(bool checked) { m_Controller->ClearXform(); }
///
-/// Delete the current xform.
+/// Delete the selected xforms.
/// Will not delete the last remaining non-final xform.
/// Called when the delete xform button is clicked.
/// Resets the rendering process.
///
/// Ignored
template
-void FractoriumEmberController::DeleteCurrentXform()
+void FractoriumEmberController::DeleteXforms()
{
- UpdateCurrentXform([&] (Xform* xform)
+ int i = 0, offset = 0, current = 0, checked = 0;
+ bool haveFinal = false;
+ size_t count;
+ QComboBox* combo = m_Fractorium->ui.CurrentXformCombo;
+
+ //Iterating over the checkboxes must be done instead of using UpdateXform() to iterate over xforms
+ //because xforms are being deleted inside the loop.
+ //Also manually calling UpdateRender() rather than using the usual Update() call because
+ //it should only be called if an xform has actually been deleted.
+ m_Fractorium->ForEachXformCheckbox([&](int i, QCheckBox* w)
{
- bool haveFinal = m_Fractorium->HaveFinal();
- QComboBox* combo = m_Fractorium->ui.CurrentXformCombo;
- int count = combo->count();
- int index = combo->currentIndex();
+ count = m_Ember.TotalXformCount();
+ haveFinal = m_Ember.UseFinalXform();//Requery every time.
+
+ if (w->isChecked())
+ checked++;
//Do not allow deleting the only remaining non-final xform.
- if (haveFinal && count <= 2 && index == 0)
+ if (haveFinal && count <= 2 && i == 0)
return;
if (!haveFinal && count == 1)
return;
- m_Ember.DeleteTotalXform(index);
- m_Fractorium->FillXforms();
- combo->setCurrentIndex(combo->count() - (haveFinal ? 2 : 1));//Set index to the last item before final.
+ if (w->isChecked())
+ {
+ //qDebug() << "Deleting " << w->text();
+ m_Ember.DeleteTotalXform(i - offset);//Subtract offset to account for previously deleted xforms.
+ offset++;
+ }
});
+
+ current = combo->currentIndex();
+ count = m_Ember.TotalXformCount();
+ haveFinal = m_Ember.UseFinalXform();//Requery again.
+
+ //Nothing was selected, so just delete current.
+ if (!checked &&
+ !(haveFinal && count <= 2 && current == 0) &&//Again disallow deleting the only remaining non-final xform.
+ !(!haveFinal && count == 1))
+ {
+ m_Ember.DeleteTotalXform(current);
+ offset++;
+ }
+
+ if (offset)
+ {
+ FillXforms();
+ combo->setCurrentIndex(combo->count() - (m_Ember.UseFinalXform() ? 2 : 1));//Set index to the last item before final. Note final is requeried one last time.
+ UpdateRender();
+ }
}
-void Fractorium::OnDeleteXformButtonClicked(bool checked) { m_Controller->DeleteCurrentXform(); }
+void Fractorium::OnDeleteXformButtonClicked(bool checked) { m_Controller->DeleteXforms(); }
///
/// Add a final xform to the ember and set it as the current xform.
@@ -201,26 +242,26 @@ void Fractorium::OnDeleteXformButtonClicked(bool checked) { m_Controller->Delete
template
void FractoriumEmberController::AddFinalXform()
{
- QComboBox* combo = m_Fractorium->ui.CurrentXformCombo;
-
//Check to see if a final xform is already present.
if (!m_Fractorium->HaveFinal())
{
- Xform xform;
+ Update([&]()
+ {
+ Xform final;
+ auto combo = m_Fractorium->ui.CurrentXformCombo;
- xform.AddVariation(new LinearVariation());//Just a placeholder so other parts of the code don't see it as being empty.
- m_Ember.SetFinalXform(xform);
- combo->addItem("Final");
- combo->setItemIcon(combo->count() - 1, m_Fractorium->m_FinalXformComboIcon);
- combo->setCurrentIndex(combo->count() - 1);//Set index to the last item.
- UpdateRender();
+ final.AddVariation(new LinearVariation());//Just a placeholder so other parts of the code don't see it as being empty.
+ m_Ember.SetFinalXform(final);
+ FillXforms();
+ combo->setCurrentIndex(combo->count() - 1);//Set index to the last item.
+ });
}
}
void Fractorium::OnAddFinalXformButtonClicked(bool checked) { m_Controller->AddFinalXform(); }
///
-/// Set the weight of the current xform.
+/// Set the weight of the selected xforms.
/// Called when weight spinner changes.
/// Resets the rendering process.
///
@@ -228,11 +269,12 @@ void Fractorium::OnAddFinalXformButtonClicked(bool checked) { m_Controller->AddF
template
void FractoriumEmberController::XformWeightChanged(double d)
{
- UpdateCurrentXform([&] (Xform* xform)
+ UpdateXform([&] (Xform* xform)
{
xform->m_Weight = d;
- SetNormalizedWeightText(xform);
- });
+ }, eXformUpdate::UPDATE_SELECTED_EXCEPT_FINAL);
+
+ SetNormalizedWeightText(CurrentXform());
}
void Fractorium::OnXformWeightChanged(double d) { m_Controller->XformWeightChanged(d); }
@@ -243,17 +285,18 @@ void Fractorium::OnXformWeightChanged(double d) { m_Controller->XformWeightChang
template
void FractoriumEmberController::EqualizeWeights()
{
- UpdateCurrentXform([&] (Xform* xform)
+ UpdateXform([&] (Xform* xform)
{
m_Ember.EqualizeWeights();
m_Fractorium->m_XformWeightSpin->setValue(xform->m_Weight);//Will trigger an update, so pass false to updateRender below.
- }, false);
+ }, eXformUpdate::UPDATE_CURRENT, false);
}
void Fractorium::OnEqualWeightButtonClicked(bool checked) { m_Controller->EqualizeWeights(); }
///
/// Set the name of the current xform.
+/// Update the corresponding xform checkbox text with the name.
/// Called when the user types in the name cell of the table.
///
/// The row of the cell
@@ -261,18 +304,18 @@ void Fractorium::OnEqualWeightButtonClicked(bool checked) { m_Controller->Equali
template
void FractoriumEmberController::XformNameChanged(int row, int col)
{
- UpdateCurrentXform([&] (Xform* xform)
+ UpdateXform([&] (Xform* xform)
{
- int index = m_Ember.GetXformIndex(xform);
+ int index = m_Ember.GetTotalXformIndex(xform);
xform->m_Name = m_Fractorium->ui.XformWeightNameTable->item(row, col)->text().toStdString();
-
+ XformCheckboxAt(index, [&](QCheckBox* checkbox) { checkbox->setText(MakeXformCaption(index)); });
//if (index != -1)
//{
// if (QTableWidgetItem* xformNameItem = m_Fractorium->ui.XaosTable->item(index, 0))
// xformNameItem->setText(MakeXaosNameString(index));
//}
- }, false);
+ }, eXformUpdate::UPDATE_CURRENT, false);
}
void Fractorium::OnXformNameChanged(int row, int col) { m_Controller->XformNameChanged(row, col); }
@@ -282,7 +325,7 @@ void Fractorium::OnXformNameChanged(int row, int col) { m_Controller->XformNameC
///
/// The xform whose values will be used to populate the widgets
template
-void FractoriumEmberController::FillWithXform(Xform* xform)
+void FractoriumEmberController::FillWithXform(Xform* xform)//Need to see where all this is called from and sync with FillXform(). Maybe rename the latter.
{
m_Fractorium->m_XformWeightSpin->SetValueStealth(xform->m_Weight);
SetNormalizedWeightText(xform);
@@ -332,32 +375,71 @@ bool FractoriumEmberController::IsFinal(Xform* xform)
///
/// Fill the xforms combo box with the xforms in the current ember.
/// Select the first one and fill all widgets with its values.
+/// Also dynamically generate a checkbox for each xform which will allow the user
+/// to select which xforms to apply operations to.
///
-void Fractorium::FillXforms()
+template
+void FractoriumEmberController::FillXforms()
{
- int i = 0, spinHeight = 20;
- QComboBox* combo = ui.CurrentXformCombo;
+ int i = 0, count = int(XformCount());
+ auto combo = m_Fractorium->ui.CurrentXformCombo;
combo->blockSignals(true);
combo->clear();
- for (i = 0; i < int(m_Controller->XformCount()); i++)
+ //First clear all dynamically created checkboxes.
+ m_Fractorium->ClearXformsSelections();
+ m_Fractorium->m_XformsSelectionLayout->blockSignals(true);
+
+ //Fill combo box and create new checkboxes.
+ for (i = 0; i < count; i++)
{
combo->addItem(ToString(i + 1));
- combo->setItemIcon(i, m_XformComboIcons[i % XFORM_COLOR_COUNT]);
+ combo->setItemIcon(i, m_Fractorium->m_XformComboIcons[i % XFORM_COLOR_COUNT]);
}
- if (m_Controller->UseFinalXform())
+ i = 0;
+ while (i < count)
{
- combo->addItem("Final");
- combo->setItemIcon(i, m_FinalXformComboIcon);
+ if (i < count - 1)
+ {
+ auto cb1 = new QCheckBox(MakeXformCaption(i), m_Fractorium);
+ auto cb2 = new QCheckBox(MakeXformCaption(i + 1), m_Fractorium);
+
+ m_Fractorium->m_XformSelections.push_back(cb1);
+ m_Fractorium->m_XformSelections.push_back(cb2);
+ m_Fractorium->m_XformsSelectionLayout->addRow(cb1, cb2);
+ i += 2;
+ }
+ else if (i < count)
+ {
+ auto cb = new QCheckBox(MakeXformCaption(i), m_Fractorium);
+
+ m_Fractorium->m_XformSelections.push_back(cb);
+ m_Fractorium->m_XformsSelectionLayout->addRow(cb, new QWidget(m_Fractorium));
+ i++;
+ }
}
-
+
+ //Special case for final xform.
+ if (UseFinalXform())
+ {
+ auto cb = new QCheckBox(MakeXformCaption(i), m_Fractorium);
+
+ m_Fractorium->m_XformSelections.push_back(cb);
+ m_Fractorium->m_XformsSelectionLayout->addRow(cb, new QWidget(m_Fractorium));
+
+ combo->addItem("Final");
+ combo->setItemIcon(i, m_Fractorium->m_FinalXformComboIcon);
+ }
+
+ m_Fractorium->m_XformsSelectionLayout->blockSignals(false);
combo->blockSignals(false);
combo->setCurrentIndex(0);
- FillXaosTable();
- OnSoloXformCheckBoxStateChanged(Qt::Unchecked);
- OnCurrentXformComboChanged(0);//Make sure the event gets called, because it won't if the zero index is already selected.
+
+ m_Fractorium->FillXaosTable();
+ m_Fractorium->OnSoloXformCheckBoxStateChanged(Qt::Unchecked);
+ m_Fractorium->OnCurrentXformComboChanged(0);//Make sure the event gets called, because it won't if the zero index is already selected.
}
template class FractoriumEmberController;
diff --git a/Source/Fractorium/FractoriumXformsAffine.cpp b/Source/Fractorium/FractoriumXformsAffine.cpp
index 1d2bfbd..783d0a8 100644
--- a/Source/Fractorium/FractoriumXformsAffine.cpp
+++ b/Source/Fractorium/FractoriumXformsAffine.cpp
@@ -169,7 +169,7 @@ void Fractorium::InitXformsAffineUI()
template
void FractoriumEmberController::AffineSetHelper(double d, int index, bool pre)
{
- UpdateCurrentXform([&] (Xform* xform)
+ UpdateXform([&] (Xform* xform)
{
Affine2D* affine = pre ? &xform->m_Affine : &xform->m_Post;
DoubleSpinBox** spinners = pre ? m_Fractorium->m_PreSpins : m_Fractorium->m_PostSpins;
@@ -220,7 +220,7 @@ void FractoriumEmberController::AffineSetHelper(double d, int index, bool pre
break;
}
}
- });
+ }, eXformUpdate::UPDATE_SELECTED);
}
///
@@ -235,16 +235,16 @@ void Fractorium::OnO1Changed(double d) { m_Controller->AffineSetHelper(d, 2, sen
void Fractorium::OnO2Changed(double d) { m_Controller->AffineSetHelper(d, 5, sender() == m_PreO2Spin); }
///
-/// Flip the current pre/post affine vertically and/or horizontally.
+/// Flip the selected pre/post affines vertically and/or horizontally.
/// Resets the rendering process.
///
/// True to flip horizontally
/// True to flip vertically
/// True if pre affine, else post affine.
template
-void FractoriumEmberController::FlipCurrentXform(bool horizontal, bool vertical, bool pre)
+void FractoriumEmberController::FlipXforms(bool horizontal, bool vertical, bool pre)
{
- UpdateCurrentXform([&] (Xform* xform)
+ UpdateXform([&] (Xform* xform)
{
Affine2D* affine = pre ? &xform->m_Affine : &xform->m_Post;
@@ -266,29 +266,31 @@ void FractoriumEmberController::FlipCurrentXform(bool horizontal, bool vertic
affine->F(-affine->F());
}
- FillAffineWithXform(xform, pre);
- });
+ }, eXformUpdate::UPDATE_SELECTED);
+
+ FillAffineWithXform(CurrentXform(), pre);
}
-void Fractorium::OnFlipHorizontalButtonClicked(bool checked) { m_Controller->FlipCurrentXform(true, false, sender() == ui.PreFlipHorizontalButton); }
-void Fractorium::OnFlipVerticalButtonClicked(bool checked) { m_Controller->FlipCurrentXform(false, true, sender() == ui.PreFlipVerticalButton); }
+void Fractorium::OnFlipHorizontalButtonClicked(bool checked) { m_Controller->FlipXforms(true, false, sender() == ui.PreFlipHorizontalButton); }
+void Fractorium::OnFlipVerticalButtonClicked(bool checked) { m_Controller->FlipXforms(false, true, sender() == ui.PreFlipVerticalButton); }
///
-/// Rotate the current pre/post affine transform x degrees.
+/// Rotate the selected pre/post affines transform x degrees.
/// Resets the rendering process.
///
/// The angle to rotate by
/// True if pre affine, else post affine.
template
-void FractoriumEmberController::RotateCurrentXformByAngle(double angle, bool pre)
+void FractoriumEmberController::RotateXformsByAngle(double angle, bool pre)
{
- UpdateCurrentXform([&] (Xform* xform)
+ UpdateXform([&] (Xform* xform)
{
Affine2D* affine = pre ? &xform->m_Affine : &xform->m_Post;
affine->Rotate(angle);
- FillAffineWithXform(xform, pre);
- });
+ }, eXformUpdate::UPDATE_SELECTED);
+
+ FillAffineWithXform(CurrentXform(), pre);
}
///
@@ -297,8 +299,8 @@ void FractoriumEmberController::RotateCurrentXformByAngle(double angle, bool
/// Resets the rendering process.
///
/// Ignored
-void Fractorium::OnRotate90CButtonClicked(bool checked) { m_Controller->RotateCurrentXformByAngle(90, sender() == ui.PreRotate90CButton); }
-void Fractorium::OnRotate90CcButtonClicked(bool checked) { m_Controller->RotateCurrentXformByAngle(-90, sender() == ui.PreRotate90CcButton); }
+void Fractorium::OnRotate90CButtonClicked(bool checked) { m_Controller->RotateXformsByAngle(90, sender() == ui.PreRotate90CButton); }
+void Fractorium::OnRotate90CcButtonClicked(bool checked) { m_Controller->RotateXformsByAngle(-90, sender() == ui.PreRotate90CcButton); }
///
/// Rotate the selected pre/post affine transform x degrees clockwise.
@@ -314,7 +316,7 @@ void Fractorium::OnRotateCButtonClicked(bool checked)
double d = ToDouble(combo->currentText(), &ok);
if (ok)
- m_Controller->RotateCurrentXformByAngle(d, pre);
+ m_Controller->RotateXformsByAngle(d, pre);
}
///
@@ -331,27 +333,28 @@ void Fractorium::OnRotateCcButtonClicked(bool checked)
double d = ToDouble(combo->currentText(), &ok);
if (ok)
- m_Controller->RotateCurrentXformByAngle(-d, pre);
+ m_Controller->RotateXformsByAngle(-d, pre);
}
///
-/// Move the current pre/post affine in the x and y directions by the specified amount.
+/// Move the selected pre/post affines in the x and y directions by the specified amount.
/// Resets the rendering process.
///
/// The x direction to move
/// The y direction to move
/// True if pre affine, else post affine.
template
-void FractoriumEmberController::MoveCurrentXform(double x, double y, bool pre)
+void FractoriumEmberController::MoveXforms(double x, double y, bool pre)
{
- UpdateCurrentXform([&] (Xform* xform)
+ UpdateXform([&] (Xform* xform)
{
Affine2D* affine = pre ? &xform->m_Affine : &xform->m_Post;
affine->C(affine->C() + x);
affine->F(affine->F() + y);
- FillAffineWithXform(xform, pre);
- });
+ }, eXformUpdate::UPDATE_SELECTED);
+
+ FillAffineWithXform(CurrentXform(), pre);
}
///
@@ -368,7 +371,7 @@ void Fractorium::OnMoveUpButtonClicked(bool checked)
double d = ToDouble(combo->currentText(), &ok);
if (ok)
- m_Controller->MoveCurrentXform(0, d, pre);
+ m_Controller->MoveXforms(0, d, pre);
}
///
@@ -385,7 +388,7 @@ void Fractorium::OnMoveDownButtonClicked(bool checked)
double d = ToDouble(combo->currentText(), &ok);
if (ok)
- m_Controller->MoveCurrentXform(0, -d, pre);
+ m_Controller->MoveXforms(0, -d, pre);
}
///
@@ -402,7 +405,7 @@ void Fractorium::OnMoveLeftButtonClicked(bool checked)
double d = ToDouble(combo->currentText(), &ok);
if (ok)
- m_Controller->MoveCurrentXform(-d, 0, pre);
+ m_Controller->MoveXforms(-d, 0, pre);
}
///
@@ -419,19 +422,19 @@ void Fractorium::OnMoveRightButtonClicked(bool checked)
double d = ToDouble(combo->currentText(), &ok);
if (ok)
- m_Controller->MoveCurrentXform(d, 0, pre);
+ m_Controller->MoveXforms(d, 0, pre);
}
///
-/// Scale the current pre/post affine by the specified amount.
+/// Scale the selected pre/post affines by the specified amount.
/// Resets the rendering process.
///
/// The scale value
/// True if pre affine, else post affine.
template
-void FractoriumEmberController::ScaleCurrentXform(double scale, bool pre)
+void FractoriumEmberController::ScaleXforms(double scale, bool pre)
{
- UpdateCurrentXform([&] (Xform* xform)
+ UpdateXform([&] (Xform* xform)
{
Affine2D* affine = pre ? &xform->m_Affine : &xform->m_Post;
@@ -439,8 +442,9 @@ void FractoriumEmberController::ScaleCurrentXform(double scale, bool pre)
affine->B(affine->B() * scale);
affine->D(affine->D() * scale);
affine->E(affine->E() * scale);
- FillAffineWithXform(xform, pre);
- });
+ }, eXformUpdate::UPDATE_SELECTED);
+
+ FillAffineWithXform(CurrentXform(), pre);
}
///
@@ -457,7 +461,7 @@ void Fractorium::OnScaleDownButtonClicked(bool checked)
double d = ToDouble(combo->currentText(), &ok);
if (ok)
- m_Controller->ScaleCurrentXform(1.0 / (d / 100.0), pre);
+ m_Controller->ScaleXforms(1.0 / (d / 100.0), pre);
}
///
@@ -474,24 +478,25 @@ void Fractorium::OnScaleUpButtonClicked(bool checked)
double d = ToDouble(combo->currentText(), &ok);
if (ok)
- m_Controller->ScaleCurrentXform(d / 100.0, pre);
+ m_Controller->ScaleXforms(d / 100.0, pre);
}
///
-/// Reset pre/post affine to the identity matrix.
+/// Reset selected pre/post affines to the identity matrix.
/// Called when reset pre/post affine buttons are clicked.
/// Resets the rendering process.
///
template
-void FractoriumEmberController::ResetCurrentXformAffine(bool pre)
+void FractoriumEmberController::ResetXformsAffine(bool pre)
{
- UpdateCurrentXform([&] (Xform* xform)
+ UpdateXform([&] (Xform* xform)
{
Affine2D* affine = pre ? &xform->m_Affine : &xform->m_Post;
affine->MakeID();
- FillAffineWithXform(xform, pre);
- });
+ }, eXformUpdate::UPDATE_SELECTED);
+
+ FillAffineWithXform(CurrentXform(), pre);
}
///
@@ -499,7 +504,7 @@ void FractoriumEmberController::ResetCurrentXformAffine(bool pre)
/// Called when reset pre/post affine buttons are clicked.
/// Resets the rendering process.
///
-void Fractorium::OnResetAffineButtonClicked(bool checked) { m_Controller->ResetCurrentXformAffine(sender() == ui.PreResetButton); }
+void Fractorium::OnResetAffineButtonClicked(bool checked) { m_Controller->ResetXformsAffine(sender() == ui.PreResetButton); }
///
/// Fill the GUI with the pre and post affine xform values.
diff --git a/Source/Fractorium/FractoriumXformsColor.cpp b/Source/Fractorium/FractoriumXformsColor.cpp
index 594d17d..6c7474a 100644
--- a/Source/Fractorium/FractoriumXformsColor.cpp
+++ b/Source/Fractorium/FractoriumXformsColor.cpp
@@ -37,7 +37,7 @@ void Fractorium::InitXformsColorUI()
}
///
-/// Set the color index of the current xform.
+/// Set the color index of the selected xforms.
/// Update the color index scrollbar to match.
/// Called when spinner in the color index cell in the palette ref table is changed.
/// Optionally resets the rendering process.
@@ -47,17 +47,14 @@ void Fractorium::InitXformsColorUI()
template
void FractoriumEmberController::XformColorIndexChanged(double d, bool updateRender)
{
- UpdateCurrentXform([&] (Xform* xform)
- {
- QScrollBar* scroll = m_Fractorium->ui.XformColorScroll;
- int scrollVal = d * scroll->maximum();
+ auto scroll = m_Fractorium->ui.XformColorScroll;
+ int scrollVal = d * scroll->maximum();
- scroll->blockSignals(true);
- scroll->setValue(scrollVal);
- scroll->blockSignals(false);
+ scroll->blockSignals(true);
+ scroll->setValue(scrollVal);
+ scroll->blockSignals(false);
- SetCurrentXformColorIndex(d);
- }, updateRender);
+ SetCurrentXformColorIndex(d, updateRender);
}
void Fractorium::OnXformColorIndexChanged(double d) { OnXformColorIndexChanged(d, true); }
@@ -65,7 +62,7 @@ void Fractorium::OnXformColorIndexChanged(double d, bool updateRender) { m_Contr
///
/// Set the color index of the current xform.
-/// Update the color index cell in the palette ref table to match.
+/// Will trigger an update which will cause the color index cell in the palette ref table to match.
/// Called when color index scrollbar is changed.
/// Resets the rendering process.
///
@@ -73,43 +70,40 @@ void Fractorium::OnXformColorIndexChanged(double d, bool updateRender) { m_Contr
template
void FractoriumEmberController::XformScrollColorIndexChanged(int d)
{
- UpdateCurrentXform([&] (Xform* xform)
- {
- m_Fractorium->m_XformColorIndexSpin->setValue(d / double(m_Fractorium->ui.XformColorScroll->maximum()));//Will trigger an update.
- }, false);
+ m_Fractorium->m_XformColorIndexSpin->setValue(d / double(m_Fractorium->ui.XformColorScroll->maximum()));//Will trigger an update.
}
void Fractorium::OnXformScrollColorIndexChanged(int d) { m_Controller->XformScrollColorIndexChanged(d); }
///
-/// Set the color speed of the current xform.
+/// Set the color speed of the selected xforms.
/// Called when xform color speed spinner is changed.
/// Resets the rendering process.
///
/// The color speed, -1-1.
template
-void FractoriumEmberController::XformColorSpeedChanged(double d) { UpdateCurrentXform([&] (Xform* xform) { xform->m_ColorSpeed = d; }); }
+void FractoriumEmberController::XformColorSpeedChanged(double d) { UpdateXform([&] (Xform* xform) { xform->m_ColorSpeed = d; }, eXformUpdate::UPDATE_SELECTED); }
void Fractorium::OnXformColorSpeedChanged(double d) { m_Controller->XformColorSpeedChanged(d); }
///
-/// Set the opacity of the current xform.
+/// Set the opacity of the selected xforms.
/// Called when xform opacity spinner is changed.
/// Resets the rendering process.
///
/// The opacity, 0-1.
template
-void FractoriumEmberController::XformOpacityChanged(double d) { UpdateCurrentXform([&] (Xform* xform) { xform->m_Opacity = d; }); }
+void FractoriumEmberController::XformOpacityChanged(double d) { UpdateXform([&] (Xform* xform) { xform->m_Opacity = d; }, eXformUpdate::UPDATE_SELECTED); }
void Fractorium::OnXformOpacityChanged(double d) { m_Controller->XformOpacityChanged(d); }
///
-/// Set the direct color percentage of the current xform.
+/// Set the direct color percentage of the selected xforms.
/// Called when xform direct color spinner is changed.
/// Note this only affects xforms that include a dc_ variation.
/// Resets the rendering process.
///
/// The direct color percentage, 0-1.
template
-void FractoriumEmberController::XformDirectColorChanged(double d) { UpdateCurrentXform([&] (Xform* xform) { xform->m_DirectColor = d; }); }
+void FractoriumEmberController::XformDirectColorChanged(double d) { UpdateXform([&] (Xform* xform) { xform->m_DirectColor = d; }, eXformUpdate::UPDATE_SELECTED); }
void Fractorium::OnXformDirectColorChanged(double d) { m_Controller->XformDirectColorChanged(d); }
///
@@ -201,27 +195,27 @@ void Fractorium::OnCurvesGreenRadioButtonToggled(bool checked) { if (checked) ui
void Fractorium::OnCurvesBlueRadioButtonToggled(bool checked) { if (checked) ui.CurvesView->SetTop(CurveIndex::BLUE); }
///
-/// Set the current xform color index spinner to the current xform's color index.
+/// Set the selected xforms color index to the passed in value.
/// Set the color cell in the palette ref table.
///
/// The index value to set, 0-1.
template
-void FractoriumEmberController::SetCurrentXformColorIndex(double d)
+void FractoriumEmberController::SetCurrentXformColorIndex(double d, bool updateRender)
{
- UpdateCurrentXform([&] (Xform* xform)
+ UpdateXform([&] (Xform* xform)
{
xform->m_ColorX = Clamp(d, 0, 1);
-
+
//Grab the current color from the index and assign it to the first cell of the first table.
v4T entry = m_Ember.m_Palette[Clamp(d * COLORMAP_LENGTH_MINUS_1, 0, m_Ember.m_Palette.Size())];
entry.r *= 255;
entry.g *= 255;
entry.b *= 255;
-
+
QRgb rgb = uint(entry.r) << 16 | uint(entry.g) << 8 | uint(entry.b);
m_Fractorium->ui.XformColorIndexTable->item(0, 0)->setBackgroundColor(QColor::fromRgb(rgb));
- }, false);
+ }, eXformUpdate::UPDATE_SELECTED, updateRender);
}
///
@@ -247,7 +241,7 @@ void FractoriumEmberController::FillCurvesControl()
}
///
-/// Set the color index, speed and opacity spinners with the values of the current xform.
+/// Set the color index, speed and opacity spinners with the values of the passed in xform.
/// Set the cells of the palette ref table as well.
///
/// The xform whose values will be copied to the GUI
diff --git a/Source/Fractorium/FractoriumXformsSelect.cpp b/Source/Fractorium/FractoriumXformsSelect.cpp
new file mode 100644
index 0000000..3b1e2cc
--- /dev/null
+++ b/Source/Fractorium/FractoriumXformsSelect.cpp
@@ -0,0 +1,127 @@
+#include "FractoriumPch.h"
+#include "Fractorium.h"
+
+///
+/// Initialize the xforms selection UI.
+///
+void Fractorium::InitXformsSelectUI()
+{
+ m_XformsSelectionLayout = (QFormLayout*)ui.XformsSelectGroupBoxScrollAreaWidget->layout();
+ connect(ui.XformsSelectAllButton, SIGNAL(clicked(bool)), this, SLOT(OnXformsSelectAllButtonClicked(bool)), Qt::QueuedConnection);
+ connect(ui.XformsSelectNoneButton, SIGNAL(clicked(bool)), this, SLOT(OnXformsSelectNoneButtonClicked(bool)), Qt::QueuedConnection);
+
+ ClearXformsSelections();
+}
+
+///
+/// Check all of the xform selection checkboxes.
+///
+/// Ignored
+void Fractorium::OnXformsSelectAllButtonClicked(bool checked) { ForEachXformCheckbox([&](int i, QCheckBox* w) { w->setChecked(true); }); }
+
+///
+/// Uncheck all of the xform selection checkboxes.
+///
+/// Ignored
+void Fractorium::OnXformsSelectNoneButtonClicked(bool checked) { ForEachXformCheckbox([&](int i, QCheckBox* w) { w->setChecked(false); }); }
+
+///
+/// Clear all of the dynamically created xform checkboxes.
+///
+void Fractorium::ClearXformsSelections()
+{
+ QLayoutItem* child = nullptr;
+
+ m_XformSelections.clear();
+ m_XformsSelectionLayout->blockSignals(true);
+
+ while (m_XformsSelectionLayout->count() && (child = m_XformsSelectionLayout->takeAt(0)))
+ {
+ auto* w = child->widget();
+ delete child;
+ delete w;
+ }
+
+ m_XformsSelectionLayout->blockSignals(false);
+}
+
+///
+/// Make a caption from an xform.
+/// The caption will be the xform count + 1, optionally followed by the xform's name.
+/// For final xforms, the string "Final" will be used in place of the count.
+///
+/// The index of xform to make a caption for
+/// The caption string
+template
+QString FractoriumEmberController::MakeXformCaption(size_t i)
+{
+ bool isFinal = m_Ember.FinalXform() == m_Ember.GetTotalXform(i);
+ QString caption = isFinal ? "Final" : QString::number(i + 1);
+
+ if (Xform* xform = m_Ember.GetTotalXform(i))
+ {
+ if (!xform->m_Name.empty())
+ caption += " (" + QString::fromStdString(xform->m_Name) + ")";
+ }
+
+ return caption;
+}
+
+///
+/// Function to perform the specified operation on every dynamically created xform selection checkbox.
+///
+/// The operation to perform
+void Fractorium::ForEachXformCheckbox(std::function func)
+{
+ int i = 0;
+
+ while (QLayoutItem* child = m_XformsSelectionLayout->itemAt(i))
+ {
+ if (auto* w = dynamic_cast(child->widget()))
+ {
+ func(i, w);
+ }
+
+ i++;
+ }
+}
+
+///
+/// Function to perform the specified operation on one dynamically created xform selection checkbox.
+///
+/// The index of the checkbox
+/// The operation to perform
+/// True if the checkbox was found, else false.
+template
+bool FractoriumEmberController::XformCheckboxAt(int i, std::function func)
+{
+ if (QLayoutItem* child = m_Fractorium->m_XformsSelectionLayout->itemAt(i))
+ {
+ if (auto* w = dynamic_cast(child->widget()))
+ {
+ func(w);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+///
+/// Function to perform the specified operation on one dynamically created xform selection checkbox.
+/// The checkbox is specified by the xform it corresponds to, rather than its index.
+///
+/// The xform that corresponds to the checkbox
+/// The operation to perform
+/// True if the checkbox was found, else false.
+template
+bool FractoriumEmberController::XformCheckboxAt(Xform* xform, std::function func)
+{
+ return XformCheckboxAt(m_Ember.GetTotalXformIndex(xform), func);
+}
+
+template class FractoriumEmberController;
+
+#ifdef DO_DOUBLE
+template class FractoriumEmberController;
+#endif
diff --git a/Source/Fractorium/FractoriumXformsVariations.cpp b/Source/Fractorium/FractoriumXformsVariations.cpp
index 03f1505..e934aae 100644
--- a/Source/Fractorium/FractoriumXformsVariations.cpp
+++ b/Source/Fractorium/FractoriumXformsVariations.cpp
@@ -129,7 +129,7 @@ void FractoriumEmberController::ClearVariationsTree()
///
/// The spinner value
template
-void FractoriumEmberController::VariationSpinBoxValueChanged(double d)
+void FractoriumEmberController::VariationSpinBoxValueChanged(double d)//Would be awesome to make this work for all.//TODO
{
QObject* objSender = m_Fractorium->sender();
QTreeWidget* tree = m_Fractorium->ui.VariationsTree;