Skip to content

Commit

Permalink
Repeat pending fills when changing parameters
Browse files Browse the repository at this point in the history
In the flood fill and magic wand tools, the fills will now update when
you change stuff like the size limit, tolerance, expansion etc. They
will cancel the current fill if that's still going and then repeat it
with the new parameters. This allows for quicker correction of fills
without having to cancel and redo them with other parameters.
  • Loading branch information
askmeaboutlo0m committed Jul 8, 2024
1 parent 41a5256 commit b60eb14
Show file tree
Hide file tree
Showing 7 changed files with 214 additions and 109 deletions.
26 changes: 11 additions & 15 deletions src/desktop/toolwidgets/fillsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,21 +136,7 @@ void FillSettings::setCompatibilityMode(bool compatibilityMode)

void FillSettings::pushSettings()
{
FloodFill *tool =
static_cast<FloodFill *>(controller()->getTool(Tool::FLOODFILL));
tool->setTolerance(
m_ui->tolerance->value() / qreal(m_ui->tolerance->maximum()));
bool shrink = m_expandGroup->checkedId() != 0;
tool->setExpansion(m_ui->expand->value() * (shrink ? -1 : 1));
tool->setFeatherRadius(m_ui->feather->value());
int size = m_ui->size->value();
tool->setSize(isSizeUnlimited(size) ? -1 : size);
tool->setOpacity(m_ui->opacity->value() / 100.0);
tool->setGap(m_ui->gap->value());
tool->setSource(FloodFill::Source(m_sourceGroup->checkedId()));

int area = m_areaGroup->checkedId();
tool->setArea(FloodFill::Area(area));
bool floodOptionsEnabled = area != int(FloodFill::Area::Selection);
m_ui->size->setEnabled(floodOptionsEnabled && !m_haveSelection);
m_ui->tolerance->setEnabled(floodOptionsEnabled);
Expand All @@ -168,13 +154,23 @@ void FillSettings::pushSettings()
m_ui->sourceFillSource->setVisible(haveFillSource);

int blendMode = m_ui->blendModeCombo->currentData().toInt();
tool->setBlendMode(blendMode);
if(canvas::blendmode::isValidEraseMode(DP_BlendMode(blendMode))) {
m_previousEraseMode = blendMode;
} else {
m_previousMode = blendMode;
}

FloodFill *tool =
static_cast<FloodFill *>(controller()->getTool(Tool::FLOODFILL));
bool shrink = m_expandGroup->checkedId() != 0;
int size = m_ui->size->value();
tool->setParameters(
m_ui->tolerance->value() / qreal(m_ui->tolerance->maximum()),
m_ui->expand->value() * (shrink ? -1 : 1), m_ui->feather->value(),
isSizeUnlimited(size) ? -1 : size, m_ui->opacity->value() / 100.0,
m_ui->gap->value(), FloodFill::Source(m_sourceGroup->checkedId()),
blendMode, FloodFill::Area(area));

m_ui->expand->setPrefix(shrink ? tr("Shrink: ") : tr("Expand: "));

if(!m_ui->sourceFillSource->isEnabled() &&
Expand Down
4 changes: 3 additions & 1 deletion src/desktop/toolwidgets/selectionsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ void SelectionSettings::pushSettings()
: QCoreApplication::translate("FillSettings", "Expand: "));
if(ctrl->activeTool() == Tool::MAGICWAND) {
static_cast<MagicWandTool *>(ctrl->getTool(Tool::MAGICWAND))
->updatePendingToolNotice();
->updateParameters();
}
}

Expand Down Expand Up @@ -239,6 +239,7 @@ QWidget *SelectionSettings::createUiWidget(QWidget *parent)
m_sizeSlider->setPrefix(
QCoreApplication::translate("FillSettings", "Size Limit: "));
m_sizeSlider->setSuffix(QCoreApplication::translate("FillSettings", "px"));
m_sizeSlider->setBlockUpdateSignalOnDrag(true);
connect(
m_sizeSlider, QOverload<int>::of(&KisSliderSpinBox::valueChanged), this,
&SelectionSettings::pushSettings);
Expand All @@ -253,6 +254,7 @@ QWidget *SelectionSettings::createUiWidget(QWidget *parent)
QCoreApplication::translate("FillSettings", "Opacity: "));
m_opacitySlider->setSuffix(
QCoreApplication::translate("FillSettings", "%"));
m_opacitySlider->setBlockUpdateSignalOnDrag(true);
connect(
m_opacitySlider, QOverload<int>::of(&KisSliderSpinBox::valueChanged),
this, &SelectionSettings::pushSettings);
Expand Down
18 changes: 18 additions & 0 deletions src/desktop/ui/fillsettings.ui
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
<property name="value">
<number>100</number>
</property>
<property name="blockUpdateSignalOnDrag">
<bool>true</bool>
</property>
</widget>
</item>
<item row="12" column="0">
Expand All @@ -67,6 +70,9 @@
<property name="maximum">
<number>254</number>
</property>
<property name="blockUpdateSignalOnDrag">
<bool>true</bool>
</property>
</widget>
</item>
<item row="12" column="1">
Expand Down Expand Up @@ -298,6 +304,9 @@
<property name="singleStep">
<number>1</number>
</property>
<property name="blockUpdateSignalOnDrag">
<bool>true</bool>
</property>
</widget>
</item>
<item row="8" column="0" colspan="2">
Expand All @@ -311,6 +320,9 @@
<property name="maximum">
<number>40</number>
</property>
<property name="blockUpdateSignalOnDrag">
<bool>true</bool>
</property>
</widget>
</item>
<item row="9" column="0" colspan="2">
Expand All @@ -324,6 +336,9 @@
<property name="maximum">
<number>32</number>
</property>
<property name="blockUpdateSignalOnDrag">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
Expand All @@ -342,6 +357,9 @@
<property name="maximum">
<number>100</number>
</property>
<property name="blockUpdateSignalOnDrag">
<bool>true</bool>
</property>
</widget>
</item>
<item>
Expand Down
128 changes: 84 additions & 44 deletions src/libclient/tools/floodfill.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ FloodFill::FloodFill(ToolController &owner)
, m_blendMode(DP_BLEND_MODE_NORMAL)
, m_area(Area::Continuous)
, m_running{false}
, m_repeat(false)
, m_cancel{false}
{
}
Expand All @@ -121,45 +122,12 @@ void FloodFill::begin(const BeginParams &params)
{
if(params.right) {
cancelMultipart();
} else if(havePending()) {
flushPending();
} else if(!m_running) {
canvas::CanvasModel *canvas = m_owner.model();
QColor fillColor = m_blendMode == DP_BLEND_MODE_ERASE
? Qt::black
: m_owner.foregroundColor();

int layerId;
switch(m_source) {
case Source::Merged:
layerId = 0;
break;
case Source::MergedWithoutBackground:
layerId = -1;
break;
case Source::FillSourceLayer:
layerId = canvas->layerlist()->fillSourceLayerId();
if(layerId > 0) {
break;
}
Q_FALLTHROUGH();
default:
layerId = m_owner.activeLayer();
break;
if(havePending()) {
flushPending();
} else {
fillAt(params.point);
}

m_running = true;
m_cancel = false;
canvas::PaintEngine *paintEngine = canvas->paintEngine();
setHandlesRightClick(true);
emit m_owner.toolNoticeRequested(
QCoreApplication::translate("FillSettings", "Filling…"));
m_owner.executeAsync(new Task{
this, m_cancel, paintEngine->viewCanvasState(),
canvas->localUserId(), params.point, fillColor, m_tolerance,
layerId, m_size, m_gap, m_expansion, m_featherRadius, m_area,
paintEngine->viewMode(), paintEngine->viewLayer(),
paintEngine->viewFrame()});
}
}

Expand Down Expand Up @@ -193,6 +161,7 @@ void FloodFill::cancelMultipart()

void FloodFill::dispose()
{
m_repeat = false;
if(m_running) {
m_cancel = true;
}
Expand All @@ -215,19 +184,87 @@ ToolState FloodFill::toolState() const
return havePending() ? ToolState::AwaitingConfirmation : ToolState::Normal;
}

void FloodFill::setOpacity(qreal opacity)
void FloodFill::setParameters(
qreal tolerance, int expansion, int featherRadius, int size, qreal opacity,
int gap, Source source, int blendMode, Area area)
{
if(opacity != m_opacity) {
bool needsUpdate = opacity != m_opacity || blendMode != m_blendMode;
bool needsRefill = tolerance != m_tolerance || expansion != m_expansion ||
featherRadius != m_featherRadius || size != m_size ||
gap != m_gap || source != m_source || area != m_area;

if(needsUpdate) {
m_opacity = opacity;
updatePendingPreview();
m_blendMode = blendMode;
if(!needsRefill) {
updatePendingPreview();
}
}

if(needsRefill) {
m_tolerance = tolerance;
m_expansion = expansion;
m_featherRadius = featherRadius;
m_size = size;
m_gap = gap;
m_source = source;
m_area = area;
repeatFill();
}
}

void FloodFill::setBlendMode(int blendMode)
void FloodFill::fillAt(const QPointF &point)
{
if(blendMode != m_blendMode) {
m_blendMode = blendMode;
updatePendingPreview();
m_repeat = false;
canvas::CanvasModel *canvas = m_owner.model();
if(canvas && !m_running) {
m_lastPoint = point;

QColor fillColor = m_blendMode == DP_BLEND_MODE_ERASE
? Qt::black
: m_owner.foregroundColor();

int layerId;
switch(m_source) {
case Source::Merged:
layerId = 0;
break;
case Source::MergedWithoutBackground:
layerId = -1;
break;
case Source::FillSourceLayer:
layerId = canvas->layerlist()->fillSourceLayerId();
if(layerId > 0) {
break;
}
Q_FALLTHROUGH();
default:
layerId = m_owner.activeLayer();
break;
}

m_running = true;
m_cancel = false;
canvas::PaintEngine *paintEngine = canvas->paintEngine();
setHandlesRightClick(true);
emit m_owner.toolNoticeRequested(
QCoreApplication::translate("FillSettings", "Filling…"));
m_owner.executeAsync(new Task(
this, m_cancel, paintEngine->viewCanvasState(),
canvas->localUserId(), point, fillColor, m_tolerance, layerId,
m_size, m_gap, m_expansion, m_featherRadius, m_area,
paintEngine->viewMode(), paintEngine->viewLayer(),
paintEngine->viewFrame()));
}
}

void FloodFill::repeatFill()
{
if(m_running) {
m_repeat = true;
m_cancel = true;
} else if(havePending()) {
fillAt(m_lastPoint);
}
}

Expand All @@ -251,6 +288,9 @@ void FloodFill::floodFillFinished(Task *task)
previewPending();
setHandlesRightClick(havePending());
m_owner.refreshToolState();
if(m_repeat) {
fillAt(m_lastPoint);
}
}

void FloodFill::updatePendingPreview()
Expand Down
19 changes: 7 additions & 12 deletions src/libclient/tools/floodfill.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,16 @@ class FloodFill final : public Tool {
void setForegroundColor(const QColor &color) override;
ToolState toolState() const override;

void setTolerance(qreal tolerance) { m_tolerance = tolerance; }
void setExpansion(int expansion) { m_expansion = expansion; }
void setFeatherRadius(int featherRadius)
{
m_featherRadius = featherRadius;
}
void setSize(int size) { m_size = size; }
void setOpacity(qreal opacity);
void setGap(int gap) { m_gap = gap; }
void setSource(Source source) { m_source = source; }
void setBlendMode(int blendMode);
void setArea(Area area) { m_area = area; }
void setParameters(
qreal tolerance, int expansion, int featherRadius, int size,
qreal opacity, int gap, Source source, int blendMode, Area area);

private:
class Task;
friend Task;

void fillAt(const QPointF &point);
void repeatFill();
void floodFillFinished(Task *task);

bool havePending() const { return !m_pendingImage.isNull(); }
Expand All @@ -76,7 +69,9 @@ class FloodFill final : public Tool {
int m_blendMode;
Area m_area;
bool m_running;
bool m_repeat;
QAtomicInt m_cancel;
QPointF m_lastPoint;
QImage m_pendingImage;
QPoint m_pendingPos;
Area m_pendingArea;
Expand Down
Loading

0 comments on commit b60eb14

Please sign in to comment.