]> git.sesse.net Git - kdenlive/blobdiff - src/colorpickerwidget.cpp
Fix playing rendered file by double click in job queue list
[kdenlive] / src / colorpickerwidget.cpp
index 8b7bc2d4bf2c36e8b9066714c52ea1affbb1d304..acd1d26982a8be5378c146f2395f5582abaa6b66 100644 (file)
 #include "colorpickerwidget.h"
 
 #include <QMouseEvent>
+#include <QHBoxLayout>
 #include <QPushButton>
+#include <QLabel>
+#include <QSpinBox>
+#include <QDesktopWidget>
 
 #include <KApplication>
-#include <KColorDialog>
 #include <KIcon>
 #include <KLocalizedString>
-#include <KDebug>
 
 #ifdef Q_WS_X11
-#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <fixx11h.h>
 
 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() - QPoint(11, -10)));
+
+        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(QCursor(KIcon("color-picker").pixmap(22, 22)));
+    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"