--User changes

-Add Ctrl+g shortcut for generating a sequence.

--Bug fixes
 -Fix indendation for variations because of type icon.
 -Fix bug when duplicating flame where the new flame wasn't being properly selected.
 -Fix bug where clearing a flame was changing size and quality when it shouldn't have.
 -Fix bug where reading an Xml palette was failing on linux.

--Code changes
 -No longer pad string with null terminator in ReadFile() because std::string already does it.
This commit is contained in:
Person 2024-05-08 07:31:55 -06:00
parent 45d936b60c
commit 4c0f03a52a
10 changed files with 58 additions and 33 deletions

View File

@ -1479,7 +1479,7 @@ public:
m_BlurCurve = 0; m_BlurCurve = 0;
m_BlurCoef = 0; m_BlurCoef = 0;
m_CamMat = m3T(0); m_CamMat = m3T(0);
m_Quality = 1; m_Quality = 30;
m_SubBatchSize = 10240; m_SubBatchSize = 10240;
m_RandPointRange = 1; m_RandPointRange = 1;
m_FuseCount = 15; m_FuseCount = 15;

View File

@ -208,6 +208,7 @@ bool PaletteList<T>::Add(const string& filename, bool force)
if (EndsWith(lower, ".xml")) if (EndsWith(lower, ".xml"))
{ {
//Subtract 1 to make reading with nullterminate set to true work on linux.
const auto doc = xmlReadMemory(static_cast<const char*>(buf.data()), static_cast<int>(buf.size()), filename.c_str(), nullptr, XML_PARSE_NONET); const auto doc = xmlReadMemory(static_cast<const char*>(buf.data()), static_cast<int>(buf.size()), filename.c_str(), nullptr, XML_PARSE_NONET);
if (doc) if (doc)

View File

@ -320,9 +320,8 @@ public:
/// </summary> /// </summary>
/// <param name="filename">The full path to the file to read</param> /// <param name="filename">The full path to the file to read</param>
/// <param name="buf">The string which will be populated with the file's contents</param> /// <param name="buf">The string which will be populated with the file's contents</param>
/// <param name="nullTerminate">Whether to append a NULL character as the last element of the vector. Needed when reading text files. Default: true.</param>
/// <returns>True if successfully read and populated, else false</returns> /// <returns>True if successfully read and populated, else false</returns>
static bool ReadFile(const char* filename, string& buf, bool nullTerminate = true) static bool ReadFile(const char* filename, string& buf)
{ {
try try
{ {
@ -332,13 +331,9 @@ static bool ReadFile(const char* filename, string& buf, bool nullTerminate = tru
if (const auto pos = ifs.tellg())//Ensure it exists and wasn't empty. if (const auto pos = ifs.tellg())//Ensure it exists and wasn't empty.
{ {
buf.resize(pos);// +streampos(nullTerminate ? 1 : 0)); buf.resize(pos);
ifs.seekg(0, ios::beg); ifs.seekg(0, ios::beg);
ifs.read(&buf[0], pos); ifs.read(&buf[0], pos);
if (nullTerminate && (buf[buf.size() - 1] != 0))//Optionally NULL terminate if they want to treat it as a string, and it's not terminated arleady.
buf.push_back(0);
return true; return true;
} }
} }

View File

@ -392,6 +392,7 @@ bool Fractorium::eventFilter(QObject* o, QEvent* e)
static int commacount = 0; static int commacount = 0;
static int periodcount = 0; static int periodcount = 0;
static int lcount = 0; static int lcount = 0;
static int ctrlgcount = 0;
const bool shift = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier); const bool shift = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
const bool ctrl = QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier); const bool ctrl = QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier);
@ -448,11 +449,22 @@ bool Fractorium::eventFilter(QObject* o, QEvent* e)
const auto focusedctrlDblSpin = dynamic_cast<QDoubleSpinBox*>(this->focusWidget()); const auto focusedctrlDblSpin = dynamic_cast<QDoubleSpinBox*>(this->focusWidget());
const auto focusedctrlCombo = dynamic_cast<QComboBox*>(this->focusWidget()); const auto focusedctrlCombo = dynamic_cast<QComboBox*>(this->focusWidget());
if (!focusedctrlEdit && if (ctrl && (ke->key() == Qt::Key_G))
!focusedctrlSpin && {
!focusedctrlDblSpin && ctrlgcount++;
!focusedctrlCombo &&
!QGuiApplication::keyboardModifiers().testFlag(Qt::AltModifier))//Must exclude these because otherwise, typing a minus key in any of the spinners will switch the xform. Also exclude alt. if (ctrlgcount >= ftimes)
{
OnSequenceGenerateButtonClicked(true);
ctrlgcount = 0;
return true;
}
}
else if (!focusedctrlEdit &&
!focusedctrlSpin &&
!focusedctrlDblSpin &&
!focusedctrlCombo &&
!QGuiApplication::keyboardModifiers().testFlag(Qt::AltModifier))//Must exclude these because otherwise, typing a minus key in any of the spinners will switch the xform. Also exclude alt.
{ {
size_t index = 0; size_t index = 0;
double vdist = 0.01; double vdist = 0.01;

View File

@ -567,7 +567,7 @@ public:
void FilteredVariations() override; void FilteredVariations() override;
void FillVariationTreeWithCurrentXform() override; void FillVariationTreeWithCurrentXform() override;
void FillVariationTreeWithXform(Xform<T>* xform); void FillVariationTreeWithXform(Xform<T>* xform);
QIcon MakeVariationIcon(const Variation<T>* var); QIcon MakeVariationIcon(const Variation<T>* var, int iconSize);
//Xforms Xaos. //Xforms Xaos.
void FillXaos() override; void FillXaos() override;

View File

@ -71,6 +71,7 @@ void FractoriumEmberController<T>::FillSummary()
const auto vp = 4; const auto vp = 4;
const auto vlen = 7; const auto vlen = 7;
const auto pc = 'f'; const auto pc = 'f';
const auto iconSize = 20;
const auto forceFinal = m_Fractorium->HaveFinal(); const auto forceFinal = m_Fractorium->HaveFinal();
const auto total = m_Ember.TotalXformCount(forceFinal); const auto total = m_Ember.TotalXformCount(forceFinal);
const auto table = m_Fractorium->ui.SummaryTable; const auto table = m_Fractorium->ui.SummaryTable;
@ -163,7 +164,7 @@ void FractoriumEmberController<T>::FillSummary()
vitem->setText(0, QString::fromStdString(var->Name())); vitem->setText(0, QString::fromStdString(var->Name()));
vitem->setText(1, QLocale::system().toString(var->m_Weight, pc, vp).rightJustified(vlen, ' ')); vitem->setText(1, QLocale::system().toString(var->m_Weight, pc, vp).rightJustified(vlen, ' '));
vitem->setFlags(draggable); vitem->setFlags(draggable);
auto qi = MakeVariationIcon(var); auto qi = MakeVariationIcon(var, iconSize);
vitem->setIcon(0, qi); vitem->setIcon(0, qi);
if (const auto parVar = dynamic_cast<ParametricVariation<T>*>(var)) if (const auto parVar = dynamic_cast<ParametricVariation<T>*>(var))

View File

@ -47,7 +47,7 @@ void Fractorium::SelectLibraryItem(size_t index)
item = emberItem; item = emberItem;
emberItem->setSelected(b); emberItem->setSelected(b);
emberItem->setCheckState(NAME_COL, i == index ? Qt::Checked : Qt::Unchecked); emberItem->setCheckState(NAME_COL, b ? Qt::Checked : Qt::Unchecked);
} }
} }
@ -164,6 +164,7 @@ void FractoriumEmberController<T>::FillLibraryTree(int selectIndex)
for (auto& it : m_EmberFile.m_Embers) for (auto& it : m_EmberFile.m_Embers)
{ {
it.m_Index = i;
auto emberItem = new EmberTreeWidgetItem<T>(&it, fileItem); auto emberItem = new EmberTreeWidgetItem<T>(&it, fileItem);
auto istr = ToString(i++); auto istr = ToString(i++);
emberItem->setText(INDEX_COL, istr); emberItem->setText(INDEX_COL, istr);
@ -175,8 +176,11 @@ void FractoriumEmberController<T>::FillLibraryTree(int selectIndex)
emberItem->setToolTip(NAME_COL, emberItem->text(NAME_COL)); emberItem->setToolTip(NAME_COL, emberItem->text(NAME_COL));
emberItem->SetImage(empy_preview, size, size); emberItem->SetImage(empy_preview, size, size);
emberItem->SetEmberPointer(&it);
} }
//tree->update();
if (selectIndex != -1) if (selectIndex != -1)
m_Fractorium->SelectLibraryItem(selectIndex); m_Fractorium->SelectLibraryItem(selectIndex);
@ -345,8 +349,7 @@ void FractoriumEmberController<T>::MoveLibraryItems(const QModelIndexList& items
return false; return false;
}); });
tree->update(); tree->update();
SyncLibrary(eLibraryUpdate(static_cast<uint>(eLibraryUpdate::INDEX) | static_cast<uint>(eLibraryUpdate::POINTER))); SyncLibrary(eLibraryUpdate(static_cast<uint>(eLibraryUpdate::INDEX) | static_cast<uint>(eLibraryUpdate::NAME) | static_cast<uint>(eLibraryUpdate::POINTER)));
//SyncLibrary(eLibraryUpdate(eLibraryUpdate::INDEX | eLibraryUpdate::POINTER | eLibraryUpdate::NAME));
} }
/// <summary> /// <summary>
@ -367,7 +370,7 @@ void FractoriumEmberController<T>::Delete(const vector<pair<size_t, QTreeWidgetI
{ {
last = uint(p.first - offset); last = uint(p.first - offset);
delete p.second; delete p.second;
SyncLibrary(eLibraryUpdate::INDEX); SyncLibrary(eLibraryUpdate(static_cast<uint>(eLibraryUpdate::INDEX) | static_cast<uint>(eLibraryUpdate::NAME) | static_cast<uint>(eLibraryUpdate::POINTER)));
m_Fractorium->SyncFileCountToSequenceCount(); m_Fractorium->SyncFileCountToSequenceCount();
} }
@ -669,7 +672,7 @@ void FractoriumEmberController<T>::SequenceGenerateButtonClicked()
const auto rotsPerBlend = it->m_RotationsPerBlend; const auto rotsPerBlend = it->m_RotationsPerBlend;
const auto linear = it->m_Linear; const auto linear = it->m_Linear;
tools.SetSpinParams(!linear, tools.SetSpinParams(!linear,
stagger,//Will be set again below if random is used. stagger,
0, 0,
0, 0,
s->Nick().toStdString(), s->Nick().toStdString(),

View File

@ -164,10 +164,12 @@ void FractoriumEmberController<T>::CopyFlameInCurrentFile()
{ {
StopAllPreviewRenderers(); StopAllPreviewRenderers();
auto ember = m_Ember; auto ember = m_Ember;
auto insertEmberIndex = m_Fractorium->ui.LibraryTree->currentIndex().row() + 1; auto model = m_Fractorium->ui.LibraryTree->selectionModel();
auto sel = model->selectedIndexes();
auto insertEmberIndex = sel.size() > 0 ? sel[0].row() + 1 : 0;
ember.m_Name = EmberFile<T>::DefaultEmberName(m_EmberFile.Size() + 1).toStdString(); ember.m_Name = EmberFile<T>::DefaultEmberName(m_EmberFile.Size() + 1).toStdString();
ember.m_Index = insertEmberIndex;//Will be overwritten below in UpdateLibraryTree(). ember.m_Index = insertEmberIndex;//Will be overwritten below in FillLibraryTree().
m_EmberFile.m_Embers.insert(Advance(m_EmberFile.m_Embers.begin(), insertEmberIndex), ember);//Will invalidate the pointers contained in the EmberTreeWidgetItems, UpdateLibraryTree() will resync. m_EmberFile.m_Embers.insert(Advance(m_EmberFile.m_Embers.begin(), insertEmberIndex), ember);//Will invalidate the pointers contained in the EmberTreeWidgetItems, FillLibraryTree() has the effect of resyncing because index, name and pointer are assigned.
m_EmberFile.MakeNamesUnique(); m_EmberFile.MakeNamesUnique();
FillLibraryTree(insertEmberIndex); FillLibraryTree(insertEmberIndex);
SetEmber(insertEmberIndex, false); SetEmber(insertEmberIndex, false);
@ -1013,6 +1015,9 @@ void FractoriumEmberController<T>::ClearFlame()
newXform.m_ColorX = m_Rand.Frand01<T>(); newXform.m_ColorX = m_Rand.Frand01<T>();
newXform.AddVariation(m_VariationList->GetVariationCopy(eVariationId::VAR_LINEAR)); newXform.AddVariation(m_VariationList->GetVariationCopy(eVariationId::VAR_LINEAR));
m_Ember.Clear(); m_Ember.Clear();
m_Ember.m_FinalRasW = m_Fractorium->m_WidthSpin->value();
m_Ember.m_FinalRasH = m_Fractorium->m_HeightSpin->value();
m_Ember.m_Quality = m_Fractorium->m_QualitySpin->value();
m_Ember.AddXform(newXform); m_Ember.AddXform(newXform);
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(); FillParamTablesAndPalette();

View File

@ -122,8 +122,8 @@ void Fractorium::InitParamsUI()
llComboVals = comboVals; llComboVals = comboVals;
SetupCombo(table, this, row, 1, m_AffineInterpTypeCombo, comboVals, SIGNAL(currentIndexChanged(int)), SLOT(OnAffineInterpTypeComboCurrentIndexChanged(int))); SetupCombo(table, this, row, 1, m_AffineInterpTypeCombo, comboVals, SIGNAL(currentIndexChanged(int)), SLOT(OnAffineInterpTypeComboCurrentIndexChanged(int)));
m_AffineInterpTypeCombo->SetCurrentIndexStealth(static_cast<int>(eAffineInterp::AFFINE_INTERP_LOG)); m_AffineInterpTypeCombo->SetCurrentIndexStealth(static_cast<int>(eAffineInterp::AFFINE_INTERP_LOG));
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_RotationsSpin, spinHeight, 0, dmax, 1, SIGNAL(valueChanged(double)), SLOT(OnRotationsChanged(double)), true, 1.0, 1.0, 0); SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_RotationsSpin, spinHeight, 0, dmax, 1, SIGNAL(valueChanged(double)), SLOT(OnRotationsChanged(double)), true, 1.0, 1.0, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_SecondsPerRotationSpin, spinHeight, 0, dmax, 1, SIGNAL(valueChanged(double)), SLOT(OnSecondsPerRotationChanged(double)), true, 1.0, 1.0, 0); SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_SecondsPerRotationSpin, spinHeight, 0, dmax, 1, SIGNAL(valueChanged(double)), SLOT(OnSecondsPerRotationChanged(double)), true, 1.0, 1.0, 0);
comboVals.clear(); comboVals.clear();
comboVals.push_back("Cw"); comboVals.push_back("Cw");
comboVals.push_back("Ccw"); comboVals.push_back("Ccw");
@ -135,8 +135,8 @@ void Fractorium::InitParamsUI()
m_BlendXformsRotateDirCombo->SetCurrentIndexStealth(0); m_BlendXformsRotateDirCombo->SetCurrentIndexStealth(0);
SetupCombo(table, this, row, 1, m_BlendInterpTypeCombo, llComboVals, SIGNAL(currentIndexChanged(int)), SLOT(OnBlendInterpTypeComboCurrentIndexChanged(int))); SetupCombo(table, this, row, 1, m_BlendInterpTypeCombo, llComboVals, SIGNAL(currentIndexChanged(int)), SLOT(OnBlendInterpTypeComboCurrentIndexChanged(int)));
m_BlendInterpTypeCombo->SetCurrentIndexStealth(1); m_BlendInterpTypeCombo->SetCurrentIndexStealth(1);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_StaggerSpin, spinHeight, 0, 1, 0.1, SIGNAL(valueChanged(double)), SLOT(OnStaggerChanged(double)), true, 0, 1.0, 0); SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_StaggerSpin, spinHeight, 0, 1, 0.1, SIGNAL(valueChanged(double)), SLOT(OnStaggerChanged(double)), true, 0, 1.0, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_TemporalFilterWidthSpin, spinHeight, 1, 10, 1, SIGNAL(valueChanged(double)), SLOT(OnTemporalFilterWidthChanged(double)), true, 1, 1, 1); SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_TemporalFilterWidthSpin, spinHeight, 1, 10, 1, SIGNAL(valueChanged(double)), SLOT(OnTemporalFilterWidthChanged(double)), true, 1, 1, 1);
comboVals = TemporalFilterCreator<float>::FilterTypes(); comboVals = TemporalFilterCreator<float>::FilterTypes();
SetupCombo(table, this, row, 1, m_TemporalFilterTypeCombo, comboVals, SIGNAL(currentTextChanged(const QString&)), SLOT(OnTemporalFilterTypeComboCurrentIndexChanged(const QString&))); SetupCombo(table, this, row, 1, m_TemporalFilterTypeCombo, comboVals, SIGNAL(currentTextChanged(const QString&)), SLOT(OnTemporalFilterTypeComboCurrentIndexChanged(const QString&)));
m_TemporalFilterTypeCombo->SetCurrentIndexStealth(static_cast<int>(eTemporalFilterType::BOX_TEMPORAL_FILTER)); m_TemporalFilterTypeCombo->SetCurrentIndexStealth(static_cast<int>(eTemporalFilterType::BOX_TEMPORAL_FILTER));

View File

@ -16,7 +16,7 @@ void Fractorium::InitXformsVariationsUI()
//Setting dimensions in the designer with a layout is futile, so must hard code here. //Setting dimensions in the designer with a layout is futile, so must hard code here.
tree->setColumnWidth(0, 170); tree->setColumnWidth(0, 170);
tree->setColumnWidth(1, 80); tree->setColumnWidth(1, 80);
tree->setColumnWidth(2, 20); //tree->setColumnWidth(2, 20);
//Set Default variation tree text and background colors for zero and non zero cases. //Set Default variation tree text and background colors for zero and non zero cases.
m_VariationTreeColorNonZero = Qt::black; m_VariationTreeColorNonZero = Qt::black;
m_VariationTreeColorZero = Qt::black; m_VariationTreeColorZero = Qt::black;
@ -107,12 +107,19 @@ void FractoriumEmberController<T>::SetupVariationsTree()
{ {
T fMin = TLOW; T fMin = TLOW;
T fMax = TMAX; T fMax = TMAX;
const int iconSize = 20;
const QSize hint0(170, 16); const QSize hint0(170, 16);
const QSize hint1(80, 16); const QSize hint1(80, 16);
const QSize hint2(20, 16); //const QSize hint2(20, 16);
QPixmap pixmap(iconSize * 3, iconSize);
auto mask = pixmap.createMaskFromColor(QColor("transparent"), Qt::MaskOutColor);
auto tree = m_Fractorium->ui.VariationsTree; auto tree = m_Fractorium->ui.VariationsTree;
tree->clear(); tree->clear();
tree->blockSignals(true); tree->blockSignals(true);
pixmap.setMask(mask);
QPainter paint(&pixmap);
paint.fillRect(QRect(0, 0, iconSize * 3, iconSize), QColor(0, 0, 0, 0));
QIcon defIcon(pixmap);
for (size_t i = 0; i < m_VariationList->Size(); i++) for (size_t i = 0; i < m_VariationList->Size(); i++)
{ {
@ -124,8 +131,8 @@ void FractoriumEmberController<T>::SetupVariationsTree()
item->setText(0, QString::fromStdString(var->Name())); item->setText(0, QString::fromStdString(var->Name()));
item->setSizeHint(0, hint0); item->setSizeHint(0, hint0);
item->setSizeHint(1, hint1); item->setSizeHint(1, hint1);
item->setSizeHint(2, hint2); //item->setSizeHint(2, hint2);
auto qi = MakeVariationIcon(var); auto qi = MakeVariationIcon(var, iconSize);
item->setIcon(0, qi); item->setIcon(0, qi);
spinBox->setRange(fMin, fMax); spinBox->setRange(fMin, fMax);
spinBox->DoubleClick(true); spinBox->DoubleClick(true);
@ -150,6 +157,7 @@ void FractoriumEmberController<T>::SetupVariationsTree()
paramWidget->setText(0, params[j].Name().c_str()); paramWidget->setText(0, params[j].Name().c_str());
paramWidget->setSizeHint(0, hint0); paramWidget->setSizeHint(0, hint0);
paramWidget->setSizeHint(1, hint1); paramWidget->setSizeHint(1, hint1);
paramWidget->setIcon(0, defIcon);
varSpinBox->setRange(params[j].Min(), params[j].Max()); varSpinBox->setRange(params[j].Min(), params[j].Max());
varSpinBox->setValue(params[j].ParamVal()); varSpinBox->setValue(params[j].ParamVal());
varSpinBox->DoubleClick(true); varSpinBox->DoubleClick(true);
@ -367,11 +375,11 @@ void FractoriumEmberController<T>::FillVariationTreeWithXform(Xform<T>* xform)
/// Blue: maintains internal state, mostly of engineering interest. /// Blue: maintains internal state, mostly of engineering interest.
/// </summary> /// </summary>
/// <param name="text">The variation to create the icon for</param> /// <param name="text">The variation to create the icon for</param>
/// <param name="size">The size of the icon in pixels</param>
/// <returns>The newly created icon</returns> /// <returns>The newly created icon</returns>
template <typename T> template <typename T>
QIcon FractoriumEmberController<T>::MakeVariationIcon(const Variation<T>* var) QIcon FractoriumEmberController<T>::MakeVariationIcon(const Variation<T>* var, int iconSize)
{ {
const int iconSize = 20;
static vector<string> dc{ "m_ColorX" }; static vector<string> dc{ "m_ColorX" };
static vector<string> assign{ "outPoint->m_X =", "outPoint->m_Y =", "outPoint->m_Z =", static vector<string> assign{ "outPoint->m_X =", "outPoint->m_Y =", "outPoint->m_Z =",
"outPoint->m_X=", "outPoint->m_Y=", "outPoint->m_Z=" }; "outPoint->m_X=", "outPoint->m_Y=", "outPoint->m_Z=" };