From a81b93d94a0c4bea0664fb481a3aaca49ac72730 Mon Sep 17 00:00:00 2001 From: Person Date: Wed, 26 Jul 2017 21:25:44 -0700 Subject: [PATCH] Bug fixes: --Fix bug where clearing the final xform, but leaving it present, then editing it would crash the program. --- Source/Ember/Ember.h | 39 +++++-- Source/Fractorium/Fractorium.cpp | 2 + Source/Fractorium/Fractorium.h | 2 +- Source/Fractorium/Fractorium.ui | 2 +- .../Fractorium/FractoriumEmberController.cpp | 21 ++-- Source/Fractorium/FractoriumInfo.cpp | 7 +- Source/Fractorium/FractoriumMenus.cpp | 17 ++- Source/Fractorium/FractoriumPalette.cpp | 3 +- Source/Fractorium/FractoriumRender.cpp | 5 +- Source/Fractorium/FractoriumXforms.cpp | 108 +++++++++--------- Source/Fractorium/FractoriumXformsSelect.cpp | 17 +-- .../Fractorium/FractoriumXformsVariations.cpp | 2 +- Source/Fractorium/GLWidget.cpp | 12 +- 13 files changed, 141 insertions(+), 96 deletions(-) diff --git a/Source/Ember/Ember.h b/Source/Ember/Ember.h index 86008dc..e562725 100644 --- a/Source/Ember/Ember.h +++ b/Source/Ember/Ember.h @@ -215,6 +215,27 @@ public: AddXforms(xformPad - XformCount()); } + /// + /// Replace the xforms vector with the one passed in. + /// + /// The xforms to replace with + /// True to move, false to copy. Default: true. + /// True if replaced, else false. + bool ReplaceXforms(vector>& xforms, bool move = true) + { + if (!xforms.empty()) + { + if (move) + m_Xforms = std::move(xforms); + else + m_Xforms = xforms; + + return true; + } + else + return false; + } + /// /// Copy this ember with optional padding xforms added. /// @@ -280,12 +301,13 @@ public: /// Delete the xform at the specified index, including the final one. /// /// The index to delete + /// If true, delete the final xform when its index is passed in even if one is not present. Default: false. /// True if success, else false. - bool DeleteTotalXform(size_t i) + bool DeleteTotalXform(size_t i, bool forceFinal = false) { if (DeleteXform(i)) { } - else if (i == XformCount() && UseFinalXform()) + else if (i == XformCount() && (forceFinal || UseFinalXform())) m_FinalXform.Clear(); else return false; @@ -310,13 +332,13 @@ public: /// Get a pointer to the xform at the specified index, including the final one. /// /// The index to get - /// If true, return the final xform when its index is requested even if one is not present + /// If true, return the final xform when its index is requested even if one is not present. Default: false. /// A pointer to the xform at the index if successful, else nullptr. Xform* GetTotalXform(size_t i, bool forceFinal = false) const { if (i < XformCount()) return const_cast*>(&m_Xforms[i]); - else if (forceFinal || (i == XformCount() && UseFinalXform())) + else if (i == XformCount() && (forceFinal || UseFinalXform())) return const_cast*>(&m_FinalXform); else return nullptr; @@ -342,13 +364,14 @@ public: /// Search the xforms, including final, to find which one's address matches the address of the specified xform. /// /// A pointer to the xform to find + /// If true, return the index of the final xform when its pointer is passed, even if a final is not present. Default: false. /// The index of the matched xform if found, else -1. - intmax_t GetTotalXformIndex(Xform* xform) const + intmax_t GetTotalXformIndex(Xform* xform, bool forceFinal = false) const { - size_t totalXformCount = TotalXformCount(); + size_t totalXformCount = TotalXformCount(forceFinal); for (size_t i = 0; i < totalXformCount; i++) - if (GetTotalXform(i) == xform) + if (GetTotalXform(i, forceFinal) == xform) return intmax_t(i); return -1; @@ -1468,7 +1491,7 @@ public: inline const Xform* FinalXform() const { return &m_FinalXform; } inline Xform* NonConstFinalXform() { return &m_FinalXform; } inline bool UseFinalXform() const { return !m_FinalXform.Empty(); } - inline size_t TotalXformCount() const { return XformCount() + (UseFinalXform() ? 1 : 0); } + inline size_t TotalXformCount(bool forceFinal = false) const { return XformCount() + ((forceFinal || UseFinalXform()) ? 1 : 0); } inline int PaletteIndex() const { return m_Palette.m_Index; } inline T BlurCoef() { return m_BlurCoef; } inline eScaleType ScaleType() const { return m_ScaleType; } diff --git a/Source/Fractorium/Fractorium.cpp b/Source/Fractorium/Fractorium.cpp index 5ff533f..1cd05dd 100644 --- a/Source/Fractorium/Fractorium.cpp +++ b/Source/Fractorium/Fractorium.cpp @@ -264,6 +264,8 @@ void FractoriumEmberController::ApplyXmlSavingTemplate(Ember& ember) /// /// Return whether the current ember contains a final xform and the GUI is aware of it. +/// Note this can be true even if the final is empty, as long as they've added one and have +/// not explicitly deleted it. /// /// True if the current ember contains a final xform, else false. bool Fractorium::HaveFinal() diff --git a/Source/Fractorium/Fractorium.h b/Source/Fractorium/Fractorium.h index fe55221..3d50b8f 100644 --- a/Source/Fractorium/Fractorium.h +++ b/Source/Fractorium/Fractorium.h @@ -405,7 +405,7 @@ private: //Xforms Selection. void ClearXformsSelections(); - void ForEachXformCheckbox(std::function func); + void ForEachXformCheckbox(std::function func); //Xaos. void FillXaosTable(); diff --git a/Source/Fractorium/Fractorium.ui b/Source/Fractorium/Fractorium.ui index f9e97e1..6537d8f 100644 --- a/Source/Fractorium/Fractorium.ui +++ b/Source/Fractorium/Fractorium.ui @@ -3423,7 +3423,7 @@ <html><head/><body><p>Set all xform color speed values to random numbers between 0 and 1, inclusive</p></body></html> - Random Color Speed + Random Color Speeds diff --git a/Source/Fractorium/FractoriumEmberController.cpp b/Source/Fractorium/FractoriumEmberController.cpp index 0b01540..54e8328 100644 --- a/Source/Fractorium/FractoriumEmberController.cpp +++ b/Source/Fractorium/FractoriumEmberController.cpp @@ -208,31 +208,32 @@ template void FractoriumEmberController::UpdateXform(std::function*)> func, eXformUpdate updateType, bool updateRender, eProcessAction action, size_t index) { int i = 0; - bool isCurrentFinal = m_Ember.IsFinalXform(CurrentXform()); + auto current = CurrentXform(); + bool forceFinal = m_Fractorium->HaveFinal(); + bool isCurrentFinal = m_Ember.IsFinalXform(current); bool doFinal = updateType != eXformUpdate::UPDATE_SELECTED_EXCEPT_FINAL && updateType != eXformUpdate::UPDATE_ALL_EXCEPT_FINAL; switch (updateType) { case eXformUpdate::UPDATE_SPECIFIC: { - if (auto xform = m_Ember.GetTotalXform(index)) + if (auto xform = m_Ember.GetTotalXform(index, forceFinal)) func(xform); } break; case eXformUpdate::UPDATE_CURRENT: { - if (auto xform = CurrentXform()) - func(xform); + if (current) + func(current); } break; case eXformUpdate::UPDATE_CURRENT_AND_SELECTED: { bool currentDone = false; - auto current = CurrentXform(); - while (auto xform = m_Ember.GetTotalXform(i)) + while (auto xform = m_Ember.GetTotalXform(i, forceFinal)) { if (i < m_Fractorium->m_XformSelections.size()) { @@ -261,7 +262,7 @@ void FractoriumEmberController::UpdateXform(std::function*)> fu { bool anyUpdated = false; - while (auto xform = (doFinal ? m_Ember.GetTotalXform(i) : m_Ember.GetXform(i))) + while (auto xform = (doFinal ? m_Ember.GetTotalXform(i, forceFinal) : m_Ember.GetXform(i))) { if (i < m_Fractorium->m_XformSelections.size()) { @@ -280,14 +281,14 @@ void FractoriumEmberController::UpdateXform(std::function*)> fu 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 (auto xform = CurrentXform()) - func(xform); + if (current) + func(current); } break; case eXformUpdate::UPDATE_ALL: { - while (auto xform = m_Ember.GetTotalXform(i++)) + while (auto xform = m_Ember.GetTotalXform(i++, forceFinal)) func(xform); } break; diff --git a/Source/Fractorium/FractoriumInfo.cpp b/Source/Fractorium/FractoriumInfo.cpp index b66d789..b305ab3 100644 --- a/Source/Fractorium/FractoriumInfo.cpp +++ b/Source/Fractorium/FractoriumInfo.cpp @@ -69,7 +69,8 @@ void FractoriumEmberController::FillSummary() int vp = 4; int vlen = 7; char pc = 'f'; - size_t x = 0, total = m_Ember.TotalXformCount(); + bool forceFinal = m_Fractorium->HaveFinal(); + size_t x = 0, total = m_Ember.TotalXformCount(forceFinal); Xform* xform = nullptr; QColor color; auto table = m_Fractorium->ui.SummaryTable; @@ -85,7 +86,7 @@ void FractoriumEmberController::FillSummary() QSize size(table->columnWidth(0), table->rowHeight(1) + 1); m_Fractorium->m_InfoPaletteItem->setData(Qt::DecorationRole, pixmap.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); - for (x = 0; x < total && (xform = m_Ember.GetTotalXform(x)); x++) + for (x = 0; x < total && (xform = m_Ember.GetTotalXform(x, forceFinal)); x++) { size_t i = 0; QString as = "Pre"; @@ -233,5 +234,5 @@ void Fractorium::ErrorReportToQTextEdit(const vector& errors, QTextEdit* template class FractoriumEmberController; #ifdef DO_DOUBLE -template class FractoriumEmberController; + template class FractoriumEmberController; #endif diff --git a/Source/Fractorium/FractoriumMenus.cpp b/Source/Fractorium/FractoriumMenus.cpp index fe2f3c4..7144c86 100644 --- a/Source/Fractorium/FractoriumMenus.cpp +++ b/Source/Fractorium/FractoriumMenus.cpp @@ -428,7 +428,9 @@ void FractoriumEmberController::Undo() { if (m_UndoList.size() > 1 && m_UndoIndex > 0) { - int index = m_Ember.GetTotalXformIndex(CurrentXform()); + bool forceFinal = m_Fractorium->HaveFinal(); + auto current = CurrentXform(); + int index = m_Ember.GetTotalXformIndex(current, forceFinal); m_LastEditWasUndoRedo = true; m_UndoIndex = std::max(0u, m_UndoIndex - 1u); SetEmber(m_UndoList[m_UndoIndex], true, false);//Don't update pointer because it's coming from the undo list... @@ -452,7 +454,9 @@ void FractoriumEmberController::Redo() { if (m_UndoList.size() > 1 && m_UndoIndex < m_UndoList.size() - 1) { - int index = m_Ember.GetTotalXformIndex(CurrentXform()); + bool forceFinal = m_Fractorium->HaveFinal(); + auto current = CurrentXform(); + int index = m_Ember.GetTotalXformIndex(current, forceFinal); m_LastEditWasUndoRedo = true; m_UndoIndex = std::min(m_UndoIndex + 1, m_UndoList.size() - 1); SetEmber(m_UndoList[m_UndoIndex], true, false); @@ -740,10 +744,11 @@ void Fractorium::OnActionResetScale(bool checked) template void FractoriumEmberController::AddReflectiveSymmetry() { + bool forceFinal = m_Fractorium->HaveFinal(); Update([&]() { m_Ember.AddSymmetry(-1, m_Rand); - auto index = m_Ember.TotalXformCount() - (m_Ember.UseFinalXform() ? 2 : 1);//Set index to the last item before final. + auto index = m_Ember.TotalXformCount(forceFinal) - (forceFinal ? 2 : 1);//Set index to the last item before final. FillXforms(int(index)); }); } @@ -757,10 +762,11 @@ void Fractorium::OnActionAddReflectiveSymmetry(bool checked) { m_Controller->Add template void FractoriumEmberController::AddRotationalSymmetry() { + bool forceFinal = m_Fractorium->HaveFinal(); Update([&]() { m_Ember.AddSymmetry(2, m_Rand); - auto index = m_Ember.TotalXformCount() - (m_Ember.UseFinalXform() ? 2 : 1);//Set index to the last item before final. + auto index = m_Ember.TotalXformCount(forceFinal) - (forceFinal ? 2 : 1);//Set index to the last item before final. FillXforms(int(index)); }); } @@ -774,10 +780,11 @@ void Fractorium::OnActionAddRotationalSymmetry(bool checked) { m_Controller->Add template void FractoriumEmberController::AddBothSymmetry() { + bool forceFinal = m_Fractorium->HaveFinal(); Update([&]() { m_Ember.AddSymmetry(-2, m_Rand); - auto index = m_Ember.TotalXformCount() - (m_Ember.UseFinalXform() ? 2 : 1);//Set index to the last item before final. + auto index = m_Ember.TotalXformCount(forceFinal) - (forceFinal ? 2 : 1);//Set index to the last item before final. FillXforms(int(index)); }); } diff --git a/Source/Fractorium/FractoriumPalette.cpp b/Source/Fractorium/FractoriumPalette.cpp index 2278b82..f816537 100644 --- a/Source/Fractorium/FractoriumPalette.cpp +++ b/Source/Fractorium/FractoriumPalette.cpp @@ -323,8 +323,9 @@ void FractoriumEmberController::PaletteEditorButtonClicked() Palette prevPal = m_TempPalette; ed->SetPalette(m_TempPalette); map colorIndices; + bool forceFinal = m_Fractorium->HaveFinal(); - while (auto xform = m_Ember.GetTotalXform(i)) + while (auto xform = m_Ember.GetTotalXform(i, forceFinal)) colorIndices[i++] = xform->m_ColorX; ed->SetColorIndices(colorIndices); diff --git a/Source/Fractorium/FractoriumRender.cpp b/Source/Fractorium/FractoriumRender.cpp index 0c18cc9..a54809d 100644 --- a/Source/Fractorium/FractoriumRender.cpp +++ b/Source/Fractorium/FractoriumRender.cpp @@ -341,10 +341,11 @@ bool FractoriumEmberController::Render() { size_t i = 0; int solo = m_Fractorium->ui.CurrentXformCombo->property("soloxform").toInt(); + bool forceFinal = m_Fractorium->HaveFinal(); if (solo != -1) { - m_TempOpacities.resize(m_Ember.TotalXformCount()); + m_TempOpacities.resize(m_Ember.TotalXformCount(forceFinal)); while (auto xform = m_Ember.GetTotalXform(i)) { @@ -357,7 +358,7 @@ bool FractoriumEmberController::Render() m_Renderer->SetEmber(m_Ember, action); if (solo != -1) - while (auto xform = m_Ember.GetTotalXform(i)) + while (auto xform = m_Ember.GetTotalXform(i, forceFinal)) xform->m_Opacity = m_TempOpacities[i++]; } diff --git a/Source/Fractorium/FractoriumXforms.cpp b/Source/Fractorium/FractoriumXforms.cpp index 8738750..b57bf12 100644 --- a/Source/Fractorium/FractoriumXforms.cpp +++ b/Source/Fractorium/FractoriumXforms.cpp @@ -46,7 +46,8 @@ void Fractorium::InitXformsUI() template Xform* FractoriumEmberController::CurrentXform() { - return m_Ember.GetTotalXform(m_Fractorium->ui.CurrentXformCombo->currentIndex()); + bool hasFinal = m_Fractorium->HaveFinal(); + return m_Ember.GetTotalXform(m_Fractorium->ui.CurrentXformCombo->currentIndex(), hasFinal);//Need to force final for the special case they created a final, then cleared it, but did not delete it. } /// @@ -67,7 +68,9 @@ void Fractorium::CurrentXform(uint i) template void FractoriumEmberController::CurrentXformComboChanged(int index) { - if (auto xform = m_Ember.GetTotalXform(index)) + bool forceFinal = m_Fractorium->HaveFinal(); + + if (auto xform = m_Ember.GetTotalXform(index, forceFinal)) { FillWithXform(xform); m_GLController->SetSelectedXform(xform); @@ -95,13 +98,14 @@ void Fractorium::OnCurrentXformComboChanged(int index) { m_Controller->CurrentXf template void FractoriumEmberController::AddXform() { + bool forceFinal = m_Fractorium->HaveFinal(); Update([&]() { Xform newXform; newXform.m_Weight = 0.25; newXform.m_ColorX = m_Rand.Frand01(); m_Ember.AddXform(newXform); - int index = int(m_Ember.TotalXformCount() - (m_Ember.UseFinalXform() ? 2 : 1));//Set index to the last item before final. + int index = int(m_Ember.TotalXformCount(forceFinal) - (forceFinal ? 2 : 1));//Set index to the last item before final. FillXforms(index); }); } @@ -119,6 +123,7 @@ void Fractorium::OnAddXformButtonClicked(bool checked) { m_Controller->AddXform( template void FractoriumEmberController::AddLinkedXform() { + bool forceFinal = m_Fractorium->HaveFinal(); UpdateXform([&](Xform* xform) { size_t i, count = m_Ember.XformCount(); @@ -148,7 +153,7 @@ void FractoriumEmberController::AddLinkedXform() xform->SetXaos(count - 1, 1);//Set the xaos value for the previous xform pointing to the new one to one. xform->m_Opacity = 0;//Clear the opacity of the previous xform. - int index = int(m_Ember.TotalXformCount() - (m_Ember.UseFinalXform() ? 2 : 1));//Set index to the last item before final. + int index = int(m_Ember.TotalXformCount(forceFinal) - (forceFinal ? 2 : 1));//Set index to the last item before final. FillXforms(index); FillXaos(); }, eXformUpdate::UPDATE_CURRENT); @@ -165,6 +170,7 @@ void Fractorium::OnAddLinkedXformButtonClicked(bool checked) { m_Controller->Add template void FractoriumEmberController::DuplicateXform() { + bool forceFinal = m_Fractorium->HaveFinal(); vector> vec; vec.reserve(m_Ember.XformCount()); UpdateXform([&] (Xform* xform) @@ -176,7 +182,7 @@ void FractoriumEmberController::DuplicateXform() for (auto& it : vec) m_Ember.AddXform(it); - int index = int(m_Ember.TotalXformCount() - (m_Ember.UseFinalXform() ? 2 : 1));//Set index to the last item before final. + int index = int(m_Ember.TotalXformCount(forceFinal) - (forceFinal ? 2 : 1));//Set index to the last item before final. FillXforms(index);//Handles xaos. }); } @@ -211,49 +217,60 @@ void Fractorium::OnClearXformButtonClicked(bool checked) { m_Controller->ClearXf template void FractoriumEmberController::DeleteXforms() { - int offset = 0, current = 0, checked = 0; - bool haveFinal = false; - size_t count; + bool removed = false; + bool haveFinal = m_Fractorium->HaveFinal(); auto combo = m_Fractorium->ui.CurrentXformCombo; + Xform* finalXform = nullptr; + vector> xforms; + xforms.reserve(m_Ember.TotalXformCount()); //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) + //Rather than go through and delete, it's easier to just make a list of what we want to keep. + m_Fractorium->ForEachXformCheckbox([&](int i, QCheckBox * w, bool isFinal) { - 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 && !(i - offset)) - return; - - if (!haveFinal && count == 1) - return; - - if (w->isChecked()) + if (!w->isChecked())//Keep if not checked. { - m_Ember.DeleteTotalXform(i - offset);//Subtract offset to account for previously deleted xforms. - offset++; + if (isFinal) + finalXform = m_Ember.NonConstFinalXform(); + else if (auto xform = m_Ember.GetXform(i)) + xforms.push_back(*xform); } }); - current = combo->currentIndex(); - count = m_Ember.TotalXformCount(); - haveFinal = m_Ember.UseFinalXform();//Requery again. + //They might not have selected any checkboxes, in which case just delete the current. + auto current = combo->currentIndex(); + auto count = m_Ember.TotalXformCount(); + bool anySelected = xforms.size() < m_Ember.XformCount(); + bool finalSelected = !finalXform && haveFinal; //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)) + if (!anySelected && !finalSelected) { - m_Ember.DeleteTotalXform(current); - offset++; + //Disallow deleting the only remaining non-final xform. + if (!(haveFinal && count <= 2 && current == 0) &&//One non-final, one final, disallow deleting non-final. + !(!haveFinal && count == 1))//One non-final, no final, disallow deleting. + { + m_Ember.DeleteTotalXform(current, haveFinal); + removed = true; + } + } + else + { + if (!xforms.empty() && (xforms.size() != m_Ember.XformCount()))//Remove if they requested to do so, but ensure it's not removing all. + { + removed = true; + m_Ember.ReplaceXforms(xforms); + } + + if (finalSelected) + { + removed = true; + m_Ember.NonConstFinalXform()->Clear(); + } } - if (offset) + if (removed) { int index = int(m_Ember.TotalXformCount() - (m_Ember.UseFinalXform() ? 2 : 1));//Set index to the last item before final. Note final is requeried one last time. FillXforms(index); @@ -262,7 +279,6 @@ void FractoriumEmberController::DeleteXforms() } void Fractorium::OnDeleteXformButtonClicked(bool checked) { m_Controller->DeleteXforms(); } - /// /// Add a final xform to the ember and set it as the current xform. /// Will only take action if a final xform is not already present. @@ -286,9 +302,7 @@ void FractoriumEmberController::AddFinalXform() }); } } - void Fractorium::OnAddFinalXformButtonClicked(bool checked) { m_Controller->AddFinalXform(); } - /// /// Set the weight of the selected xforms. /// Called when weight spinner changes. @@ -304,9 +318,7 @@ void FractoriumEmberController::XformWeightChanged(double d) }, eXformUpdate::UPDATE_SELECTED_EXCEPT_FINAL); SetNormalizedWeightText(CurrentXform()); } - void Fractorium::OnXformWeightChanged(double d) { m_Controller->XformWeightChanged(d); } - /// /// Equalize the weights of all xforms in the ember. /// @@ -319,9 +331,7 @@ void FractoriumEmberController::EqualizeWeights() m_Fractorium->m_XformWeightSpin->setValue(xform->m_Weight);//Will trigger an update, so pass false to updateRender below. }, 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. @@ -332,17 +342,16 @@ void Fractorium::OnEqualWeightButtonClicked(bool checked) { m_Controller->Equali template void FractoriumEmberController::XformNameChanged(int row, int col) { + bool forceFinal = m_Fractorium->HaveFinal(); UpdateXform([&] (Xform* xform) { - int index = m_Ember.GetTotalXformIndex(xform); + int index = m_Ember.GetTotalXformIndex(xform, forceFinal); xform->m_Name = m_Fractorium->ui.XformWeightNameTable->item(row, col)->text().toStdString(); XformCheckboxAt(index, [&](QCheckBox * checkbox) { checkbox->setText(MakeXformCaption(index)); }); }, eXformUpdate::UPDATE_CURRENT, false); FillSummary();//Manually update because this does not trigger a render, which is where this would normally be called. } - void Fractorium::OnXformNameChanged(int row, int col) { m_Controller->XformNameChanged(row, col); } - /// /// Set the animate field of the selected xforms. /// This has no effect on interactive rendering, it only sets a value @@ -373,9 +382,7 @@ void FractoriumEmberController::XformAnimateChanged(int state) } }, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll()); } - void Fractorium::OnXformAnimateCheckBoxStateChanged(int state) { m_Controller->XformAnimateChanged(state); } - /// /// Fill all GUI widgets with values from the passed in xform. /// @@ -399,7 +406,6 @@ void FractoriumEmberController::FillWithXform(Xform* xform)//Need to see w FillAffineWithXform(xform, true); FillAffineWithXform(xform, false); } - /// /// Set the normalized weight of the current xform as the suffix text of the weight spinner. /// @@ -416,7 +422,6 @@ void FractoriumEmberController::SetNormalizedWeightText(Xform* xform) m_Fractorium->m_XformWeightSpin->setSuffix(QString(" (") + QLocale::system().toString(double(m_NormalizedWeights[index]), 'g', 3) + ")"); } } - /// /// Determine whether the specified xform is the final xform in the ember. /// @@ -427,7 +432,6 @@ bool FractoriumEmberController::IsFinal(Xform* xform) { return (m_Fractorium->HaveFinal() && (xform == m_Ember.FinalXform())); } - /// /// Fill the xforms combo box with the xforms in the current ember. /// Select the index passed in and fill all widgets with its values. @@ -498,9 +502,7 @@ void FractoriumEmberController::FillXforms(int index) m_Fractorium->OnSoloXformCheckBoxStateChanged(Qt::Unchecked); m_Fractorium->OnCurrentXformComboChanged(index);//Make sure the event gets called, because it won't if the zero index is already selected. } - template class FractoriumEmberController; - #ifdef DO_DOUBLE -template class FractoriumEmberController; -#endif + template class FractoriumEmberController; +#endif \ No newline at end of file diff --git a/Source/Fractorium/FractoriumXformsSelect.cpp b/Source/Fractorium/FractoriumXformsSelect.cpp index 7bcc35d..cbc8174 100644 --- a/Source/Fractorium/FractoriumXformsSelect.cpp +++ b/Source/Fractorium/FractoriumXformsSelect.cpp @@ -16,13 +16,13 @@ void Fractorium::InitXformsSelectUI() /// Check all of the xform selection checkboxes. /// /// Ignored -void Fractorium::OnXformsSelectAllButtonClicked(bool checked) { ForEachXformCheckbox([&](int i, QCheckBox * w) { w->setChecked(true); }); } +void Fractorium::OnXformsSelectAllButtonClicked(bool checked) { ForEachXformCheckbox([&](int i, QCheckBox * w, bool isFinal) { w->setChecked(true); }); } /// /// Uncheck all of the xform selection checkboxes. /// /// Ignored -void Fractorium::OnXformsSelectNoneButtonClicked(bool checked) { ForEachXformCheckbox([&](int i, QCheckBox * w) { w->setChecked(false); }); } +void Fractorium::OnXformsSelectNoneButtonClicked(bool checked) { ForEachXformCheckbox([&](int i, QCheckBox * w, bool isFinal) { w->setChecked(false); }); } /// /// Return whether the checkbox at the specified index is checked. @@ -67,10 +67,11 @@ void Fractorium::ClearXformsSelections() template QString FractoriumEmberController::MakeXformCaption(size_t i) { - bool isFinal = m_Ember.FinalXform() == m_Ember.GetTotalXform(i); + bool forceFinal = m_Fractorium->HaveFinal(); + bool isFinal = m_Ember.FinalXform() == m_Ember.GetTotalXform(i, forceFinal); QString caption = isFinal ? "Final" : QString::number(i + 1); - if (auto xform = m_Ember.GetTotalXform(i)) + if (auto xform = m_Ember.GetTotalXform(i, forceFinal)) if (!xform->m_Name.empty()) caption += " (" + QString::fromStdString(xform->m_Name) + ")"; @@ -81,12 +82,13 @@ QString FractoriumEmberController::MakeXformCaption(size_t i) /// Function to perform the specified operation on every dynamically created xform selection checkbox. /// /// The operation to perform -void Fractorium::ForEachXformCheckbox(std::function func) +void Fractorium::ForEachXformCheckbox(std::function func) { int i = 0; + bool haveFinal = HaveFinal(); for (auto& cb : m_XformSelections) - func(i++, cb); + func(i++, cb, haveFinal && cb == m_XformSelections.back()); } /// @@ -120,7 +122,8 @@ bool FractoriumEmberController::XformCheckboxAt(int i, std::function bool FractoriumEmberController::XformCheckboxAt(Xform* xform, std::function func) { - return XformCheckboxAt(m_Ember.GetTotalXformIndex(xform), func); + bool forceFinal = m_Fractorium->HaveFinal(); + return XformCheckboxAt(m_Ember.GetTotalXformIndex(xform, forceFinal), func); } template class FractoriumEmberController; diff --git a/Source/Fractorium/FractoriumXformsVariations.cpp b/Source/Fractorium/FractoriumXformsVariations.cpp index 5923f45..642ce8c 100644 --- a/Source/Fractorium/FractoriumXformsVariations.cpp +++ b/Source/Fractorium/FractoriumXformsVariations.cpp @@ -215,7 +215,7 @@ void FractoriumEmberController::VariationSpinBoxValueChanged(double d)//Would if (isParam) { //Do not take action if the xform doesn't contain the variation which this param is part of. - if (ParametricVariation* xformParVar = dynamic_cast*>(xformVar))//The parametric cast of the xform's variation. + if (auto xformParVar = dynamic_cast*>(xformVar))//The parametric cast of the xform's variation. if (xformParVar->SetParamVal(sender->ParamName().c_str(), d)) update = true; } diff --git a/Source/Fractorium/GLWidget.cpp b/Source/Fractorium/GLWidget.cpp index 377a571..8b7ef51 100644 --- a/Source/Fractorium/GLWidget.cpp +++ b/Source/Fractorium/GLWidget.cpp @@ -290,6 +290,7 @@ void GLEmberController::DrawAffines(bool pre, bool post) auto ember = m_FractoriumEmberController->CurrentEmber(); bool dragging = m_DragState == eDragState::DragDragging; + bool forceFinal = m_Fractorium->HaveFinal(); //Draw grid if control key is pressed. if ((m_GL->hasFocus() && GetControl()) || m_Fractorium->DrawGrid()) @@ -307,7 +308,7 @@ void GLEmberController::DrawAffines(bool pre, bool post) { size_t i = 0; - while (auto xform = ember->GetTotalXform(i)) + while (auto xform = ember->GetTotalXform(i, forceFinal)) { bool selected = m_Fractorium->IsXformSelected(i++) || (dragging ? (m_SelectedXform == xform) : (m_HoverXform == xform)); DrawAffine(xform, true, selected); @@ -322,7 +323,7 @@ void GLEmberController::DrawAffines(bool pre, bool post) { size_t i = 0; - while (auto xform = ember->GetTotalXform(i)) + while (auto xform = ember->GetTotalXform(i, forceFinal)) { bool selected = m_Fractorium->IsXformSelected(i++) || (dragging ? (m_SelectedXform == xform) : (m_HoverXform == xform)); DrawAffine(xform, false, selected); @@ -1035,6 +1036,8 @@ int GLEmberController::UpdateHover(v3T& glCoords) if (m_Fractorium->DrawXforms())//Don't bother checking anything if the user wants to see no xforms. { + bool forceFinal = m_Fractorium->HaveFinal(); + //If there's a selected/current xform, check it first so it gets precedence over the others. if (m_SelectedXform) { @@ -1047,12 +1050,13 @@ int GLEmberController::UpdateHover(v3T& glCoords) if (CheckXformHover(m_SelectedXform, glCoords, bestDist, checkSelPre, checkSelPost)) { m_HoverXform = m_SelectedXform; - bestIndex = int(ember->GetTotalXformIndex(m_SelectedXform)); + bestIndex = int(ember->GetTotalXformIndex(m_SelectedXform, forceFinal)); } } //Check all xforms. - while (auto xform = ember->GetTotalXform(i)) + + while (auto xform = ember->GetTotalXform(i, forceFinal)) { if (preAll || (pre && m_HoverXform == xform))//Only check pre affine if they are shown. {