diff --git a/plugins/tools/basictools/CMakeLists.txt b/plugins/tools/basictools/CMakeLists.txt index 0d6420ff77..83a57a26f3 100644 --- a/plugins/tools/basictools/CMakeLists.txt +++ b/plugins/tools/basictools/CMakeLists.txt @@ -1,45 +1,46 @@ if (NOT APPLE) add_subdirectory(tests) endif () include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) set(kritadefaulttools_SOURCES default_tools.cc kis_tool_colorpicker.cc kis_tool_brush.cc kis_tool_line.cc kis_tool_line_helper.cpp kis_tool_fill.cc kis_tool_rectangle.cc kis_tool_ellipse.cc kis_tool_gradient.cc kis_tool_measure.cc kis_tool_path.cc kis_tool_move.cc kis_tool_movetooloptionswidget.cpp strokes/move_stroke_strategy.cpp strokes/move_selection_stroke_strategy.cpp kis_tool_multihand.cpp + kis_tool_multihand_config.cpp kis_tool_pencil.cc ) -ki18n_wrap_ui(kritadefaulttools_SOURCES wdgcolorpicker.ui wdgmovetool.ui) +ki18n_wrap_ui(kritadefaulttools_SOURCES wdgcolorpicker.ui wdgmovetool.ui wdgmultihandtool.ui) qt5_add_resources(kritadefaulttools_SOURCES defaulttools.qrc ) add_library(kritadefaulttools MODULE ${kritadefaulttools_SOURCES}) generate_export_header(kritadefaulttools BASE_NAME kritadefaulttools) target_link_libraries(kritadefaulttools kritaui kritabasicflakes) target_link_libraries(kritadefaulttools ${Boost_SYSTEM_LIBRARY}) install(TARGETS kritadefaulttools DESTINATION ${KRITA_PLUGIN_INSTALL_DIR}) ########### install files ############### install( FILES KisToolPath.action KisToolPencil.action DESTINATION ${DATA_INSTALL_DIR}/krita/actions) diff --git a/plugins/tools/basictools/kis_tool_multihand.cpp b/plugins/tools/basictools/kis_tool_multihand.cpp index 9db599c512..452429af8c 100644 --- a/plugins/tools/basictools/kis_tool_multihand.cpp +++ b/plugins/tools/basictools/kis_tool_multihand.cpp @@ -1,408 +1,423 @@ /* * Copyright (c) 2011 Lukáš Tvrdý * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * 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 #include #include #include #include #include #include - #include "kis_canvas2.h" #include "kis_cursor.h" #include "kis_tool_multihand_helper.h" +#include "kis_tool_multihand_config.h" static const int MAXIMUM_BRUSHES = 50; #include #ifdef Q_OS_WIN // quoting DRAND48(3) man-page: // These functions are declared obsolete by SVID 3, // which states that rand(3) should be used instead. #define drand48() (static_cast(qrand()) / static_cast(RAND_MAX)) #endif KisToolMultihand::KisToolMultihand(KoCanvasBase *canvas) : KisToolBrush(canvas), m_transformMode(SYMMETRY), m_angle(0), m_handsCount(6), m_mirrorVertically(false), m_mirrorHorizontally(false), m_showAxes(false), m_translateRadius(100), m_setupAxesFlag(false) { + + m_helper = new KisToolMultihandHelper(paintingInformationBuilder(), kundo2_i18n("Multibrush Stroke"), recordingAdapter()); resetHelper(m_helper); if (image()) { m_axesPoint = QPointF(0.5 * image()->width(), 0.5 * image()->height()); } + } KisToolMultihand::~KisToolMultihand() { } void KisToolMultihand::beginPrimaryAction(KoPointerEvent *event) { if(m_setupAxesFlag) { setMode(KisTool::OTHER); m_axesPoint = convertToPixelCoord(event->point); requestUpdateOutline(event->point, 0); updateCanvas(); } else { initTransformations(); KisToolFreehand::beginPrimaryAction(event); } } void KisToolMultihand::continuePrimaryAction(KoPointerEvent *event) { if(mode() == KisTool::OTHER) { m_axesPoint = convertToPixelCoord(event->point); requestUpdateOutline(event->point, 0); updateCanvas(); } else { KisToolFreehand::continuePrimaryAction(event); } } void KisToolMultihand::endPrimaryAction(KoPointerEvent *event) { if(mode() == KisTool::OTHER) { setMode(KisTool::HOVER_MODE); requestUpdateOutline(event->point, 0); finishAxesSetup(); } else { KisToolFreehand::endPrimaryAction(event); } } void KisToolMultihand::paint(QPainter& gc, const KoViewConverter &converter) { 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){ 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)); } } } void KisToolMultihand::initTransformations() { QVector transformations; QTransform m; if(m_transformMode == SYMMETRY) { qreal angle = 0; qreal angleStep = (2 * M_PI) / m_handsCount; for(int i = 0; i < m_handsCount; i++) { m.translate(m_axesPoint.x(), m_axesPoint.y()); m.rotateRadians(angle); m.translate(-m_axesPoint.x(), -m_axesPoint.y()); transformations << m; m.reset(); angle += angleStep; } } else if(m_transformMode == MIRROR) { transformations << m; if (m_mirrorHorizontally) { m.translate(m_axesPoint.x(),m_axesPoint.y()); m.rotateRadians(m_angle); m.scale(-1,1); m.rotateRadians(-m_angle); m.translate(-m_axesPoint.x(), -m_axesPoint.y()); transformations << m; m.reset(); } if (m_mirrorVertically) { m.translate(m_axesPoint.x(),m_axesPoint.y()); m.rotateRadians(m_angle); m.scale(1,-1); m.rotateRadians(-m_angle); m.translate(-m_axesPoint.x(), -m_axesPoint.y()); transformations << m; m.reset(); } if (m_mirrorVertically && m_mirrorHorizontally){ m.translate(m_axesPoint.x(),m_axesPoint.y()); m.rotateRadians(m_angle); m.scale(-1,-1); m.rotateRadians(-m_angle); m.translate(-m_axesPoint.x(), -m_axesPoint.y()); transformations << m; m.reset(); } } else if(m_transformMode == SNOWFLAKE) { qreal angle = 0; qreal angleStep = (2 * M_PI) / m_handsCount/4; for(int i = 0; i < m_handsCount*4; i++) { if ((i%2)==1) { m.translate(m_axesPoint.x(), m_axesPoint.y()); m.rotateRadians(m_angle-angleStep); m.rotateRadians(angle); m.scale(-1,1); m.rotateRadians(-m_angle+angleStep); m.translate(-m_axesPoint.x(), -m_axesPoint.y()); transformations << m; m.reset(); angle += angleStep*2; } else { m.translate(m_axesPoint.x(), m_axesPoint.y()); m.rotateRadians(m_angle-angleStep); m.rotateRadians(angle); m.rotateRadians(-m_angle+angleStep); m.translate(-m_axesPoint.x(), -m_axesPoint.y()); transformations << m; m.reset(); angle += angleStep*2; } } } else /* if(m_transformationNode == TRANSLATE) */ { /** * TODO: currently, the seed is the same for all the * strokes */ for (int i = 0; i < m_handsCount; i++){ qreal angle = drand48() * M_PI * 2; qreal length = drand48(); // convert the Polar coordinates to Cartesian coordinates qreal nx = (m_translateRadius * cos(angle) * length); qreal ny = (m_translateRadius * sin(angle) * length); m.translate(m_axesPoint.x(),m_axesPoint.y()); m.rotateRadians(m_angle); m.translate(nx,ny); m.rotateRadians(-m_angle); m.translate(-m_axesPoint.x(), -m_axesPoint.y()); transformations << m; m.reset(); } } m_helper->setupTransformations(transformations); } QWidget* KisToolMultihand::createOptionWidget() { QWidget *widget = KisToolBrush::createOptionWidget(); + QWidget* customUI = new KisToolMultiHandConfigWidget(); + + // TODO: add this a bit differently to the widget later inside the config + customUI->layout()->addWidget(widget); + + + // TODO: add the rest of the control below to the UI widget and hook up + + + +/* m_axesChCkBox = new QCheckBox(i18n("Show Axes")); connect(m_axesChCkBox,SIGNAL(toggled(bool)),this, SLOT(slotSetAxesVisible(bool))); m_axesPointBtn = new QPushButton(i18n("Axes point"), widget); m_axesPointBtn->setCheckable(true); connect(m_axesPointBtn, SIGNAL(clicked(bool)),this, SLOT(activateAxesPointModeSetup())); - addOptionWidgetOption(m_axesPointBtn, m_axesChCkBox); + addOptionWidgetOption(m_axesPointBtn, m_axesChCkBox); // this just adds it to the main layout m_axesAngleSlider = new KisDoubleSliderSpinBox(widget); m_axesAngleSlider->setToolTip(i18n("Set axes angle (degrees)")); m_axesAngleSlider->setSuffix(QChar(Qt::Key_degree)); m_axesAngleSlider->setRange(0.0, 90.0,1); m_axesAngleSlider->setEnabled(true); connect(m_axesAngleSlider, SIGNAL(valueChanged(qreal)),this, SLOT(slotSetAxesAngle(qreal))); addOptionWidgetOption(m_axesAngleSlider, new QLabel(i18n("Axes Angle:"))); m_transformModesComboBox = new QComboBox(widget); m_transformModesComboBox->addItem(i18n("Symmetry"),int(SYMMETRY)); m_transformModesComboBox->addItem(i18n("Mirror"),int(MIRROR)); m_transformModesComboBox->addItem(i18n("Translate"),int(TRANSLATE)); m_transformModesComboBox->addItem(i18n("Snowflake"),int(SNOWFLAKE)); connect(m_transformModesComboBox,SIGNAL(currentIndexChanged(int)),SLOT(slotSetTransformMode(int))); addOptionWidgetOption(m_transformModesComboBox); m_handsCountSlider = new KisSliderSpinBox(widget); m_handsCountSlider->setToolTip(i18n("Brush count")); m_handsCountSlider->setRange(1, MAXIMUM_BRUSHES); m_handsCountSlider->setEnabled(true); connect(m_handsCountSlider, SIGNAL(valueChanged(int)),this, SLOT(slotSetHandsCount(int))); addOptionWidgetOption(m_handsCountSlider); m_modeCustomOption = new QStackedWidget(widget); QWidget * symmetryWidget = new QWidget(m_modeCustomOption); m_modeCustomOption->addWidget(symmetryWidget); QWidget * mirrorWidget = new QWidget(m_modeCustomOption); m_mirrorHorizontallyChCkBox = new QCheckBox(i18n("Horizontally")); m_mirrorVerticallyChCkBox = new QCheckBox(i18n("Vertically")); connect(m_mirrorHorizontallyChCkBox,SIGNAL(toggled(bool)),this, SLOT(slotSetMirrorHorizontally(bool))); connect(m_mirrorVerticallyChCkBox,SIGNAL(toggled(bool)),this, SLOT(slotSetMirrorVertically(bool))); QGridLayout * mirrorLayout = new QGridLayout(mirrorWidget); mirrorLayout->addWidget(m_mirrorHorizontallyChCkBox,0,0); mirrorLayout->addWidget(m_mirrorVerticallyChCkBox,0,1); mirrorWidget->setLayout(mirrorLayout); m_modeCustomOption->addWidget(mirrorWidget); QWidget * translateWidget = new QWidget(m_modeCustomOption); m_translateRadiusSlider = new KisSliderSpinBox(translateWidget); m_translateRadiusSlider->setRange(0, 200); m_translateRadiusSlider->setSuffix(i18n(" px")); connect(m_translateRadiusSlider,SIGNAL(valueChanged(int)),this,SLOT(slotSetTranslateRadius(int))); QFormLayout *radiusLayout = new QFormLayout(translateWidget); radiusLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); radiusLayout->addRow(i18n("Radius"), m_translateRadiusSlider); translateWidget->setLayout(radiusLayout); m_modeCustomOption->addWidget(translateWidget); m_modeCustomOption->setCurrentIndex(m_transformModesComboBox->currentIndex()); addOptionWidgetOption(m_modeCustomOption); // read values from configuration file m_axesChCkBox->setChecked((bool)m_configGroup.readEntry("showAxes", false)); m_mirrorHorizontallyChCkBox->setChecked((bool)m_configGroup.readEntry("mirrorHorizontally", false)); m_mirrorVerticallyChCkBox->setChecked((bool)m_configGroup.readEntry("mirrorVertically", false)); m_axesAngleSlider->setValue(m_configGroup.readEntry("axesAngle", 0.0)); m_transformModesComboBox->setCurrentIndex(m_configGroup.readEntry("transformMode", 0)); m_translateRadiusSlider->setValue(m_configGroup.readEntry("translateRadius", 0)); m_handsCountSlider->setValue(m_configGroup.readEntry("handsCount", 4)); +*/ - return widget; + return customUI; } void KisToolMultihand::activateAxesPointModeSetup() { if (m_axesPointBtn->isChecked()){ m_setupAxesFlag = true; useCursor(KisCursor::crossCursor()); updateCanvas(); } else { finishAxesSetup(); } } void KisToolMultihand::finishAxesSetup() { m_setupAxesFlag = false; m_axesPointBtn->setChecked(false); resetCursorStyle(); updateCanvas(); } void KisToolMultihand::updateCanvas() { KisCanvas2 *kisCanvas = dynamic_cast(canvas()); Q_ASSERT(kisCanvas); kisCanvas->updateCanvas(); } void KisToolMultihand::slotSetHandsCount(int count) { m_handsCount = count; m_configGroup.writeEntry("handsCount", count); } void KisToolMultihand::slotSetAxesAngle(qreal angle) { //negative so axes rotates counter clockwise m_angle = -angle*M_PI/180; updateCanvas(); m_configGroup.writeEntry("axesAngle", angle); } void KisToolMultihand::slotSetTransformMode(int index) { m_transformMode = enumTransforModes(m_transformModesComboBox->itemData(index).toInt()); m_modeCustomOption->setCurrentIndex(index); m_handsCountSlider->setVisible(m_transformMode != MIRROR); m_configGroup.writeEntry("transformMode", index); } void KisToolMultihand::slotSetAxesVisible(bool vis) { m_showAxes = vis; updateCanvas(); m_configGroup.writeEntry("showAxes", vis); } void KisToolMultihand::slotSetMirrorVertically(bool mirror) { m_mirrorVertically = mirror; m_configGroup.writeEntry("mirrorVertically", mirror); } void KisToolMultihand::slotSetMirrorHorizontally(bool mirror) { m_mirrorHorizontally = mirror; m_configGroup.writeEntry("mirrorHorizontally", mirror); } void KisToolMultihand::slotSetTranslateRadius(int radius) { m_translateRadius = radius; m_configGroup.writeEntry("translateRadius", radius); } diff --git a/plugins/tools/basictools/kis_tool_multihand.h b/plugins/tools/basictools/kis_tool_multihand.h index 08bcbcd2c6..d6888c102d 100644 --- a/plugins/tools/basictools/kis_tool_multihand.h +++ b/plugins/tools/basictools/kis_tool_multihand.h @@ -1,116 +1,117 @@ /* * Copyright (c) 2011 Lukáš Tvrdý * Copyright (c) 2011 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_TOOL_MULTIHAND_H #define __KIS_TOOL_MULTIHAND_H #include "kis_tool_brush.h" #include + class QPushButton; class QCheckBox; class QComboBox; class QStackedWidget; class KisSliderSpinBox; class KisToolMultihandHelper; class KisToolMultihand : public KisToolBrush { Q_OBJECT public: KisToolMultihand(KoCanvasBase *canvas); ~KisToolMultihand(); void beginPrimaryAction(KoPointerEvent *event); void continuePrimaryAction(KoPointerEvent *event); void endPrimaryAction(KoPointerEvent *event); protected: void paint(QPainter& gc, const KoViewConverter &converter); QWidget* createOptionWidget(); private: void initTransformations(); void finishAxesSetup(); void updateCanvas(); private Q_SLOTS: void activateAxesPointModeSetup(); void slotSetHandsCount(int count); void slotSetAxesAngle(qreal angle); void slotSetTransformMode(int qcomboboxIndex); void slotSetAxesVisible(bool vis); void slotSetMirrorVertically(bool mirror); void slotSetMirrorHorizontally(bool mirror); void slotSetTranslateRadius(int radius); private: KisToolMultihandHelper *m_helper; enum enumTransforModes { SYMMETRY, MIRROR, TRANSLATE, SNOWFLAKE }; enumTransforModes m_transformMode; QPointF m_axesPoint; qreal m_angle; int m_handsCount; bool m_mirrorVertically; bool m_mirrorHorizontally; bool m_showAxes; 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; }; class KisToolMultiBrushFactory : public KoToolFactoryBase { public: KisToolMultiBrushFactory() : KoToolFactoryBase("KritaShape/KisToolMultiBrush") { setToolTip(i18n("Multibrush Tool")); // Temporarily setSection(TOOL_TYPE_SHAPE); setIconName(koIconNameCStr("krita_tool_multihand")); setShortcut(QKeySequence(Qt::Key_Q)); setPriority(11); setActivationShapeId(KRITA_TOOL_ACTIVATION_ID); } virtual ~KisToolMultiBrushFactory() {} virtual KoToolBase * createTool(KoCanvasBase *canvas) { return new KisToolMultihand(canvas); } }; #endif /* __KIS_TOOL_MULTIHAND_H */ diff --git a/plugins/tools/basictools/kis_tool_multihand_config.cpp b/plugins/tools/basictools/kis_tool_multihand_config.cpp new file mode 100644 index 0000000000..c65a01eac5 --- /dev/null +++ b/plugins/tools/basictools/kis_tool_multihand_config.cpp @@ -0,0 +1,33 @@ +/* + Copyright (C) 2016 Scott Petrovic + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#include +#include "kis_tool_multihand_config.h" + +KisToolMultiHandConfigWidget::KisToolMultiHandConfigWidget(QWidget* parent) + : QWidget(parent) +{ + setupUi(this); +} + + +KisToolMultiHandConfigWidget::~KisToolMultiHandConfigWidget() +{ + +} diff --git a/plugins/tools/basictools/kis_tool_multihand_config.h b/plugins/tools/basictools/kis_tool_multihand_config.h new file mode 100644 index 0000000000..a917c47100 --- /dev/null +++ b/plugins/tools/basictools/kis_tool_multihand_config.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2016 Scott Petrovic + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#ifndef KISTOOLMULTIHANDCONFIG_H +#define KISTOOLMULTIHANDCONFIG_H + +#include "ui_wdgmultihandtool.h" + + +class KisToolMultiHandConfigWidget : public QWidget, public Ui::WdgMultiHandTool +{ + Q_OBJECT + +public: + KisToolMultiHandConfigWidget(QWidget *parent=0); + ~KisToolMultiHandConfigWidget(); + +//Q_SIGNALS: + + +//public Q_SLOTS: + //void cropTypeSelectableChanged(); + +//private: + //KisToolCrop* m_cropTool; +}; + +#endif // KISTOOLMULTIHANDCONFIG_H diff --git a/plugins/tools/basictools/wdgmultihandtool.ui b/plugins/tools/basictools/wdgmultihandtool.ui new file mode 100644 index 0000000000..833fd726c8 --- /dev/null +++ b/plugins/tools/basictools/wdgmultihandtool.ui @@ -0,0 +1,25 @@ + + + WdgMultiHandTool + + + + 0 + 0 + 271 + 69 + + + + + + + Multi-hand tool options + + + + + + + +