|
|
|
/*
|
|
|
|
* Copyright (c) 1999 Matthias Elter <me@kde.org>
|
|
|
|
* Copyright (c) 2002 Patrick Julien <freak@codepimps.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 <string.h>
|
|
|
|
|
|
|
|
#include <tqpoint.h>
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqcheckbox.h>
|
|
|
|
#include <tqcombobox.h>
|
|
|
|
#include <tqlistview.h>
|
|
|
|
#include <tqspinbox.h>
|
|
|
|
|
|
|
|
#include <kaction.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <tqcolor.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
|
|
|
|
#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<const TQ_UINT8**>(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<KisChannelInfo *> 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(KActionCollection *collection)
|
|
|
|
{
|
|
|
|
m_action = static_cast<KRadioAction *>(collection->action(name()));
|
|
|
|
|
|
|
|
if (m_action == 0) {
|
|
|
|
m_action = new KRadioAction(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<KisResource*> palettes = srv->resources();
|
|
|
|
|
|
|
|
for(uint i = 0; i < palettes.count(); i++) {
|
|
|
|
KisPalette* palette = dynamic_cast<KisPalette*>(*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<KisPalette*>(resource);
|
|
|
|
if (palette) {
|
|
|
|
m_optionsWidget-> cmbPalette->insertItem(palette->name());
|
|
|
|
m_palettes.append(palette);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|