mirror of
https://bitbucket.org/mfeemster/fractorium.git
synced 2025-01-21 21:20:07 -05:00
8086cfa731
--User changes -Allow users to set the Exp value when using the Exp temporal filter type. -Set the default temporal filter type to be Box, which does not alter the palette values at all during animation. This is done to avoid confusion when using Gaussian or Exp which can produce darkened images. --Bug fixes -Sending a sequence to the final render dialog when the keyframes had non zero rotate and center Y values would produce off center animations when rendered. -Temporal filters were being unnecessarily recreated many times when rendering or generating sequences. -Exp filter was always treated like a Box filter. --Code changes -Add a new member function SaveCurrentAsXml(QString filename = "") to the controllers which is only used for testing. -Modernize some C++ code.
389 lines
9.9 KiB
C++
389 lines
9.9 KiB
C++
#include "FractoriumPch.h"
|
|
#include "SpinBox.h"
|
|
#include "FractoriumSettings.h"
|
|
|
|
QTimer SpinBox::s_Timer;
|
|
|
|
/// <summary>
|
|
/// Constructor that passes parent to the base and sets up height and step.
|
|
/// Specific focus policy is used to allow the user to hover over the control
|
|
/// and change its value using the mouse wheel without explicitly having to click
|
|
/// inside of it.
|
|
/// </summary>
|
|
/// <param name="p">The parent widget. Default: nullptr.</param>
|
|
/// <param name="h">The height of the spin box. Default: 16.</param>
|
|
/// <param name="step">The step used to increment/decrement the spin box when using the mouse wheel. Default: 1.</param>
|
|
SpinBox::SpinBox(QWidget* p, int h, int step)
|
|
: QSpinBox(p)
|
|
{
|
|
m_DoubleClick = false;
|
|
m_DoubleClickLowVal = 0;
|
|
m_DoubleClickNonZero = 0;
|
|
m_DoubleClickZero = 1;
|
|
m_Step = step;
|
|
m_SmallStep = 1;
|
|
m_Settings = FractoriumSettings::DefInstance();
|
|
setSingleStep(step);
|
|
setFrame(false);
|
|
setButtonSymbols(QAbstractSpinBox::NoButtons);
|
|
setFocusPolicy(Qt::StrongFocus);
|
|
setMinimumHeight(h);//setGeometry() has no effect, so set both of these instead.
|
|
setMaximumHeight(h);
|
|
setContextMenuPolicy(Qt::PreventContextMenu);
|
|
lineEdit()->installEventFilter(this);
|
|
lineEdit()->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
|
connect(this, SIGNAL(valueChanged(int)), this, SLOT(onSpinBoxValueChanged(int)), Qt::QueuedConnection);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the value of the control without triggering signals.
|
|
/// </summary>
|
|
/// <param name="d">The value to set it to</param>
|
|
void SpinBox::SetValueStealth(int d)
|
|
{
|
|
blockSignals(true);
|
|
setValue(d);
|
|
blockSignals(false);
|
|
}
|
|
|
|
void SpinBox::SetValueStealth(size_t d) { SetValueStealth(static_cast<int>(d)); }
|
|
|
|
/// <summary>
|
|
/// Set whether to respond to double click events.
|
|
/// </summary>
|
|
/// <param name="b">True if this should respond to double click events, else false.</param>
|
|
void SpinBox::DoubleClick(bool b)
|
|
{
|
|
m_DoubleClick = b;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the value to be used instead of zero to represent the lower value
|
|
/// used when responding to a double click.
|
|
/// </summary>
|
|
/// <param name="val">The value to be used for the lower value instead of zero</param>
|
|
void SpinBox::DoubleClickLowVal(int val)
|
|
{
|
|
m_DoubleClickLowVal = val;
|
|
}
|
|
|
|
int SpinBox::DoubleClickLowVal()
|
|
{
|
|
return m_DoubleClickLowVal;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the value to be used when the user double clicks the spinner while
|
|
/// it contains zero.
|
|
/// </summary>
|
|
/// <param name="val">The value to be used</param>
|
|
void SpinBox::DoubleClickZero(int val)
|
|
{
|
|
m_DoubleClickZero = val;
|
|
}
|
|
|
|
int SpinBox::DoubleClickZero()
|
|
{
|
|
return m_DoubleClickZero;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the value to be used when the user double clicks the spinner while
|
|
/// it contains a non-zero value.
|
|
/// </summary>
|
|
/// <param name="val">The value to be used</param>
|
|
void SpinBox::DoubleClickNonZero(int val)
|
|
{
|
|
m_DoubleClickNonZero = val;
|
|
}
|
|
|
|
int SpinBox::DoubleClickNonZero()
|
|
{
|
|
return m_DoubleClickNonZero;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the small step to be used when the user holds down shift while scrolling.
|
|
/// The default is step / 10, so use this if something else is needed.
|
|
/// </summary>
|
|
/// <param name="step">The small step to use for scrolling while the shift key is down</param>
|
|
void SpinBox::SmallStep(int step)
|
|
{
|
|
m_SmallStep = std::min(1, step);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Expose the underlying QLineEdit control to the caller.
|
|
/// </summary>
|
|
/// <returns>A pointer to the QLineEdit</returns>
|
|
QLineEdit* SpinBox::lineEdit()
|
|
{
|
|
return QSpinBox::lineEdit();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Another workaround for the persistent text selection bug in Qt.
|
|
/// </summary>
|
|
void SpinBox::onSpinBoxValueChanged(int i)
|
|
{
|
|
lineEdit()->deselect();//Gets rid of nasty "feature" that always has text selected.
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called while the timer is activated due to the right mouse button being held down.
|
|
/// </summary>
|
|
void SpinBox::OnTimeout()
|
|
{
|
|
int xdistance = m_MouseMovePoint.x() - m_MouseDownPoint.x();
|
|
int ydistance = m_MouseMovePoint.y() - m_MouseDownPoint.y();
|
|
int distance = abs(xdistance) > abs(ydistance) ? xdistance : ydistance;
|
|
distance = Sqr(distance) * (distance < 0 ? -1 : 1);
|
|
double scale, val;
|
|
int d = value();
|
|
bool shift = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
|
bool ctrl = QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier);
|
|
double amount = (m_SmallStep + m_Step) * 0.5;
|
|
|
|
if (shift)
|
|
scale = 0.001;
|
|
else if (ctrl)
|
|
scale = 0.01;
|
|
else
|
|
scale = 0.01;
|
|
|
|
val = d + (distance * amount * scale);
|
|
setValue(int(val));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Event filter for taking special action on double click events.
|
|
/// </summary>
|
|
/// <param name="o">The object</param>
|
|
/// <param name="e">The eevent</param>
|
|
/// <returns>false</returns>
|
|
bool SpinBox::eventFilter(QObject* o, QEvent* e)
|
|
{
|
|
if (!isEnabled())
|
|
return QSpinBox::eventFilter(o, e);
|
|
|
|
const auto me = dynamic_cast<QMouseEvent*>(e);
|
|
|
|
if (me)
|
|
{
|
|
if (!m_Settings->ToggleType() &&//Ensure double click toggles, not right click.
|
|
me->type() == QMouseEvent::MouseButtonPress &&
|
|
me->button() == Qt::RightButton)
|
|
{
|
|
m_MouseDownPoint = m_MouseMovePoint = me->pos();
|
|
StartTimer();
|
|
e->accept();
|
|
return true;
|
|
}
|
|
else if (!m_Settings->ToggleType() &&
|
|
me->type() == QMouseEvent::MouseButtonRelease &&
|
|
me->button() == Qt::RightButton)
|
|
{
|
|
StopTimer();
|
|
m_MouseDownPoint = m_MouseMovePoint = me->pos();
|
|
e->accept();
|
|
return true;
|
|
}
|
|
else if (!m_Settings->ToggleType() &&
|
|
me->type() == QMouseEvent::MouseMove &&
|
|
QGuiApplication::mouseButtons() & Qt::RightButton)
|
|
{
|
|
m_MouseMovePoint = me->pos();
|
|
e->accept();
|
|
return true;
|
|
}
|
|
else if (m_DoubleClick &&
|
|
((!m_Settings->ToggleType() && e->type() == QMouseEvent::MouseButtonDblClick && me->button() == Qt::LeftButton) ||
|
|
(m_Settings->ToggleType() && me->type() == QMouseEvent::MouseButtonRelease && me->button() == Qt::RightButton)))
|
|
{
|
|
if (m_DoubleClickLowVal == value())
|
|
{
|
|
m_DoubleClickZeroEvent(this, m_DoubleClickZero);
|
|
setValue(m_DoubleClickZero);
|
|
}
|
|
else
|
|
{
|
|
m_DoubleClickNonZeroEvent(this, m_DoubleClickNonZero);
|
|
setValue(m_DoubleClickNonZero);
|
|
}
|
|
|
|
e->accept();
|
|
return true;
|
|
}
|
|
}
|
|
else if (isEnabled())
|
|
{
|
|
if (e->type() == QEvent::Wheel)
|
|
{
|
|
if (QWheelEvent* we = dynamic_cast<QWheelEvent*>(e))
|
|
{
|
|
const auto shift = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
|
const auto ctrl = QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier);
|
|
|
|
if (we->angleDelta().ry() > 0)
|
|
{
|
|
if (shift)
|
|
{
|
|
setSingleStep(m_SmallStep);
|
|
setValue(value() + m_SmallStep);
|
|
}
|
|
else
|
|
{
|
|
setSingleStep(m_Step);
|
|
setValue(value() + (ctrl ? m_Step * 10 : m_Step));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (shift)
|
|
{
|
|
setSingleStep(m_SmallStep);
|
|
setValue(value() - m_SmallStep);
|
|
}
|
|
else
|
|
{
|
|
setSingleStep(m_Step);
|
|
setValue(value() - (ctrl ? m_Step * 10 : m_Step));
|
|
}
|
|
}
|
|
|
|
e->accept();
|
|
return true;
|
|
}
|
|
}
|
|
else if (dynamic_cast<QKeyEvent*>(e))
|
|
{
|
|
e->accept();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return QSpinBox::eventFilter(o, e);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Override which is for handling specific key presses while this control is focused.
|
|
/// In particular, + = and up arrow increase the value, equivalent to scrolling the mouse wheel up, while also observing shift/ctrl modifiers.
|
|
/// Values are decreased in the same way by pressing - _ or down arrow.
|
|
/// </summary>
|
|
/// <param name="ke">The key event</param>
|
|
void SpinBox::keyPressEvent(QKeyEvent* ke)
|
|
{
|
|
bool shift = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
|
bool ctrl = QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier);
|
|
|
|
if (ke->key() == Qt::Key_Up)
|
|
{
|
|
if (shift)
|
|
{
|
|
setSingleStep(m_SmallStep);
|
|
setValue(value() + m_SmallStep);
|
|
}
|
|
else
|
|
{
|
|
setSingleStep(m_Step);
|
|
setValue(value() + (ctrl ? m_Step * 10 : m_Step));
|
|
}
|
|
|
|
ke->accept();
|
|
}
|
|
else if (ke->key() == Qt::Key_Down)
|
|
{
|
|
if (shift)
|
|
{
|
|
setSingleStep(m_SmallStep);
|
|
setValue(value() - m_SmallStep);
|
|
}
|
|
else
|
|
{
|
|
setSingleStep(m_Step);
|
|
setValue(value() - (ctrl ? m_Step * 10 : m_Step));
|
|
}
|
|
|
|
ke->accept();
|
|
}
|
|
else if (ke->key() == Qt::Key_Space)
|
|
{
|
|
if (m_DoubleClickLowVal == value())
|
|
{
|
|
m_DoubleClickZeroEvent(this, m_DoubleClickZero);
|
|
setValue(m_DoubleClickZero);
|
|
}
|
|
else
|
|
{
|
|
m_DoubleClickNonZeroEvent(this, m_DoubleClickNonZero);
|
|
setValue(m_DoubleClickNonZero);
|
|
}
|
|
}
|
|
else
|
|
QSpinBox::keyPressEvent(ke);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when focus enters the spinner.
|
|
/// </summary>
|
|
/// <param name="e">The event</param>
|
|
void SpinBox::focusInEvent(QFocusEvent* e)
|
|
{
|
|
StopTimer();
|
|
QSpinBox::focusInEvent(e);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when focus leaves the spinner.
|
|
/// Qt has a nasty "feature" that leaves the text in a spinner selected
|
|
/// and the cursor visible, regardless of whether it has the focus.
|
|
/// Manually clear both here.
|
|
/// </summary>
|
|
/// <param name="e">The event</param>
|
|
void SpinBox::focusOutEvent(QFocusEvent* e)
|
|
{
|
|
StopTimer();
|
|
QSpinBox::focusOutEvent(e);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when focus enters the spinner.
|
|
/// Must set the focus to make sure key down messages don't erroneously go to the GLWidget.
|
|
/// </summary>
|
|
/// <param name="e">The event</param>
|
|
void SpinBox::enterEvent(QEvent* e)
|
|
{
|
|
StopTimer();
|
|
QSpinBox::enterEvent(e);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when focus leaves the spinner.
|
|
/// Must clear the focus to make sure key down messages don't erroneously go to the GLWidget.
|
|
/// </summary>
|
|
/// <param name="e">The event</param>
|
|
void SpinBox::leaveEvent(QEvent* e)
|
|
{
|
|
StopTimer();
|
|
QSpinBox::leaveEvent(e);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Start the timer in response to the right mouse button being pressed.
|
|
/// </summary>
|
|
void SpinBox::StartTimer()
|
|
{
|
|
s_Timer.stop();
|
|
connect(&s_Timer, SIGNAL(timeout()), this, SLOT(OnTimeout()));
|
|
s_Timer.start(300);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stop the timer in response to the left mouse button being pressed.
|
|
/// </summary>
|
|
void SpinBox::StopTimer()
|
|
{
|
|
s_Timer.stop();
|
|
disconnect(&s_Timer, SIGNAL(timeout()), this, SLOT(OnTimeout()));
|
|
}
|