/* * Copyright (c) 1999 Matthias Elter * Copyright (c) 2002 Patrick Julien * Copyright (c) 2005 Boudewijn Rempt * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_tool_selectsimilar.h" void selectByColor(KisPaintDeviceSP dev, KisSelectionSP selection, const TQ_UINT8 * c, int fuzziness, enumSelectionMode mode) { // XXX: Multithread this! TQ_INT32 x, y, w, h; dev->exactBounds(x, y, w, h); KisColorSpace * cs = dev->colorSpace(); for (int y2 = y; y2 < y + h; ++y2) { KisHLineIterator hiter = dev->createHLineIterator(x, y2, w, false); KisHLineIterator selIter = selection->createHLineIterator(x, y2, w, true); while (!hiter.isDone()) { //if (dev->colorSpace()->hasAlpha()) // opacity = dev->colorSpace()->getAlpha(hiter.rawData()); TQ_UINT8 match = cs->difference(c, hiter.rawData()); if (mode == SELECTION_ADD) { if (match <= fuzziness) { *(selIter.rawData()) = MAX_SELECTED; } } else if (mode == SELECTION_SUBTRACT) { if (match <= fuzziness) { *(selIter.rawData()) = MIN_SELECTED; } } ++hiter; ++selIter; } } } KisToolSelectSimilar::KisToolSelectSimilar() : super(i18n("Select Similar Colors")) { setName("tool_select_similar"); m_addCursor = KisCursor::load("tool_similar_selection_plus_cursor.png", 1, 21); m_subtractCursor = KisCursor::load("tool_similar_selection_minus_cursor.png", 1, 21); setCursor(m_addCursor); m_subject = 0; m_optWidget = 0; m_selectionOptionsWidget = 0; m_fuzziness = 20; m_currentSelectAction = m_defaultSelectAction = SELECTION_ADD; m_timer = new TQTimer(this); connect(m_timer, TQ_SIGNAL(timeout()), TQ_SLOT(slotTimer()) ); } KisToolSelectSimilar::~KisToolSelectSimilar() { } void KisToolSelectSimilar::activate() { KisToolNonPaint::activate(); m_timer->start(50); setPickerCursor(m_currentSelectAction); if (m_selectionOptionsWidget) { m_selectionOptionsWidget->slotActivated(); } } void KisToolSelectSimilar::deactivate() { m_timer->stop(); } void KisToolSelectSimilar::buttonPress(KisButtonPressEvent *e) { if (m_subject) { TQApplication::setOverrideCursor(KisCursor::waitCursor()); KisImageSP img; KisPaintDeviceSP dev; TQPoint pos; TQ_UINT8 opacity = OPACITY_OPAQUE; if (e->button() != TQt::LeftButton && e->button() != TQt::RightButton) return; if (!(img = m_subject->currentImg())) return; dev = img->activeDevice(); if (!dev || !img->activeLayer()->visible()) return; pos = TQPoint(e->pos().floorX(), e->pos().floorY()); KisSelectedTransaction *t = 0; if (img->undo()) t = new KisSelectedTransaction(i18n("Similar Selection"),dev); KisColor c = dev->colorAt(pos.x(), pos.y()); opacity = dev->colorSpace()->getAlpha(c.data()); // XXX we should make this configurable: "allow to select transparent" // if (opacity > OPACITY_TRANSPARENT) selectByColor(dev, dev->selection(), c.data(), m_fuzziness, m_currentSelectAction); dev->setDirty(); dev->emitSelectionChanged(); if(img->undo()) img->undoAdapter()->addCommand(t); m_subject->canvasController()->updateCanvas(); TQApplication::restoreOverrideCursor(); } } void KisToolSelectSimilar::slotTimer() { #if KDE_IS_VERSION(3,4,0) int state = kapp->keyboardMouseState() & (TQt::ShiftButton|TQt::ControlButton|TQt::AltButton); #else int state = kapp->keyboardModifiers() & (TDEApplication::ShiftModifier |TDEApplication::ControlModifier|TDEApplication::Modifier1); #endif enumSelectionMode action; if (state == TQt::ShiftButton) action = SELECTION_ADD; else if (state == TQt::ControlButton) action = SELECTION_SUBTRACT; else action = m_defaultSelectAction; if (action != m_currentSelectAction) { m_currentSelectAction = action; setPickerCursor(action); } } void KisToolSelectSimilar::setPickerCursor(enumSelectionMode action) { switch (action) { case SELECTION_ADD: m_subject->canvasController()->setCanvasCursor(m_addCursor); break; case SELECTION_SUBTRACT: m_subject->canvasController()->setCanvasCursor(m_subtractCursor); } } void KisToolSelectSimilar::setup(TDEActionCollection *collection) { m_action = static_cast(collection->action(name())); if (m_action == 0) { m_action = new TDERadioAction(i18n("&Similar Selection"), "tool_similar_selection", "Ctrl+E", this, TQ_SLOT(activate()), collection, name()); TQ_CHECK_PTR(m_action); m_action->setToolTip(i18n("Select similar colors")); m_action->setExclusiveGroup("tools"); m_ownAction = true; } } void KisToolSelectSimilar::update(KisCanvasSubject *subject) { super::update(subject); m_subject = subject; } void KisToolSelectSimilar::slotSetFuzziness(int fuzziness) { m_fuzziness = fuzziness; } void KisToolSelectSimilar::slotSetAction(int action) { m_defaultSelectAction = (enumSelectionMode)action; } TQWidget* KisToolSelectSimilar::createOptionWidget(TQWidget* parent) { m_optWidget = new TQWidget(parent); TQ_CHECK_PTR(m_optWidget); m_optWidget->setCaption(i18n("Similar Selection")); TQVBoxLayout * l = new TQVBoxLayout(m_optWidget, 0, 6); TQ_CHECK_PTR(l); m_selectionOptionsWidget = new KisSelectionOptions(m_optWidget, m_subject); TQ_CHECK_PTR(m_selectionOptionsWidget); l->addWidget(m_selectionOptionsWidget); connect (m_selectionOptionsWidget, TQ_SIGNAL(actionChanged(int)), this, TQ_SLOT(slotSetAction(int))); TQHBoxLayout * hbox = new TQHBoxLayout(l); TQ_CHECK_PTR(hbox); TQLabel * lbl = new TQLabel(i18n("Fuzziness: "), m_optWidget); TQ_CHECK_PTR(lbl); hbox->addWidget(lbl); KIntNumInput * input = new KIntNumInput(m_optWidget, "fuzziness"); TQ_CHECK_PTR(input); input->setRange(0, 200, 10, true); input->setValue(20); hbox->addWidget(input); connect(input, TQ_SIGNAL(valueChanged(int)), this, TQ_SLOT(slotSetFuzziness(int))); l->addItem(new TQSpacerItem(1, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding)); return m_optWidget; } TQWidget* KisToolSelectSimilar::optionWidget() { return m_optWidget; } #include "kis_tool_selectsimilar.moc"