summaryrefslogtreecommitdiffstats
path: root/chalk/plugins/viewplugins/colorrange/dlg_colorrange.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chalk/plugins/viewplugins/colorrange/dlg_colorrange.cpp')
-rw-r--r--chalk/plugins/viewplugins/colorrange/dlg_colorrange.cpp351
1 files changed, 351 insertions, 0 deletions
diff --git a/chalk/plugins/viewplugins/colorrange/dlg_colorrange.cpp b/chalk/plugins/viewplugins/colorrange/dlg_colorrange.cpp
new file mode 100644
index 000000000..82748f4c8
--- /dev/null
+++ b/chalk/plugins/viewplugins/colorrange/dlg_colorrange.cpp
@@ -0,0 +1,351 @@
+/*
+ * dlg_colorrange.cpp - part of KimageShop^WKrayon^WChalk
+ *
+ * Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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 <tqapplication.h>
+#include <tqpushbutton.h>
+#include <tqcheckbox.h>
+#include <tqslider.h>
+#include <tqcombobox.h>
+#include <tqpixmap.h>
+#include <tqimage.h>
+#include <tqlabel.h>
+#include <tqcolor.h>
+#include <tqradiobutton.h>
+
+#include <knuminput.h>
+#include <tdelocale.h>
+#include <kdebug.h>
+#include <tdeaction.h>
+
+#include <kis_canvas_subject.h>
+#include <kis_iterators_pixel.h>
+#include <kis_layer.h>
+#include <kis_paint_device.h>
+#include <kis_selection.h>
+#include <kis_selection_manager.h>
+#include <kis_types.h>
+#include <kis_undo_adapter.h>
+#include <kis_view.h>
+#include <kis_colorspace.h>
+#include <kis_profile.h>
+#include <kis_color_conversions.h>
+#include <kis_selected_transaction.h>
+#include <kis_cursor.h>
+
+#include "dlg_colorrange.h"
+#include "wdg_colorrange.h"
+
+namespace {
+
+// XXX: Poynton says: hsv/hls is not what one ought to use for colour calculations.
+// Unfortunately, I don't know enough to be able to use anything else.
+
+ bool isReddish(int h)
+ {
+ return ((h > 330 && h < 360) || ( h > 0 && h < 40));
+ }
+
+ bool isYellowish(int h)
+ {
+ return (h> 40 && h < 65);
+ }
+
+ bool isGreenish(int h)
+ {
+ return (h > 70 && h < 155);
+ }
+
+ bool isCyanish(int h)
+ {
+ return (h > 150 && h < 190);
+ }
+
+ bool isBlueish(int h)
+ {
+ return (h > 185 && h < 270);
+ }
+
+ bool isMagentaish(int h)
+ {
+ return (h > 265 && h < 330);
+ }
+
+ bool isHighlight(int v)
+ {
+ return (v > 200);
+ }
+
+ bool isMidTone(int v)
+ {
+ return (v > 100 && v < 200);
+ }
+
+ bool isShadow(int v)
+ {
+ return (v < 100);
+ }
+
+}
+
+TQ_UINT32 matchColors(const TQColor & c, enumAction action)
+{
+ int r = c.red();
+ int g = c.green();
+ int b = c.blue();
+
+ int h, s, v;
+ rgb_to_hsv(r, g, b, &h, &s, &v);
+
+
+
+ // XXX: Map the degree in which the colors conform to the requirement
+ // to a range of selectedness between 0 and 255
+
+ // XXX: Implement out-of-gamut using lcms
+
+ switch(action) {
+
+ case REDS:
+ if (isReddish(h))
+ return MAX_SELECTED;
+ else
+ return MIN_SELECTED;
+ case YELLOWS:
+ if (isYellowish(h)) {
+ return MAX_SELECTED;
+ }
+ else
+ return MIN_SELECTED;
+ case GREENS:
+ if (isGreenish(h))
+ return MAX_SELECTED;
+ else
+ return MIN_SELECTED;
+ case CYANS:
+ if (isCyanish(h))
+ return MAX_SELECTED;
+ else
+ return MIN_SELECTED;
+ case BLUES:
+ if (isBlueish(h))
+ return MAX_SELECTED;
+ else
+ return MIN_SELECTED;
+ case MAGENTAS:
+ if (isMagentaish(h))
+ return MAX_SELECTED;
+ else
+ return MIN_SELECTED;
+ case HIGHLIGHTS:
+ if (isHighlight(v))
+ return MAX_SELECTED;
+ else
+ return MIN_SELECTED;
+ case MIDTONES:
+ if (isMidTone(v))
+ return MAX_SELECTED;
+ else
+ return MIN_SELECTED;
+ case SHADOWS:
+ if (isShadow(v))
+ return MAX_SELECTED;
+ else
+ return MIN_SELECTED;
+ };
+
+ return MIN_SELECTED;
+}
+
+
+
+DlgColorRange::DlgColorRange( KisView * view, KisPaintDeviceSP dev, TQWidget * parent, const char * name)
+ : super (parent, name, true, i18n("Color Range"), Ok | Cancel, Ok)
+{
+ m_dev = dev;
+ m_view = view;
+
+ m_subject = view->canvasSubject();
+
+ m_page = new WdgColorRange(this, "color_range");
+ TQ_CHECK_PTR(m_page);
+
+ setCaption(i18n("Color Range"));
+ setMainWidget(m_page);
+ resize(m_page->sizeHint());
+
+ if (m_dev->image()->undo()) m_transaction = new KisSelectedTransaction(i18n("Select by Color Range"), m_dev);
+
+ if(! m_dev->hasSelection())
+ m_dev->selection()->clear();
+ m_selection = m_dev->selection();
+
+ updatePreview();
+
+ m_invert = false;
+ m_mode = SELECTION_ADD;
+ m_currentAction = REDS;
+
+ connect(this, TQT_SIGNAL(okClicked()),
+ this, TQT_SLOT(okClicked()));
+
+ connect(this, TQT_SIGNAL(cancelClicked()),
+ this, TQT_SLOT(cancelClicked()));
+
+ connect(m_page->chkInvert, TQT_SIGNAL(clicked()),
+ this, TQT_SLOT(slotInvertClicked()));
+
+ connect(m_page->cmbSelect, TQT_SIGNAL(activated(int)),
+ this, TQT_SLOT(slotSelectionTypeChanged(int)));
+
+ connect (m_page->radioAdd, TQT_SIGNAL(toggled(bool)),
+ this, TQT_SLOT(slotAdd(bool)));
+
+ connect (m_page->radioSubtract, TQT_SIGNAL(toggled(bool)),
+ this, TQT_SLOT(slotSubtract(bool)));
+
+ connect (m_page->bnSelect, TQT_SIGNAL(clicked()),
+ this, TQT_SLOT(slotSelectClicked()));
+
+ connect (m_page->bnDeselect, TQT_SIGNAL(clicked()),
+ this, TQT_SLOT(slotDeselectClicked()));
+
+}
+
+DlgColorRange::~DlgColorRange()
+{
+ delete m_page;
+}
+
+
+void DlgColorRange::updatePreview()
+{
+ if (!m_selection) return;
+
+ TQ_INT32 x, y, w, h;
+ m_dev->exactBounds(x, y, w, h);
+ TQPixmap pix = TQPixmap(m_selection->maskImage().smoothScale(350, 350, TQ_ScaleMin));
+ m_subject->canvasController()->updateCanvas();
+ m_page->pixSelection->setPixmap(pix);
+}
+
+void DlgColorRange::okClicked()
+{
+ m_dev->setDirty();
+ m_dev->emitSelectionChanged();
+
+ if (m_dev->image()->undo()) m_subject->undoAdapter()->addCommand(m_transaction);
+ accept();
+}
+
+void DlgColorRange::cancelClicked()
+{
+ if (m_dev->image()->undo()) m_transaction->unexecute();
+
+ m_subject->canvasController()->updateCanvas();
+ reject();
+}
+
+void DlgColorRange::slotInvertClicked()
+{
+ m_invert = m_page->chkInvert->isChecked();
+}
+
+void DlgColorRange::slotSelectionTypeChanged(int index)
+{
+ m_currentAction = (enumAction)index;
+}
+
+void DlgColorRange::slotSubtract(bool on)
+{
+ if (on)
+ m_mode = SELECTION_SUBTRACT;
+}
+void DlgColorRange::slotAdd(bool on)
+{
+ if (on)
+ m_mode = SELECTION_ADD;
+}
+
+void DlgColorRange::slotSelectClicked()
+{
+ TQApplication::setOverrideCursor(KisCursor::waitCursor());
+ // XXX: Multithread this!
+ TQ_INT32 x, y, w, h;
+ m_dev->exactBounds(x, y, w, h);
+ KisColorSpace * cs = m_dev->colorSpace();
+ TQ_UINT8 opacity;
+ for (int y2 = y; y2 < h - y; ++y2) {
+ KisHLineIterator hiter = m_dev->createHLineIterator(x, y2, w, false);
+ KisHLineIterator selIter = m_selection ->createHLineIterator(x, y2, w, true);
+ while (!hiter.isDone()) {
+ TQColor c;
+
+ cs->toTQColor(hiter.rawData(), &c, &opacity);
+ // Don't try to select transparent pixels.
+ if (opacity > OPACITY_TRANSPARENT) {
+ TQ_UINT8 match = matchColors(c, m_currentAction);
+
+ if (match) {
+ // Personally, I think the invert option a bit silly. But it's possible I don't quite understand it. BSAR.
+ if (!m_invert) {
+ if (m_mode == SELECTION_ADD) {
+ *(selIter.rawData()) = match;
+ }
+ else if (m_mode == SELECTION_SUBTRACT) {
+ TQ_UINT8 selectedness = *(selIter.rawData());
+ if (match < selectedness) {
+ *(selIter.rawData()) = selectedness - match;
+ }
+ else {
+ *(selIter.rawData()) = 0;
+ }
+ }
+ }
+ else {
+ if (m_mode == SELECTION_ADD) {
+ TQ_UINT8 selectedness = *(selIter.rawData());
+ if (match < selectedness) {
+ *(selIter.rawData()) = selectedness - match;
+ }
+ else {
+ *(selIter.rawData()) = 0;
+ }
+ }
+ else if (m_mode == SELECTION_SUBTRACT) {
+ *(selIter.rawData()) = match;
+ }
+ }
+ }
+ }
+ ++hiter;
+ ++selIter;
+ }
+ }
+ updatePreview();
+ TQApplication::restoreOverrideCursor();
+}
+
+void DlgColorRange::slotDeselectClicked()
+{
+ m_dev->selection()->clear();
+ updatePreview();
+}
+
+
+#include "dlg_colorrange.moc"