1.0.0.2 12/05/2016

--User changes
 -Add many tooltips to help clarify functionality.
 -Select multiple flames in library for del/move. Still only one allowed to be set as the current.
 -Show checkbox for current flame. Remember this is not necessarily what's selected.
 -User can now drag a square to select xforms, which keeps in sync with checkboxes.
 -Remove --nframes from command line. Replace with new params: --loopframes, --interpframes, --interploops.
 -Add two new options to EmberGenome: --cwloops --cwinterploops to specify whether rotation should go clockwise instead of the default counter clockwise.
 -Add these to Fractorium as checkboxes.
 -Apply All now also works for toggling animate flag on xforms.
 -Options dialog now allows user to set whether double click toggles spinners, or right click does.

--Bug fixes
 -Selecting final and non-final xforms, and then dragging the non-final did not drag the final with it.
 -Selecting all xforms when a final was present, then deleting crashed the program.
 -Remove support for ppm files in the command line programs, it's an outdated format.
 -Switching between SP and DP kept reapplying the palette adjustments.

--Code changes
 -Move build system to Visual Studio 2015 and Qt 5.6.
 -SSE used during addition of points to the histogram.
 -Remove last remnants of old flam3 C code and replace with C++.
 -Remove unused code involving tbb::task_group.
 -Make settings object a global shared_ptr singleton, so it doesn't have to be passed around.
This commit is contained in:
Person
2016-12-05 19:04:33 -08:00
parent 53ec438a25
commit 5cdfe0b6b9
83 changed files with 4892 additions and 1156 deletions

View File

@ -58,7 +58,7 @@
<enum>QFrame::NoFrame</enum>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;br/&gt;Fractorium 1.0.0.1&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;A Qt-based fractal flame editor which uses a C++ re-write of the flam3 algorithm named Ember and a GPU capable version named EmberCL which implements a portion of the cuburn algorithm in OpenCL.&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;a href=&quot;http://fractorium.com&quot;&gt;fractorium.com&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&lt;br/&gt;Lead: Matt Feemster&lt;br/&gt;Contributors: Simon Detheridge&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;br/&gt;Fractorium 1.0.0.2&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;A Qt-based fractal flame editor which uses a C++ re-write of the flam3 algorithm named Ember and a GPU capable version named EmberCL which implements a portion of the cuburn algorithm in OpenCL.&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;a href=&quot;http://fractorium.com&quot;&gt;fractorium.com&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&lt;br/&gt;Lead: Matt Feemster&lt;br/&gt;Contributors: Simon Detheridge&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>

View File

@ -1,5 +1,6 @@
#include "FractoriumPch.h"
#include "DoubleSpinBox.h"
#include "FractoriumSettings.h"
QTimer DoubleSpinBox::s_Timer;
@ -15,7 +16,6 @@ QTimer DoubleSpinBox::s_Timer;
DoubleSpinBox::DoubleSpinBox(QWidget* p, int h, double step)
: QDoubleSpinBox(p)
{
m_Select = false;
m_DoubleClick = false;
m_DoubleClickNonZero = 0;
m_DoubleClickZero = 1;
@ -159,36 +159,39 @@ void DoubleSpinBox::OnTimeout()
bool DoubleSpinBox::eventFilter(QObject* o, QEvent* e)
{
QMouseEvent* me = dynamic_cast<QMouseEvent*>(e);
auto settings = FractoriumSettings::DefInstance();
if (isEnabled() &&
me &&
me->type() == QMouseEvent::MouseButtonPress &&
me->button() == Qt::RightButton)
if (isEnabled() && me)
{
m_MouseDownPoint = m_MouseMovePoint = me->pos();
StartTimer();
}
else if (isEnabled() &&
me &&
me->type() == QMouseEvent::MouseButtonRelease &&
me->button() == Qt::RightButton)
{
StopTimer();
m_MouseDownPoint = m_MouseMovePoint = me->pos();
}
else if (isEnabled() &&
me &&
me->type() == QMouseEvent::MouseMove &&
QGuiApplication::mouseButtons() & Qt::RightButton)
{
m_MouseMovePoint = me->pos();
}
else if (m_DoubleClick && e->type() == QMouseEvent::MouseButtonDblClick && isEnabled())
{
if (IsNearZero(value()))
setValue(m_DoubleClickZero);
else
setValue(m_DoubleClickNonZero);
if (!settings->ToggleType() &&//Ensure double click toggles, not right click.
me->type() == QMouseEvent::MouseButtonPress &&
me->button() == Qt::RightButton)
{
m_MouseDownPoint = m_MouseMovePoint = me->pos();
StartTimer();
}
else if (!settings->ToggleType() &&
me->type() == QMouseEvent::MouseButtonRelease &&
me->button() == Qt::RightButton)
{
StopTimer();
m_MouseDownPoint = m_MouseMovePoint = me->pos();
}
else if (!settings->ToggleType() &&
me->type() == QMouseEvent::MouseMove &&
QGuiApplication::mouseButtons() & Qt::RightButton)
{
m_MouseMovePoint = me->pos();
}
else if (m_DoubleClick &&
((!settings->ToggleType() && e->type() == QMouseEvent::MouseButtonDblClick && me->button() == Qt::LeftButton) ||
(settings->ToggleType() && me->type() == QMouseEvent::MouseButtonRelease && me->button() == Qt::RightButton)))
{
if (IsNearZero(value()))
setValue(m_DoubleClickZero);
else
setValue(m_DoubleClickNonZero);
}
}
else
{

View File

@ -6,6 +6,8 @@
/// DoubleSpinBox and VariationTreeDoubleSpinBox classes.
/// </summary>
enum class eSpinToggle : et { NONE = 0, SPIN_DOUBLE_CLICK = 1, SPIN_RIGHT_CLICK = 2 };
/// <summary>
/// A derivation to prevent the spin box from selecting its own text
/// when editing. Also to prevent multiple spin boxes from all having
@ -43,7 +45,6 @@ private:
void StartTimer();
void StopTimer();
bool m_Select;
bool m_DoubleClick;
double m_DoubleClickNonZero;
double m_DoubleClickZero;

View File

@ -73,6 +73,7 @@ public:
m_Ember(ember)
{
setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
setCheckState(0, Qt::Unchecked);
}
/// <summary>
@ -86,6 +87,7 @@ public:
m_Ember(ember)
{
setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
setCheckState(0, Qt::Unchecked);
}
/// <summary>

View File

@ -10,7 +10,7 @@
/// <param name="settings">Pointer to the global settings object to use</param>
/// <param name="p">The parent widget</param>
/// <param name="f">The window flags. Default: 0.</param>
FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(FractoriumSettings* settings, QWidget* p, Qt::WindowFlags f)
FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(QWidget* p, Qt::WindowFlags f)
: QDialog(p, f)
{
ui.setupUi(this);
@ -19,7 +19,7 @@ FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(FractoriumSettings* set
QTableWidget* table = ui.FinalRenderParamsTable;
m_Info = OpenCLInfo::Instance();
m_Fractorium = qobject_cast<Fractorium*>(p);
m_Settings = settings;
m_Settings = FractoriumSettings::DefInstance();
ui.FinalRenderThreadCountSpin->setRange(1, Timing::ProcessorCount());
connect(ui.FinalRenderEarlyClipCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnEarlyClipCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.FinalRenderYAxisUpCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnYAxisUpCheckBoxStateChanged(int)), Qt::QueuedConnection);

View File

@ -50,7 +50,7 @@ class FractoriumFinalRenderDialog : public QDialog
#endif
public:
FractoriumFinalRenderDialog(FractoriumSettings* settings, QWidget* p, Qt::WindowFlags f = 0);
FractoriumFinalRenderDialog(QWidget* p, Qt::WindowFlags f = 0);
void Show(bool fromSequence);
bool EarlyClip();
bool YAxisUp();
@ -132,7 +132,7 @@ private:
TwoButtonComboWidget* m_Tbcw;
QLineEdit* m_PrefixEdit;
QLineEdit* m_SuffixEdit;
FractoriumSettings* m_Settings;
shared_ptr<FractoriumSettings> m_Settings;
Fractorium* m_Fractorium;
shared_ptr<OpenCLInfo> m_Info;
vector<OpenCLWrapper> m_Wrappers;

View File

@ -14,7 +14,7 @@ FinalRenderEmberControllerBase::FinalRenderEmberControllerBase(FractoriumFinalRe
m_FinalRenderDialog(finalRenderDialog)
{
m_FinishedImageCount.store(0);
m_Settings = m_Fractorium->m_Settings;
m_Settings = FractoriumSettings::DefInstance();
}
/// <summary>
@ -28,8 +28,8 @@ void FinalRenderEmberController<T>::CancelRender()
{
if (m_Result.isRunning())
{
tbb::task_group g;
g.run([&]
//tbb::task_group g;
std::thread th([&]
{
m_Run = false;
@ -61,7 +61,7 @@ void FinalRenderEmberController<T>::CancelRender()
}
}
});
g.wait();
Join(th);
while (m_Result.isRunning())
QApplication::processEvents();

View File

@ -81,7 +81,7 @@ protected:
QFuture<void> m_Result;
std::function<void (void)> m_FinalRenderFunc;
FractoriumSettings* m_Settings;
shared_ptr<FractoriumSettings> m_Settings;
FractoriumFinalRenderDialog* m_FinalRenderDialog;
FinalRenderGuiState m_GuiState;
std::recursive_mutex m_ProgressCs;
@ -161,7 +161,7 @@ public:
using PreviewRenderer<T>::m_PreviewEmber;
using PreviewRenderer<T>::m_PreviewRenderer;
using PreviewRenderer<T>::m_PreviewFinalImage;
FinalRenderPreviewRenderer(FinalRenderEmberController<T>* controller) : m_Controller(controller)
{
}

View File

@ -45,13 +45,13 @@ Fractorium::Fractorium(QWidget* p)
m_VarSortMode = 1;//Sort by weight by default.
m_PaletteSortMode = 0;//Sort by palette ascending by default.
m_ColorDialog = new QColorDialog(this);
m_Settings = new FractoriumSettings(this);
m_Settings = FractoriumSettings::Instance();
m_QssDialog = new QssDialog(this);
m_FileDialog = nullptr;//Use lazy instantiation upon first use.
m_FolderDialog = nullptr;
m_FinalRenderDialog = new FractoriumFinalRenderDialog(m_Settings, this);
m_OptionsDialog = new FractoriumOptionsDialog(m_Settings, this);
m_VarDialog = new FractoriumVariationsDialog(m_Settings, this);
m_FinalRenderDialog = new FractoriumFinalRenderDialog(this);
m_OptionsDialog = new FractoriumOptionsDialog(this);
m_VarDialog = new FractoriumVariationsDialog(this);
m_AboutDialog = new FractoriumAboutDialog(this);
//Put the about dialog in the screen center.
const QRect screen = QApplication::desktop()->screenGeometry();
@ -157,6 +157,7 @@ Fractorium::Fractorium(QWidget* p)
if (ifs.is_open())
{
string total, qs;
total.reserve(20 * 1024);
while (std::getline(ifs, qs))
total += qs + "\n";
@ -213,9 +214,9 @@ Fractorium::~Fractorium()
/// <param name="worldY">The cartesian world y coordinate</param>
void Fractorium::SetCoordinateStatus(int rasX, int rasY, float worldX, float worldY)
{
//Use sprintf rather than allocating and concatenating 6 QStrings for efficiency since this is called on every mouse move.
sprintf_s(m_CoordinateString, sizeof(m_CoordinateString), "Window: %4d, %4d World: %2.2f, %2.2f", rasX, rasY, worldX, worldY);
m_CoordinateStatusLabel->setText(QString(m_CoordinateString));
static QString coords;
coords.sprintf("Window: %4d, %4d World: %2.2f, %2.2f", rasX, rasY, worldX, worldY);
m_CoordinateStatusLabel->setText(coords);
}
/// <summary>
@ -327,10 +328,10 @@ bool Fractorium::eventFilter(QObject* o, QEvent* e)
//Require shift for deleting to prevent it from triggering when the user enters delete in the edit box.
if (ke->key() == Qt::Key_Delete && e->type() == QEvent::KeyRelease && shift)
{
auto p = GetCurrentEmberIndex();
auto v = GetCurrentEmberIndex();
if (ui.LibraryTree->topLevelItem(0)->childCount() > 1 && p.second)
OnDelete(p);
if (ui.LibraryTree->topLevelItem(0)->childCount() > 1)
OnDelete(v);
}
}
}

View File

@ -162,7 +162,7 @@ public slots:
//Library.
void OnEmberTreeItemChanged(QTreeWidgetItem* item, int col);
void OnEmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col);
void OnDelete(const pair<size_t, QTreeWidgetItem*>& p);
void OnDelete(const vector<pair<size_t, QTreeWidgetItem*>>& v);
void OnSequenceTreeItemChanged(QTreeWidgetItem* item, int col);
void OnSequenceStartPreviewsButtonClicked(bool checked);
void OnSequenceStopPreviewsButtonClicked(bool checked);
@ -175,6 +175,7 @@ public slots:
void OnSequenceRandomizeFramesPerRotCheckBoxStateChanged(int state);
void OnSequenceRandomizeRotationsCheckBoxStateChanged(int state);
void OnSequenceRandomizeBlendFramesCheckBoxStateChanged(int state);
void OnSequenceRandomizeRotationsPerBlendCheckBoxStateChanged(int state);
void OnSequenceStaggerSpinBoxChanged(double d);
void OnSequenceRandomStaggerMaxSpinBoxChanged(double d);
void OnSequenceStartFlameSpinBoxChanged(int d);
@ -370,7 +371,7 @@ private:
void SyncOptionsToToolbar();
//Library.
pair<size_t, QTreeWidgetItem*> GetCurrentEmberIndex();
vector<pair<size_t, QTreeWidgetItem*>> GetCurrentEmberIndex();
void SyncSequenceSettings();
//Params.
@ -459,7 +460,7 @@ private:
DoubleSpinBox* m_XformWeightSpin;
SpinnerButtonWidget* m_XformWeightSpinnerButtonWidget;
QFormLayout* m_XformsSelectionLayout;
QVector<QCheckBox*> m_XformSelections;
vector<QCheckBox*> m_XformSelections;
//Xforms Color.
QTableWidgetItem* m_XformColorValueItem;
@ -522,13 +523,7 @@ private:
QProgressBar* m_ProgressBar;
QLabel* m_RenderStatusLabel;
QLabel* m_CoordinateStatusLabel;
FractoriumSettings* m_Settings;
char m_ULString[64];
char m_URString[64];
char m_LRString[64];
char m_LLString[64];
char m_WHString[64];
char m_DEString[64];
shared_ptr<FractoriumSettings> m_Settings;
char m_CoordinateString[128];
QColor m_XformComboColors[XFORM_COLOR_COUNT], m_FinalXformComboColor;
QIcon m_XformComboIcons[XFORM_COLOR_COUNT], m_FinalXformComboIcon;

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
#pragma once
#include "FractoriumPch.h"
#include "FractoriumSettings.h"
/// <summary>
/// Fractorium global utility functions.
@ -30,6 +31,7 @@
template<typename spinType, typename valType>
static void SetupSpinner(QTableWidget* table, const QObject* receiver, int& row, int col, spinType*& spinBox, int height, valType min, valType max, valType step, const char* signal, const char* slot, bool incRow = true, valType val = 0, valType doubleClickZero = -999, valType doubleClickNonZero = -999)
{
auto settings = FractoriumSettings::DefInstance();
spinBox = new spinType(table, height, step);
spinBox->setRange(min, max);
spinBox->setValue(val);
@ -450,3 +452,21 @@ bool ConstrainHigh(T* low, T* high)
return false;
}
/// <summary>
/// Move all, possibly disjointly, selected items in a range to
/// a new location and update all existing locations.
/// Atribution: Sean Parent, Going Native 2013.
/// </summary>
/// <param name="f">The location of the first selected item, or the start of the collection.</param>
/// <param name="l">The location of the last selected item, or the end of the collection.</param>
/// <returns>A pair of iterators representing the start and end locations of the list of newly moved items</returns>
template <typename I, typename S>
pair<I, I> Gather(I f, I l, I p, S s)
{
return
{
stable_partition(f, p, [&](const typename iterator_traits<I>::value_type & x) { return !s(x); }),
stable_partition(p, l, s)
};
}

View File

@ -151,7 +151,10 @@ void FractoriumEmberController<T>::SetEmber(size_t index, bool verbatim)
for (int i = 0; i < top->childCount(); i++)
{
if (auto emberItem = dynamic_cast<EmberTreeWidgetItem<T>*>(top->child(i)))
{
emberItem->setSelected(i == index);
emberItem->setCheckState(0, i == index ? Qt::Checked : Qt::Unchecked);
}
}
}
@ -228,9 +231,9 @@ void FractoriumEmberController<T>::UpdateXform(std::function<void(Xform<T>*)> fu
while (auto xform = m_Ember.GetTotalXform(i))
{
if (auto child = m_Fractorium->m_XformsSelectionLayout->itemAt(i))
if (i < m_Fractorium->m_XformSelections.size())
{
if (auto w = qobject_cast<QCheckBox*>(child->widget()))
if (auto w = m_Fractorium->m_XformSelections[i])
{
if (w->isChecked())
{
@ -257,9 +260,9 @@ void FractoriumEmberController<T>::UpdateXform(std::function<void(Xform<T>*)> fu
while (auto xform = (doFinal ? m_Ember.GetTotalXform(i) : m_Ember.GetXform(i)))
{
if (auto child = m_Fractorium->m_XformsSelectionLayout->itemAt(i))
if (i < m_Fractorium->m_XformSelections.size())
{
if (auto w = qobject_cast<QCheckBox*>(child->widget()))
if (auto w = m_Fractorium->m_XformSelections[i])
{
if (w->isChecked())
{

View File

@ -127,8 +127,8 @@ public:
virtual void StopLibraryPreviewRender() { }
virtual void StopSequencePreviewRender() { }
virtual void StopAllPreviewRenderers() { }
virtual void MoveLibraryItems(int startRow, int destRow) { }
virtual void Delete(const pair<size_t, QTreeWidgetItem*>& p) { }
virtual void MoveLibraryItems(const QModelIndexList& items, int destRow) { }
virtual void Delete(const vector<pair<size_t, QTreeWidgetItem*>>& v) { }
virtual void FillSequenceTree() { }
virtual void SequenceGenerateButtonClicked() { }
virtual void SequenceSaveButtonClicked() { }
@ -191,6 +191,8 @@ public:
virtual void RandomXformsAffine(bool pre) { }
virtual void FillBothAffines() { }
double LockedScale() { return m_LockedScale; }
double LockedX() { return m_LockedX; }
double LockedY() { return m_LockedY; }
void LockedScale(double scale) { m_LockedScale = scale; }
virtual void LockAffineScaleCheckBoxStateChanged(int state) { }
@ -265,6 +267,8 @@ protected:
uint m_FailedRenders = 0;
size_t m_UndoIndex = 0;
double m_LockedScale = 1;
double m_LockedX = 0;
double m_LockedY = 0;
eRendererType m_RenderType = eRendererType::CPU_RENDERER;
eEditUndoState m_EditState;
GLuint m_OutputTexID = 0;
@ -372,8 +376,8 @@ public:
virtual void SyncLibrary(eLibraryUpdate update) override;
virtual void FillLibraryTree(int selectIndex = -1) override;
virtual void UpdateLibraryTree() override;
virtual void MoveLibraryItems(int startRow, int destRow) override;
virtual void Delete(const pair<size_t, QTreeWidgetItem*>& p) override;
virtual void MoveLibraryItems(const QModelIndexList& items, int destRow) override;
virtual void Delete(const vector<pair<size_t, QTreeWidgetItem*>>& v) override;
virtual void EmberTreeItemChanged(QTreeWidgetItem* item, int col) override;
virtual void EmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) override;
void RenderPreviews(QTreeWidget* tree, TreePreviewRenderer<T>* renderer, EmberFile<T>& file, uint start = UINT_MAX, uint end = UINT_MAX);
@ -477,6 +481,10 @@ public:
virtual void ClearXaos() override;
virtual void RandomXaos() override;
//Xforms Selection.
bool XformCheckboxAt(int i, std::function<void(QCheckBox*)> func);
bool XformCheckboxAt(Xform<T>* xform, std::function<void(QCheckBox*)> func);
//Palette.
virtual size_t InitPaletteList(const string& s) override;
virtual bool FillPaletteTable(const string& s) override;
@ -512,8 +520,6 @@ private:
//Xforms Selection.
QString MakeXformCaption(size_t i);
bool XformCheckboxAt(int i, std::function<void(QCheckBox*)> func);
bool XformCheckboxAt(Xform<T>* xform, std::function<void(QCheckBox*)> func);
//Palette.
void UpdateAdjustedPaletteGUI(Palette<T>& palette);
@ -624,7 +630,7 @@ public:
using PreviewRenderer<T>::m_PreviewEmber;
using PreviewRenderer<T>::m_PreviewRenderer;
using PreviewRenderer<T>::m_PreviewFinalImage;
/// <summary>
/// Initializes a new instance of the <see cref="TreePreviewRenderer{T}"/> class.
/// </summary>

View File

@ -183,25 +183,28 @@ void Fractorium::FillSummary()
/// </summary>
void Fractorium::UpdateHistogramBounds()
{
if (RendererBase* r = m_Controller->Renderer())
static QString ul, ur, lr, ll, wh, g, de;
if (auto r = m_Controller->Renderer())
{
sprintf_s(m_ULString, sizeof(m_ULString), "UL: %3.3f, %3.3f", r->LowerLeftX(), r->UpperRightY());//These bounds include gutter padding.
sprintf_s(m_URString, sizeof(m_URString), "UR: %3.3f, %3.3f", -r->LowerLeftX(), r->UpperRightY());
sprintf_s(m_LRString, sizeof(m_LRString), "LR: %3.3f, %3.3f", -r->LowerLeftX(), r->LowerLeftY());
sprintf_s(m_LLString, sizeof(m_LLString), "LL: %3.3f, %3.3f", r->LowerLeftX(), r->LowerLeftY());
sprintf_s(m_WHString, sizeof(m_WHString), "W x H: %4lu x %4lu", r->SuperRasW(), r->SuperRasH());
ui.InfoBoundsLabelUL->setText(QString(m_ULString));
ui.InfoBoundsLabelUR->setText(QString(m_URString));
ui.InfoBoundsLabelLR->setText(QString(m_LRString));
ui.InfoBoundsLabelLL->setText(QString(m_LLString));
ui.InfoBoundsLabelWH->setText(QString(m_WHString));
ui.InfoBoundsTable->item(0, 1)->setText(ToString<qulonglong>(r->GutterWidth()));
ul.sprintf("UL: %3.3f, %3.3f", r->LowerLeftX(), r->UpperRightY());//These bounds include gutter padding.
ur.sprintf("UR: %3.3f, %3.3f", -r->LowerLeftX(), r->UpperRightY());
lr.sprintf("LR: %3.3f, %3.3f", -r->LowerLeftX(), r->LowerLeftY());
ll.sprintf("LL: %3.3f, %3.3f", r->LowerLeftX(), r->LowerLeftY());
wh.sprintf("W x H: %4u x %4u", r->SuperRasW(), r->SuperRasH());
g.sprintf("%u", (uint)r->GutterWidth());
ui.InfoBoundsLabelUL->setText(ul);
ui.InfoBoundsLabelUR->setText(ur);
ui.InfoBoundsLabelLR->setText(lr);
ui.InfoBoundsLabelLL->setText(ll);
ui.InfoBoundsLabelWH->setText(wh);
ui.InfoBoundsTable->item(0, 1)->setText(g);
if (r->GetDensityFilter())
{
uint deWidth = (r->GetDensityFilter()->FilterWidth() * 2) + 1;
sprintf_s(m_DEString, sizeof(m_DEString), "%d x %d", deWidth, deWidth);
ui.InfoBoundsTable->item(1, 1)->setText(QString(m_DEString));
auto deWidth = (r->GetDensityFilter()->FilterWidth() * 2) + 1;
de.sprintf("%d x %d", deWidth, deWidth);
ui.InfoBoundsTable->item(1, 1)->setText(de);
}
else
ui.InfoBoundsTable->item(1, 1)->setText("N/A");

View File

@ -26,31 +26,33 @@ void Fractorium::InitLibraryUI()
connect(ui.SequenceRenderButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceRenderButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.SequenceSaveButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceSaveButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.SequenceOpenButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceOpenButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.SequenceRandomizeStaggerCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSequenceRandomizeStaggerCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomizeFramesPerRotCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSequenceRandomizeFramesPerRotCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomizeRotationsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSequenceRandomizeRotationsCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomizeBlendFramesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSequenceRandomizeBlendFramesCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceStaggerSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSequenceStaggerSpinBoxChanged(double)), Qt::QueuedConnection);
connect(ui.SequenceRandomStaggerMaxSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSequenceRandomStaggerMaxSpinBoxChanged(double)), Qt::QueuedConnection);
connect(ui.SequenceStartFlameSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceStartFlameSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceStopFlameSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceStopFlameSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceFramesPerRotSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceFramesPerRotSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomFramesPerRotMaxSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceRandomFramesPerRotMaxSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRotationsSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSequenceRotationsSpinBoxChanged(double)), Qt::QueuedConnection);
connect(ui.SequenceRandomRotationsMaxSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSequenceRandomRotationsMaxSpinBoxChanged(double)), Qt::QueuedConnection);
connect(ui.SequenceBlendFramesSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceBlendFramesSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomBlendMaxFramesSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceRandomBlendMaxFramesSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomizeStaggerCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSequenceRandomizeStaggerCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomizeFramesPerRotCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSequenceRandomizeFramesPerRotCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomizeRotationsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSequenceRandomizeRotationsCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomizeBlendFramesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSequenceRandomizeBlendFramesCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomizeRotationsPerBlendCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSequenceRandomizeRotationsPerBlendCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceStaggerSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSequenceStaggerSpinBoxChanged(double)), Qt::QueuedConnection);
connect(ui.SequenceRandomStaggerMaxSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSequenceRandomStaggerMaxSpinBoxChanged(double)), Qt::QueuedConnection);
connect(ui.SequenceStartFlameSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceStartFlameSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceStopFlameSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceStopFlameSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceFramesPerRotSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceFramesPerRotSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomFramesPerRotMaxSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceRandomFramesPerRotMaxSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRotationsSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSequenceRotationsSpinBoxChanged(double)), Qt::QueuedConnection);
connect(ui.SequenceRandomRotationsMaxSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSequenceRandomRotationsMaxSpinBoxChanged(double)), Qt::QueuedConnection);
connect(ui.SequenceBlendFramesSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceBlendFramesSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomBlendMaxFramesSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceRandomBlendMaxFramesSpinBoxChanged(int)), Qt::QueuedConnection);
}
/// <summary>
/// Get the index of the currently selected ember in the library tree.
/// </summary>
/// <returns>A pair containing the index of the item clicked and a pointer to the item</param>
pair<size_t, QTreeWidgetItem*> Fractorium::GetCurrentEmberIndex()
vector<pair<size_t, QTreeWidgetItem*>> Fractorium::GetCurrentEmberIndex()
{
int index = 0;
QTreeWidgetItem* item = nullptr;
auto tree = ui.LibraryTree;
vector<pair<size_t, QTreeWidgetItem*>> v;
if (auto top = tree->topLevelItem(0))
{
@ -58,14 +60,14 @@ pair<size_t, QTreeWidgetItem*> Fractorium::GetCurrentEmberIndex()
{
item = top->child(index);
if (item && !item->isSelected())
index++;
else
break;
if (item && item->isSelected())
v.push_back(make_pair(index, item));
index++;
}
}
return make_pair(index, item);
return v;
}
/// <summary>
@ -218,6 +220,9 @@ void FractoriumEmberController<T>::EmberTreeItemChanged(QTreeWidgetItem* item, i
if (auto emberItem = dynamic_cast<EmberTreeWidgetItem<T>*>(item))
{
if (!emberItem->isSelected())//Checking/unchecking other items shouldn't perform the processing below.
return;
if (emberItem->text(0).isEmpty())//Prevent empty string.
{
emberItem->UpdateEditText();
@ -225,11 +230,16 @@ void FractoriumEmberController<T>::EmberTreeItemChanged(QTreeWidgetItem* item, i
}
string oldName = emberItem->GetEmber()->m_Name;//First preserve the previous name.
string newName = emberItem->text(0).toStdString();
if (oldName == newName)//If nothing changed, nothing to do.
return;
tree->blockSignals(true);
emberItem->UpdateEmberName();//Copy edit text to the ember's name variable.
m_EmberFile.MakeNamesUnique();//Ensure all names remain unique.
SyncLibrary(eLibraryUpdate::NAME);//Copy all ember names to the tree items since some might have changed to be made unique.
string newName = emberItem->GetEmber()->m_Name;//Get the new, final, unique name.
newName = emberItem->GetEmber()->m_Name;//Get the new, final, unique name.
if (m_EmberFilePointer == emberItem->GetEmber() && oldName != newName)//If the ember edited was the current one, and the name was indeed changed, update the name of the current one.
{
@ -263,20 +273,15 @@ void Fractorium::OnEmberTreeItemChanged(QTreeWidgetItem* item, int col) { m_Cont
/// Clears the undo state.
/// Resets the rendering process.
/// Called when the user double clicks on a library tree item.
/// This will get called twice for some reason, and there's no way to prevent it.
/// Doesn't seem to cause any problems.
/// This will get called twice for some reason, so the check state is checked to prevent duplicate processing.
/// </summary>
/// <param name="item">The item double clicked on</param>
/// <param name="col">The column clicked, ignored.</param>
/// <param name="col">The column clicked</param>
template <typename T>
void FractoriumEmberController<T>::EmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col)
{
if (auto emberItem = dynamic_cast<EmberTreeWidgetItem<T>*>(item))
{
//qDebug() << "Setting current ember to: " << QString::fromStdString(emberItem->GetEmber()->m_Name);
ClearUndo();
SetEmber(*emberItem->GetEmber(), false, true);
}
if (item->checkState(col) == Qt::Unchecked)
SetEmber(m_Fractorium->ui.LibraryTree->currentIndex().row(), false);
}
void Fractorium::OnEmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) { m_Controller->EmberTreeItemDoubleClicked(item, col); }
@ -287,32 +292,56 @@ void Fractorium::OnEmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) {
/// <param name="startRow">The index of the source item to move</param>
/// <param name="destRow">The destination index to move the item to</param>
template <typename T>
void FractoriumEmberController<T>::MoveLibraryItems(int startRow, int destRow)
void FractoriumEmberController<T>::MoveLibraryItems(const QModelIndexList& items, int destRow)
{
int i = 0;
auto startRow = items[0].row();
auto tree = m_Fractorium->ui.LibraryTree;
auto top = tree->topLevelItem(0);
list<QString> names;
for (auto& item : items)
if (auto temp = m_EmberFile.Get(item.row()))
names.push_back(QString::fromStdString(temp->m_Name));
auto b = m_EmberFile.m_Embers.begin();
auto s = Advance(b, startRow);
auto d = Advance(b, destRow);
m_EmberFile.m_Embers.splice(d, m_EmberFile.m_Embers, s);
SyncLibrary(eLibraryUpdate::INDEX);//Only indices need syncing.
auto result = Gather(b, m_EmberFile.m_Embers.end(), Advance(b, destRow), [&](const Ember<T>& ember)
{
auto qname = QString::fromStdString(ember.m_Name);
auto position = std::find(names.begin(), names.end(), qname);
if (position != names.end())
{
names.erase(position);
return true;
}
return false;
});
SyncLibrary(eLibraryUpdate(eLibraryUpdate::INDEX | eLibraryUpdate::POINTER));
}
/// <summary>
/// Delete the currently selected item in the tree.
/// Note this is not necessarilly the current ember, it's just the item
/// in the tree that is selected.
/// Delete the currently selected items in the tree.
/// Note this is not necessarilly the current ember, it's just the items
/// in the tree that are selected.
/// </summary>
/// <param name="p">A pair containing the index of the item clicked and a pointer to the item</param>
/// <param name="v">A vector of pairs, each containing the index of the item selected and a pointer to the item</param>
template <typename T>
void FractoriumEmberController<T>::Delete(const pair<size_t, QTreeWidgetItem*>& p)
void FractoriumEmberController<T>::Delete(const vector<pair<size_t, QTreeWidgetItem*>>& v)
{
if (m_EmberFile.Delete(p.first))
size_t offset = 0;
for (auto& p : v)
{
delete p.second;
SyncLibrary(eLibraryUpdate::INDEX);
m_Fractorium->SyncFileCountToSequenceCount();
if (p.second && m_EmberFile.Delete(p.first - offset))
{
delete p.second;
SyncLibrary(eLibraryUpdate::INDEX);
m_Fractorium->SyncFileCountToSequenceCount();
}
offset++;
}
//If there is now only one item left and it wasn't selected, select it.
@ -327,10 +356,10 @@ void FractoriumEmberController<T>::Delete(const pair<size_t, QTreeWidgetItem*>&
/// Called when the user presses and releases the delete key while the library tree has the focus,
/// and an item is selected.
/// </summary>
/// <param name="p">A pair containing the index of the item clicked and a pointer to the item</param>
void Fractorium::OnDelete(const pair<size_t, QTreeWidgetItem*>& p)
/// <param name="v">A vector of pairs, each containing the index of the item selected and a pointer to the item</param>
void Fractorium::OnDelete(const vector<pair<size_t, QTreeWidgetItem*>>& v)
{
m_Controller->Delete(p);
m_Controller->Delete(v);
}
/// <summary>
@ -506,18 +535,30 @@ void FractoriumEmberController<T>::SequenceGenerateButtonClicked()
Ember<T> result;
auto& ui = m_Fractorium->ui;
auto s = m_Fractorium->m_Settings;
//Bools for determining whether to use hard coded vs. random values.
bool randStagger = ui.SequenceRandomizeStaggerCheckBox->isChecked();
bool randFramesRot = ui.SequenceRandomizeFramesPerRotCheckBox->isChecked();
bool randRot = ui.SequenceRandomizeRotationsCheckBox->isChecked();
bool randBlend = ui.SequenceRandomizeBlendFramesCheckBox->isChecked();
bool randBlendRot = ui.SequenceRandomizeRotationsPerBlendCheckBox->isChecked();
//The direction to rotate the loops.
bool loopsCw = ui.SequenceRotationsCWCheckBox->isChecked();
bool loopsBlendCw = ui.SequenceRotationsPerBlendCWCheckBox->isChecked();
//Whether to stagger, default is 1 which means no stagger.
double stagger = ui.SequenceStaggerSpinBox->value();
double staggerMax = ui.SequenceRandomStaggerMaxSpinBox->value();
//Rotations on keyframes.
double rots = ui.SequenceRotationsSpinBox->value();
double rotsMax = ui.SequenceRandomRotationsMaxSpinBox->value();
//Number of frames it takes to rotate a keyframe.
int framesPerRot = ui.SequenceFramesPerRotSpinBox->value();
int framesPerRotMax = ui.SequenceRandomFramesPerRotMaxSpinBox->value();
//Number of frames it takes to interpolate.
int framesBlend = ui.SequenceBlendFramesSpinBox->value();
int framesBlendMax = ui.SequenceRandomBlendMaxFramesSpinBox->value();
//Number of rotations performed during interpolation.
int rotsPerBlend = ui.SequenceRotationsPerBlendSpinBox->value();
int rotsPerBlendMax = ui.SequenceRotationsPerBlendMaxSpinBox->value();
size_t start = ui.SequenceStartFlameSpinBox->value();
size_t stop = ui.SequenceStopFlameSpinBox->value();
size_t startCount = ui.SequenceStartCountSpinBox->value();
@ -533,6 +574,24 @@ void FractoriumEmberController<T>::SequenceGenerateButtonClicked()
#else
"~/.config/fractorium";
#endif
if (!randRot && !randBlend)
{
if ((!rots || !framesPerRot) && !framesBlend)
{
QMessageBox::critical(m_Fractorium, "Animation sequence parameters error",
"Rotations and Frames per rot, or blend frames must be positive and non-zero");
return;
}
if (framesPerRot > 1 && !rots)//Because framesPerRot control has a min value of 1, check greater than 1. Also don't need to check the inverse like in EmberGenome.
{
QMessageBox::critical(m_Fractorium, "Animation sequence parameters error",
"Frames per rot cannot be positive while Rotations is zero");
return;
}
}
SheepTools<T, float> tools(palettePath, EmberCommon::CreateRenderer<T>(eRendererType::CPU_RENDERER, devices, false, 0, emberReport));
tools.SetSpinParams(true,
stagger,//Will be set again below if random is used.
@ -584,7 +643,7 @@ void FractoriumEmberController<T>::SequenceGenerateButtonClicked()
for (frame = 0; frame < roundFrames; frame++)
{
blend = frame / rotFrames;
tools.Spin(embers[0], nullptr, result, startCount + frameCount++, blend);//Result is cleared and reassigned each time inside of Spin().
tools.Spin(embers[0], nullptr, result, startCount + frameCount++, blend, loopsCw);//Result is cleared and reassigned each time inside of Spin().
FormatName(result, os, padding);
m_SequenceFile.m_Embers.push_back(result);
}
@ -594,7 +653,7 @@ void FractoriumEmberController<T>::SequenceGenerateButtonClicked()
//result will be the starting point for the interp phase below.
frame = roundFrames;
blend = frame / rotFrames;
tools.Spin(embers[0], nullptr, result, startCount + frameCount, blend);//Do not increment frameCount here.
tools.Spin(embers[0], nullptr, result, startCount + frameCount, blend, loopsCw);//Do not increment frameCount here.
FormatName(result, os, padding);
}
@ -606,6 +665,8 @@ void FractoriumEmberController<T>::SequenceGenerateButtonClicked()
auto it2 = it;//Need a quick temporary to avoid modifying it which is used in the loop.
embers[1] = *(++it2);//Get the next ember to be used with blending below.
size_t blendFrames = randBlend ? m_Rand.Frand<double>(framesBlend, framesBlendMax) : framesBlend;
double d = randBlendRot ? m_Rand.Frand<double>(rotsPerBlend, rotsPerBlendMax) : double(rotsPerBlend);
size_t rpb = size_t(std::round(d));
if (randStagger)
tools.Stagger(m_Rand.Frand<double>(stagger, staggerMax));
@ -615,7 +676,7 @@ void FractoriumEmberController<T>::SequenceGenerateButtonClicked()
bool seqFlag = frame == 0 || (frame == blendFrames - 1);
blend = frame / double(blendFrames);
result.Clear();
tools.SpinInter(&embers[0], nullptr, result, startCount + frameCount++, seqFlag, blend);
tools.SpinInter(&embers[0], nullptr, result, startCount + frameCount++, seqFlag, blend, rpb, loopsBlendCw);
FormatName(result, os, padding);
m_SequenceFile.m_Embers.push_back(result);
}
@ -623,7 +684,7 @@ void FractoriumEmberController<T>::SequenceGenerateButtonClicked()
}
it = Advance(m_EmberFile.m_Embers.begin(), stop);
tools.Spin(*it, nullptr, result, startCount + frameCount, 0);
tools.Spin(*it, nullptr, result, startCount + frameCount, 0, loopsBlendCw);
FormatName(result, os, padding);
m_SequenceFile.m_Embers.push_back(result);
FillSequenceTree();//The sequence has been generated, now create preview thumbnails.
@ -730,6 +791,7 @@ void Fractorium::OnSequenceRandomizeStaggerCheckBoxStateChanged(int state) { ui.
void Fractorium::OnSequenceRandomizeFramesPerRotCheckBoxStateChanged(int state) { ui.SequenceRandomFramesPerRotMaxSpinBox->setEnabled(state); }
void Fractorium::OnSequenceRandomizeRotationsCheckBoxStateChanged(int state) { ui.SequenceRandomRotationsMaxSpinBox->setEnabled(state); }
void Fractorium::OnSequenceRandomizeBlendFramesCheckBoxStateChanged(int state) { ui.SequenceRandomBlendMaxFramesSpinBox->setEnabled(state); }
void Fractorium::OnSequenceRandomizeRotationsPerBlendCheckBoxStateChanged(int state) { ui.SequenceRotationsPerBlendMaxSpinBox->setEnabled(state); }
/// <summary>
/// Constrain all min/max spinboxes.

View File

@ -642,6 +642,8 @@ bool Fractorium::CreateRendererFromOptions()
//If using OpenCL, will only get here if creating RendererCL failed, but creating a backup CPU Renderer succeeded.
ShowCritical("Renderer Creation Error", "Error creating renderer, most likely a GPU problem. Using CPU instead.");
m_Settings->OpenCL(false);
ui.ActionCpu->setChecked(true);
ui.ActionCL->setChecked(false);
m_OptionsDialog->ui.OpenCLCheckBox->setChecked(false);
m_FinalRenderDialog->ui.FinalRenderOpenCLCheckBox->setChecked(false);
ok = false;
@ -674,11 +676,9 @@ bool Fractorium::CreateControllerFromOptions()
double scale;
uint current = 0;
#ifdef DO_DOUBLE
Ember<double> ed;
EmberFile<double> efd;
Palette<double> tempPalette;
#else
Ember<float> ed;
EmberFile<float> efd;
Palette<float> tempPalette;
#endif
@ -689,16 +689,13 @@ bool Fractorium::CreateControllerFromOptions()
{
scale = m_Controller->LockedScale();
m_Controller->StopAllPreviewRenderers();//Must stop any previews first, else changing controllers will crash the program and SaveCurrentToOpenedFile() will return 0.
current = m_Controller->SaveCurrentToOpenedFile(false);
m_Controller->CopyTempPalette(tempPalette);//Convert float to double or save double verbatim;
current = m_Controller->SaveCurrentToOpenedFile(false);
//Replace below with this once LLVM fixes a crash in their compiler with default lambda parameters.//TODO
//m_Controller->CopyEmber(ed);
//m_Controller->CopyEmberFile(efd);
#ifdef DO_DOUBLE
m_Controller->CopyEmber(ed, [&](Ember<double>& ember) { });
m_Controller->CopyEmberFile(efd, false, [&](Ember<double>& ember) { });
#else
m_Controller->CopyEmber(ed, [&](Ember<float>& ember) { });
m_Controller->CopyEmberFile(efd, false, [&](Ember<float>& ember) { });
#endif
m_Controller->Shutdown();
@ -715,7 +712,9 @@ bool Fractorium::CreateControllerFromOptions()
//Restore the ember and ember file.
if (m_Controller.get())
{
ed.m_Palette = tempPalette;//Restore base temp palette. Adjustments will be then be applied and stored back in in m_Ember.m_Palette below.
if (auto prev = efd.Get(current))//Restore base temp palette. Adjustments will be then be applied and stored back in in m_Ember.m_Palette below.
prev->m_Palette = tempPalette;
m_Controller->SetEmberFile(efd, true);
m_Controller->SetEmber(current, true);
m_Controller->LockedScale(scale);

View File

@ -5,12 +5,11 @@
/// Constructor that passes the parent to the base and sets up reasonable defaults
/// if the settings file was not present or corrupted.
/// </summary>
/// <param name="p">The parent widget</param>
FractoriumSettings::FractoriumSettings(QObject* p)
FractoriumSettings::FractoriumSettings()
#ifdef _WIN32
: QSettings(QSettings::IniFormat, QSettings::UserScope, "Fractorium", "Fractorium", p)
: QSettings(QSettings::IniFormat, QSettings::UserScope, "Fractorium", "Fractorium", nullptr)
#else
: QSettings(QSettings::IniFormat, QSettings::UserScope, "fractorium", "fractorium", p)
: QSettings(QSettings::IniFormat, QSettings::UserScope, "fractorium", "fractorium", nullptr)
#endif
{
EnsureDefaults();
@ -110,6 +109,9 @@ void FractoriumSettings::Double(bool b) { setValue(DOUBLEPRECISION, b);
bool FractoriumSettings::ShowAllXforms() { return value(SHOWALLXFORMS).toBool(); }
void FractoriumSettings::ShowAllXforms(bool b) { setValue(SHOWALLXFORMS, b); }
bool FractoriumSettings::ToggleType() { return value(TOGGLETYPE).toBool(); }
void FractoriumSettings::ToggleType(bool b) { setValue(TOGGLETYPE, b); }
bool FractoriumSettings::ContinuousUpdate() { return value(CONTUPDATE).toBool(); }
void FractoriumSettings::ContinuousUpdate(bool b) { setValue(CONTUPDATE, b); }

View File

@ -13,6 +13,7 @@
#define DOUBLEPRECISION "render/dp64"
#define CONTUPDATE "render/continuousupdate"
#define SHOWALLXFORMS "render/dragshowallxforms"
#define TOGGLETYPE "render/toggletype"
#define DEVICES "render/devices"
#define THREADCOUNT "render/threadcount"
#define CPUDEFILTER "render/cpudefilter"
@ -86,11 +87,11 @@
/// runs of Fractorium. Each of these generally corresponds
/// to items in the options dialog and the final render dialog.
/// </summary>
class FractoriumSettings : public QSettings
class FractoriumSettings : public QSettings, public Singleton<FractoriumSettings>
{
Q_OBJECT
public:
FractoriumSettings(QObject* p);
SINGLETON_DERIVED_IMPL(FractoriumSettings);
void EnsureDefaults();
bool EarlyClip();
@ -111,6 +112,9 @@ public:
bool ShowAllXforms();
void ShowAllXforms(bool b);
bool ToggleType();
void ToggleType(bool b);
bool ContinuousUpdate();
void ContinuousUpdate(bool b);
@ -281,4 +285,7 @@ public:
QString Theme();
void Theme(const QString& s);
private:
FractoriumSettings();
};

View File

@ -228,7 +228,7 @@ void FractoriumEmberController<T>::DeleteXforms()
checked++;
//Do not allow deleting the only remaining non-final xform.
if (haveFinal && count <= 2 && i == 0)
if (haveFinal && count <= 2 && !(i - offset))
return;
if (!haveFinal && count == 1)
@ -354,10 +354,24 @@ void Fractorium::OnXformNameChanged(int row, int col) { m_Controller->XformNameC
template <typename T>
void FractoriumEmberController<T>::XformAnimateChanged(int state)
{
UpdateXform([&](Xform<T>* xform)
bool final = IsFinal(CurrentXform());
auto index = m_Fractorium->ui.CurrentXformCombo->currentIndex();
UpdateAll([&](Ember<T>& ember)
{
xform->m_Animate = state > 0 ? 1 : 0;
}, eXformUpdate::UPDATE_SELECTED, false);
if (final)//If the current xform was final, only apply to other embers which also have a final xform.
{
if (ember.UseFinalXform())
{
auto xform = ember.NonConstFinalXform();
xform->m_Animate = state > 0 ? 1 : 0;
}
}
else//Current was not final, so apply to other embers which have a non-final xform at this index.
{
if (auto xform = ember.GetXform(index))
xform->m_Animate = state > 0 ? 1 : 0;
}
}, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll());
}
void Fractorium::OnXformAnimateCheckBoxStateChanged(int state) { m_Controller->XformAnimateChanged(state); }

View File

@ -163,6 +163,8 @@ template <typename T>
void FractoriumEmberController<T>::LockAffineScaleCheckBoxStateChanged(int state)
{
m_LockedScale = m_Ember.m_PixelsPerUnit;
m_LockedX = m_Ember.m_CenterX;
m_LockedY = m_Ember.m_CenterY;
m_Fractorium->ui.GLDisplay->update();
}

View File

@ -8,6 +8,9 @@ void Fractorium::InitXformsColorUI()
{
int spinHeight = 20, row = 0;
m_XformColorValueItem = new QTableWidgetItem();
//Can't set this in the designer, so do it here.
m_XformColorValueItem->setToolTip("The index in the palette the current xform uses.\r\n\r\n"
"This value can be changed by scrolling the mouse wheel in the box displaying the value or by dragging the scroll bar.");
ui.XformColorIndexTable->setItem(0, 0, m_XformColorValueItem);
m_PaletteRefItem = new QTableWidgetItem();
ui.XformPaletteRefTable->setItem(0, 0, m_PaletteRefItem);

View File

@ -31,8 +31,8 @@ void Fractorium::OnXformsSelectNoneButtonClicked(bool checked) { ForEachXformChe
/// <param name="checked">True if checked, else false.</param>
bool Fractorium::IsXformSelected(size_t i)
{
if (auto child = m_XformsSelectionLayout->itemAt(int(i)))
if (auto w = qobject_cast<QCheckBox*>(child->widget()))
if (i < m_XformSelections.size())
if (auto w = m_XformSelections[i])
return w->isChecked();
return false;
@ -70,7 +70,7 @@ QString FractoriumEmberController<T>::MakeXformCaption(size_t i)
bool isFinal = m_Ember.FinalXform() == m_Ember.GetTotalXform(i);
QString caption = isFinal ? "Final" : QString::number(i + 1);
if (Xform<T>* xform = m_Ember.GetTotalXform(i))
if (auto xform = m_Ember.GetTotalXform(i))
{
if (!xform->m_Name.empty())
caption += " (" + QString::fromStdString(xform->m_Name) + ")";
@ -87,13 +87,8 @@ void Fractorium::ForEachXformCheckbox(std::function<void(int, QCheckBox*)> func)
{
int i = 0;
while (QLayoutItem* child = m_XformsSelectionLayout->itemAt(i))
{
if (auto w = qobject_cast<QCheckBox*>(child->widget()))
func(i, w);
i++;
}
for (auto& cb : m_XformSelections)
func(i++, cb);
}
/// <summary>
@ -105,9 +100,9 @@ void Fractorium::ForEachXformCheckbox(std::function<void(int, QCheckBox*)> func)
template <typename T>
bool FractoriumEmberController<T>::XformCheckboxAt(int i, std::function<void(QCheckBox*)> func)
{
if (auto child = m_Fractorium->m_XformsSelectionLayout->itemAt(i))
if (i < m_Fractorium->m_XformSelections.size())
{
if (auto w = qobject_cast<QCheckBox*>(child->widget()))
if (auto w = m_Fractorium->m_XformSelections[i])
{
func(w);
return true;

View File

@ -19,7 +19,7 @@ enum class eHoverType : et { HoverNone, HoverXAxis, HoverYAxis, HoverTranslation
/// <summary>
/// Dragging an affine transform or panning, rotating or scaling the image.
/// </summary>
enum class eDragState : et { DragNone, DragPanning, DragDragging, DragRotateScale };
enum class eDragState : et { DragNone, DragSelect, DragPanning, DragDragging, DragRotateScale };
/// <summary>
/// Dragging with no keys pressed, shift, control or alt.

View File

@ -333,6 +333,22 @@ void GLEmberController<T>::DrawAffines(bool pre, bool post)
m_GL->glEnd();
m_GL->glPointSize(1.0f);//Restore point size.
}
else if (m_DragState == eDragState::DragSelect)
{
m_GL->glLineWidth(2.0f);
m_GL->glBegin(GL_LINES);
m_GL->glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
m_GL->glVertex2f(m_MouseDownWorldPos.x, m_MouseDownWorldPos.y);//UL->UR
m_GL->glVertex2f(m_MouseWorldPos.x, m_MouseDownWorldPos.y);
m_GL->glVertex2f(m_MouseDownWorldPos.x, m_MouseWorldPos.y);//LL->LR
m_GL->glVertex2f(m_MouseWorldPos.x, m_MouseWorldPos.y);
m_GL->glVertex2f(m_MouseDownWorldPos.x, m_MouseDownWorldPos.y);//UL->LL
m_GL->glVertex2f(m_MouseDownWorldPos.x, m_MouseWorldPos.y);
m_GL->glVertex2f(m_MouseWorldPos.x, m_MouseDownWorldPos.y);//UR->LR
m_GL->glVertex2f(m_MouseWorldPos.x, m_MouseWorldPos.y);
m_GL->glEnd();
m_GL->glLineWidth(1.0f);
}
else if (m_HoverType != eHoverType::HoverNone && m_HoverXform == m_SelectedXform)//Draw large turquoise dot on hover if they are hovering over the selected xform.
{
m_GL->glPointSize(6.0f);
@ -514,6 +530,9 @@ void GLEmberController<T>::MouseRelease(QMouseEvent* e)
if (m_DragState == eDragState::DragDragging && (e->button() & Qt::LeftButton))
UpdateHover(mouseFlipped);
if (m_DragState == eDragState::DragNone)
m_Fractorium->OnXformsSelectNoneButtonClicked(false);
m_DragState = eDragState::DragNone;
m_DragModifier = 0;
m_GL->repaint();//Force immediate redraw.
@ -571,6 +590,26 @@ void GLEmberController<T>::MouseMove(QMouseEvent* e)
m_FractoriumEmberController->FillAffineWithXform(m_SelectedXform, pre);//Update the spinners in the affine tab of the main window.
m_FractoriumEmberController->UpdateRender();//Restart the rendering process.
}
else if ((m_DragState == eDragState::DragNone || m_DragState == eDragState::DragSelect) && (e->buttons() & Qt::LeftButton))
{
m_DragState = eDragState::DragSelect;//Only set drag state once the user starts moving the mouse with the left button down.
//Iterate over each xform, seeing if it's in the bounding box.
QPointF tl(m_MouseDownWorldPos.x, m_MouseDownWorldPos.y);
QPointF br(m_MouseWorldPos.x, m_MouseWorldPos.y);
QRectF qrf(tl, br);
T scale = m_FractoriumEmberController->AffineScaleCurrentToLocked();
int i = 0;
m_FractoriumEmberController->UpdateXform([&](Xform<T>* xform)
{
QPointF cd(xform->m_Affine.C() * scale, xform->m_Affine.F() * scale);
bool b = qrf.contains(cd);
m_FractoriumEmberController->XformCheckboxAt(i, [&](QCheckBox * cb)
{
cb->setChecked(b);
});
i++;
}, eXformUpdate::UPDATE_ALL, false);
}
else if (m_DragState == eDragState::DragPanning)//Translating the whole image.
{
T x = -(m_MouseWorldPos.x - m_MouseDownWorldPos.x);

View File

@ -18,7 +18,7 @@ void LibraryTreeWidget::SetMainWindow(Fractorium* f)
void LibraryTreeWidget::dropEvent(QDropEvent* de)
{
QModelIndex droppedIndex = indexAt(de->pos());
auto items = selectionModel()->selectedIndexes();
auto items = selectionModel()->selectedRows();
if (!droppedIndex.isValid())//Don't process drop because it's outside of the droppable area.
{
@ -33,7 +33,7 @@ void LibraryTreeWidget::dropEvent(QDropEvent* de)
if (dp == QAbstractItemView::BelowItem)
row++;
m_Fractorium->m_Controller->MoveLibraryItems(items[0].row(), row);
QTimer::singleShot(500, [ = ]() { m_Fractorium->m_Controller->MoveLibraryItems(items, row); });//Need to fire this after this event has internally reshuffled the items.
}
QTreeWidget::dropEvent(de);

View File

@ -8,12 +8,12 @@
/// <param name="settings">A pointer to the settings object to use</param>
/// <param name="p">The parent widget. Default: nullptr.</param>
/// <param name="f">The window flags. Default: 0.</param>
FractoriumOptionsDialog::FractoriumOptionsDialog(FractoriumSettings* settings, QWidget* p, Qt::WindowFlags f)
FractoriumOptionsDialog::FractoriumOptionsDialog(QWidget* p, Qt::WindowFlags f)
: QDialog(p, f)
{
int i, row = 0, spinHeight = 20;
ui.setupUi(this);
m_Settings = settings;
m_Settings = FractoriumSettings::DefInstance();
m_Info = OpenCLInfo::Instance();
QTableWidget* table = ui.OptionsXmlSavingTable;
ui.ThreadCountSpin->setRange(1, Timing::ProcessorCount());
@ -66,6 +66,7 @@ bool FractoriumOptionsDialog::ContinuousUpdate() { return ui.ContinuousUpdateChe
bool FractoriumOptionsDialog::OpenCL() { return ui.OpenCLCheckBox->isChecked(); }
bool FractoriumOptionsDialog::Double() { return ui.DoublePrecisionCheckBox->isChecked(); }
bool FractoriumOptionsDialog::ShowAllXforms() { return ui.ShowAllXformsCheckBox->isChecked(); }
bool FractoriumOptionsDialog::ToggleType() { return ui.ToggleTypeCheckBox->isChecked(); }
bool FractoriumOptionsDialog::AutoUnique() { return ui.AutoUniqueCheckBox->isChecked(); }
uint FractoriumOptionsDialog::ThreadCount() { return ui.ThreadCountSpin->value(); }
uint FractoriumOptionsDialog::RandomCount() { return ui.RandomCountSpin->value(); }
@ -172,6 +173,7 @@ void FractoriumOptionsDialog::GuiToData()
m_Settings->OpenCL(OpenCL());
m_Settings->Double(Double());
m_Settings->ShowAllXforms(ShowAllXforms());
m_Settings->ToggleType(ToggleType());
m_Settings->ThreadCount(ThreadCount());
m_Settings->RandomCount(RandomCount());
m_Settings->CpuSubBatch(ui.CpuSubBatchSpin->value());
@ -204,6 +206,7 @@ void FractoriumOptionsDialog::DataToGui()
ui.OpenCLCheckBox->setChecked(m_Settings->OpenCL());
ui.DoublePrecisionCheckBox->setChecked(m_Settings->Double());
ui.ShowAllXformsCheckBox->setChecked(m_Settings->ShowAllXforms());
ui.ToggleTypeCheckBox->setChecked(m_Settings->ToggleType());
ui.ThreadCountSpin->setValue(m_Settings->ThreadCount());
ui.RandomCountSpin->setValue(m_Settings->RandomCount());
ui.CpuSubBatchSpin->setValue(m_Settings->CpuSubBatch());

View File

@ -24,7 +24,7 @@ class FractoriumOptionsDialog : public QDialog
friend Fractorium;
public:
FractoriumOptionsDialog(FractoriumSettings* settings, QWidget* p = nullptr, Qt::WindowFlags f = 0);
FractoriumOptionsDialog(QWidget* p = nullptr, Qt::WindowFlags f = 0);
public slots:
void OnOpenCLCheckBoxStateChanged(int state);
@ -45,6 +45,7 @@ private:
bool OpenCL();
bool Double();
bool ShowAllXforms();
bool ToggleType();
bool AutoUnique();
uint ThreadCount();
uint RandomCount();
@ -59,5 +60,5 @@ private:
QLineEdit* m_IdEdit;
QLineEdit* m_UrlEdit;
QLineEdit* m_NickEdit;
FractoriumSettings* m_Settings;
shared_ptr<FractoriumSettings> m_Settings;
};

View File

@ -414,6 +414,16 @@ in interactive mode for each mouse movement</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="ToggleTypeCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Checked: right clicking toggles spin boxes, right button dragging disabled.&lt;/p&gt;&lt;p&gt;Unchecked: double clicking toggles spin boxes, right button dragging enabled.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Right Click Toggles Spinboxes</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="OptionsXmlSavingTab">

View File

@ -57,27 +57,22 @@ QssDialog::QssDialog(Fractorium* parent) :
m_LastStyle = m_Parent->styleSheet();
setWindowTitle("QSS Editor - default.qss");
connect(ui->QssEdit, SIGNAL(textChanged()), this, SLOT(SlotTextChanged()));
QToolBar* toolBar = new QToolBar(this);
QMenu* colorActionMenu = new QMenu(this);
QMenu* geomActionMenu = new QMenu(this);
QMenu* borderActionMenu = new QMenu(this);
QMenu* styleActionMenu = new QMenu(this);
(m_ColorActionMapper = new QSignalMapper(this))->setMapping(m_AddColorAction, QString());
(m_GeomActionMapper = new QSignalMapper(this))->setMapping(m_AddGeomAction, QString());
(m_BorderActionMapper = new QSignalMapper(this))->setMapping(m_AddBorderAction, QString());
(m_StyleActionMapper = new QSignalMapper(this))->setMapping(m_AddStyleAction, QString());
connect(ui->QssLoadButton, SIGNAL(clicked()), this, SLOT(LoadButton_clicked()), Qt::QueuedConnection);
connect(ui->QssSaveButton, SIGNAL(clicked()), this, SLOT(SaveButton_clicked()), Qt::QueuedConnection);
connect(ui->QssBasicButton, SIGNAL(clicked()), this, SLOT(BasicButton_clicked()), Qt::QueuedConnection);
connect(ui->QssMediumButton, SIGNAL(clicked()), this, SLOT(MediumButton_clicked()), Qt::QueuedConnection);
connect(ui->QssAdvancedButton, SIGNAL(clicked()), this, SLOT(AdvancedButton_clicked()), Qt::QueuedConnection);
connect(m_AddFontAction, SIGNAL(triggered()), this, SLOT(SlotAddFont()));
QVector<QPair<QString, QString>> colorVec;
colorVec.reserve(12);
colorVec.push_back(QPair<QString, QString>("color", ""));
colorVec.push_back(QPair<QString, QString>("background-color", ""));
@ -94,14 +89,12 @@ QssDialog::QssDialog(Fractorium* parent) :
for (auto& c : colorVec)
{
auto colorAction = colorActionMenu->addAction(c.first);
m_ColorMap[c.first] = c.second;
connect(colorAction, SIGNAL(triggered()), m_ColorActionMapper, SLOT(map()));
m_ColorActionMapper->setMapping(colorAction, c.first);
}
QVector<QPair<QString, QString>> geomVec;
geomVec.reserve(12);
geomVec.push_back(QPair<QString, QString>("width", "100px"));
geomVec.push_back(QPair<QString, QString>("height", "50px"));
@ -120,14 +113,12 @@ QssDialog::QssDialog(Fractorium* parent) :
for (auto& g : geomVec)
{
auto geomAction = geomActionMenu->addAction(g.first);
m_GeomMap[g.first] = g.second;
connect(geomAction, SIGNAL(triggered()), m_GeomActionMapper, SLOT(map()));
m_GeomActionMapper->setMapping(geomAction, g.first);
}
QVector<QPair<QString, QString>> borderVec;
borderVec.reserve(8);
borderVec.push_back(QPair<QString, QString>("border", "1px solid black"));
borderVec.push_back(QPair<QString, QString>("border-top", "1px inset black"));
@ -141,18 +132,16 @@ QssDialog::QssDialog(Fractorium* parent) :
for (auto& b : borderVec)
{
auto borderAction = borderActionMenu->addAction(b.first);
m_BorderMap[b.first] = b.second;
connect(borderAction, SIGNAL(triggered()), m_BorderActionMapper, SLOT(map()));
m_BorderActionMapper->setMapping(borderAction, b.first);
}
auto styles = QStyleFactory::keys();
for (auto& s : styles)
{
auto styleAction = styleActionMenu->addAction(s);
m_StyleMap[s] = s;
connect(styleAction, SIGNAL(triggered()), m_StyleActionMapper, SLOT(map()));
m_StyleActionMapper->setMapping(styleAction, s);
@ -162,12 +151,10 @@ QssDialog::QssDialog(Fractorium* parent) :
connect(m_GeomActionMapper, SIGNAL(mapped(QString)), this, SLOT(SlotAddGeom(QString)));
connect(m_BorderActionMapper, SIGNAL(mapped(QString)), this, SLOT(SlotAddBorder(QString)));
connect(m_StyleActionMapper, SIGNAL(mapped(QString)), this, SLOT(SlotSetTheme(QString)));
m_AddColorAction->setMenu(colorActionMenu);
m_AddGeomAction->setMenu(geomActionMenu);
m_AddBorderAction->setMenu(borderActionMenu);
m_AddStyleAction->setMenu(styleActionMenu);
toolBar->addAction(m_AddColorAction);
toolBar->addAction(m_AddGeomAction);
toolBar->addAction(m_AddBorderAction);
@ -237,7 +224,6 @@ QList<QString> QssDialog::GetClassNames(bool includeObjectNames)
{
QSet<QString> dlgSet;
auto dlgWidgetList = dlg->findChildren<QWidget*>();//Find all children of the dialog.
dlgSet.insert(classAndName);//Add the basic dialog class name, opening curly brace will be added later.
classAndName += " ";
@ -290,8 +276,10 @@ bool QssDialog::IsStyleSheetValid(const QString& styleSheet)
{
QCss::Parser parser(styleSheet);
QCss::StyleSheet sheet;
if (parser.parse(&sheet))
return true;
QString fullSheet = QStringLiteral("* { ");
fullSheet += styleSheet;
fullSheet += QLatin1Char('}');
@ -344,7 +332,7 @@ void QssDialog::showEvent(QShowEvent* e)
m_LastTheme = m_Parent->m_Theme;//The style() member cannot be relied upon, it is *not* the same object passed to setStyle();
SetText(m_LastStyle);
}
QDialog::showEvent(e);
}
@ -378,12 +366,12 @@ void QssDialog::SlotAddColor(const QString& s)
if (color.alpha() == 255)
{
colorStr = QString(QStringLiteral("rgb(%1, %2, %3)")).arg(
color.red()).arg(color.green()).arg(color.blue());
color.red()).arg(color.green()).arg(color.blue());
}
else
{
colorStr = QString(QStringLiteral("rgba(%1, %2, %3, %4)")).arg(
color.red()).arg(color.green()).arg(color.blue()).arg(color.alpha());
color.red()).arg(color.green()).arg(color.blue()).arg(color.alpha());
}
InsertCssProperty(s, colorStr);
@ -396,7 +384,6 @@ void QssDialog::SlotAddColor(const QString& s)
void QssDialog::SlotAddGeom(const QString& s)
{
auto val = m_GeomMap[s];
InsertCssProperty(s, val);
}
@ -407,7 +394,6 @@ void QssDialog::SlotAddGeom(const QString& s)
void QssDialog::SlotAddBorder(const QString& s)
{
auto val = m_BorderMap[s];
InsertCssProperty(s, val);
}
@ -446,14 +432,16 @@ void QssDialog::SlotAddFont()
switch (font.style())
{
case QFont::StyleItalic:
fontStr += QStringLiteral("italic ");
break;
case QFont::StyleOblique:
fontStr += QStringLiteral("oblique ");
break;
default:
break;
case QFont::StyleItalic:
fontStr += QStringLiteral("italic ");
break;
case QFont::StyleOblique:
fontStr += QStringLiteral("oblique ");
break;
default:
break;
}
fontStr += QString::number(font.pointSize());
@ -526,10 +514,7 @@ void QssDialog::SaveButton_clicked()
string s = Text().toStdString();
if (of.is_open())
{
of << s;
of.close();
}
else
QMessageBox::critical(this, "File save error", "Failed to save " + path + ", style will not be set as default");
}
@ -547,10 +532,7 @@ void QssDialog::SaveAsDefault()
auto s = Text().toStdString();
if (of.is_open())
{
of << s;
of.close();
}
else
QMessageBox::critical(this, "File save error", "Failed to save " + path + ", style will not be set as default");
}
@ -615,13 +597,12 @@ void QssDialog::InsertCssProperty(const QString& name, const QString& value)
cursor.beginEditBlock();
cursor.removeSelectedText();
cursor.movePosition(QTextCursor::EndOfLine);
//Simple check to see if we're in a selector scope.
const QTextDocument* doc = editor->document();
const QTextCursor closing = doc->find(QStringLiteral("}"), cursor, QTextDocument::FindBackward);
const QTextCursor opening = doc->find(QStringLiteral("{"), cursor, QTextDocument::FindBackward);
const bool inSelector = !opening.isNull() && (closing.isNull() ||
closing.position() < opening.position());
closing.position() < opening.position());
QString insertion;
//Reasonable attempt at positioning things correctly. This can and often is wrong, but is sufficient for our purposes.
@ -666,9 +647,7 @@ void QssDialog::SetupFileDialog()
QString QssDialog::OpenFile()
{
QStringList filenames;
SetupFileDialog();
m_FileDialog->setFileMode(QFileDialog::ExistingFile);
m_FileDialog->setAcceptMode(QFileDialog::AcceptOpen);
m_FileDialog->setNameFilter("Qss (*.qss)");
@ -688,7 +667,6 @@ QString QssDialog::OpenFile()
QString QssDialog::SaveFile()
{
QStringList filenames;
SetupFileDialog();
m_FileDialog->setFileMode(QFileDialog::AnyFile);
m_FileDialog->setAcceptMode(QFileDialog::AcceptSave);

View File

@ -1,5 +1,6 @@
#include "FractoriumPch.h"
#include "SpinBox.h"
#include "FractoriumSettings.h"
QTimer SpinBox::s_Timer;
@ -15,7 +16,6 @@ QTimer SpinBox::s_Timer;
SpinBox::SpinBox(QWidget* p, int h, int step)
: QSpinBox(p)
{
m_Select = false;
m_DoubleClick = false;
m_DoubleClickNonZero = 0;
m_DoubleClickZero = 1;
@ -135,36 +135,39 @@ void SpinBox::OnTimeout()
bool SpinBox::eventFilter(QObject* o, QEvent* e)
{
QMouseEvent* me = dynamic_cast<QMouseEvent*>(e);
auto settings = FractoriumSettings::DefInstance();
if (isEnabled() &&
me &&
me->type() == QMouseEvent::MouseButtonPress &&
me->button() == Qt::RightButton)
if (isEnabled() && me)
{
m_MouseDownPoint = m_MouseMovePoint = me->pos();
StartTimer();
}
else if (isEnabled() &&
me &&
me->type() == QMouseEvent::MouseButtonRelease &&
me->button() == Qt::RightButton)
{
StopTimer();
m_MouseDownPoint = m_MouseMovePoint = me->pos();
}
else if (isEnabled() &&
me &&
me->type() == QMouseEvent::MouseMove &&
QGuiApplication::mouseButtons() & Qt::RightButton)
{
m_MouseMovePoint = me->pos();
}
else if (m_DoubleClick && e->type() == QMouseEvent::MouseButtonDblClick && isEnabled())
{
if (value() == 0)
setValue(m_DoubleClickZero);
else
setValue(m_DoubleClickNonZero);
if (!settings->ToggleType() &&//Ensure double click toggles, not right click.
me->type() == QMouseEvent::MouseButtonPress &&
me->button() == Qt::RightButton)
{
m_MouseDownPoint = m_MouseMovePoint = me->pos();
StartTimer();
}
else if (!settings->ToggleType() &&
me->type() == QMouseEvent::MouseButtonRelease &&
me->button() == Qt::RightButton)
{
StopTimer();
m_MouseDownPoint = m_MouseMovePoint = me->pos();
}
else if (!settings->ToggleType() &&
me->type() == QMouseEvent::MouseMove &&
QGuiApplication::mouseButtons() & Qt::RightButton)
{
m_MouseMovePoint = me->pos();
}
else if (m_DoubleClick &&
((!settings->ToggleType() && e->type() == QMouseEvent::MouseButtonDblClick && me->button() == Qt::LeftButton) ||
(settings->ToggleType() && me->type() == QMouseEvent::MouseButtonRelease && me->button() == Qt::RightButton)))
{
if (IsNearZero(value()))
setValue(m_DoubleClickZero);
else
setValue(m_DoubleClickNonZero);
}
}
else
{
@ -172,9 +175,9 @@ bool SpinBox::eventFilter(QObject* o, QEvent* e)
{
//Take special action for shift to reduce the scroll amount. Control already
//increases it automatically.
if (QWheelEvent* wev = dynamic_cast<QWheelEvent*>(e))
if (QWheelEvent* we = dynamic_cast<QWheelEvent*>(e))
{
Qt::KeyboardModifiers mod = wev->modifiers();
Qt::KeyboardModifiers mod = we->modifiers();
if (mod.testFlag(Qt::ShiftModifier))
setSingleStep(m_SmallStep);

View File

@ -1,6 +1,7 @@
#pragma once
#include "FractoriumPch.h"
#include "DoubleSpinBox.h"
/// <summary>
/// SpinBox class.
@ -41,7 +42,6 @@ private:
void StartTimer();
void StopTimer();
bool m_Select;
bool m_DoubleClick;
int m_DoubleClickNonZero;
int m_DoubleClickZero;

View File

@ -8,13 +8,13 @@
/// <param name="settings">Pointer to the global settings object to use</param>
/// <param name="p">The parent widget. Default: nullptr.</param>
/// <param name="f">The window flags. Default: 0.</param>
FractoriumVariationsDialog::FractoriumVariationsDialog(FractoriumSettings* settings, QWidget* p, Qt::WindowFlags f)
FractoriumVariationsDialog::FractoriumVariationsDialog(QWidget* p, Qt::WindowFlags f)
: QDialog(p, f),
m_Settings(settings),
m_VariationList(VariationList<float>::Instance())
{
ui.setupUi(this);
auto table = ui.VariationsTable;
m_Settings = FractoriumSettings::DefInstance();
m_Vars = m_Settings->Variations();
Populate();
OnSelectAllButtonClicked(true);

View File

@ -19,7 +19,7 @@ class FractoriumVariationsDialog : public QDialog
{
Q_OBJECT
public:
FractoriumVariationsDialog(FractoriumSettings* settings, QWidget* p = nullptr, Qt::WindowFlags f = nullptr);
FractoriumVariationsDialog(QWidget* p = nullptr, Qt::WindowFlags f = nullptr);
void ForEachCell(std::function<void(QTableWidgetItem* cb)> func);
void ForEachSelectedCell(std::function<void(QTableWidgetItem* cb)> func);
void SyncSettings();
@ -46,6 +46,6 @@ private:
shared_ptr<VariationList<float>> m_VariationList;
vector<QCheckBox*> m_CheckBoxes;
QMap<QString, QVariant> m_Vars;
FractoriumSettings* m_Settings;
shared_ptr<FractoriumSettings> m_Settings;
Ui::VariationsDialog ui;
};