X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fcolorpickerwidget.cpp;h=acd1d26982a8be5378c146f2395f5582abaa6b66;hb=74060c1cfa66f939caf045b5a92c608acdae3b81;hp=a2a54e87edfb42e6cccfad84491aaad0c8ed2812;hpb=b7e8d432838c4f60032f7dfbb27b1122c5d42655;p=kdenlive diff --git a/src/colorpickerwidget.cpp b/src/colorpickerwidget.cpp index a2a54e87..acd1d269 100644 --- a/src/colorpickerwidget.cpp +++ b/src/colorpickerwidget.cpp @@ -21,16 +21,19 @@ #include "colorpickerwidget.h" #include +#include #include +#include +#include +#include #include -#include #include #include -#include #ifdef Q_WS_X11 -#include +#include +#include class KCDPickerFilter: public QWidget { @@ -56,12 +59,26 @@ ColorPickerWidget::ColorPickerWidget(QWidget *parent) : { #ifdef Q_WS_X11 m_filter = 0; + m_image = NULL; #endif + QHBoxLayout *layout = new QHBoxLayout(this); + QPushButton *button = new QPushButton(this); button->setIcon(KIcon("color-picker")); button->setToolTip(i18n("Pick a color on the screen")); connect(button, SIGNAL(clicked()), this, SLOT(slotSetupEventFilter())); + + m_size = new QSpinBox(this); + m_size->setMinimum(1); + // Use qMin here, as we might run into troubles with the cursor otherwise. + m_size->setMaximum(qMin(qApp->desktop()->geometry().width(), qApp->desktop()->geometry().height())); + m_size->setValue(1); + + layout->addWidget(button); + layout->addStretch(1); + layout->addWidget(new QLabel(i18n("Width of square to pick color from:"))); + layout->addWidget(m_size); } ColorPickerWidget::~ColorPickerWidget() @@ -72,6 +89,67 @@ ColorPickerWidget::~ColorPickerWidget() #endif } +QColor ColorPickerWidget::averagePickedColor(const QPoint pos) +{ + int size = m_size->value(); + int x0 = qMax(0, pos.x() - size / 2); + int y0 = qMax(0, pos.y() - size / 2); + int x1 = qMin(qApp->desktop()->geometry().width(), pos.x() + size / 2); + int y1 = qMin(qApp->desktop()->geometry().height(), pos.y() + size / 2); + + // take care of loss when dividing odd sizes + if (size % 2 != 0) { + if (x1 < qApp->desktop()->geometry().width()) ++x1; + if (y1 < qApp->desktop()->geometry().height()) ++y1; + } + + int numPixel = (x1 - x0) * (y1 - y0); + + int sumR = 0; + int sumG = 0; + int sumB = 0; + + // only show message for size > 200 because for smaller values it slows down to much + if (size > 200) + emit displayMessage(i18n("Requesting color information..."), 0); + + /* + Only getting the image once for the whole rect + results in a vast speed improvement. + */ +#ifdef Q_WS_X11 + Window root = RootWindow(QX11Info::display(), QX11Info::appScreen()); + m_image = XGetImage(QX11Info::display(), root, x0, y0, x1 - x0, y1 - y0, -1, ZPixmap); +#else + QWidget *desktop = QApplication::desktop(); + m_image = QPixmap::grabWindow(desktop->winId(), x0, y0, x1 - x0, y1 - y0).toImage(); +#endif + + for (int i = x0; i < x1; ++i) { + for (int j = y0; j < y1; ++j) { + QColor color; + color = grabColor(QPoint(i - x0, j - y0), false); + sumR += color.red(); + sumG += color.green(); + sumB += color.blue(); + } + + // Warning: slows things down, so don't do it for every pixel (the inner for loop) + if (size > 200) + emit displayMessage(i18n("Requesting color information..."), (int)(((i - x0) * (y1 - y0)) / (qreal)numPixel * 100)); + } + +#ifdef Q_WS_X11 + XDestroyImage(m_image); + m_image = NULL; +#endif + + if (size > 200) + emit displayMessage(i18n("Calculated average color for rectangle."), -1); + + return QColor(sumR / numPixel, sumG / numPixel, sumB / numPixel); +} + void ColorPickerWidget::mousePressEvent(QMouseEvent* event) { if (event->button() != Qt::LeftButton) { @@ -86,9 +164,12 @@ void ColorPickerWidget::mouseReleaseEvent(QMouseEvent *event) { if (m_filterActive) { closeEventFilter(); - // does not work this way - //if (event->button() == Qt::LeftButton) - emit colorPicked(KColorDialog::grabColor(event->globalPos())); + + if (m_size->value() == 1) + emit colorPicked(grabColor(event->globalPos())); + else + emit colorPicked(averagePickedColor(event->globalPos())); + return; } QWidget::mouseReleaseEvent(event); @@ -113,7 +194,10 @@ void ColorPickerWidget::slotSetupEventFilter() m_filter = new KCDPickerFilter(this); kapp->installX11EventFilter(m_filter); #endif - grabMouse(Qt::CrossCursor); + if (m_size->value() < 10) + grabMouse(QCursor(KIcon("color-picker").pixmap(22, 22), 0, 21)); + else + grabMouse(QCursor(KIcon("kdenlive-select-all").pixmap(m_size->value(), m_size->value()))); grabKeyboard(); } @@ -129,4 +213,45 @@ void ColorPickerWidget::closeEventFilter() releaseKeyboard(); } +QColor ColorPickerWidget::grabColor(const QPoint &p, bool destroyImage) +{ +#ifdef Q_WS_X11 + /* + we use the X11 API directly in this case as we are not getting back a valid + return from QPixmap::grabWindow in the case where the application is using + an argb visual + */ + if( !qApp->desktop()->geometry().contains( p )) + return QColor(); + unsigned long xpixel; + if (m_image == NULL) { + Window root = RootWindow(QX11Info::display(), QX11Info::appScreen()); + m_image = XGetImage(QX11Info::display(), root, p.x(), p.y(), 1, 1, -1, ZPixmap); + xpixel = XGetPixel(m_image, 0, 0); + } else { + xpixel = XGetPixel(m_image, p.x(), p.y()); + } + if (destroyImage) { + XDestroyImage(m_image); + m_image = 0; + } + XColor xcol; + xcol.pixel = xpixel; + xcol.flags = DoRed | DoGreen | DoBlue; + XQueryColor(QX11Info::display(), + DefaultColormap(QX11Info::display(), QX11Info::appScreen()), + &xcol); + return QColor::fromRgbF(xcol.red / 65535.0, xcol.green / 65535.0, xcol.blue / 65535.0); +#else + if (m_image.isNull()) { + QWidget *desktop = QApplication::desktop(); + QPixmap pm = QPixmap::grabWindow(desktop->winId(), p.x(), p.y(), 1, 1); + QImage i = pm.toImage(); + return i.pixel(0, 0); + } else { + return m_image.pixel(p.x(), p.y()); + } +#endif +} + #include "colorpickerwidget.moc"