mirror of
https://bitbucket.org/mfeemster/fractorium.git
synced 2025-07-01 22:06:10 -04:00
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:
@ -58,7 +58,7 @@
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><html><head/><body><p align="center"><br/>Fractorium 1.0.0.1</p><p align="center"><span style=" font-size:10pt;">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.</span></p><p align="center"><a href="http://fractorium.com">fractorium.com</a><span style=" font-size:10pt;"><br/>Lead: Matt Feemster<br/>Contributors: Simon Detheridge</span></p></body></html></string>
|
||||
<string><html><head/><body><p align="center"><br/>Fractorium 1.0.0.2</p><p align="center"><span style=" font-size:10pt;">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.</span></p><p align="center"><a href="http://fractorium.com">fractorium.com</a><span style=" font-size:10pt;"><br/>Lead: Matt Feemster<br/>Contributors: Simon Detheridge</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
@ -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)
|
||||
};
|
||||
}
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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>
|
||||
|
@ -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");
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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); }
|
||||
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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); }
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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><html><head/><body><p>Checked: right clicking toggles spin boxes, right button dragging disabled.</p><p>Unchecked: double clicking toggles spin boxes, right button dragging enabled.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Right Click Toggles Spinboxes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="OptionsXmlSavingTab">
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
Reference in New Issue
Block a user