Skip to content

Commit

Permalink
Drag adjustment of fill and magic wand tolerance
Browse files Browse the repository at this point in the history
Similar to how the magic wand tool works in GIMP, clicking and dragging
left and right will temporarily adjust the tolerance and show a preview
of the effect thereof.

Note that this is not how the fill tool works in GIMP, that just seems
to have bogus behavior there when you drag it.

Implements #1327.
  • Loading branch information
askmeaboutlo0m committed Nov 1, 2024
1 parent c362abe commit 0cf4dec
Show file tree
Hide file tree
Showing 11 changed files with 246 additions and 33 deletions.
1 change: 1 addition & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Unreleased Version 2.2.2-pre
* Fix: The Delete Empty Annotations can now be undone without undoing what happened before it as well.
* Feature: Empty annotations are now automatically deleted when you deselect them, to avoid the common clutter of stray empty annotations across the canvas. If you really did want an empty annotation, you can hit undo and it will return.
* Server Feature: Setting a minimum protocol version of dp:4.24.0 now tells clients that they're using a Drawpile version too old for this server, rather than leaving them sitting at a session list where they can join no sessions.
* Feature: Allow clicking and dragging the fill and magic wand tools to adjust the tolerance.

2024-08-09 Version 2.2.2-beta.3
* Fix: Use more accurate timers for performance profiles if the platform supports it.
Expand Down
29 changes: 27 additions & 2 deletions src/desktop/toolwidgets/fillsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ QWidget *FillSettings::createUiWidget(QWidget *parent)
&FillSettings::updateSettings);
connect(
m_ui->tolerance, QOverload<int>::of(&QSpinBox::valueChanged), this,
&FillSettings::updateSettings);
&FillSettings::updateTolerance);
connect(
m_ui->size, QOverload<int>::of(&QSpinBox::valueChanged), this,
&FillSettings::updateSettings);
Expand Down Expand Up @@ -195,6 +195,10 @@ QWidget *FillSettings::createUiWidget(QWidget *parent)
&FillSettings::setButtonState);
setButtonState(false, false);

connect(
controller(), &ToolController::floodFillDragChanged, this,
&FillSettings::setDragState);

QWidget *disabledWidget = new QWidget;
QVBoxLayout *disabledLayout = new QVBoxLayout(disabledWidget);

Expand Down Expand Up @@ -259,7 +263,8 @@ void FillSettings::pushSettings()
static_cast<FloodFill *>(controller()->getTool(Tool::FLOODFILL));
int size = m_ui->size->value();
tool->setParameters(
m_ui->tolerance->value() / qreal(m_ui->tolerance->maximum()),
m_toleranceBeforeDrag < 0 ? m_ui->tolerance->value()
: m_toleranceBeforeDrag,
m_ui->expandShrink->effectiveValue(), m_ui->expandShrink->kernel(),
m_ui->feather->value(), isSizeUnlimited(size) ? -1 : size,
m_ui->opacity->value() / 100.0, m_ui->gap->value(),
Expand Down Expand Up @@ -410,6 +415,13 @@ void FillSettings::stepAdjust1(bool increase)
}
}

void FillSettings::updateTolerance()
{
if(m_toleranceBeforeDrag < 0) {
updateSettings();
}
}

void FillSettings::updateSettings()
{
if(!m_updating) {
Expand Down Expand Up @@ -481,6 +493,19 @@ void FillSettings::setButtonState(bool running, bool pending)
m_ui->cancelButton->setEnabled(running || pending);
}

void FillSettings::setDragState(bool dragging, int tolerance)
{
if(dragging) {
if(m_toleranceBeforeDrag < 0) {
m_toleranceBeforeDrag = m_ui->tolerance->value();
}
m_ui->tolerance->setValue(tolerance);
} else if(m_toleranceBeforeDrag >= 0) {
m_ui->tolerance->setValue(m_toleranceBeforeDrag);
m_toleranceBeforeDrag = -1;
}
}

void FillSettings::updateWidgets()
{
if(m_stack) {
Expand Down
3 changes: 3 additions & 0 deletions src/desktop/toolwidgets/fillsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public slots:
QWidget *createUiWidget(QWidget *parent) override;

private:
void updateTolerance();
void updateSettings();

void updateSize();
Expand All @@ -72,6 +73,7 @@ public slots:
void selectBlendMode(int blendMode);

void setButtonState(bool running, bool pending);
void setDragState(bool dragging, int tolerance);
void updateWidgets();

QWidget *m_headerWidget = nullptr;
Expand All @@ -84,6 +86,7 @@ public slots:
QButtonGroup *m_areaGroup = nullptr;
int m_previousMode;
int m_previousEraseMode;
int m_toleranceBeforeDrag = -1;
qreal m_quickAdjust1 = 0.0;
bool m_featureAccess = true;
bool m_haveSelection = false;
Expand Down
29 changes: 26 additions & 3 deletions src/desktop/toolwidgets/selectionsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,7 @@ void SelectionSettings::pushSettings()
int size = m_sizeSlider->value();
selectionParams.size = isSizeUnlimited(size) ? -1 : size;
selectionParams.opacity = m_opacitySlider->value() / 100.0;
selectionParams.tolerance =
m_toleranceSlider->value() / qreal(m_toleranceSlider->maximum());
selectionParams.tolerance = m_toleranceSlider->value();
selectionParams.expansion = m_expandShrink->effectiveValue();
selectionParams.featherRadius = m_featherSlider->value();
selectionParams.gap = m_closeGapsSlider->value();
Expand Down Expand Up @@ -268,7 +267,7 @@ QWidget *SelectionSettings::createUiWidget(QWidget *parent)
m_toleranceSlider->setBlockUpdateSignalOnDrag(true);
connect(
m_toleranceSlider, QOverload<int>::of(&KisSliderSpinBox::valueChanged),
this, &SelectionSettings::pushSettings);
this, &SelectionSettings::updateTolerance);
magicWandLayout->addRow(m_toleranceSlider);

m_expandShrink = new widgets::ExpandShrinkSpinner;
Expand Down Expand Up @@ -420,6 +419,10 @@ QWidget *SelectionSettings::createUiWidget(QWidget *parent)

setActiveTool(tools::Tool::SELECTION);
updateSize(m_sizeSlider->value());
connect(
controller(), &ToolController::magicWandDragChanged, this,
&SelectionSettings::setDragState);

return widget;
}

Expand All @@ -433,6 +436,13 @@ void SelectionSettings::updateSize(int size)
emit pixelSizeChanged(calculatePixelSize(size, unlimited));
}

void SelectionSettings::updateTolerance()
{
if(m_toleranceBeforeDrag < 0) {
pushSettings();
}
}

bool SelectionSettings::isSizeUnlimited(int size)
{
return size >= props::size.max;
Expand All @@ -443,4 +453,17 @@ int SelectionSettings::calculatePixelSize(int size, bool unlimited)
return unlimited ? 0 : size * 2 + 1;
}

void SelectionSettings::setDragState(bool dragging, int tolerance)
{
if(dragging) {
if(m_toleranceBeforeDrag < 0) {
m_toleranceBeforeDrag = m_toleranceSlider->value();
}
m_toleranceSlider->setValue(tolerance);
} else if(m_toleranceBeforeDrag >= 0) {
m_toleranceSlider->setValue(m_toleranceBeforeDrag);
m_toleranceBeforeDrag = -1;
}
}

}
4 changes: 4 additions & 0 deletions src/desktop/toolwidgets/selectionsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,12 @@ public slots:
enum Area { Continuous, Similar };

void updateSize(int size);
void updateTolerance();
static bool isSizeUnlimited(int size);
static int calculatePixelSize(int size, bool unlimited);

void setDragState(bool dragging, int tolerance);

QWidget *m_headerWidget = nullptr;
QButtonGroup *m_headerGroup = nullptr;
QWidget *m_selectionContainer = nullptr;
Expand All @@ -77,6 +80,7 @@ public slots:
QButtonGroup *m_sourceGroup = nullptr;
QButtonGroup *m_areaGroup = nullptr;
QPushButton *m_startTransformButton = nullptr;
int m_toleranceBeforeDrag = -1;
bool m_isMagicWand = false;
};

Expand Down
38 changes: 35 additions & 3 deletions src/libclient/tools/clickdetector.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@

namespace tools {

class DragDetector;

class ClickDetector final {
friend class DragDetector;

public:
void begin(const QPointF &viewPos, DeviceType deviceType)
{
Expand Down Expand Up @@ -43,8 +47,8 @@ class ClickDetector final {
m_clicks = 0;
}

bool isClick() { return m_clicks != 0; }
int clicks() { return m_clicks; }
bool isClick() const { return m_clicks != 0; }
int clicks() const { return m_clicks; }

private:
static constexpr int CLICK_TIME = 150;
Expand All @@ -56,7 +60,7 @@ class ClickDetector final {
QGuiApplication::styleHints()->mouseDoubleClickInterval());
}

qreal getClickDistance(DeviceType deviceType)
static qreal getClickDistance(DeviceType deviceType)
{
int distance;
switch(deviceType) {
Expand Down Expand Up @@ -84,6 +88,34 @@ class ClickDetector final {
unsigned int m_clicks = 0;
};

class DragDetector final {
public:
void begin(const QPointF &viewPos, DeviceType deviceType)
{
m_clickDistance = ClickDetector::getClickDistance(deviceType);
m_timer.setRemainingTime(ClickDetector::CLICK_TIME);
m_startViewPos = viewPos;
m_dragThresholdHit = false;
}

void motion(const QPointF &viewPos)
{
if(!m_dragThresholdHit && !m_timer.hasExpired()) {
if(QLineF(m_startViewPos, viewPos).length() > m_clickDistance) {
m_dragThresholdHit = true;
}
}
}

bool isDrag() const { return m_dragThresholdHit || m_timer.hasExpired(); }

private:
QDeadlineTimer m_timer;
qreal m_clickDistance = 0.0;
QPointF m_startViewPos;
bool m_dragThresholdHit = false;
};

}

#endif
Loading

0 comments on commit 0cf4dec

Please sign in to comment.