|
|
|
/*
|
|
|
|
* kis_tool_fill.cc - part of Krayon
|
|
|
|
*
|
|
|
|
* Copyright (c) 2000 John Califf <jcaliff@compuzone.net>
|
|
|
|
* Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
|
|
|
|
* Copyright (c) 2004 Bart Coppens <kde@bartcoppens.be>
|
|
|
|
*
|
|
|
|
* 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 <kaction.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kcommand.h>
|
|
|
|
#include <tqlabel.h>
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqcheckbox.h>
|
|
|
|
|
|
|
|
#include <tqcolor.h>
|
|
|
|
|
|
|
|
#include "knuminput.h"
|
|
|
|
|
|
|
|
#include "kis_layer.h"
|
|
|
|
#include "kis_cursor.h"
|
|
|
|
#include "kis_painter.h"
|
|
|
|
#include "kis_tool_brush.h"
|
|
|
|
#include "kis_cmb_composite.h"
|
|
|
|
#include "kis_tool_fill.h"
|
|
|
|
#include "kis_colorspace.h"
|
|
|
|
#include "kis_button_press_event.h"
|
|
|
|
#include "kis_button_release_event.h"
|
|
|
|
#include "kis_move_event.h"
|
|
|
|
#include "kis_pattern.h"
|
|
|
|
#include "kis_fill_painter.h"
|
|
|
|
#include "kis_progress_display_interface.h"
|
|
|
|
#include "kis_undo_adapter.h"
|
|
|
|
#include "kis_canvas_subject.h"
|
|
|
|
#include "kis_selection.h"
|
|
|
|
|
|
|
|
KisToolFill::KisToolFill()
|
|
|
|
: super(i18n("Fill")), m_wasPressed(false)
|
|
|
|
{
|
|
|
|
setName("tool_fill");
|
|
|
|
m_subject = 0;
|
|
|
|
m_oldColor = 0;
|
|
|
|
m_threshold = 15;
|
|
|
|
m_usePattern = false;
|
|
|
|
m_unmerged = false;
|
|
|
|
m_fillOnlySelection = false;
|
|
|
|
|
|
|
|
setCursor(KisCursor::load("tool_fill_cursor.png", 6, 6));
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisToolFill::update(KisCanvasSubject *subject)
|
|
|
|
{
|
|
|
|
m_subject = subject;
|
|
|
|
m_currentImage = subject->currentImg();
|
|
|
|
|
|
|
|
super::update(m_subject);
|
|
|
|
}
|
|
|
|
|
|
|
|
KisToolFill::~KisToolFill()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KisToolFill::flood(int startX, int startY)
|
|
|
|
{
|
|
|
|
KisPaintDeviceSP device = m_currentImage->activeDevice();
|
|
|
|
if (!device) return false;
|
|
|
|
|
|
|
|
if (m_fillOnlySelection) {
|
|
|
|
TQRect rc = device->selection()->selectedRect();
|
|
|
|
KisPaintDeviceSP filled = new KisPaintDevice(device->colorSpace(), "filled");
|
|
|
|
KisFillPainter painter(filled);
|
|
|
|
if (m_usePattern)
|
|
|
|
painter.fillRect(rc.x(), rc.y(), rc.width(), rc.height(),
|
|
|
|
m_subject->currentPattern());
|
|
|
|
else
|
|
|
|
painter.fillRect(rc.x(), rc.y(), rc.width(), rc.height(),
|
|
|
|
m_subject->fgColor(), m_opacity);
|
|
|
|
painter.end();
|
|
|
|
KisPainter painter2(device);
|
|
|
|
if (m_currentImage->undo()) painter2.beginTransaction(i18n("Fill"));
|
|
|
|
painter2.bltSelection(rc.x(), rc.y() , m_compositeOp, filled, m_opacity,
|
|
|
|
rc.x(), rc.y(), rc.width(), rc.height());
|
|
|
|
|
|
|
|
device->setDirty(filled->extent());
|
|
|
|
notifyModified();
|
|
|
|
|
|
|
|
if (m_currentImage->undo()) {
|
|
|
|
m_currentImage->undoAdapter()->addCommand(painter2.endTransaction());
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
KisFillPainter painter(device);
|
|
|
|
if (m_currentImage->undo()) painter.beginTransaction(i18n("Flood Fill"));
|
|
|
|
painter.setPaintColor(m_subject->fgColor());
|
|
|
|
painter.setOpacity(m_opacity);
|
|
|
|
painter.setFillThreshold(m_threshold);
|
|
|
|
painter.setCompositeOp(m_compositeOp);
|
|
|
|
painter.setPattern(m_subject->currentPattern());
|
|
|
|
painter.setSampleMerged(!m_unmerged);
|
|
|
|
painter.setCareForSelection(true);
|
|
|
|
|
|
|
|
KisProgressDisplayInterface *progress = m_subject->progressDisplay();
|
|
|
|
if (progress) {
|
|
|
|
progress->setSubject(&painter, true, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_usePattern)
|
|
|
|
painter.fillPattern(startX, startY);
|
|
|
|
else
|
|
|
|
painter.fillColor(startX, startY);
|
|
|
|
|
|
|
|
device->setDirty(painter.dirtyRect());
|
|
|
|
notifyModified();
|
|
|
|
|
|
|
|
if (m_currentImage->undo()) {
|
|
|
|
m_currentImage->undoAdapter()->addCommand(painter.endTransaction());
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisToolFill::buttonPress(KisButtonPressEvent *e)
|
|
|
|
{
|
|
|
|
m_startPos = e->pos();
|
|
|
|
m_wasPressed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisToolFill::buttonRelease(KisButtonReleaseEvent *e)
|
|
|
|
{
|
|
|
|
if (!m_subject) return;
|
|
|
|
if (!m_currentImage || !m_currentImage->activeDevice()) return;
|
|
|
|
if (e->button() != Qt::LeftButton) return;
|
|
|
|
if(!m_wasPressed) return;
|
|
|
|
m_wasPressed = false;
|
|
|
|
int x, y;
|
|
|
|
x = m_startPos.floorX();
|
|
|
|
y = m_startPos.floorY();
|
|
|
|
if (!m_currentImage->bounds().contains(x, y)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
flood(x, y);
|
|
|
|
notifyModified();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQWidget* KisToolFill::createOptionWidget(TQWidget* parent)
|
|
|
|
{
|
|
|
|
TQWidget *widget = super::createOptionWidget(parent);
|
|
|
|
|
|
|
|
m_lbThreshold = new TQLabel(i18n("Threshold: "), widget);
|
|
|
|
m_slThreshold = new KIntNumInput( widget, "int_widget");
|
|
|
|
m_slThreshold->setRange( 1, 100);
|
|
|
|
m_slThreshold->setSteps( 3, 3);
|
|
|
|
m_slThreshold->setValue(m_threshold);
|
|
|
|
connect(m_slThreshold, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slotSetThreshold(int)));
|
|
|
|
|
|
|
|
m_checkUsePattern = new TQCheckBox(i18n("Use pattern"), widget);
|
|
|
|
m_checkUsePattern->setChecked(m_usePattern);
|
|
|
|
connect(m_checkUsePattern, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotSetUsePattern(bool)));
|
|
|
|
|
|
|
|
m_checkSampleMerged = new TQCheckBox(i18n("Limit to current layer"), widget);
|
|
|
|
m_checkSampleMerged->setChecked(m_unmerged);
|
|
|
|
connect(m_checkSampleMerged, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotSetSampleMerged(bool)));
|
|
|
|
|
|
|
|
m_checkFillSelection = new TQCheckBox(i18n("Fill entire selection"), widget);
|
|
|
|
m_checkFillSelection->setChecked(m_fillOnlySelection);
|
|
|
|
connect(m_checkFillSelection, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotSetFillSelection(bool)));
|
|
|
|
|
|
|
|
addOptionWidgetOption(m_slThreshold, m_lbThreshold);
|
|
|
|
|
|
|
|
addOptionWidgetOption(m_checkFillSelection);
|
|
|
|
addOptionWidgetOption(m_checkSampleMerged);
|
|
|
|
addOptionWidgetOption(m_checkUsePattern);
|
|
|
|
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisToolFill::slotSetThreshold(int threshold)
|
|
|
|
{
|
|
|
|
m_threshold = threshold;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisToolFill::slotSetUsePattern(bool state)
|
|
|
|
{
|
|
|
|
m_usePattern = state;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisToolFill::slotSetSampleMerged(bool state)
|
|
|
|
{
|
|
|
|
m_unmerged = state;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisToolFill::slotSetFillSelection(bool state)
|
|
|
|
{
|
|
|
|
m_fillOnlySelection = state;
|
|
|
|
m_slThreshold->setEnabled(!state);
|
|
|
|
m_checkSampleMerged->setEnabled(!state);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisToolFill::setup(KActionCollection *collection)
|
|
|
|
{
|
|
|
|
m_action = static_cast<KRadioAction *>(collection->action(name()));
|
|
|
|
|
|
|
|
if (m_action == 0) {
|
|
|
|
m_action = new KRadioAction(i18n("&Fill"),
|
|
|
|
"tool_color_fill",
|
|
|
|
TQt::Key_F,
|
|
|
|
this,
|
|
|
|
TQT_SLOT(activate()),
|
|
|
|
collection,
|
|
|
|
name());
|
|
|
|
m_action->setToolTip(i18n("Contiguous fill"));
|
|
|
|
m_action->setExclusiveGroup("tools");
|
|
|
|
m_ownAction = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "kis_tool_fill.moc"
|