diff --git a/libs/ui/tool/kis_tool.h b/libs/ui/tool/kis_tool.h --- a/libs/ui/tool/kis_tool.h +++ b/libs/ui/tool/kis_tool.h @@ -288,14 +288,15 @@ void blockUntilOperationsFinishedForced(); protected: - enum ToolMode { + enum ToolMode: int { HOVER_MODE, PAINT_MODE, SECONDARY_PAINT_MODE, MIRROR_AXIS_SETUP_MODE, GESTURE_MODE, PAN_MODE, - OTHER // not used now + OTHER, // tool-specific modes, like multibrush's symmetry axis setup + OTHER_1 }; virtual void setMode(ToolMode mode); diff --git a/plugins/tools/basictools/kis_tool_multihand.h b/plugins/tools/basictools/kis_tool_multihand.h --- a/plugins/tools/basictools/kis_tool_multihand.h +++ b/plugins/tools/basictools/kis_tool_multihand.h @@ -41,10 +41,16 @@ void continuePrimaryAction(KoPointerEvent *event) override; void endPrimaryAction(KoPointerEvent *event) override; + void beginAlternateAction(KoPointerEvent *event, AlternateAction action) override; + void continueAlternateAction(KoPointerEvent *event, AlternateAction action) override; + void endAlternateAction(KoPointerEvent *event, AlternateAction action) override; + + void mouseMoveEvent(KoPointerEvent* event) override; + protected: void paint(QPainter& gc, const KoViewConverter &converter) override; - + QWidget* createOptionWidget() override; private: @@ -62,11 +68,13 @@ void slotSetMirrorVertically(bool mirror); void slotSetMirrorHorizontally(bool mirror); void slotSetTranslateRadius(int radius); + void slotAddSubbrushesMode(bool checked); + void slotRemoveAllSubbrushes(); private: KisToolMultihandHelper *m_helper; - enum enumTransforModes { SYMMETRY, MIRROR, TRANSLATE, SNOWFLAKE }; + enum enumTransforModes:int { SYMMETRY=0, MIRROR, TRANSLATE, SNOWFLAKE, COPYTRANSLATE }; enumTransforModes m_transformMode; QPointF m_axesPoint; qreal m_angle; @@ -77,16 +85,9 @@ int m_translateRadius; bool m_setupAxesFlag; - QComboBox * m_transformModesComboBox; - KisSliderSpinBox *m_handsCountSlider; - KisDoubleSliderSpinBox *m_axesAngleSlider; - QCheckBox *m_axesChCkBox; - QStackedWidget *m_modeCustomOption; - QCheckBox *m_mirrorVerticallyChCkBox; - QCheckBox *m_mirrorHorizontallyChCkBox; - KisSliderSpinBox *m_translateRadiusSlider; - QPushButton *m_axesPointBtn; - + bool m_addSubbrushesMode; + QPointF m_lastToolPos; + QVector m_subbrOriginalLocations; KisToolMultiHandConfigWidget* customUI; }; diff --git a/plugins/tools/basictools/kis_tool_multihand.cpp b/plugins/tools/basictools/kis_tool_multihand.cpp --- a/plugins/tools/basictools/kis_tool_multihand.cpp +++ b/plugins/tools/basictools/kis_tool_multihand.cpp @@ -16,7 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - #include "kis_tool_multihand.h" #include @@ -53,7 +52,8 @@ m_mirrorHorizontally(false), m_showAxes(false), m_translateRadius(100), - m_setupAxesFlag(false) + m_setupAxesFlag(false), + m_addSubbrushesMode(false) , customUI(0) { @@ -72,16 +72,20 @@ { } - - void KisToolMultihand::beginPrimaryAction(KoPointerEvent *event) { if(m_setupAxesFlag) { setMode(KisTool::OTHER); m_axesPoint = convertToPixelCoord(event->point); requestUpdateOutline(event->point, 0); updateCanvas(); } + else if (m_addSubbrushesMode){ + QPointF newPoint = convertToPixelCoord(event->point); + m_subbrOriginalLocations << newPoint; + requestUpdateOutline(event->point, 0); + updateCanvas(); + } else { initTransformations(); KisToolFreehand::beginPrimaryAction(event); @@ -96,6 +100,7 @@ updateCanvas(); } else { + requestUpdateOutline(event->point, 0); KisToolFreehand::continuePrimaryAction(event); } } @@ -112,31 +117,97 @@ } } +void KisToolMultihand::beginAlternateAction(KoPointerEvent* event, AlternateAction action) +{ + if (action != ChangeSize || m_transformMode != COPYTRANSLATE || !m_addSubbrushesMode) { + KisToolBrush::beginAlternateAction(event, action); + return; + } + setMode(KisTool::OTHER_1); + m_axesPoint = convertToPixelCoord(event->point); + requestUpdateOutline(event->point, 0); + updateCanvas(); +} + +void KisToolMultihand::continueAlternateAction(KoPointerEvent* event, AlternateAction action) +{ + if (action != ChangeSize || m_transformMode != COPYTRANSLATE || !m_addSubbrushesMode) { + KisToolBrush::continueAlternateAction(event, action); + return; + } + if (mode() == KisTool::OTHER_1) { + m_axesPoint = convertToPixelCoord(event->point); + requestUpdateOutline(event->point, 0); + updateCanvas(); + } +} + +void KisToolMultihand::endAlternateAction(KoPointerEvent* event, AlternateAction action) +{ + if (action != ChangeSize || m_transformMode != COPYTRANSLATE || !m_addSubbrushesMode) { + KisToolBrush::continueAlternateAction(event, action); + return; + } + if (mode() == KisTool::OTHER_1) { + setMode(KisTool::HOVER_MODE); + } +} + +void KisToolMultihand::mouseMoveEvent(KoPointerEvent* event) +{ + if (mode() == HOVER_MODE) { + m_lastToolPos=convertToPixelCoord(event->point); + } + KisToolBrush::mouseMoveEvent(event); +} + void KisToolMultihand::paint(QPainter& gc, const KoViewConverter &converter) { + QPainterPath path; + if (m_transformMode == COPYTRANSLATE) { + for (QPointF dPos : m_subbrOriginalLocations) { + if (m_addSubbrushesMode) { + path.addEllipse(dPos, 10, 10); // Show subbrush reference locations + path.moveTo(dPos.x() - 15, dPos.y()); + path.lineTo(dPos.x() + 15, dPos.y()); + path.moveTo(dPos.x(), dPos.y() - 15); + path.lineTo(dPos.x(), dPos.y() + 15); + } + else { + // Show where subbrush strokes are predicted to land + path += m_currentOutline.translated(dPos - m_axesPoint); + } + } + if (m_addSubbrushesMode) { + // add a cross shape to the main tool outline as well + + path.moveTo(m_lastToolPos.x() - 15, m_lastToolPos.y()); + path.lineTo(m_lastToolPos.x() + 15, m_lastToolPos.y()); + path.moveTo(m_lastToolPos.x(), m_lastToolPos.y() - 15); + path.lineTo(m_lastToolPos.x(), m_lastToolPos.y() + 15); + } + } if(m_setupAxesFlag) { int diagonal = (currentImage()->height() + currentImage()->width()); - QPainterPath path; path.moveTo(m_axesPoint.x()-diagonal*cos(m_angle), m_axesPoint.y()-diagonal*sin(m_angle)); path.lineTo(m_axesPoint.x()+diagonal*cos(m_angle), m_axesPoint.y()+diagonal*sin(m_angle)); path.moveTo(m_axesPoint.x()-diagonal*cos(m_angle+M_PI_2), m_axesPoint.y()-diagonal*sin(m_angle+M_PI_2)); path.lineTo(m_axesPoint.x()+diagonal*cos(m_angle+M_PI_2), m_axesPoint.y()+diagonal*sin(m_angle+M_PI_2)); - paintToolOutline(&gc, pixelToView(path)); } else { KisToolFreehand::paint(gc, converter); - if(m_showAxes){ + // Force paint axeslines of "origin" point when in COPYTRANSLATE addSubbrushes mode. + if(m_showAxes || (m_transformMode == COPYTRANSLATE && m_addSubbrushesMode)){ int diagonal = (currentImage()->height() + currentImage()->width()); - QPainterPath path; path.moveTo(m_axesPoint.x()-diagonal*cos(m_angle), m_axesPoint.y()-diagonal*sin(m_angle)); path.lineTo(m_axesPoint.x()+diagonal*cos(m_angle), m_axesPoint.y()+diagonal*sin(m_angle)); path.moveTo(m_axesPoint.x()-diagonal*cos(m_angle+M_PI_2), m_axesPoint.y()-diagonal*sin(m_angle+M_PI_2)); path.lineTo(m_axesPoint.x()+diagonal*cos(m_angle+M_PI_2), m_axesPoint.y()+diagonal*sin(m_angle+M_PI_2)); - paintToolOutline(&gc, pixelToView(path)); } } + paintToolOutline(&gc, pixelToView(path)); } void KisToolMultihand::initTransformations() @@ -222,7 +293,7 @@ } } } - else /* if(m_transformationNode == TRANSLATE) */ { + else if(m_transformMode == TRANSLATE) { /** * TODO: currently, the seed is the same for all the * strokes @@ -243,6 +314,14 @@ transformations << m; m.reset(); } + } else if (m_transformMode == COPYTRANSLATE) { + transformations << m; + for (QPointF dPos : m_subbrOriginalLocations) { + QPointF resPos = dPos-m_axesPoint; // Calculate the difference between subbrush reference position and "origin" reference + m.translate(resPos.x(), resPos.y()); + transformations << m; + m.reset(); + } } m_helper->setupTransformations(transformations); @@ -255,7 +334,7 @@ customUI = new KisToolMultiHandConfigWidget(); // brush smoothing option. - customUI->layout()->addWidget(widget); + //customUI->layout()->addWidget(widget); customUI->smoothingOptionsLayout->addWidget(widget); @@ -274,6 +353,7 @@ customUI->multihandTypeCombobox->addItem(i18n("Mirror"),int(MIRROR)); customUI->multihandTypeCombobox->addItem(i18n("Translate"),int(TRANSLATE)); customUI->multihandTypeCombobox->addItem(i18n("Snowflake"),int(SNOWFLAKE)); + customUI->multihandTypeCombobox->addItem(i18n("Copy Translate"),int(COPYTRANSLATE)); connect(customUI->multihandTypeCombobox,SIGNAL(currentIndexChanged(int)),this, SLOT(slotSetTransformMode(int))); customUI->multihandTypeCombobox->setCurrentIndex(m_configGroup.readEntry("transformMode", 0)); slotSetTransformMode(customUI->multihandTypeCombobox->currentIndex()); @@ -286,8 +366,6 @@ connect( customUI->axisRotationSpinbox, SIGNAL(valueChanged(qreal)),this, SLOT(slotSetAxesAngle(qreal))); - - // symmetry mode options customUI->brushCountSpinBox->setRange(1, MAXIMUM_BRUSHES); connect(customUI->brushCountSpinBox, SIGNAL(valueChanged(int)),this, SLOT(slotSetHandsCount(int))); @@ -307,6 +385,9 @@ connect(customUI->translationRadiusSpinbox,SIGNAL(valueChanged(int)),this,SLOT(slotSetTranslateRadius(int))); + // Copy translate mode options and actions + connect(customUI->addSubbrushButton, &QPushButton::clicked, this, &KisToolMultihand::slotAddSubbrushesMode); + connect(customUI->removeSubbrushButton, &QPushButton::clicked, this, &KisToolMultihand::slotRemoveAllSubbrushes); // snowflake re-uses the existing options, so there is no special parameters for that... @@ -374,22 +455,33 @@ customUI->radiusLabel->setVisible(false); customUI->brushCountSpinBox->setVisible(false); customUI->brushesLabel->setVisible(false); + customUI->subbrushLabel->setVisible(false); + customUI->addSubbrushButton->setVisible(false); + customUI->removeSubbrushButton->setVisible(false); // turn on what we need - if (index == int(MIRROR)) { + if (index == MIRROR) { customUI->horizontalCheckbox->setVisible(true); customUI->verticalCheckbox->setVisible(true); } - if (index == int(TRANSLATE)) { - customUI->translationRadiusSpinbox->setVisible(true); - customUI->radiusLabel->setVisible(true); + else if (index == TRANSLATE) { + customUI->translationRadiusSpinbox->setVisible(true); + customUI->radiusLabel->setVisible(true); + customUI->brushCountSpinBox->setVisible(true); + customUI->brushesLabel->setVisible(true); } - if (index == int(SYMMETRY) || index == int(SNOWFLAKE) || index == int(TRANSLATE) ) { + else if (index == SYMMETRY || index == SNOWFLAKE || index == TRANSLATE ) { customUI->brushCountSpinBox->setVisible(true); customUI->brushesLabel->setVisible(true); } + + else if (index == COPYTRANSLATE) { + customUI->subbrushLabel->setVisible(true); + customUI->addSubbrushButton->setVisible(true); + customUI->removeSubbrushButton->setVisible(true); + } } @@ -419,3 +511,15 @@ m_configGroup.writeEntry("translateRadius", radius); } +void KisToolMultihand::slotAddSubbrushesMode(bool checked) +{ + m_addSubbrushesMode = checked; + updateCanvas(); +} + +void KisToolMultihand::slotRemoveAllSubbrushes() +{ + m_subbrOriginalLocations.clear(); + updateCanvas(); +} + diff --git a/plugins/tools/basictools/kis_tool_multihand_config.h b/plugins/tools/basictools/kis_tool_multihand_config.h --- a/plugins/tools/basictools/kis_tool_multihand_config.h +++ b/plugins/tools/basictools/kis_tool_multihand_config.h @@ -16,7 +16,6 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - #ifndef KISTOOLMULTIHANDCONFIG_H #define KISTOOLMULTIHANDCONFIG_H diff --git a/plugins/tools/basictools/wdgmultihandtool.ui b/plugins/tools/basictools/wdgmultihandtool.ui --- a/plugins/tools/basictools/wdgmultihandtool.ui +++ b/plugins/tools/basictools/wdgmultihandtool.ui @@ -7,7 +7,7 @@ 0 0 200 - 282 + 290 @@ -45,103 +45,62 @@ 7 - - + + 0 0 - Type: + Brushes: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - true - - - - 0 - 0 - - - - Move - - - false - - - - - - - true - - - - 0 - 0 - - - - Reset - - - false - - - - + + - - + + + + Subbrushes: + + - - + + 0 0 - Rotation: + Radius: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + 0 0 - - - 0 - 15 - + + Horizontal - - - - + @@ -154,79 +113,151 @@ - - + + 0 0 - Brushes: + Rotation: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + 0 0 + + + 0 + 15 + + + + + + - Horizontal + Vertical - - + + 0 0 - - Qt::LeftToRight - - Origin: + Type: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - Vertical - - + + + + + + true + + + + 0 + 0 + + + + Move + + + false + + + + + + + true + + + + 0 + 0 + + + + Reset + + + false + + + + - - + + + + + 0 0 + + Qt::LeftToRight + - Radius: + Origin: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + + + + + Add + + + true + + + false + + + + + + + Remove All + + + + + + + @@ -252,7 +283,7 @@
kis_slider_spin_box.h
1 - + KisDoubleSliderSpinBox QWidget
kis_slider_spin_box.h