Use spin boxes for float properties.

This commit is contained in:
Leonardo Zide
2025-06-26 17:12:15 -07:00
parent 6f30ad275c
commit ed24c15b20
7 changed files with 424 additions and 28 deletions
+211
View File
@@ -0,0 +1,211 @@
#include "lc_global.h"
#include "lc_doublespinbox.h"
#include "lc_qutils.h"
lcDoubleSpinBox::lcDoubleSpinBox(QWidget* Parent)
: QDoubleSpinBox(Parent)
{
lineEdit()->installEventFilter(this);
connect(lineEdit(), &QLineEdit::returnPressed, this, &lcDoubleSpinBox::ReturnPressed);
}
void lcDoubleSpinBox::SetValue(double Value)
{
if (!hasFocus())
mInitialValue = Value;
setValue(Value);
}
QString lcDoubleSpinBox::textFromValue(double Value) const
{
return lcFormatValueLocalized(Value);
}
void lcDoubleSpinBox::CancelEditing()
{
emit EditingCanceled();
setValue(mInitialValue);
}
void lcDoubleSpinBox::FinishEditing()
{
if (value() == mInitialValue)
return;
emit EditingFinished();
mInitialValue = value();
}
void lcDoubleSpinBox::ReturnPressed()
{
FinishEditing();
clearFocus();
}
void lcDoubleSpinBox::HandleMousePressEvent(QMouseEvent* MouseEvent)
{
if (MouseEvent->buttons() == Qt::LeftButton)
{
mDragMode = DragMode::Start;
mLastPosition = GetGlobalMousePosition(MouseEvent);
}
else
{
if (mDragMode == DragMode::Value)
CancelEditing();
mDragMode = DragMode::None;
}
}
bool lcDoubleSpinBox::HandleMouseMoveEvent(QMouseEvent* MouseEvent, QObject* Object)
{
if (mDragMode != DragMode::None)
{
if (mDragMode == DragMode::Start)
{
if (lineEdit()->selectionLength() > 0 && Object != this)
{
mDragMode = DragMode::None;
}
else
{
QPoint Position = GetGlobalMousePosition(MouseEvent);
if (abs(mLastPosition.y() - Position.y()) > 3)
{
mDragMode = DragMode::Value;
mLastPosition = QCursor::pos();
}
}
}
if (mDragMode == DragMode::Value)
{
QPoint Position = QCursor::pos();
stepBy(mLastPosition.y() - Position.y());
QScreen* Screen = QGuiApplication::screenAt(mapToGlobal(QPoint(width() / 2, height() / 2)));
if (Screen)
{
int ScreenHeight = Screen->geometry().height();
if (Position.y() <= 0)
{
Position.setY(ScreenHeight - 2);
QCursor::setPos(Position);
}
else if (Position.y() >= ScreenHeight - 1)
{
Position.setY(1);
QCursor::setPos(Position);
}
}
mLastPosition = Position;
MouseEvent->accept();
return true;
}
}
return false;
}
void lcDoubleSpinBox::HandleMouseReleaseEvent(QMouseEvent* MouseEvent)
{
Q_UNUSED(MouseEvent);
if (mDragMode == DragMode::Value)
{
FinishEditing();
clearFocus();
}
mDragMode = DragMode::None;
}
bool lcDoubleSpinBox::eventFilter(QObject* Object, QEvent* Event)
{
switch (Event->type())
{
case QEvent::MouseButtonPress:
if (Object == lineEdit())
HandleMousePressEvent(reinterpret_cast<QMouseEvent*>(Event));
break;
case QEvent::MouseMove:
if (Object == lineEdit())
HandleMouseMoveEvent(reinterpret_cast<QMouseEvent*>(Event), Object);
break;
case QEvent::MouseButtonRelease:
if (Object == lineEdit())
HandleMouseReleaseEvent(reinterpret_cast<QMouseEvent*>(Event));
break;
default:
break;
}
return QDoubleSpinBox::eventFilter(Object, Event);
}
void lcDoubleSpinBox::mousePressEvent(QMouseEvent* MouseEvent)
{
HandleMousePressEvent(MouseEvent);
QDoubleSpinBox::mousePressEvent(MouseEvent);
}
void lcDoubleSpinBox::mouseMoveEvent(QMouseEvent* MouseEvent)
{
if (!HandleMouseMoveEvent(MouseEvent, this))
QDoubleSpinBox::mouseMoveEvent(MouseEvent);
}
void lcDoubleSpinBox::mouseReleaseEvent(QMouseEvent* MouseEvent)
{
HandleMouseReleaseEvent(MouseEvent);
QDoubleSpinBox::mouseReleaseEvent(MouseEvent);
}
bool lcDoubleSpinBox::event(QEvent* Event)
{
if (Event->type() == QEvent::ShortcutOverride)
{
QKeyEvent* KeyEvent = static_cast<QKeyEvent*>(Event);
if (KeyEvent->key() == Qt::Key_Escape)
{
if (mDragMode == DragMode::Value)
CancelEditing();
mDragMode = DragMode::None;
clearFocus();
KeyEvent->accept();
}
}
return QDoubleSpinBox::event(Event);
}
void lcDoubleSpinBox::focusOutEvent(QFocusEvent* FocusEvent)
{
if (value() != mInitialValue)
CancelEditing();
QDoubleSpinBox::focusOutEvent(FocusEvent);
}
+56
View File
@@ -0,0 +1,56 @@
#pragma once
class lcDoubleSpinBox : public QDoubleSpinBox
{
Q_OBJECT
public:
lcDoubleSpinBox(QWidget* Parent);
virtual ~lcDoubleSpinBox() = default;
void SetValue(double Value);
QString textFromValue(double Value) const override;
bool eventFilter(QObject* Object, QEvent* Event) override;
void mousePressEvent(QMouseEvent* MouseEvent) override;
void mouseMoveEvent(QMouseEvent* MouseEvent) override;
void mouseReleaseEvent(QMouseEvent* MouseEvent) override;
void focusOutEvent(QFocusEvent* FocusEvent) override;
signals:
void EditingCanceled();
void EditingFinished();
protected slots:
void CancelEditing();
void FinishEditing();
void ReturnPressed();
protected:
bool event(QEvent* Event) override;
static QPoint GetGlobalMousePosition(QMouseEvent* MouseEvent)
{
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
return MouseEvent->globalPos();
#else
return MouseEvent->globalPosition().toPoint();
#endif
}
void HandleMousePressEvent(QMouseEvent* MouseEvent);
bool HandleMouseMoveEvent(QMouseEvent* MouseEvent, QObject* Object);
void HandleMouseReleaseEvent(QMouseEvent* MouseEvent);
enum class DragMode
{
None,
Start,
Value
};
double mInitialValue = 0.0;
QPoint mLastPosition;
DragMode mDragMode = DragMode::None;
};
+90 -6
View File
@@ -3376,7 +3376,7 @@ void lcModel::SetCameraOrthographic(lcCamera* Camera, bool Ortho)
gMainWindow->UpdateSelectedObjects(false);
}
void lcModel::SetCameraFOV(lcCamera* Camera, float FOV)
void lcModel::SetCameraFOV(lcCamera* Camera, float FOV, bool Checkpoint)
{
if (Camera->m_fovy == FOV)
return;
@@ -3384,11 +3384,13 @@ void lcModel::SetCameraFOV(lcCamera* Camera, float FOV)
Camera->m_fovy = FOV;
Camera->UpdatePosition(mCurrentStep);
SaveCheckpoint(tr("Changing FOV"));
if (Checkpoint)
SaveCheckpoint(tr("Changing FOV"));
UpdateAllViews();
}
void lcModel::SetCameraZNear(lcCamera* Camera, float ZNear)
void lcModel::SetCameraZNear(lcCamera* Camera, float ZNear, bool Checkpoint)
{
if (Camera->m_zNear == ZNear)
return;
@@ -3396,11 +3398,13 @@ void lcModel::SetCameraZNear(lcCamera* Camera, float ZNear)
Camera->m_zNear = ZNear;
Camera->UpdatePosition(mCurrentStep);
SaveCheckpoint(tr("Editing Camera"));
if (Checkpoint)
SaveCheckpoint(tr("Editing Camera"));
UpdateAllViews();
}
void lcModel::SetCameraZFar(lcCamera* Camera, float ZFar)
void lcModel::SetCameraZFar(lcCamera* Camera, float ZFar, bool Checkpoint)
{
if (Camera->m_zFar == ZFar)
return;
@@ -3408,7 +3412,9 @@ void lcModel::SetCameraZFar(lcCamera* Camera, float ZFar)
Camera->m_zFar = ZFar;
Camera->UpdatePosition(mCurrentStep);
SaveCheckpoint(tr("Editing Camera"));
if (Checkpoint)
SaveCheckpoint(tr("Editing Camera"));
UpdateAllViews();
}
@@ -3447,6 +3453,84 @@ void lcModel::SetObjectsProperty(const std::vector<lcObject*>& Objects, lcObject
}
}
void lcModel::EndPropertyEdit(lcObjectPropertyId PropertyId, bool Accept)
{
if (!Accept)
{
if (!mUndoHistory.empty())
LoadCheckPoint(mUndoHistory.front());
return;
}
switch (PropertyId)
{
case lcObjectPropertyId::PieceId:
case lcObjectPropertyId::PieceColor:
case lcObjectPropertyId::PieceStepShow:
case lcObjectPropertyId::PieceStepHide:
case lcObjectPropertyId::CameraName:
case lcObjectPropertyId::CameraType:
break;
case lcObjectPropertyId::CameraFOV:
SaveCheckpoint(tr("Changing FOV"));
break;
case lcObjectPropertyId::CameraNear:
case lcObjectPropertyId::CameraFar:
SaveCheckpoint(tr("Editing Camera"));
break;
case lcObjectPropertyId::CameraPositionX:
case lcObjectPropertyId::CameraPositionY:
case lcObjectPropertyId::CameraPositionZ:
case lcObjectPropertyId::CameraTargetX:
case lcObjectPropertyId::CameraTargetY:
case lcObjectPropertyId::CameraTargetZ:
case lcObjectPropertyId::CameraUpX:
case lcObjectPropertyId::CameraUpY:
case lcObjectPropertyId::CameraUpZ:
SaveCheckpoint(tr("Move"));
break;
case lcObjectPropertyId::LightName:
case lcObjectPropertyId::LightType:
case lcObjectPropertyId::LightColor:
case lcObjectPropertyId::LightBlenderPower:
case lcObjectPropertyId::LightPOVRayPower:
case lcObjectPropertyId::LightCastShadow:
case lcObjectPropertyId::LightPOVRayFadeDistance:
case lcObjectPropertyId::LightPOVRayFadePower:
case lcObjectPropertyId::LightPointBlenderRadius:
case lcObjectPropertyId::LightSpotBlenderRadius:
case lcObjectPropertyId::LightDirectionalBlenderAngle:
case lcObjectPropertyId::LightAreaSizeX:
case lcObjectPropertyId::LightAreaSizeY:
case lcObjectPropertyId::LightSpotConeAngle:
case lcObjectPropertyId::LightSpotPenumbraAngle:
case lcObjectPropertyId::LightSpotPOVRayTightness:
case lcObjectPropertyId::LightAreaShape:
case lcObjectPropertyId::LightAreaPOVRayGridX:
case lcObjectPropertyId::LightAreaPOVRayGridY:
break;
case lcObjectPropertyId::ObjectPositionX:
case lcObjectPropertyId::ObjectPositionY:
case lcObjectPropertyId::ObjectPositionZ:
SaveCheckpoint(tr("Move"));
break;
case lcObjectPropertyId::ObjectRotationX:
case lcObjectPropertyId::ObjectRotationY:
case lcObjectPropertyId::ObjectRotationZ:
SaveCheckpoint(tr("Rotate"));
break;
case lcObjectPropertyId::Count:
break;
}
}
bool lcModel::AnyPiecesSelected() const
{
for (const std::unique_ptr<lcPiece>& Piece : mPieces)
+4 -3
View File
@@ -377,11 +377,12 @@ public:
void SetSelectedPiecesStepHide(lcStep Step);
void SetObjectsProperty(const std::vector<lcObject*>& Objects, lcObjectPropertyId PropertyId, QVariant Value);
void EndPropertyEdit(lcObjectPropertyId PropertyId, bool Accept);
void SetCameraOrthographic(lcCamera* Camera, bool Ortho);
void SetCameraFOV(lcCamera* Camera, float FOV);
void SetCameraZNear(lcCamera* Camera, float ZNear);
void SetCameraZFar(lcCamera* Camera, float ZFar);
void SetCameraFOV(lcCamera* Camera, float FOV, bool Checkpoint);
void SetCameraZNear(lcCamera* Camera, float ZNear, bool Checkpoint);
void SetCameraZFar(lcCamera* Camera, float ZFar, bool Checkpoint);
void ShowPropertiesDialog();
void ShowSelectByNameDialog();
+56 -18
View File
@@ -1,6 +1,7 @@
#include "lc_global.h"
#include "lc_propertieswidget.h"
#include "lc_keyframewidget.h"
#include "lc_doublespinbox.h"
#include "object.h"
#include "piece.h"
#include "camera.h"
@@ -246,9 +247,9 @@ void lcPropertiesWidget::AddBoolProperty(lcObjectPropertyId PropertyId, const QS
mLayoutRow++;
}
void lcPropertiesWidget::FloatChanged()
void lcPropertiesWidget::FloatEditingFinished()
{
QLineEdit* Widget = qobject_cast<QLineEdit*>(sender());
lcDoubleSpinBox* Widget = qobject_cast<lcDoubleSpinBox*>(sender());
lcObjectPropertyId PropertyId = GetEditorWidgetPropertyId(Widget);
if (PropertyId == lcObjectPropertyId::Count)
@@ -256,15 +257,50 @@ void lcPropertiesWidget::FloatChanged()
lcModel* Model = gMainWindow->GetActiveModel();
if (!Model)
return;
Model->EndPropertyEdit(PropertyId, true);
}
void lcPropertiesWidget::FloatEditingCanceled()
{
lcDoubleSpinBox* Widget = qobject_cast<lcDoubleSpinBox*>(sender());
lcObjectPropertyId PropertyId = GetEditorWidgetPropertyId(Widget);
if (PropertyId == lcObjectPropertyId::Count)
return;
lcModel* Model = gMainWindow->GetActiveModel();
if (!Model)
return;
Model->EndPropertyEdit(PropertyId, false);
}
void lcPropertiesWidget::FloatChanged(const QString& TextValue)
{
lcDoubleSpinBox* Widget = qobject_cast<lcDoubleSpinBox*>(sender());
lcObjectPropertyId PropertyId = GetEditorWidgetPropertyId(Widget);
float Value = lcParseValueLocalized(TextValue);
ChangeFloatValue(PropertyId, Value, true);
}
void lcPropertiesWidget::ChangeFloatValue(lcObjectPropertyId PropertyId, float Value, bool Dragging)
{
if (PropertyId == lcObjectPropertyId::Count)
return;
lcModel* Model = gMainWindow->GetActiveModel();
if (!Model)
return;
lcPiece* Piece = dynamic_cast<lcPiece*>(mFocusObject);
lcCamera* Camera = dynamic_cast<lcCamera*>(mFocusObject);
lcLight* Light = dynamic_cast<lcLight*>(mFocusObject);
float Value = lcParseValueLocalized(Widget->text());
// todo: mouse drag
if (PropertyId == lcObjectPropertyId::ObjectPositionX || PropertyId == lcObjectPropertyId::ObjectPositionY || PropertyId == lcObjectPropertyId::ObjectPositionZ)
{
@@ -282,7 +318,7 @@ void lcPropertiesWidget::FloatChanged()
lcVector3 Distance = Position - Center;
Model->MoveSelectedObjects(Distance, false, false, true, true, true);
Model->MoveSelectedObjects(Distance, false, false, true, !Dragging, true);
}
else if (PropertyId == lcObjectPropertyId::ObjectRotationX || PropertyId == lcObjectPropertyId::ObjectRotationY || PropertyId == lcObjectPropertyId::ObjectRotationZ)
{
@@ -302,7 +338,7 @@ void lcPropertiesWidget::FloatChanged()
else if (PropertyId == lcObjectPropertyId::ObjectRotationZ)
Rotation[2] = Value;
Model->RotateSelectedObjects(Rotation - InitialRotation, true, false, true, true);
Model->RotateSelectedObjects(Rotation - InitialRotation, true, false, true, !Dragging);
}
else if (Piece || Light)
{
@@ -338,7 +374,7 @@ void lcPropertiesWidget::FloatChanged()
lcVector3 Distance = End - Start;
Model->MoveSelectedObjects(Distance, false, false, true, true, true);
Model->MoveSelectedObjects(Distance, false, false, true, !Dragging, true);
if (Camera)
{
@@ -375,7 +411,7 @@ void lcPropertiesWidget::FloatChanged()
lcVector3 Distance = End - Start;
Model->MoveSelectedObjects(Distance, false, false, true, true, true);
Model->MoveSelectedObjects(Distance, false, false, true, !Dragging, true);
if (Camera)
{
@@ -412,7 +448,7 @@ void lcPropertiesWidget::FloatChanged()
lcVector3 Distance = End - Start;
Model->MoveSelectedObjects(Distance, false, false, true, true, true);
Model->MoveSelectedObjects(Distance, false, false, true, !Dragging, true);
if (Camera)
{
@@ -424,28 +460,28 @@ void lcPropertiesWidget::FloatChanged()
{
if (PropertyId == lcObjectPropertyId::CameraFOV)
{
Model->SetCameraFOV(Camera, Value);
Model->SetCameraFOV(Camera, Value, !Dragging);
}
else if (PropertyId == lcObjectPropertyId::CameraNear)
{
Model->SetCameraZNear(Camera, Value);
Model->SetCameraZNear(Camera, Value, !Dragging);
}
else if (PropertyId == lcObjectPropertyId::CameraFar)
{
Model->SetCameraZFar(Camera, Value);
Model->SetCameraZFar(Camera, Value, !Dragging);
}
}
}
void lcPropertiesWidget::UpdateFloat(lcObjectPropertyId PropertyId, float Value)
{
QLineEdit* Widget = qobject_cast<QLineEdit*>(mPropertyWidgets[static_cast<int>(PropertyId)].Editor);
lcDoubleSpinBox* Widget = qobject_cast<lcDoubleSpinBox*>(mPropertyWidgets[static_cast<int>(PropertyId)].Editor);
if (Widget)
{
QSignalBlocker Blocker(Widget);
Widget->setText(lcFormatValueLocalized(Value));
Widget->SetValue(Value);
}
UpdateKeyFrameWidget(PropertyId);
@@ -455,12 +491,14 @@ void lcPropertiesWidget::AddFloatProperty(lcObjectPropertyId PropertyId, const Q
{
AddLabel(PropertyId, Text, ToolTip);
QLineEdit* Widget = new QLineEdit(this);
lcDoubleSpinBox* Widget = new lcDoubleSpinBox(this);
Widget->setToolTip(ToolTip);
Widget->setValidator(new QDoubleValidator(Min, Max, 1, Widget));
Widget->setRange(Min, Max);
connect(Widget, &QLineEdit::editingFinished, this, &lcPropertiesWidget::FloatChanged);
connect(Widget, &lcDoubleSpinBox::EditingCanceled, this, &lcPropertiesWidget::FloatEditingCanceled);
connect(Widget, &lcDoubleSpinBox::EditingFinished, this, &lcPropertiesWidget::FloatEditingFinished);
connect(Widget, &lcDoubleSpinBox::textChanged, this, &lcPropertiesWidget::FloatChanged);
mLayout->addWidget(Widget, mLayoutRow, 2);
+5 -1
View File
@@ -18,7 +18,9 @@ protected slots:
void CategoryStateChanged(bool Expanded);
void KeyFrameChanged();
void BoolChanged();
void FloatChanged();
void FloatEditingFinished();
void FloatEditingCanceled();
void FloatChanged(const QString& TextValue);
void IntegerChanged();
void StepNumberChanged();
void StringChanged();
@@ -113,6 +115,8 @@ protected:
void UpdatePieceColor(lcObjectPropertyId PropertyId);
void UpdatePieceId(lcObjectPropertyId PropertyId);
void ChangeFloatValue(lcObjectPropertyId PropertyId, float Value, bool Dragging);
void SetEmpty();
void SetPiece(const std::vector<lcObject*>& Selection, lcObject* Focus);
void SetCamera(const std::vector<lcObject*>& Selection, lcObject* Focus);
+2
View File
@@ -188,6 +188,7 @@ SOURCES += \
common/lc_colors.cpp \
common/lc_commands.cpp \
common/lc_context.cpp \
common/lc_doublespinbox.cpp \
common/lc_edgecolordialog.cpp \
common/lc_file.cpp \
common/lc_findreplacewidget.cpp \
@@ -261,6 +262,7 @@ HEADERS += \
common/lc_colors.h \
common/lc_commands.h \
common/lc_context.h \
common/lc_doublespinbox.h \
common/lc_edgecolordialog.h \
common/lc_file.h \
common/lc_findreplacewidget.h \