Commit 80497587 authored by Agata Cacko's avatar Agata Cacko

Allow Clone Brush to reset origin after every stroke

Summary:
This commit introduces the behaviour of Clone Brush
that allows for always starting a new stroke
as if the offset wasn't set yet, which means it always
starts from the same source/origin point.
Usecases: painting multiple leaves, flowers, crosses etc.
in less regular way than what could be created with regular
Clone Brush.

BUG:402559

Test Plan:
- save and load brush with and without the new option enabled
- use the same brush with and without the new option enabled
- use both versions without setting the origin
- switch between enabled and disabled option after setting the origin
- check whether the tooltip works

Reviewers: #krita, dkazakov

Reviewed By: #krita, dkazakov

Subscribers: dkazakov

Tags: #krita

Differential Revision: https://phabricator.kde.org/D20653
parent 4e602f7a
......@@ -131,6 +131,11 @@ bool KisPaintOpSettings::mousePressEvent(const KisPaintInformation &paintInforma
return true; // ignore the event by default
}
bool KisPaintOpSettings::mouseReleaseEvent()
{
return true; // ignore the event by default
}
void KisPaintOpSettings::setRandomOffset(const KisPaintInformation &paintInformation)
{
if (getBool("Texture/Pattern/Enabled")) {
......
......@@ -86,11 +86,18 @@ public:
/**
* This function is called by a tool when the mouse is pressed. It's useful if
* the paintop needs mouse interaction for instance in the case of the clone op.
* If the tool is supposed to ignore the event, the paint op should return false
* and if the tool is supposed to use the event, return true.
* If the tool is supposed to ignore the event, the paint op should return true
* and if the tool is supposed to use the event, return false.
* See kis_tool_freehand:tryPickByPaintOp()
*/
virtual bool mousePressEvent(const KisPaintInformation &paintInformation, Qt::KeyboardModifiers modifiers, KisNodeWSP currentNode);
/**
* This function is called by a tool when the mouse is released. It's useful if
* the paintop needs mouse interaction for instance in the case of the clone op.
* If the tool is supposed to ignore the event, the paint op should return true
* and if the tool is supposed to use the event, return false.
*/
virtual bool mouseReleaseEvent();
/**
* Clone the current settings object. Override this if your settings instance doesn't
* store everything as properties.
......
......@@ -188,6 +188,8 @@ void KisToolFreehand::doStroke(KoPointerEvent *event)
void KisToolFreehand::endStroke()
{
m_helper->endPaint();
bool paintOpIgnoredEvent = currentPaintOpPreset()->settings()->mouseReleaseEvent();
Q_UNUSED(paintOpIgnoredEvent);
}
bool KisToolFreehand::primaryActionSupportsHiResEvents() const
......@@ -285,6 +287,8 @@ bool KisToolFreehand::tryPickByPaintOp(KoPointerEvent *event, AlternateAction ac
perspective, 0, 0),
event->modifiers(),
currentNode());
// DuplicateOP during the picking of new source point (origin)
// is the only paintop that returns "false" here
return !paintOpIgnoredEvent;
}
......
......@@ -52,6 +52,7 @@ KisDuplicateOpOption::KisDuplicateOpOption()
connect(m_optionWidget->cbHealing, SIGNAL(toggled(bool)), SLOT(emitSettingChanged()));
connect(m_optionWidget->cbPerspective, SIGNAL(toggled(bool)), SLOT(emitSettingChanged()));
connect(m_optionWidget->cbSourcePoint, SIGNAL(toggled(bool)), SLOT(emitSettingChanged()));
connect(m_optionWidget->cbResetSourcePoint, SIGNAL(toggled(bool)), SLOT(emitSettingChanged()));
connect(m_optionWidget->chkCloneProjection, SIGNAL(toggled(bool)), SLOT(emitSettingChanged()));
setConfigurationPage(m_optionWidget);
......@@ -92,6 +93,16 @@ void KisDuplicateOpOption::setMoveSourcePoint(bool move)
m_optionWidget->cbSourcePoint->setChecked(move);
}
bool KisDuplicateOpOption::resetSourcePoint() const
{
return m_optionWidget->cbResetSourcePoint->isChecked();
}
void KisDuplicateOpOption::setResetSourcePoint(bool reset)
{
m_optionWidget->cbResetSourcePoint->setChecked(reset);
}
bool KisDuplicateOpOption::cloneFromProjection() const
{
return m_optionWidget->chkCloneProjection->isChecked();
......@@ -109,6 +120,7 @@ void KisDuplicateOpOption::writeOptionSetting(KisPropertiesConfigurationSP setti
op.duplicate_healing = healing();
op.duplicate_correct_perspective = correctPerspective();
op.duplicate_move_source_point = moveSourcePoint();
op.duplicate_reset_source_point = resetSourcePoint();
op.duplicate_clone_from_projection = cloneFromProjection();
op.writeOptionSetting(setting);
......@@ -122,6 +134,7 @@ void KisDuplicateOpOption::readOptionSetting(const KisPropertiesConfigurationSP
m_optionWidget->cbHealing->setChecked(op.duplicate_healing);
m_optionWidget->cbPerspective->setChecked(op.duplicate_correct_perspective);
m_optionWidget->cbSourcePoint->setChecked(op.duplicate_move_source_point);
m_optionWidget->cbResetSourcePoint->setChecked(op.duplicate_reset_source_point);
m_optionWidget->chkCloneProjection->setChecked(op.duplicate_clone_from_projection);
}
......
......@@ -23,6 +23,7 @@
const QString DUPLICATE_HEALING = "Duplicateop/Healing";
const QString DUPLICATE_CORRECT_PERSPECTIVE = "Duplicateop/CorrectPerspective";
const QString DUPLICATE_MOVE_SOURCE_POINT = "Duplicateop/MoveSourcePoint";
const QString DUPLICATE_RESET_SOURCE_POINT = "Duplicateop/ResetSourcePoint";
const QString DUPLICATE_CLONE_FROM_PROJECTION = "Duplicateop/CloneFromProjection";
class KisDuplicateOpOptionsWidget;
......@@ -43,6 +44,9 @@ private:
bool moveSourcePoint() const;
void setMoveSourcePoint(bool move);
bool resetSourcePoint() const;
void setResetSourcePoint(bool resetSource);
bool cloneFromProjection() const;
void setCloneFromProjection(bool cloneFromProjection);
public:
......@@ -63,12 +67,14 @@ struct KisDuplicateOptionProperties : public KisPaintopPropertiesBase
bool duplicate_healing;
bool duplicate_correct_perspective;
bool duplicate_move_source_point;
bool duplicate_reset_source_point;
bool duplicate_clone_from_projection;
void readOptionSettingImpl(const KisPropertiesConfiguration* setting) override {
duplicate_healing = setting->getBool(DUPLICATE_HEALING, false);
duplicate_correct_perspective = setting->getBool(DUPLICATE_CORRECT_PERSPECTIVE, false);
duplicate_move_source_point = setting->getBool(DUPLICATE_MOVE_SOURCE_POINT, true);
duplicate_reset_source_point = setting->getBool(DUPLICATE_RESET_SOURCE_POINT, false);
duplicate_clone_from_projection = setting->getBool(DUPLICATE_CLONE_FROM_PROJECTION, false);
}
......@@ -76,6 +82,7 @@ struct KisDuplicateOptionProperties : public KisPaintopPropertiesBase
setting->setProperty(DUPLICATE_HEALING, duplicate_healing);
setting->setProperty(DUPLICATE_CORRECT_PERSPECTIVE, duplicate_correct_perspective);
setting->setProperty(DUPLICATE_MOVE_SOURCE_POINT, duplicate_move_source_point);
setting->setProperty(DUPLICATE_RESET_SOURCE_POINT, duplicate_reset_source_point);
setting->setProperty(DUPLICATE_CLONE_FROM_PROJECTION, duplicate_clone_from_projection);
}
};
......
......@@ -40,7 +40,7 @@
#include <kis_dom_utils.h>
KisDuplicateOpSettings::KisDuplicateOpSettings()
: m_isOffsetNotUptodate(false)
: m_isOffsetNotUptodate(false), m_duringPaintingStroke(false)
{
}
......@@ -81,16 +81,26 @@ bool KisDuplicateOpSettings::mousePressEvent(const KisPaintInformation &info, Qt
ignoreEvent = false;
}
else {
if (m_isOffsetNotUptodate) {
bool resetOrigin = getBool(DUPLICATE_RESET_SOURCE_POINT);
if (m_isOffsetNotUptodate || resetOrigin) {
m_offset = info.pos() - m_position;
m_isOffsetNotUptodate = false;
}
m_duringPaintingStroke = true;
ignoreEvent = true;
}
return ignoreEvent;
}
bool KisDuplicateOpSettings::mouseReleaseEvent()
{
m_duringPaintingStroke = false;
bool ignoreEvent = true;
return ignoreEvent;
}
KisNodeWSP KisDuplicateOpSettings::sourceNode() const
{
return m_sourceNode;
......@@ -129,6 +139,7 @@ KisPaintOpSettingsSP KisDuplicateOpSettings::clone() const
s->m_isOffsetNotUptodate = m_isOffsetNotUptodate;
s->m_position = m_position;
s->m_sourceNode = m_sourceNode;
s->m_duringPaintingStroke = m_duringPaintingStroke;
return setting;
}
......@@ -149,7 +160,11 @@ QPainterPath KisDuplicateOpSettings::brushOutline(const KisPaintInformation &inf
QPainterPath copy(path);
QRectF rect2 = copy.boundingRect();
if (m_isOffsetNotUptodate || !getBool(DUPLICATE_MOVE_SOURCE_POINT)) {
bool shouldStayInOrigin = m_isOffsetNotUptodate // the clone brush right now waits for first stroke with a new origin, so stays at origin point
|| !getBool(DUPLICATE_MOVE_SOURCE_POINT) // the brush always use the same source point, so stays at origin point
|| (!m_duringPaintingStroke && getBool(DUPLICATE_RESET_SOURCE_POINT)); // during the stroke, with reset Origin selected, outline should stay at origin point
if (shouldStayInOrigin) {
copy.translate(m_position - info.pos());
}
else {
......
......@@ -42,7 +42,19 @@ public:
QPointF offset() const;
QPointF position() const;
/**
* This function is called by a tool when the mouse is pressed.
* Returns false if picking new origin is in action,
* and returns true otherwise (i.e. if brush is starting a new stroke).
* See kis_tool_freehand:tryPickByPaintOp()
*/
bool mousePressEvent(const KisPaintInformation& pos, Qt::KeyboardModifiers modifiers, KisNodeWSP currentNode) override;
/**
* This function is called by a tool when the mouse is released.
* If the tool is supposed to ignore the event, the paint op should return true
* and if the tool is supposed to use the event, return false.
*/
bool mouseReleaseEvent() override;
void activate() override;
void fromXML(const QDomElement& elt) override;
......@@ -61,9 +73,10 @@ public:
Q_DISABLE_COPY(KisDuplicateOpSettings)
QPointF m_offset;
bool m_isOffsetNotUptodate;
bool m_isOffsetNotUptodate; // true between the act of setting a new origin and the first stroke
bool m_duringPaintingStroke; // true if the stroke is begin painted now, false otherwise
QPointF m_position; // Give the position of the last alt-click
KisNodeWSP m_sourceNode;
KisNodeWSP m_sourceNode; // Give the node of the source point (origin)
QList<KisUniformPaintOpPropertyWSP> m_uniformProperties;
};
......
......@@ -45,6 +45,19 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbResetSourcePoint">
<property name="toolTip">
<string>Reset the origin every time you make a new stroke.</string>
</property>
<property name="text">
<string>Source point reset before a new stroke</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chkCloneProjection">
<property name="toolTip">
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment