diff --git a/toonz/sources/common/tunit/tunit.cpp b/toonz/sources/common/tunit/tunit.cpp index 1d6063ea99..90bbf638c2 100644 --- a/toonz/sources/common/tunit/tunit.cpp +++ b/toonz/sources/common/tunit/tunit.cpp @@ -532,6 +532,20 @@ std::wstring TMeasuredValue::toWideString(int decimals) const { return ::to_wstring(s) + L" " + measure; } +//------------------------------------------------------------------- + +void TMeasuredValue::modifyValue(double direction, int precision) { + for (int i = 0; i < precision; i++) { + direction /= 10; + } + std::wstring currExtension = + getMeasure()->getCurrentUnit()->getDefaultExtension(); + // use a smaller value for inches and cm + if (currExtension == L"\"" || currExtension == L"cm") direction /= 10; + double v = getValue(CurrentUnit); + setValue(CurrentUnit, v + direction); +} + //=================================================================== namespace { diff --git a/toonz/sources/include/tools/tooloptions.h b/toonz/sources/include/tools/tooloptions.h index 66fe951f36..64e7a4b6f9 100644 --- a/toonz/sources/include/tools/tooloptions.h +++ b/toonz/sources/include/tools/tooloptions.h @@ -19,6 +19,7 @@ #include #include #include +#include // STD includes #include @@ -63,6 +64,7 @@ class PegbarCenterField; class RGBLabel; class MeasuredValueField; class PaletteController; +class ClickableLabel; class QLabel; class QPushButton; @@ -200,21 +202,28 @@ class ArrowToolOptionsBox final : public ToolOptionsBox { PegbarChannelField *m_motionPathPosField; PegbarChannelField *m_ewPosField; PegbarChannelField *m_nsPosField; - QLabel *m_ewPosLabel; - QLabel *m_nsPosLabel; PegbarChannelField *m_zField; NoScaleField *m_noScaleZField; + ClickableLabel *m_motionPathPosLabel; + ClickableLabel *m_ewPosLabel; + ClickableLabel *m_nsPosLabel; + ClickableLabel *m_zLabel; + ToolOptionCheckbox *m_lockEWPosCheckbox; ToolOptionCheckbox *m_lockNSPosCheckbox; // SO = Stacked Order - QLabel *m_soLabel; + ClickableLabel *m_soLabel; PegbarChannelField *m_soField; // Rotation + ClickableLabel *m_rotationLabel; PegbarChannelField *m_rotationField; // Scale + ClickableLabel *m_globalScaleLabel; + ClickableLabel *m_scaleHLabel; + ClickableLabel *m_scaleVLabel; PegbarChannelField *m_globalScaleField; PegbarChannelField *m_scaleHField; PegbarChannelField *m_scaleVField; @@ -223,12 +232,16 @@ class ArrowToolOptionsBox final : public ToolOptionsBox { ToolOptionCombo *m_maintainCombo; // Shear + ClickableLabel *m_shearHLabel; + ClickableLabel *m_shearVLabel; PegbarChannelField *m_shearHField; PegbarChannelField *m_shearVField; ToolOptionCheckbox *m_lockShearHCheckbox; ToolOptionCheckbox *m_lockShearVCheckbox; // Center Position + ClickableLabel *m_ewCenterLabel; + ClickableLabel *m_nsCenterLabel; PegbarCenterField *m_ewCenterField; PegbarCenterField *m_nsCenterField; ToolOptionCheckbox *m_lockEWCenterCheckbox; @@ -315,6 +328,16 @@ class IconViewField final : public QWidget { protected: void paintEvent(QPaintEvent *e); + // these are used for dragging on the icon to + // change the value of the field + void mousePressEvent(QMouseEvent *) override; + void mouseMoveEvent(QMouseEvent *) override; + void mouseReleaseEvent(QMouseEvent *) override; + +signals: + void onMousePress(QMouseEvent *event); + void onMouseMove(QMouseEvent *event); + void onMouseRelease(QMouseEvent *event); }; //----------------------------------------------------------------------------- @@ -351,8 +374,10 @@ class SelectionToolOptionsBox final : public ToolOptionsBox, void onPropertyChanged(); protected slots: - void onScaleXValueChanged(); - void onScaleYValueChanged(); + // addToUndo is only set to false when dragging with the mouse + // to set the value. It is set to true on mouse release. + void onScaleXValueChanged(bool addToUndo = true); + void onScaleYValueChanged(bool addToUndo = true); void onSetSaveboxCheckboxChanged(bool); }; diff --git a/toonz/sources/include/toonzqt/doublefield.h b/toonz/sources/include/toonzqt/doublefield.h index a390af3393..13281b60fd 100644 --- a/toonz/sources/include/toonzqt/doublefield.h +++ b/toonz/sources/include/toonzqt/doublefield.h @@ -32,6 +32,9 @@ namespace DVGui { class DVAPI DoubleValueLineEdit : public LineEdit { Q_OBJECT + int m_xMouse; + bool m_mouseDragEditing = false; + public: DoubleValueLineEdit(QWidget *parent = 0) : LineEdit(parent) {} ~DoubleValueLineEdit() {} @@ -49,6 +52,12 @@ class DVAPI DoubleValueLineEdit : public LineEdit { * lostFocus. */ void focusOutEvent(QFocusEvent *) override; + // these are only used for mouse dragging + // to set the value of the field. + void mousePressEvent(QMouseEvent *) override; + void mouseMoveEvent(QMouseEvent *) override; + void mouseReleaseEvent(QMouseEvent *) override; + signals: /*! To emit when value change. */ void valueChanged(); @@ -217,6 +226,9 @@ class DVAPI MeasuredDoubleLineEdit : public DoubleValueLineEdit { double m_errorHighlighting; int m_errorHighlightingTimerId; int m_decimals; + int m_xMouse; + bool m_labelClicked = false; + bool m_mouseDragEditing = false; public: MeasuredDoubleLineEdit(QWidget *parent = 0); @@ -241,11 +253,21 @@ class DVAPI MeasuredDoubleLineEdit : public DoubleValueLineEdit { protected: void timerEvent(QTimerEvent *e) override; + // these are only used for mouse dragging + // to set the value of the field. + void mousePressEvent(QMouseEvent *) override; + void mouseMoveEvent(QMouseEvent *) override; + void mouseReleaseEvent(QMouseEvent *) override; protected slots: void onEditingFinished(); void onTextChanged(const QString &); + + // This allows the field to be set by dragging on the label + void receiveMouseMove(QMouseEvent *event); + void receiveMousePress(QMouseEvent *event); + void receiveMouseRelease(QMouseEvent *event); }; //============================================================================= diff --git a/toonz/sources/include/toonzqt/functionsheet.h b/toonz/sources/include/toonzqt/functionsheet.h index a8547522f5..50ab8312a1 100644 --- a/toonz/sources/include/toonzqt/functionsheet.h +++ b/toonz/sources/include/toonzqt/functionsheet.h @@ -66,6 +66,11 @@ class FunctionSheetCellViewer final : public Spreadsheet::CellPanel { DVGui::LineEdit *m_lineEdit; int m_editRow, m_editCol; + // for mouse dragging to adjust the value + double m_currentValue = 0.0; + double m_updatedValue = 0.0; + int m_mouseXPosition; + public: FunctionSheetCellViewer(FunctionSheet *parent); @@ -83,6 +88,10 @@ class FunctionSheetCellViewer final : public Spreadsheet::CellPanel { private slots: void onCellEditorEditingFinished(); + + // double clicking opens the line edit where mouse dragging + // can change the value. It sends a signal to this slot. + void onMouseMovedInLineEdit(QMouseEvent *event); }; class FunctionSheet final : public SpreadsheetViewer { diff --git a/toonz/sources/include/toonzqt/intfield.h b/toonz/sources/include/toonzqt/intfield.h index 09748959e5..70e1820cd7 100644 --- a/toonz/sources/include/toonzqt/intfield.h +++ b/toonz/sources/include/toonzqt/intfield.h @@ -86,6 +86,8 @@ class DVAPI IntLineEdit : public LineEdit { //! If digits is less than 1 the line edit show the natural number without //! prepend zeros. int m_showedDigits; + int m_xMouse; + bool m_mouseDragEditing = false; public: IntLineEdit(QWidget *parent = 0, int value = 1, @@ -119,6 +121,11 @@ class DVAPI IntLineEdit : public LineEdit { /*! If focus is lost and current text value is out of range emit signal \b editingFinished.*/ void focusOutEvent(QFocusEvent *) override; + + // for dragging the mouse to set the value + void mousePressEvent(QMouseEvent *) override; + void mouseMoveEvent(QMouseEvent *) override; + void mouseReleaseEvent(QMouseEvent *) override; }; //============================================================================= diff --git a/toonz/sources/include/toonzqt/lineedit.h b/toonz/sources/include/toonzqt/lineedit.h index 88fde3b1ce..fca909c141 100644 --- a/toonz/sources/include/toonzqt/lineedit.h +++ b/toonz/sources/include/toonzqt/lineedit.h @@ -33,6 +33,7 @@ class DVAPI LineEdit : public QLineEdit { bool m_isReturnPressed; bool m_forbiddenSpecialChars; + bool m_mouseDragEditing = false; public: LineEdit(QWidget *parent = 0, bool forbiddenSpecialChars = false); @@ -43,13 +44,22 @@ class DVAPI LineEdit : public QLineEdit { ~LineEdit() {} + // In the function editor, ctrl + dragging on the lineedit + // can adjust the value. + bool getMouseDragEditing() { return m_mouseDragEditing; } + void setMouseDragEditing(bool status) { m_mouseDragEditing = status; } + protected: void focusInEvent(QFocusEvent *event) override; void keyPressEvent(QKeyEvent *event) override; + void mouseMoveEvent(QMouseEvent *) override; signals: void focusIn(); void returnPressedNow(); + // this signal is only used for mouse drag value editing in the function + // panel. + void mouseMoved(QMouseEvent *); }; //----------------------------------------------------------------------------- diff --git a/toonz/sources/include/tunit.h b/toonz/sources/include/tunit.h index 084309191a..83adac5de5 100644 --- a/toonz/sources/include/tunit.h +++ b/toonz/sources/include/tunit.h @@ -151,6 +151,12 @@ class DVAPI TMeasuredValue { void setMeasure(const TMeasure *measure); void setMeasure(std::string measureName); + // used for mouse dragging to change value + // precision is how many times to divide by 10 to adjust value + // nothing calls precision yet, since just basic functionality + // is in place for dragging + void modifyValue(double direction, int precision = 0); + enum UnitType { MainUnit, CurrentUnit }; double getValue(UnitType uType) const { diff --git a/toonz/sources/tnztools/plastictool.cpp b/toonz/sources/tnztools/plastictool.cpp index 93f7a30c96..ea3c9c0cc6 100644 --- a/toonz/sources/tnztools/plastictool.cpp +++ b/toonz/sources/tnztools/plastictool.cpp @@ -471,7 +471,7 @@ PlasticToolOptionsBox::PlasticToolOptionsBox(QWidget *parent, TTool *tool, distanceField->setGlobalKey(&l_plasticTool.m_globalKey, &l_plasticTool.m_relayGroup); - QLabel *distanceLabel = new QLabel(tr("Distance")); + ClickableLabel *distanceLabel = new ClickableLabel(tr("Distance")); distanceLabel->setFixedHeight(20); // Angle @@ -480,7 +480,7 @@ PlasticToolOptionsBox::PlasticToolOptionsBox(QWidget *parent, TTool *tool, angleField->setGlobalKey(&l_plasticTool.m_globalKey, &l_plasticTool.m_relayGroup); - QLabel *angleLabel = new QLabel(tr("Angle")); + ClickableLabel *angleLabel = new ClickableLabel(tr("Angle")); angleLabel->setFixedHeight(20); // SO @@ -489,7 +489,7 @@ PlasticToolOptionsBox::PlasticToolOptionsBox(QWidget *parent, TTool *tool, soField->setGlobalKey(&l_plasticTool.m_globalKey, &l_plasticTool.m_relayGroup); - QLabel *soLabel = new QLabel(tr("SO")); + ClickableLabel *soLabel = new ClickableLabel(tr("SO")); soLabel->setFixedHeight(20); QHBoxLayout *animateLayout = animateOptionsBox->hLayout(); @@ -500,6 +500,26 @@ PlasticToolOptionsBox::PlasticToolOptionsBox(QWidget *parent, TTool *tool, animateLayout->insertWidget(0, distanceField); animateLayout->insertWidget(0, distanceLabel); + ret = ret && connect(distanceLabel, SIGNAL(onMousePress(QMouseEvent *)), + distanceField, SLOT(receiveMousePress(QMouseEvent *))); + ret = ret && connect(distanceLabel, SIGNAL(onMouseMove(QMouseEvent *)), + distanceField, SLOT(receiveMouseMove(QMouseEvent *))); + ret = ret && connect(distanceLabel, SIGNAL(onMouseRelease(QMouseEvent *)), + distanceField, SLOT(receiveMouseRelease(QMouseEvent *))); + ret = ret && connect(angleLabel, SIGNAL(onMousePress(QMouseEvent *)), + angleField, SLOT(receiveMousePress(QMouseEvent *))); + ret = ret && connect(angleLabel, SIGNAL(onMouseMove(QMouseEvent *)), + angleField, SLOT(receiveMouseMove(QMouseEvent *))); + ret = ret && connect(angleLabel, SIGNAL(onMouseRelease(QMouseEvent *)), + angleField, SLOT(receiveMouseRelease(QMouseEvent *))); + ret = ret && connect(soLabel, SIGNAL(onMousePress(QMouseEvent *)), soField, + SLOT(receiveMousePress(QMouseEvent *))); + ret = ret && connect(soLabel, SIGNAL(onMouseMove(QMouseEvent *)), soField, + SLOT(receiveMouseMove(QMouseEvent *))); + ret = ret && connect(soLabel, SIGNAL(onMouseRelease(QMouseEvent *)), soField, + SLOT(receiveMouseRelease(QMouseEvent *))); + assert(ret); + onPropertyChanged(); } diff --git a/toonz/sources/tnztools/tooloptions.cpp b/toonz/sources/tnztools/tooloptions.cpp index 902f72c5ac..16f0ea7aa3 100644 --- a/toonz/sources/tnztools/tooloptions.cpp +++ b/toonz/sources/tnztools/tooloptions.cpp @@ -469,8 +469,12 @@ ArrowToolOptionsBox::ArrowToolOptionsBox( m_zField = new PegbarChannelField(m_tool, TStageObject::T_Z, "field", frameHandle, objHandle, xshHandle, this); m_noScaleZField = new NoScaleField(m_tool, "field"); - m_ewPosLabel = new QLabel(tr("E/W:"), this); - m_nsPosLabel = new QLabel(tr("N/S:"), this); + + m_zLabel = new ClickableLabel(tr("Z:"), this); + m_motionPathPosLabel = new ClickableLabel(tr("Position:"), this); + m_ewPosLabel = new ClickableLabel(tr("E/W:"), this); + m_nsPosLabel = new ClickableLabel(tr("N/S:"), this); + // Lock E/W TBoolProperty *lockProp = dynamic_cast(m_pg->getProperty("Lock Position E/W")); @@ -484,11 +488,12 @@ ArrowToolOptionsBox::ArrowToolOptionsBox( m_lockNSPosCheckbox = new ToolOptionCheckbox(m_tool, lockProp, toolHandle, this); // stacking order - m_soLabel = new QLabel(tr("SO:"), this); + m_soLabel = new ClickableLabel(tr("SO:"), this); m_soField = new PegbarChannelField(m_tool, TStageObject::T_SO, "field", frameHandle, objHandle, xshHandle, this); /* --- Rotation --- */ + m_rotationLabel = new ClickableLabel(tr("Rotation:"), this); m_rotationField = new PegbarChannelField(m_tool, TStageObject::T_Angle, "field", frameHandle, objHandle, xshHandle, this); @@ -503,6 +508,11 @@ ArrowToolOptionsBox::ArrowToolOptionsBox( m_scaleVField = new PegbarChannelField(m_tool, TStageObject::T_ScaleY, "field", frameHandle, objHandle, xshHandle, this); + + m_globalScaleLabel = new ClickableLabel(tr("Global:"), this); + m_scaleHLabel = new ClickableLabel(tr("H:"), this); + m_scaleVLabel = new ClickableLabel(tr("V:"), this); + TEnumProperty *scaleConstraintProp = dynamic_cast(m_pg->getProperty("Scale Constraint:")); if (scaleConstraintProp) @@ -526,6 +536,9 @@ ArrowToolOptionsBox::ArrowToolOptionsBox( m_shearVField = new PegbarChannelField(m_tool, TStageObject::T_ShearY, "field", frameHandle, objHandle, xshHandle, this); + m_shearHLabel = new ClickableLabel(tr("H:"), this); + m_shearVLabel = new ClickableLabel(tr("V:"), this); + // Lock Shear H lockProp = dynamic_cast(m_pg->getProperty("Lock Shear H")); if (lockProp) @@ -542,6 +555,9 @@ ArrowToolOptionsBox::ArrowToolOptionsBox( new PegbarCenterField(m_tool, 0, "field", objHandle, xshHandle, this); m_nsCenterField = new PegbarCenterField(m_tool, 1, "field", objHandle, xshHandle, this); + m_ewCenterLabel = new ClickableLabel(tr("E/W:"), this); + m_nsCenterLabel = new ClickableLabel(tr("N/S:"), this); + // Lock E/W Center lockProp = dynamic_cast(m_pg->getProperty("Lock Center E/W")); @@ -606,7 +622,7 @@ ArrowToolOptionsBox::ArrowToolOptionsBox( posFrame->setLayout(posLay); m_mainStackedWidget->addWidget(posFrame); { - posLay->addWidget(new QLabel(tr("Position"), this), 0); + posLay->addWidget(m_motionPathPosLabel, 0); posLay->addSpacing(ITEM_SPACING); posLay->addWidget(m_motionPathPosField, 0); @@ -625,7 +641,7 @@ ArrowToolOptionsBox::ArrowToolOptionsBox( posLay->addSpacing(ITEM_SPACING); - posLay->addWidget(new QLabel(tr("Z:"), this), 0); + posLay->addWidget(m_zLabel, 0); posLay->addSpacing(LABEL_SPACING); posLay->addWidget(m_zField, 10); posLay->addSpacing(LABEL_SPACING); @@ -649,7 +665,7 @@ ArrowToolOptionsBox::ArrowToolOptionsBox( rotFrame->setLayout(rotLay); m_mainStackedWidget->addWidget(rotFrame); { - rotLay->addWidget(new QLabel(tr("Rotation"), this), 0); + rotLay->addWidget(m_rotationLabel, 0); rotLay->addSpacing(ITEM_SPACING); rotLay->addWidget(m_rotationField, 10); @@ -668,20 +684,20 @@ ArrowToolOptionsBox::ArrowToolOptionsBox( scaleLay->addWidget(new QLabel(tr("Scale"), this), 0); scaleLay->addSpacing(ITEM_SPACING); - scaleLay->addWidget(new QLabel(tr("Global:"), this), 0); + scaleLay->addWidget(m_globalScaleLabel, 0); scaleLay->addSpacing(LABEL_SPACING); scaleLay->addWidget(m_globalScaleField, 10); scaleLay->addSpacing(ITEM_SPACING); - scaleLay->addWidget(new QLabel(tr("H:"), this), 0); + scaleLay->addWidget(m_scaleHLabel, 0); scaleLay->addSpacing(LABEL_SPACING); scaleLay->addWidget(m_scaleHField, 10); scaleLay->addWidget(m_lockScaleHCheckbox, 0); scaleLay->addSpacing(ITEM_SPACING); - scaleLay->addWidget(new QLabel(tr("V:"), this), 0); + scaleLay->addWidget(m_scaleVLabel, 0); scaleLay->addSpacing(LABEL_SPACING); scaleLay->addWidget(m_scaleVField, 10); scaleLay->addWidget(m_lockScaleVCheckbox, 0); @@ -706,14 +722,14 @@ ArrowToolOptionsBox::ArrowToolOptionsBox( shearLay->addWidget(new QLabel(tr("Shear"), this), 0); shearLay->addSpacing(ITEM_SPACING); - shearLay->addWidget(new QLabel(tr("H:"), this), 0); + shearLay->addWidget(m_shearHLabel, 0); shearLay->addSpacing(LABEL_SPACING); shearLay->addWidget(m_shearHField, 10); shearLay->addWidget(m_lockShearHCheckbox, 0); shearLay->addSpacing(ITEM_SPACING); - shearLay->addWidget(new QLabel(tr("V:"), this), 0); + shearLay->addWidget(m_shearVLabel, 0); shearLay->addSpacing(LABEL_SPACING); shearLay->addWidget(m_shearVField, 10); shearLay->addWidget(m_lockShearVCheckbox, 0); @@ -734,14 +750,14 @@ ArrowToolOptionsBox::ArrowToolOptionsBox( centerPosLay->addWidget(new QLabel(tr("Center Position"), this), 0); centerPosLay->addSpacing(ITEM_SPACING); - centerPosLay->addWidget(new QLabel(tr("E/W:"), this), 0); + centerPosLay->addWidget(m_ewCenterLabel, 0); centerPosLay->addSpacing(LABEL_SPACING); centerPosLay->addWidget(m_ewCenterField, 10); centerPosLay->addWidget(m_lockEWCenterCheckbox, 0); centerPosLay->addSpacing(ITEM_SPACING); - centerPosLay->addWidget(new QLabel(tr("N/S:"), this), 0); + centerPosLay->addWidget(m_nsCenterLabel, 0); centerPosLay->addSpacing(LABEL_SPACING); centerPosLay->addWidget(m_nsCenterField, 10); centerPosLay->addWidget(m_lockNSCenterCheckbox, 0); @@ -816,6 +832,85 @@ ArrowToolOptionsBox::ArrowToolOptionsBox( SLOT(onScaleTypeChanged(int))); } + connect(m_motionPathPosLabel, SIGNAL(onMousePress(QMouseEvent *)), + m_motionPathPosField, SLOT(receiveMousePress(QMouseEvent *))); + connect(m_motionPathPosLabel, SIGNAL(onMouseMove(QMouseEvent *)), + m_motionPathPosField, SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_motionPathPosLabel, SIGNAL(onMouseRelease(QMouseEvent *)), + m_motionPathPosField, SLOT(receiveMouseRelease(QMouseEvent *))); + connect(m_ewPosLabel, SIGNAL(onMousePress(QMouseEvent *)), m_ewPosField, + SLOT(receiveMousePress(QMouseEvent *))); + connect(m_ewPosLabel, SIGNAL(onMouseMove(QMouseEvent *)), m_ewPosField, + SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_ewPosLabel, SIGNAL(onMouseRelease(QMouseEvent *)), m_ewPosField, + SLOT(receiveMouseRelease(QMouseEvent *))); + connect(m_nsPosLabel, SIGNAL(onMousePress(QMouseEvent *)), m_nsPosField, + SLOT(receiveMousePress(QMouseEvent *))); + connect(m_nsPosLabel, SIGNAL(onMouseMove(QMouseEvent *)), m_nsPosField, + SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_nsPosLabel, SIGNAL(onMouseRelease(QMouseEvent *)), m_nsPosField, + SLOT(receiveMouseRelease(QMouseEvent *))); + connect(m_zLabel, SIGNAL(onMousePress(QMouseEvent *)), m_zField, + SLOT(receiveMousePress(QMouseEvent *))); + connect(m_zLabel, SIGNAL(onMouseMove(QMouseEvent *)), m_zField, + SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_zLabel, SIGNAL(onMouseRelease(QMouseEvent *)), m_zField, + SLOT(receiveMouseRelease(QMouseEvent *))); + connect(m_soLabel, SIGNAL(onMousePress(QMouseEvent *)), m_soField, + SLOT(receiveMousePress(QMouseEvent *))); + connect(m_soLabel, SIGNAL(onMouseMove(QMouseEvent *)), m_soField, + SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_soLabel, SIGNAL(onMouseRelease(QMouseEvent *)), m_soField, + SLOT(receiveMouseRelease(QMouseEvent *))); + connect(m_rotationLabel, SIGNAL(onMousePress(QMouseEvent *)), m_rotationField, + SLOT(receiveMousePress(QMouseEvent *))); + connect(m_rotationLabel, SIGNAL(onMouseMove(QMouseEvent *)), m_rotationField, + SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_rotationLabel, SIGNAL(onMouseRelease(QMouseEvent *)), + m_rotationField, SLOT(receiveMouseRelease(QMouseEvent *))); + connect(m_globalScaleLabel, SIGNAL(onMousePress(QMouseEvent *)), + m_globalScaleField, SLOT(receiveMousePress(QMouseEvent *))); + connect(m_globalScaleLabel, SIGNAL(onMouseMove(QMouseEvent *)), + m_globalScaleField, SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_globalScaleLabel, SIGNAL(onMouseRelease(QMouseEvent *)), + m_globalScaleField, SLOT(receiveMouseRelease(QMouseEvent *))); + connect(m_scaleHLabel, SIGNAL(onMousePress(QMouseEvent *)), m_scaleHField, + SLOT(receiveMousePress(QMouseEvent *))); + connect(m_scaleHLabel, SIGNAL(onMouseMove(QMouseEvent *)), m_scaleHField, + SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_scaleHLabel, SIGNAL(onMouseRelease(QMouseEvent *)), m_scaleHField, + SLOT(receiveMouseRelease(QMouseEvent *))); + connect(m_scaleVLabel, SIGNAL(onMousePress(QMouseEvent *)), m_scaleVField, + SLOT(receiveMousePress(QMouseEvent *))); + connect(m_scaleVLabel, SIGNAL(onMouseMove(QMouseEvent *)), m_scaleVField, + SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_scaleVLabel, SIGNAL(onMouseRelease(QMouseEvent *)), m_scaleVField, + SLOT(receiveMouseRelease(QMouseEvent *))); + connect(m_shearHLabel, SIGNAL(onMousePress(QMouseEvent *)), m_shearHField, + SLOT(receiveMousePress(QMouseEvent *))); + connect(m_shearHLabel, SIGNAL(onMouseMove(QMouseEvent *)), m_shearHField, + SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_shearHLabel, SIGNAL(onMouseRelease(QMouseEvent *)), m_shearHField, + SLOT(receiveMouseRelease(QMouseEvent *))); + connect(m_shearVLabel, SIGNAL(onMousePress(QMouseEvent *)), m_shearVField, + SLOT(receiveMousePress(QMouseEvent *))); + connect(m_shearVLabel, SIGNAL(onMouseMove(QMouseEvent *)), m_shearVField, + SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_shearVLabel, SIGNAL(onMouseRelease(QMouseEvent *)), m_shearVField, + SLOT(receiveMouseRelease(QMouseEvent *))); + connect(m_ewCenterLabel, SIGNAL(onMousePress(QMouseEvent *)), m_ewCenterField, + SLOT(receiveMousePress(QMouseEvent *))); + connect(m_ewCenterLabel, SIGNAL(onMouseMove(QMouseEvent *)), m_ewCenterField, + SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_ewCenterLabel, SIGNAL(onMouseRelease(QMouseEvent *)), + m_ewCenterField, SLOT(receiveMouseRelease(QMouseEvent *))); + connect(m_nsCenterLabel, SIGNAL(onMousePress(QMouseEvent *)), m_nsCenterField, + SLOT(receiveMousePress(QMouseEvent *))); + connect(m_nsCenterLabel, SIGNAL(onMouseMove(QMouseEvent *)), m_nsCenterField, + SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_nsCenterLabel, SIGNAL(onMouseRelease(QMouseEvent *)), + m_nsCenterField, SLOT(receiveMouseRelease(QMouseEvent *))); + if (globalKeyProp) { std::string actionName = "A_ToolOption_" + globalKeyProp->getId(); QAction *a = CommandManager::instance()->getAction(actionName.c_str()); @@ -1006,6 +1101,18 @@ void IconViewField::paintEvent(QPaintEvent *e) { p.drawPixmap(QRect(0, 3, 21, 17), m_pm[m_iconType]); } +void IconViewField::mousePressEvent(QMouseEvent *event) { + emit onMousePress(event); +} + +void IconViewField::mouseMoveEvent(QMouseEvent *event) { + emit onMouseMove(event); +} + +void IconViewField::mouseReleaseEvent(QMouseEvent *event) { + emit onMouseRelease(event); +} + //----------------------------------------------------------------------------- SelectionToolOptionsBox::SelectionToolOptionsBox(QWidget *parent, TTool *tool, @@ -1028,9 +1135,9 @@ SelectionToolOptionsBox::SelectionToolOptionsBox(QWidget *parent, TTool *tool, IconViewField *iconView = new IconViewField(this, IconViewField::Icon_ScalePeg); - m_scaleXLabel = new QLabel(tr("H:"), this); + m_scaleXLabel = new ClickableLabel(tr("H:"), this); m_scaleXField = new SelectionScaleField(selectionTool, 0, "Scale X"); - m_scaleYLabel = new QLabel(tr("V:"), this); + m_scaleYLabel = new ClickableLabel(tr("V:"), this); m_scaleYField = new SelectionScaleField(selectionTool, 1, "Scale Y"); m_scaleLink = new DVGui::CheckBox(tr("Link"), this); @@ -1040,9 +1147,9 @@ SelectionToolOptionsBox::SelectionToolOptionsBox(QWidget *parent, TTool *tool, IconViewField *moveIconView = new IconViewField(this, IconViewField::Icon_Position); - m_moveXLabel = new QLabel(tr("E/W:"), this); + m_moveXLabel = new ClickableLabel(tr("E/W:"), this); m_moveXField = new SelectionMoveField(selectionTool, 0, "Move X"); - m_moveYLabel = addLabel(tr("N/S:")); + m_moveYLabel = new ClickableLabel(tr("N/S:"), this); m_moveYField = new SelectionMoveField(selectionTool, 1, "Move Y"); if (rasterSelectionTool) { @@ -1097,6 +1204,13 @@ SelectionToolOptionsBox::SelectionToolOptionsBox(QWidget *parent, TTool *tool, new IconViewField(this, IconViewField::Icon_Thickness); m_thickChangeField = new ThickChangeField(selectionTool, tr("Thickness")); + connect(thicknessIconView, SIGNAL(onMousePress(QMouseEvent *)), + m_thickChangeField, SLOT(receiveMousePress(QMouseEvent *))); + connect(thicknessIconView, SIGNAL(onMouseMove(QMouseEvent *)), + m_thickChangeField, SLOT(receiveMouseMove(QMouseEvent *))); + connect(thicknessIconView, SIGNAL(onMouseRelease(QMouseEvent *)), + m_thickChangeField, SLOT(receiveMouseRelease(QMouseEvent *))); + addSeparator(); hLayout()->addWidget(thicknessIconView, 0); hLayout()->addWidget(m_thickChangeField, 10); @@ -1123,14 +1237,43 @@ SelectionToolOptionsBox::SelectionToolOptionsBox(QWidget *parent, TTool *tool, hLayout()->addStretch(1); // assert(ret); - bool ret = connect(m_scaleXField, SIGNAL(valueChange()), - SLOT(onScaleXValueChanged())); - ret = ret && connect(m_scaleYField, SIGNAL(valueChange()), - SLOT(onScaleYValueChanged())); + bool ret = connect(m_scaleXField, SIGNAL(valueChange(bool)), + SLOT(onScaleXValueChanged(bool))); + ret = ret && connect(m_scaleYField, SIGNAL(valueChange(bool)), + SLOT(onScaleYValueChanged(bool))); if (m_setSaveboxCheckbox) ret = ret && connect(m_setSaveboxCheckbox, SIGNAL(toggled(bool)), SLOT(onSetSaveboxCheckboxChanged(bool))); - + connect(m_scaleXLabel, SIGNAL(onMousePress(QMouseEvent *)), m_scaleXField, + SLOT(receiveMousePress(QMouseEvent *))); + connect(m_scaleXLabel, SIGNAL(onMouseMove(QMouseEvent *)), m_scaleXField, + SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_scaleXLabel, SIGNAL(onMouseRelease(QMouseEvent *)), m_scaleXField, + SLOT(receiveMouseRelease(QMouseEvent *))); + connect(m_scaleYLabel, SIGNAL(onMousePress(QMouseEvent *)), m_scaleYField, + SLOT(receiveMousePress(QMouseEvent *))); + connect(m_scaleYLabel, SIGNAL(onMouseMove(QMouseEvent *)), m_scaleYField, + SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_scaleYLabel, SIGNAL(onMouseRelease(QMouseEvent *)), m_scaleYField, + SLOT(receiveMouseRelease(QMouseEvent *))); + connect(rotIconView, SIGNAL(onMousePress(QMouseEvent *)), m_rotationField, + SLOT(receiveMousePress(QMouseEvent *))); + connect(rotIconView, SIGNAL(onMouseMove(QMouseEvent *)), m_rotationField, + SLOT(receiveMouseMove(QMouseEvent *))); + connect(rotIconView, SIGNAL(onMouseRelease(QMouseEvent *)), m_rotationField, + SLOT(receiveMouseRelease(QMouseEvent *))); + connect(m_moveXLabel, SIGNAL(onMousePress(QMouseEvent *)), m_moveXField, + SLOT(receiveMousePress(QMouseEvent *))); + connect(m_moveXLabel, SIGNAL(onMouseMove(QMouseEvent *)), m_moveXField, + SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_moveXLabel, SIGNAL(onMouseRelease(QMouseEvent *)), m_moveXField, + SLOT(receiveMouseRelease(QMouseEvent *))); + connect(m_moveYLabel, SIGNAL(onMousePress(QMouseEvent *)), m_moveYField, + SLOT(receiveMousePress(QMouseEvent *))); + connect(m_moveYLabel, SIGNAL(onMouseMove(QMouseEvent *)), m_moveYField, + SLOT(receiveMouseMove(QMouseEvent *))); + connect(m_moveYLabel, SIGNAL(onMouseRelease(QMouseEvent *)), m_moveYField, + SLOT(receiveMouseRelease(QMouseEvent *))); // assert(ret); updateStatus(); @@ -1170,22 +1313,22 @@ void SelectionToolOptionsBox::updateStatus() { //----------------------------------------------------------------------------- -void SelectionToolOptionsBox::onScaleXValueChanged() { +void SelectionToolOptionsBox::onScaleXValueChanged(bool addToUndo) { if (!m_scaleLink->isChecked() || m_scaleXField->getValue() == m_scaleYField->getValue()) return; m_scaleYField->setValue(m_scaleXField->getValue()); - m_scaleYField->applyChange(); + m_scaleYField->applyChange(addToUndo); } //----------------------------------------------------------------------------- -void SelectionToolOptionsBox::onScaleYValueChanged() { +void SelectionToolOptionsBox::onScaleYValueChanged(bool addToUndo) { if (!m_scaleLink->isChecked() || m_scaleXField->getValue() == m_scaleYField->getValue()) return; m_scaleXField->setValue(m_scaleYField->getValue()); - m_scaleXField->applyChange(); + m_scaleXField->applyChange(addToUndo); } //----------------------------------------------------------------------------- diff --git a/toonz/sources/tnztools/tooloptionscontrols.cpp b/toonz/sources/tnztools/tooloptionscontrols.cpp index 8708fbdae0..050baa7efb 100644 --- a/toonz/sources/tnztools/tooloptionscontrols.cpp +++ b/toonz/sources/tnztools/tooloptionscontrols.cpp @@ -13,7 +13,6 @@ #include "toonz/tpalettehandle.h" #include "toonz/tobjecthandle.h" #include "toonz/stage2.h" -#include "toonz/stageobjectutil.h" #include "toonz/doubleparamcmd.h" #include "toonz/preferences.h" @@ -992,6 +991,13 @@ void MeasuredValueField::setMeasure(std::string name) { void MeasuredValueField::commit() { if (!m_modified && !isReturnPressed()) return; + // commit is called when the field comes out of focus. + // mouse drag will call this - return if coming from mouse drag. + // else undo is set twice + if (m_mouseEdit) { + m_mouseEdit = false; + return; + } int err = 1; bool isSet = m_value->setValue(text().toStdWString(), &err); m_modified = false; @@ -1054,6 +1060,65 @@ void MeasuredValueField::setPrecision(int precision) { setText(QString::fromStdWString(m_value->toWideString(m_precision))); } +//----------------------------------------------------------------------------- + +void MeasuredValueField::mousePressEvent(QMouseEvent *e) { + if (!isEnabled()) return; + if ((e->buttons() == Qt::MiddleButton) || m_labelClicked) { + m_xMouse = e->x(); + m_mouseEdit = true; + m_originalValue = m_value->getValue(TMeasuredValue::CurrentUnit); + } else + QLineEdit::mousePressEvent(e); +} + +//----------------------------------------------------------------------------- + +void MeasuredValueField::mouseMoveEvent(QMouseEvent *e) { + if (!isEnabled()) return; + if ((e->buttons() == Qt::MiddleButton) || m_labelClicked) { + m_value->modifyValue((e->x() - m_xMouse) / 2); + setText(QString::fromStdWString(m_value->toWideString(m_precision))); + m_xMouse = e->x(); + // measuredValueChanged to update the UI, but don't add to undo + emit measuredValueChanged(m_value, false); + } else + QLineEdit::mouseMoveEvent(e); +} + +//----------------------------------------------------------------------------- + +void MeasuredValueField::mouseReleaseEvent(QMouseEvent *e) { + if (!isEnabled()) return; + // m_mouseEdit will be set false in commit + if (m_mouseEdit) { + // This seems redundant, but this is necessary for undo to work + double valueToRestore = m_value->getValue(TMeasuredValue::CurrentUnit); + m_value->setValue(TMeasuredValue::CurrentUnit, m_originalValue); + setText(QString::fromStdWString(m_value->toWideString(m_precision))); + emit measuredValueChanged(m_value, false); + // add this to undo + m_value->setValue(TMeasuredValue::CurrentUnit, valueToRestore); + setText(QString::fromStdWString(m_value->toWideString(m_precision))); + emit measuredValueChanged(m_value, true); + clearFocus(); + } else { + if (!hasSelectedText()) selectAll(); + } +} + +void MeasuredValueField::receiveMousePress(QMouseEvent *e) { + m_labelClicked = true; + mousePressEvent(e); +} + +void MeasuredValueField::receiveMouseMove(QMouseEvent *e) { mouseMoveEvent(e); } + +void MeasuredValueField::receiveMouseRelease(QMouseEvent *e) { + mouseReleaseEvent(e); + m_labelClicked = false; +} + //============================================================================= namespace { @@ -1077,8 +1142,8 @@ PegbarChannelField::PegbarChannelField(TTool *tool, , m_objHandle(objHandle) , m_xshHandle(xshHandle) , m_scaleType(eNone) { - bool ret = connect(this, SIGNAL(measuredValueChanged(TMeasuredValue *)), - SLOT(onChange(TMeasuredValue *))); + bool ret = connect(this, SIGNAL(measuredValueChanged(TMeasuredValue *, bool)), + SLOT(onChange(TMeasuredValue *, bool))); assert(ret); // NOTA: per le unita' di misura controlla anche tpegbar.cpp switch (actionId) { @@ -1118,7 +1183,7 @@ PegbarChannelField::PegbarChannelField(TTool *tool, //----------------------------------------------------------------------------- -void PegbarChannelField::onChange(TMeasuredValue *fld) { +void PegbarChannelField::onChange(TMeasuredValue *fld, bool addToUndo) { if (!m_tool->isEnabled()) return; // the camera will crash with a value of 0 @@ -1128,38 +1193,42 @@ void PegbarChannelField::onChange(TMeasuredValue *fld) { fld->setValue(TMeasuredValue::MainUnit, 0.0001); } } - TUndoManager::manager()->beginBlock(); - TStageObjectValues before; - before.setFrameHandle(m_frameHandle); - before.setObjectHandle(m_objHandle); - before.setXsheetHandle(m_xshHandle); - before.add(m_actionId); bool modifyConnectedActionId = false; - if (m_scaleType != eNone) { - modifyConnectedActionId = true; - if (m_actionId == TStageObject::T_ScaleX) - before.add(TStageObject::T_ScaleY); - else if (m_actionId == TStageObject::T_ScaleY) - before.add(TStageObject::T_ScaleX); - else - modifyConnectedActionId = false; - } - if (m_isGlobalKeyframe) { - before.add(TStageObject::T_Angle); - before.add(TStageObject::T_X); - before.add(TStageObject::T_Y); - before.add(TStageObject::T_Z); - before.add(TStageObject::T_SO); - before.add(TStageObject::T_ScaleX); - before.add(TStageObject::T_ScaleY); - before.add(TStageObject::T_Scale); - before.add(TStageObject::T_Path); - before.add(TStageObject::T_ShearX); - before.add(TStageObject::T_ShearY); + if (addToUndo) TUndoManager::manager()->beginBlock(); + // m_firstMouseDrag is set to true only if addToUndo is false + // and only for the first drag + // This should always fire if addToUndo is true + if (!m_firstMouseDrag) { + m_before.setFrameHandle(m_frameHandle); + m_before.setObjectHandle(m_objHandle); + m_before.setXsheetHandle(m_xshHandle); + m_before.add(m_actionId); + if (m_scaleType != eNone) { + modifyConnectedActionId = true; + if (m_actionId == TStageObject::T_ScaleX) + m_before.add(TStageObject::T_ScaleY); + else if (m_actionId == TStageObject::T_ScaleY) + m_before.add(TStageObject::T_ScaleX); + else + modifyConnectedActionId = false; + } + if (m_isGlobalKeyframe) { + m_before.add(TStageObject::T_Angle); + m_before.add(TStageObject::T_X); + m_before.add(TStageObject::T_Y); + m_before.add(TStageObject::T_Z); + m_before.add(TStageObject::T_SO); + m_before.add(TStageObject::T_ScaleX); + m_before.add(TStageObject::T_ScaleY); + m_before.add(TStageObject::T_Scale); + m_before.add(TStageObject::T_Path); + m_before.add(TStageObject::T_ShearX); + m_before.add(TStageObject::T_ShearY); + } + m_before.updateValues(); } - before.updateValues(); TStageObjectValues after; - after = before; + after = m_before; double v = fld->getValue(TMeasuredValue::MainUnit); if (modifyConnectedActionId) { double oldv1 = after.getValue(0); @@ -1178,10 +1247,14 @@ void PegbarChannelField::onChange(TMeasuredValue *fld) { if (viewer) m_tool->invalidate(); setCursorPosition(0); - UndoStageObjectMove *undo = new UndoStageObjectMove(before, after); - undo->setObjectHandle(m_objHandle); - TUndoManager::manager()->add(undo); - TUndoManager::manager()->endBlock(); + if (addToUndo) { + UndoStageObjectMove *undo = new UndoStageObjectMove(m_before, after); + undo->setObjectHandle(m_objHandle); + TUndoManager::manager()->add(undo); + TUndoManager::manager()->endBlock(); + m_firstMouseDrag = false; + } + if (!addToUndo && !m_firstMouseDrag) m_firstMouseDrag = true; m_objHandle->notifyObjectIdChanged(false); } @@ -1219,15 +1292,15 @@ PegbarCenterField::PegbarCenterField(TTool *tool, int index, QString name, , m_xshHandle(xshHandle) { TStageObjectId objId = m_tool->getObjectId(); setMeasure(m_index == 0 ? "length.x" : "length.y"); - connect(this, SIGNAL(measuredValueChanged(TMeasuredValue *)), - SLOT(onChange(TMeasuredValue *))); + connect(this, SIGNAL(measuredValueChanged(TMeasuredValue *, bool)), + SLOT(onChange(TMeasuredValue *, bool))); updateStatus(); setMaximumWidth(getMaximumWidthForEditToolField(this)); } //----------------------------------------------------------------------------- -void PegbarCenterField::onChange(TMeasuredValue *fld) { +void PegbarCenterField::onChange(TMeasuredValue *fld, bool addToUndo) { if (!m_tool->isEnabled()) return; TXsheet *xsh = m_tool->getXsheet(); int frame = m_tool->getFrame(); @@ -1235,9 +1308,9 @@ void PegbarCenterField::onChange(TMeasuredValue *fld) { TStageObject *obj = xsh->getStageObject(objId); - double v = fld->getValue(TMeasuredValue::MainUnit); - TPointD center = obj->getCenter(frame); - TPointD oldCenter = center; + double v = fld->getValue(TMeasuredValue::MainUnit); + TPointD center = obj->getCenter(frame); + if (!m_firstMouseDrag) m_oldCenter = center; if (m_index == 0) center.x = v; else @@ -1245,12 +1318,15 @@ void PegbarCenterField::onChange(TMeasuredValue *fld) { obj->setCenter(frame, center); m_tool->invalidate(); - UndoStageObjectCenterMove *undo = - new UndoStageObjectCenterMove(objId, frame, oldCenter, center); - undo->setObjectHandle(m_objHandle); - undo->setXsheetHandle(m_xshHandle); - TUndoManager::manager()->add(undo); - + if (addToUndo) { + UndoStageObjectCenterMove *undo = + new UndoStageObjectCenterMove(objId, frame, m_oldCenter, center); + undo->setObjectHandle(m_objHandle); + undo->setXsheetHandle(m_xshHandle); + TUndoManager::manager()->add(undo); + m_firstMouseDrag = false; + } + if (!addToUndo && !m_firstMouseDrag) m_firstMouseDrag = true; m_objHandle->notifyObjectIdChanged(false); } @@ -1274,15 +1350,17 @@ NoScaleField::NoScaleField(TTool *tool, QString name) : MeasuredValueField(0, name), ToolOptionControl(tool, "") { TStageObjectId objId = m_tool->getObjectId(); setMeasure("zdepth"); - connect(this, SIGNAL(measuredValueChanged(TMeasuredValue *)), - SLOT(onChange(TMeasuredValue *))); + connect(this, SIGNAL(measuredValueChanged(TMeasuredValue *, bool)), + SLOT(onChange(TMeasuredValue *, bool))); updateStatus(); setMaximumWidth(getMaximumWidthForEditToolField(this)); } //----------------------------------------------------------------------------- -void NoScaleField::onChange(TMeasuredValue *fld) { +void NoScaleField::onChange(TMeasuredValue *fld, bool addToUndo) { + // addToUndo isn't needed here as the field denominator + // doesn't have an undo if (!m_tool->isEnabled()) return; TXsheet *xsh = m_tool->getXsheet(); int frame = m_tool->getFrame(); @@ -1392,8 +1470,8 @@ int getMaximumWidthForSelectionToolField(QWidget *widget) { SelectionScaleField::SelectionScaleField(SelectionTool *tool, int id, QString name) : MeasuredValueField(0, name), m_tool(tool), m_id(id) { - bool ret = connect(this, SIGNAL(measuredValueChanged(TMeasuredValue *)), - SLOT(onChange(TMeasuredValue *))); + bool ret = connect(this, SIGNAL(measuredValueChanged(TMeasuredValue *, bool)), + SLOT(onChange(TMeasuredValue *, bool))); assert(ret); setMeasure("scale"); updateStatus(); @@ -1403,7 +1481,7 @@ SelectionScaleField::SelectionScaleField(SelectionTool *tool, int id, //----------------------------------------------------------------------------- -bool SelectionScaleField::applyChange() { +bool SelectionScaleField::applyChange(bool addToUndo) { if (!m_tool || (m_tool->isSelectionEmpty() && !m_tool->isLevelType())) return false; DragSelectionTool::DragTool *scaleTool = createNewScaleTool(m_tool, 0); @@ -1444,17 +1522,17 @@ bool SelectionScaleField::applyChange() { scaleTool->transform(pointIndex, newPos); // This line invokes GUI update using the // value set above - if (!m_tool->isLevelType()) scaleTool->addTransformUndo(); + if (!m_tool->isLevelType() && addToUndo) scaleTool->addTransformUndo(); setCursorPosition(0); return true; } //----------------------------------------------------------------------------- -void SelectionScaleField::onChange(TMeasuredValue *fld) { +void SelectionScaleField::onChange(TMeasuredValue *fld, bool addToUndo) { if (!m_tool->isEnabled()) return; - if (!applyChange()) return; - emit valueChange(); + if (!applyChange(addToUndo)) return; + emit valueChange(addToUndo); } //----------------------------------------------------------------------------- @@ -1478,8 +1556,8 @@ void SelectionScaleField::updateStatus() { SelectionRotationField::SelectionRotationField(SelectionTool *tool, QString name) : MeasuredValueField(0, name), m_tool(tool) { - bool ret = connect(this, SIGNAL(measuredValueChanged(TMeasuredValue *)), - SLOT(onChange(TMeasuredValue *))); + bool ret = connect(this, SIGNAL(measuredValueChanged(TMeasuredValue *, bool)), + SLOT(onChange(TMeasuredValue *, bool))); assert(ret); setMeasure("angle"); updateStatus(); @@ -1489,7 +1567,7 @@ SelectionRotationField::SelectionRotationField(SelectionTool *tool, //----------------------------------------------------------------------------- -void SelectionRotationField::onChange(TMeasuredValue *fld) { +void SelectionRotationField::onChange(TMeasuredValue *fld, bool addToUndo) { if (!m_tool || !m_tool->isEnabled() || (m_tool->isSelectionEmpty() && !m_tool->isLevelType())) return; @@ -1505,7 +1583,7 @@ void SelectionRotationField::onChange(TMeasuredValue *fld) { deformValues.m_rotationAngle = p; // Instruction order is relevant here rotationTool->transform(aff, p - deformValues.m_rotationAngle); // - if (!m_tool->isLevelType()) rotationTool->addTransformUndo(); + if (!m_tool->isLevelType() && addToUndo) rotationTool->addTransformUndo(); setCursorPosition(0); } @@ -1529,8 +1607,8 @@ void SelectionRotationField::updateStatus() { SelectionMoveField::SelectionMoveField(SelectionTool *tool, int id, QString name) : MeasuredValueField(0, name), m_tool(tool), m_id(id) { - bool ret = connect(this, SIGNAL(measuredValueChanged(TMeasuredValue *)), - SLOT(onChange(TMeasuredValue *))); + bool ret = connect(this, SIGNAL(measuredValueChanged(TMeasuredValue *, bool)), + SLOT(onChange(TMeasuredValue *, bool))); assert(ret); if (m_id == 0) setMeasure("length.x"); @@ -1545,7 +1623,7 @@ SelectionMoveField::SelectionMoveField(SelectionTool *tool, int id, //----------------------------------------------------------------------------- -void SelectionMoveField::onChange(TMeasuredValue *fld) { +void SelectionMoveField::onChange(TMeasuredValue *fld, bool addToUndo) { if (!m_tool || !m_tool->isEnabled() || (m_tool->isSelectionEmpty() && !m_tool->isLevelType())) return; @@ -1566,7 +1644,7 @@ void SelectionMoveField::onChange(TMeasuredValue *fld) { 1 / Stage::inch * newMove; // Instruction order relevant here moveTool->transform(aff); // - if (!m_tool->isLevelType()) moveTool->addTransformUndo(); + if (!m_tool->isLevelType() && addToUndo) moveTool->addTransformUndo(); setCursorPosition(0); } @@ -1593,8 +1671,8 @@ void SelectionMoveField::updateStatus() { ThickChangeField::ThickChangeField(SelectionTool *tool, QString name) : MeasuredValueField(0, name), m_tool(tool) { - bool ret = connect(this, SIGNAL(measuredValueChanged(TMeasuredValue *)), - SLOT(onChange(TMeasuredValue *))); + bool ret = connect(this, SIGNAL(measuredValueChanged(TMeasuredValue *, bool)), + SLOT(onChange(TMeasuredValue *, bool))); assert(ret); setMeasure(""); updateStatus(); @@ -1604,7 +1682,7 @@ ThickChangeField::ThickChangeField(SelectionTool *tool, QString name) //----------------------------------------------------------------------------- -void ThickChangeField::onChange(TMeasuredValue *fld) { +void ThickChangeField::onChange(TMeasuredValue *fld, bool addToUndo) { if (!m_tool || (m_tool->isSelectionEmpty() && !m_tool->isLevelType())) return; DragSelectionTool::VectorChangeThicknessTool *changeThickTool = @@ -1624,7 +1702,9 @@ void ThickChangeField::onChange(TMeasuredValue *fld) { // deformValues.m_maxSelectionThickness = p; // // Seems that the actual update is performed inside // the above change..() instruction... >_< - changeThickTool->addUndo(); + if (addToUndo) { + changeThickTool->addUndo(); + } m_tool->computeBBox(); m_tool->invalidate(); m_tool->notifyImageChanged(m_tool->getCurrentFid()); @@ -1644,3 +1724,31 @@ void ThickChangeField::updateStatus() { setValue(2 * m_tool->m_deformValues.m_maxSelectionThickness); setCursorPosition(0); } + +//============================================================================= + +ClickableLabel::ClickableLabel(const QString &text, QWidget *parent, + Qt::WindowFlags f) + : QLabel(text, parent, f) {} + +//----------------------------------------------------------------------------- + +ClickableLabel::~ClickableLabel() {} + +//----------------------------------------------------------------------------- + +void ClickableLabel::mousePressEvent(QMouseEvent *event) { + emit onMousePress(event); +} + +//----------------------------------------------------------------------------- + +void ClickableLabel::mouseMoveEvent(QMouseEvent *event) { + emit onMouseMove(event); +} + +//----------------------------------------------------------------------------- + +void ClickableLabel::mouseReleaseEvent(QMouseEvent *event) { + emit onMouseRelease(event); +} \ No newline at end of file diff --git a/toonz/sources/tnztools/tooloptionscontrols.h b/toonz/sources/tnztools/tooloptionscontrols.h index c55f417011..8acfce965f 100644 --- a/toonz/sources/tnztools/tooloptionscontrols.h +++ b/toonz/sources/tnztools/tooloptionscontrols.h @@ -22,6 +22,7 @@ // TnzLib includes #include "toonz/txsheet.h" #include "toonz/tstageobject.h" +#include "toonz/stageobjectutil.h" // STD includes #include @@ -30,6 +31,7 @@ #include #include #include +#include #undef DVAPI #undef DVVAR @@ -325,12 +327,20 @@ class DVAPI MeasuredValueField : public DVGui::LineEdit { bool m_modified; double m_errorHighlighting; QTimer m_errorHighlightingTimer; - + int m_xMouse = -1; int m_precision; + bool m_mouseEdit = false; + bool m_labelClicked = false; + double m_originalValue; protected: bool m_isGlobalKeyframe; + // these are used for mouse dragging to edit a value + void mousePressEvent(QMouseEvent *) override; + void mouseMoveEvent(QMouseEvent *) override; + void mouseReleaseEvent(QMouseEvent *) override; + public: MeasuredValueField(QWidget *parent, QString name = "numfield"); ~MeasuredValueField(); @@ -355,9 +365,15 @@ protected slots: void onTextChanged(const QString &); void errorHighlightingTick(); + // clicking on the label connected to a field + // can be used to drag and change the value + void receiveMouseMove(QMouseEvent *event); + void receiveMousePress(QMouseEvent *event); + void receiveMouseRelease(QMouseEvent *event); + signals: - void measuredValueChanged(TMeasuredValue *value); + void measuredValueChanged(TMeasuredValue *value, bool addToUndo = true); }; //----------------------------------------------------------------------------- @@ -370,6 +386,8 @@ class PegbarChannelField final : public MeasuredValueField, TObjectHandle *m_objHandle; TXsheetHandle *m_xshHandle; enum ScaleType { eNone = 0, eAR = 1, eMass = 2 } m_scaleType; + TStageObjectValues m_before; + bool m_firstMouseDrag = false; public: PegbarChannelField(TTool *tool, enum TStageObject::Channel actionId, @@ -386,8 +404,9 @@ public slots: void onScaleTypeChanged(int type); protected slots: - - void onChange(TMeasuredValue *fld); + // add to undo is only false if mouse dragging to change the value + // on mouse release, add to undo is true + void onChange(TMeasuredValue *fld, bool addToUndo = true); }; //----------------------------------------------------------------------------- @@ -399,6 +418,8 @@ class DVAPI PegbarCenterField final : public MeasuredValueField, int m_index; // 0 = x, 1 = y TObjectHandle *m_objHandle; TXsheetHandle *m_xshHandle; + TPointD m_oldCenter; + bool m_firstMouseDrag = false; public: PegbarCenterField(TTool *tool, int index, QString name, @@ -410,8 +431,9 @@ class DVAPI PegbarCenterField final : public MeasuredValueField, void updateStatus() override; protected slots: - - void onChange(TMeasuredValue *fld); + // add to undo is only false if mouse dragging to change the value + // on mouse release, add to undo is true + void onChange(TMeasuredValue *fld, bool addToUndo = true); }; //----------------------------------------------------------------------------- @@ -426,8 +448,9 @@ class NoScaleField final : public MeasuredValueField, public ToolOptionControl { void updateStatus() override; protected slots: - - void onChange(TMeasuredValue *fld); + // add to undo is only false if mouse dragging to change the value + // on mouse release, add to undo is true + void onChange(TMeasuredValue *fld, bool addToUndo = true); }; //----------------------------------------------------------------------------- @@ -462,6 +485,7 @@ class SelectionScaleField final : public MeasuredValueField { int m_id; SelectionTool *m_tool; + double m_originalValue; public: SelectionScaleField(SelectionTool *tool, int actionId, QString name); @@ -469,13 +493,15 @@ class SelectionScaleField final : public MeasuredValueField { ~SelectionScaleField() {} void updateStatus(); - bool applyChange(); + bool applyChange(bool addToUndo = true); protected slots: - void onChange(TMeasuredValue *fld); + // add to undo is only false if mouse dragging to change the value + // on mouse release, add to undo is true + void onChange(TMeasuredValue *fld, bool addToUndo = true); signals: - void valueChange(); + void valueChange(bool addToUndo); }; //----------------------------------------------------------------------------- @@ -493,7 +519,9 @@ class SelectionRotationField final : public MeasuredValueField { void updateStatus(); protected slots: - void onChange(TMeasuredValue *fld); + // add to undo is only false if mouse dragging to change the value + // on mouse release, add to undo is true + void onChange(TMeasuredValue *fld, bool addToUndo = true); }; //----------------------------------------------------------------------------- @@ -512,7 +540,9 @@ class SelectionMoveField final : public MeasuredValueField { void updateStatus(); protected slots: - void onChange(TMeasuredValue *fld); + // add to undo is only false if mouse dragging to change the value + // on mouse release, add to undo is true + void onChange(TMeasuredValue *fld, bool addToUndo = true); }; //----------------------------------------------------------------------------- @@ -530,7 +560,32 @@ class ThickChangeField final : public MeasuredValueField { void updateStatus(); protected slots: - void onChange(TMeasuredValue *fld); + void onChange(TMeasuredValue *fld, bool addToUndo = true); }; +//----------------------------------------------------------------------------- + +// The ClickableLabel class is used to allow click and dragging +// on a label to change the value of a linked field +class ClickableLabel : public QLabel { + Q_OBJECT + +protected: + void mousePressEvent(QMouseEvent *) override; + void mouseMoveEvent(QMouseEvent *) override; + void mouseReleaseEvent(QMouseEvent *) override; + +public: + ClickableLabel(const QString &text, QWidget *parent = Q_NULLPTR, + Qt::WindowFlags f = Qt::WindowFlags()); + ~ClickableLabel(); + +signals: + void onMousePress(QMouseEvent *event); + void onMouseMove(QMouseEvent *event); + void onMouseRelease(QMouseEvent *event); +}; + +//----------------------------------------------------------------------------- + #endif diff --git a/toonz/sources/toonzqt/doublefield.cpp b/toonz/sources/toonzqt/doublefield.cpp index 75904c2962..7058a09c4a 100644 --- a/toonz/sources/toonzqt/doublefield.cpp +++ b/toonz/sources/toonzqt/doublefield.cpp @@ -39,6 +39,39 @@ void DoubleValueLineEdit::focusOutEvent(QFocusEvent *e) { QLineEdit::focusOutEvent(e); } +//----------------------------------------------------------------------------- + +void DoubleValueLineEdit::mousePressEvent(QMouseEvent *e) { + if (e->buttons() == Qt::MiddleButton) { + m_xMouse = e->x(); + m_mouseDragEditing = true; + } else + QLineEdit::mousePressEvent(e); +} + +//----------------------------------------------------------------------------- + +void DoubleValueLineEdit::mouseMoveEvent(QMouseEvent *e) { + if (e->buttons() == Qt::MiddleButton) { + setValue(getValue() + ((e->x() - m_xMouse) / 2)); + m_xMouse = e->x(); + emit valueChanged(); + } else + QLineEdit::mouseMoveEvent(e); +} + +//----------------------------------------------------------------------------- + +void DoubleValueLineEdit::mouseReleaseEvent(QMouseEvent *e) { + if ((e->buttons() == Qt::NoButton && m_mouseDragEditing)) { + m_mouseDragEditing = false; + clearFocus(); + } else { + if (!hasSelectedText()) selectAll(); + QLineEdit::mouseReleaseEvent(e); + } +} + //============================================================================= // DoubleValueField //----------------------------------------------------------------------------- @@ -461,6 +494,60 @@ void MeasuredDoubleLineEdit::timerEvent(QTimerEvent *) { } } +//----------------------------------------------------------------------------- + +void MeasuredDoubleLineEdit::mousePressEvent(QMouseEvent *e) { + if ((e->buttons() == Qt::MiddleButton) || m_labelClicked) { + m_xMouse = e->x(); + m_mouseDragEditing = true; + } else + QLineEdit::mousePressEvent(e); +} + +//----------------------------------------------------------------------------- + +void MeasuredDoubleLineEdit::mouseMoveEvent(QMouseEvent *e) { + if ((e->buttons() == Qt::MiddleButton) || m_labelClicked) { + int precision = (m_maxValue > 100) ? 0 : ((m_maxValue > 10) ? 1 : 2); + m_value->modifyValue((e->x() - m_xMouse) / 2, precision); + m_xMouse = e->x(); + valueToText(); + m_modified = false; + } else + QLineEdit::mouseMoveEvent(e); +} + +//----------------------------------------------------------------------------- + +void MeasuredDoubleLineEdit::mouseReleaseEvent(QMouseEvent *e) { + if ((e->buttons() == Qt::NoButton && m_mouseDragEditing) || m_labelClicked) { + m_xMouse = -1; + m_modified = true; + onEditingFinished(); + clearFocus(); + m_mouseDragEditing = false; + m_labelClicked = false; + + } else { + if (!hasSelectedText()) selectAll(); + QLineEdit::mouseReleaseEvent(e); + } +} + +void MeasuredDoubleLineEdit::receiveMousePress(QMouseEvent *e) { + m_labelClicked = true; + mousePressEvent(e); +} + +void MeasuredDoubleLineEdit::receiveMouseMove(QMouseEvent *e) { + mouseMoveEvent(e); +} + +void MeasuredDoubleLineEdit::receiveMouseRelease(QMouseEvent *e) { + mouseReleaseEvent(e); + m_labelClicked = false; +} + //============================================================================= // MeasuredDoubleField //----------------------------------------------------------------------------- diff --git a/toonz/sources/toonzqt/functionsheet.cpp b/toonz/sources/toonzqt/functionsheet.cpp index 0963ff2c56..ebd8819efc 100644 --- a/toonz/sources/toonzqt/functionsheet.cpp +++ b/toonz/sources/toonzqt/functionsheet.cpp @@ -501,6 +501,8 @@ FunctionSheetCellViewer::FunctionSheetCellViewer(FunctionSheet *parent) m_lineEdit->hide(); bool ret = connect(m_lineEdit, SIGNAL(editingFinished()), this, SLOT(onCellEditorEditingFinished())); + ret = ret && connect(m_lineEdit, SIGNAL(mouseMoved(QMouseEvent *)), this, + SLOT(onMouseMovedInLineEdit(QMouseEvent *))); assert(ret); setMouseTracking(true); @@ -689,7 +691,7 @@ void FunctionSheetCellViewer::mouseDoubleClickEvent(QMouseEvent *e) { TMeasure *measure = curve->getMeasure(); const TUnit *unit = measure ? measure->getCurrentUnit() : 0; if (unit) v = unit->convertTo(v); - + m_currentValue = v; m_lineEdit->setText(QString::number(v, 'f', 4)); // in order to put the cursor to the left end m_lineEdit->setSelection(m_lineEdit->text().length(), @@ -719,7 +721,8 @@ void FunctionSheetCellViewer::mouseDoubleClickEvent(QMouseEvent *e) { void FunctionSheetCellViewer::onCellEditorEditingFinished() { QString text = m_lineEdit->text(); - if (!text.isEmpty() && m_lineEdit->isReturnPressed()) { + if (!text.isEmpty() && + (m_lineEdit->isReturnPressed() || m_lineEdit->getMouseDragEditing())) { double value = text.toDouble(); TDoubleParam *curve = m_sheet->getCurve(m_editCol); if (curve) { @@ -744,8 +747,22 @@ void FunctionSheetCellViewer::mousePressEvent(QMouseEvent *e) { m_lineEdit->clearFocus(); m_sheet->setFocus(); } - - if (e->button() == Qt::LeftButton || e->button() == Qt::MidButton) + if (e->button() == Qt::LeftButton && e->modifiers() == Qt::ControlModifier) { + mouseDoubleClickEvent(e); + if (m_lineEdit->text() != "") { + m_lineEdit->setMouseDragEditing(true); + m_mouseXPosition = e->x(); + } + } else if (e->button() == Qt::LeftButton && + e->modifiers() == Qt::AltModifier) { + CellPosition cellPosition = getViewer()->xyToPosition(e->pos()); + int row = cellPosition.frame(); + int col = cellPosition.layer(); + TDoubleParam *curve = m_sheet->getCurve(col); + if (curve) { + KeyframeSetter::removeKeyframeAt(curve, row); + } + } else if (e->button() == Qt::LeftButton || e->button() == Qt::MidButton) Spreadsheet::CellPanel::mousePressEvent(e); else if (e->button() == Qt::RightButton) { update(); @@ -756,7 +773,12 @@ void FunctionSheetCellViewer::mousePressEvent(QMouseEvent *e) { //----------------------------------------------------------------------------- void FunctionSheetCellViewer::mouseReleaseEvent(QMouseEvent *e) { - Spreadsheet::CellPanel::mouseReleaseEvent(e); + if (m_lineEdit->getMouseDragEditing()) { + std::string textValue = m_lineEdit->text().toStdString(); + onCellEditorEditingFinished(); + m_lineEdit->setMouseDragEditing(false); + } else + Spreadsheet::CellPanel::mouseReleaseEvent(e); /* CellPosition cellPosition = getViewer ()->xyToPosition (e->pos ()); int row = cellPosition.frame (); @@ -770,7 +792,18 @@ m_sheet->setDragTool(0); //----------------------------------------------------------------------------- void FunctionSheetCellViewer::mouseMoveEvent(QMouseEvent *e) { - Spreadsheet::CellPanel::mouseMoveEvent(e); + if (m_lineEdit->getMouseDragEditing()) { + double newValue = m_currentValue + ((e->x() - m_mouseXPosition) / 2); + m_lineEdit->setText(QString::number(newValue, 'f', 4)); + m_updatedValue = newValue; + } else + Spreadsheet::CellPanel::mouseMoveEvent(e); +} + +//----------------------------------------------------------------------------- + +void FunctionSheetCellViewer::onMouseMovedInLineEdit(QMouseEvent *event) { + if (m_lineEdit->getMouseDragEditing()) mouseMoveEvent(event); } //----------------------------------------------------------------------------- diff --git a/toonz/sources/toonzqt/intfield.cpp b/toonz/sources/toonzqt/intfield.cpp index 8e429fe23c..7db073908c 100644 --- a/toonz/sources/toonzqt/intfield.cpp +++ b/toonz/sources/toonzqt/intfield.cpp @@ -205,6 +205,38 @@ void IntLineEdit::setLineEditBackgroundColor(QColor color) { setStyleSheet(sheet); } +//----------------------------------------------------------------------------- + +void IntLineEdit::mousePressEvent(QMouseEvent *e) { + if (e->buttons() == Qt::MiddleButton) { + m_xMouse = e->x(); + m_mouseDragEditing = true; + } else + QLineEdit::mousePressEvent(e); +} + +//----------------------------------------------------------------------------- + +void IntLineEdit::mouseMoveEvent(QMouseEvent *e) { + if (e->buttons() == Qt::MiddleButton) { + setValue(getValue() + ((e->x() - m_xMouse) / 2)); + m_xMouse = e->x(); + } else + QLineEdit::mouseMoveEvent(e); +} + +//----------------------------------------------------------------------------- + +void IntLineEdit::mouseReleaseEvent(QMouseEvent *e) { + if ((e->buttons() == Qt::NoButton && m_mouseDragEditing)) { + m_mouseDragEditing = false; + clearFocus(); + } else { + if (!hasSelectedText()) selectAll(); + QLineEdit::mouseReleaseEvent(e); + } +} + //============================================================================= // IntField //----------------------------------------------------------------------------- diff --git a/toonz/sources/toonzqt/lineedit.cpp b/toonz/sources/toonzqt/lineedit.cpp index 743fddbb23..e7a3892e23 100644 --- a/toonz/sources/toonzqt/lineedit.cpp +++ b/toonz/sources/toonzqt/lineedit.cpp @@ -63,3 +63,10 @@ void LineEdit::keyPressEvent(QKeyEvent *event) { QLineEdit::keyPressEvent(event); } } + +//----------------------------------------------------------------------------- + +void LineEdit::mouseMoveEvent(QMouseEvent *event) { + emit(mouseMoved(event)); + QLineEdit::mouseMoveEvent(event); +}