/* * Copyright (c) 1999 Matthias Elter * Copyright (c) 2002 Patrick Julien * * 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 "kis_layer.h" #include "kis_cursor.h" #include "kis_canvas_subject.h" #include "kis_image.h" #include "kis_paint_device.h" #include "kis_tool_colorpicker.h" #include "kis_tool_colorpicker.moc" #include "kis_button_press_event.h" #include "kis_canvas_subject.h" #include "kis_iterators_pixel.h" #include "kis_color.h" #include "kis_resourceserver.h" #include "kis_palette.h" #include "wdgcolorpicker.h" namespace { // The location of the sample all visible layers in the combobox const int SAMPLE_MERGED = 0; } KisToolColorPicker::KisToolColorPicker() : super (i18n("Color Picker")) { setName("tool_colorpicker"); setCursor(KisCursor::pickerCursor()); m_optionsWidget = 0; m_subject = 0; m_radius = 1; m_addPalette = false; m_updateColor = true; m_normaliseValues = false; m_pickedColor = KisColor(); } KisToolColorPicker::~KisToolColorPicker() { } void KisToolColorPicker::update(KisCanvasSubject *subject) { m_subject = subject; super::update(m_subject); } void KisToolColorPicker::buttonPress(KisButtonPressEvent *e) { if (m_subject) { if (e->button() != Qt::LeftButton && e->button() != Qt::RightButton) return; KisImageSP img; if (!m_subject || !(img = m_subject->currentImg())) return; KisPaintDeviceSP dev = img->activeDevice(); if (!dev) return; bool sampleMerged = m_optionsWidget->cmbSources->currentItem() == SAMPLE_MERGED; if (!sampleMerged) { if (!img->activeLayer()) { KMessageBox::information(0, i18n("Cannot pick a color as no layer is active.")); return; } if (!img->activeLayer()-> visible()) { KMessageBox::information(0, i18n("Cannot pick a color as the active layer is not visible.")); return; } } TQPoint pos = TQPoint(e->pos().floorX(), e->pos().floorY()); if (!img->bounds().contains(pos)) { return; } if (sampleMerged) { dev = img->mergedImage(); } if (m_radius == 1) { m_pickedColor = dev->colorAt (pos.x(), pos.y()); } else { // radius 2 ==> 9 pixels, 3 => 9 pixels, etc static int counts[] = { 0, 1, 9, 25, 45, 69, 109, 145, 193, 249 }; KisColorSpace* cs = dev->colorSpace(); int pixelSize = cs->pixelSize(); TQ_UINT8* data = new TQ_UINT8[pixelSize]; TQ_UINT8** pixels = new TQ_UINT8*[counts[m_radius]]; TQ_UINT8* weights = new TQ_UINT8[counts[m_radius]]; int i = 0; // dummy init KisHLineIteratorPixel iter = dev->createHLineIterator(0, 0, 1, false);; for (int y = - m_radius; y <= m_radius; y++) { for (int x = - m_radius; x <= m_radius; x++) { if (x*x + y*y < m_radius * m_radius) { iter = dev->createHLineIterator(pos.x() + x, pos.y() + y, 1, false); pixels[i] = new TQ_UINT8[pixelSize]; memcpy(pixels[i], iter.rawData(), pixelSize); if (x == 0 && y == 0) { // Because the sum of the weights must be 255, // we cheat a bit, and weigh the center pixel differently in order // to sum to 255 in total // It's -(counts -1), because we'll add the center one implicitly // through that calculation weights[i] = 255 - (counts[m_radius]-1) * (255 / counts[m_radius]); } else { weights[i] = 255 / counts[m_radius]; } i++; } } } // Weird, I can't do that directly :/ const TQ_UINT8** cpixels = const_cast(pixels); cs->mixColors(cpixels, weights, counts[m_radius], data); m_pickedColor = KisColor(data, cs); for (i = 0; i < counts[m_radius]; i++) delete[] pixels[i]; delete[] pixels; delete[] data; } displayPickedColor(); if (m_updateColor) { if (e->button() == Qt::LeftButton) m_subject->setFGColor(m_pickedColor); else m_subject->setBGColor(m_pickedColor); } if (m_addPalette) { // Convert to RGB to add to palette, we ought to have our own format :( KisPaletteEntry ent; ent.color = m_pickedColor.toTQColor(); // We don't ask for a name, too intrusive here KisPalette* palette = m_palettes.at(m_optionsWidget-> cmbPalette->currentItem()); palette->add(ent); if (!palette->save()) { KMessageBox::error(0, i18n("Cannot write to palette file %1. Maybe it is read-only.").arg(palette->filename()), i18n("Palette")); } } } } void KisToolColorPicker::displayPickedColor() { if (m_pickedColor.data() && m_optionsWidget) { TQValueVector channels = m_pickedColor.colorSpace()->channels(); m_optionsWidget->listViewChannels->clear(); for (int i = channels.count() - 1; i >= 0 ; --i) { TQString channelValueText; if (m_normaliseValues) { channelValueText = i18n("%1%").arg(m_pickedColor.colorSpace()->normalisedChannelValueText(m_pickedColor.data(), i)); } else { channelValueText = m_pickedColor.colorSpace()->channelValueText(m_pickedColor.data(), i); } m_optionsWidget->listViewChannels->insertItem(new TQListViewItem(m_optionsWidget->listViewChannels, channels[i]->name(), channelValueText)); } } } void KisToolColorPicker::setup(TDEActionCollection *collection) { m_action = static_cast(collection->action(name())); if (m_action == 0) { m_action = new TDERadioAction(i18n("&Color Picker"), "tool_colorpicker", TQt::Key_P, this, TQT_SLOT(activate()), collection, name()); m_action->setToolTip(i18n("Color picker")); m_action->setExclusiveGroup("tools"); m_ownAction = true; } } TQWidget* KisToolColorPicker::createOptionWidget(TQWidget* parent) { m_optionsWidget = new ColorPickerOptionsWidget(parent); m_optionsWidget->cbUpdateCurrentColour->setChecked(m_updateColor); m_optionsWidget->cmbSources->setCurrentItem(0); m_optionsWidget->cbNormaliseValues->setChecked(m_normaliseValues); m_optionsWidget->cbPalette->setChecked(m_addPalette); m_optionsWidget->radius->setValue(m_radius); m_optionsWidget->listViewChannels->setSorting(-1); connect(m_optionsWidget->cbUpdateCurrentColour, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotSetUpdateColor(bool))); connect(m_optionsWidget->cbNormaliseValues, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotSetNormaliseValues(bool))); connect(m_optionsWidget->cbPalette, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotSetAddPalette(bool))); connect(m_optionsWidget->radius, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotChangeRadius(int))); KisResourceServerBase* srv = KisResourceServerRegistry::instance()->get("PaletteServer"); if (!srv) { return m_optionsWidget; } TQValueList palettes = srv->resources(); for(uint i = 0; i < palettes.count(); i++) { KisPalette* palette = dynamic_cast(*palettes.at(i)); if (palette) { m_optionsWidget->cmbPalette->insertItem(palette->name()); m_palettes.append(palette); } } connect(srv, TQT_SIGNAL(resourceAdded(KisResource*)), this, TQT_SLOT(slotAddPalette(KisResource*))); return m_optionsWidget; } TQWidget* KisToolColorPicker::optionWidget() { return m_optionsWidget; } void KisToolColorPicker::slotSetUpdateColor(bool state) { m_updateColor = state; } void KisToolColorPicker::slotSetNormaliseValues(bool state) { m_normaliseValues = state; displayPickedColor(); } void KisToolColorPicker::slotSetAddPalette(bool state) { m_addPalette = state; } void KisToolColorPicker::slotChangeRadius(int value) { m_radius = value; } void KisToolColorPicker::slotAddPalette(KisResource* resource) { KisPalette* palette = dynamic_cast(resource); if (palette) { m_optionsWidget-> cmbPalette->insertItem(palette->name()); m_palettes.append(palette); } }