]> git.sesse.net Git - kdenlive/blobdiff - src/colorpickerwidget.cpp
Const'ref
[kdenlive] / src / colorpickerwidget.cpp
index 0c971ef16a9948e62922c92e8e6c55cd5821e612..a9b8ce860973cb5aa22c3ad999bbf04efcb15664 100644 (file)
 
 #include <QMouseEvent>
 #include <QHBoxLayout>
-#include <QPushButton>
+#include <QToolButton>
 #include <QLabel>
 #include <QSpinBox>
 #include <QDesktopWidget>
+#include <QFrame>
 
 #include <KApplication>
 #include <KIcon>
+#include <KDebug>
 #include <KLocalizedString>
 
 #ifdef Q_WS_X11
 #include <X11/Xutil.h>
 #include <fixx11h.h>
+#endif 
 
-class KCDPickerFilter: public QWidget
+MyFrame::MyFrame(QWidget* parent) :
+    QFrame(parent)
 {
-public:
-    KCDPickerFilter(QWidget* parent): QWidget(parent) {}
-
-    virtual bool x11Event(XEvent* event) {
-        if (event->type == ButtonRelease) {
-            QMouseEvent e(QEvent::MouseButtonRelease, QPoint(),
-            QPoint(event->xmotion.x_root, event->xmotion.y_root) , Qt::NoButton, Qt::NoButton, Qt::NoModifier);
-            QApplication::sendEvent(parentWidget(), &e);
-            return true;
-        }
-        return false;
-    }
-};
-#endif 
+    setFrameStyle(QFrame::Box | QFrame::Plain);
+    setWindowOpacity(0.5);
+    setWindowFlags(Qt::FramelessWindowHint);
+}
+
+// virtual
+void MyFrame::hideEvent ( QHideEvent * event )
+{
+    QFrame::hideEvent(event);
+    // We need a timer here since hiding the frame will trigger a monitor refresh timer that will
+    // repaint the monitor after 70 ms.
+    QTimer::singleShot(250, this, SIGNAL(getColor()));
+}
 
 
 ColorPickerWidget::ColorPickerWidget(QWidget *parent) :
@@ -58,88 +61,98 @@ ColorPickerWidget::ColorPickerWidget(QWidget *parent) :
         m_filterActive(false)
 {
 #ifdef Q_WS_X11
-    m_filter = 0;
-    m_image = 0;
+    m_image = NULL;
 #endif
 
     QHBoxLayout *layout = new QHBoxLayout(this);
+    layout->setContentsMargins(0, 0, 0, 0);
 
-    QPushButton *button = new QPushButton(this);
+    QToolButton *button = new QToolButton(this);
     button->setIcon(KIcon("color-picker"));
-    button->setToolTip(i18n("Pick a color on the screen"));
+    button->setToolTip("<p>" + i18n("Pick a color on the screen. By pressing the mouse button and then moving your mouse you can select a section of the screen from which to get an average color.") + "</p>");
+    button->setAutoRaise(true);
     connect(button, SIGNAL(clicked()), this, SLOT(slotSetupEventFilter()));
 
-    m_size = new QSpinBox(this);
-    m_size->setMinimum(1);
-    // Use qMax here, to make it possible to get the average for the whole screen
-    m_size->setMaximum(qMax(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);
+    setFocusPolicy(Qt::StrongFocus);
+
+    m_grabRectFrame = new MyFrame();
+    m_grabRectFrame->hide();
 }
 
 ColorPickerWidget::~ColorPickerWidget()
 {
-#ifdef Q_WS_X11
-    if (m_filterActive && kapp)
-        kapp->removeX11EventFilter(m_filter);
-#endif
+    delete m_grabRectFrame;
+    if (m_filterActive) removeEventFilter(this);
 }
 
-QColor ColorPickerWidget::averagePickedColor(const QPoint pos)
+void ColorPickerWidget::slotGetAverageColor()
 {
-    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);
+    disconnect(m_grabRectFrame, SIGNAL(getColor()), this, SLOT(slotGetAverageColor()));
+    m_grabRect = m_grabRect.normalized();
+
+    int numPixel = m_grabRect.width() * m_grabRect.height();
 
     int sumR = 0;
     int sumG = 0;
     int sumB = 0;
 
+    // only show message for larger rects because of the overhead displayMessage creates
+    if (numPixel > 40000)
+        emit displayMessage(i18n("Requesting color information..."), 0);
+
     /*
-     Only getting the XImage once for the whole rect,
+     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);
-#endif
-
-    for (int i = x0; i < x1; ++i) {
-        for (int j = y0; j < y1; ++j) {
-            QColor color;
-#ifdef Q_WS_X11
-            color = grabColor(QPoint(i - x0, j - y0), false);
+    m_image = XGetImage(QX11Info::display(), root, m_grabRect.x(), m_grabRect.y(), m_grabRect.width(), m_grabRect.height(), -1, ZPixmap);
 #else
-            color = grabColor(QPoint(i, j));
+    QWidget *desktop = QApplication::desktop();
+    m_image = QPixmap::grabWindow(desktop->winId(), m_grabRect.x(), m_grabRect.y(), m_grabRect.width(), m_grabRect.height()).toImage();
 #endif
+
+    for (int x = 0; x < m_grabRect.width(); ++x) {
+        for (int y = 0; y < m_grabRect.height(); ++y) {
+            QColor color = grabColor(QPoint(x, y), 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 (numPixel > 40000)
+            emit displayMessage(i18n("Requesting color information..."), (int)(x * m_grabRect.height() / (qreal)numPixel * 100));
     }
 
 #ifdef Q_WS_X11
     XDestroyImage(m_image);
-    m_image = 0;
+    m_image = NULL;
 #endif
 
-    int numPixel = (x1 - x0) * (y1 - y0);
-    return QColor(sumR / numPixel, sumG / numPixel, sumB / numPixel);
+    if (numPixel > 40000)
+        emit displayMessage(i18n("Calculated average color for rectangle."), -1);
+
+    emit colorPicked(QColor(sumR / numPixel, sumG / numPixel, sumB / numPixel));
+    emit disableCurrentFilter(false);
 }
 
 void ColorPickerWidget::mousePressEvent(QMouseEvent* event)
 {
     if (event->button() != Qt::LeftButton) {
         closeEventFilter();
+       emit disableCurrentFilter(false);
         event->accept();
         return;
     }
+
+    if (m_filterActive) {
+        m_grabRect = QRect(event->globalPos(), QSize(0, 0));
+        m_grabRectFrame->setGeometry(m_grabRect);
+        m_grabRectFrame->show();
+    }
+
     QWidget::mousePressEvent(event);
 }
 
@@ -148,52 +161,62 @@ void ColorPickerWidget::mouseReleaseEvent(QMouseEvent *event)
     if (m_filterActive) {
         closeEventFilter();
 
-        if (m_size->value() == 1)
-            emit colorPicked(grabColor(event->globalPos()));
-        else
-            emit colorPicked(averagePickedColor(event->globalPos()));
+        m_grabRect.setWidth(event->globalX() - m_grabRect.x());
+        m_grabRect.setHeight(event->globalY() - m_grabRect.y());
 
+        if (m_grabRect.width() * m_grabRect.height() == 0) {
+           m_grabRectFrame->hide();
+            emit colorPicked(grabColor(event->globalPos()));
+           emit disableCurrentFilter(false);
+        } else {
+            // delay because m_grabRectFrame does not hide immediately
+            connect(m_grabRectFrame, SIGNAL(getColor()), this, SLOT(slotGetAverageColor()));
+           m_grabRectFrame->hide();
+        }
         return;
     }
     QWidget::mouseReleaseEvent(event);
 }
 
-void ColorPickerWidget::keyPressEvent(QKeyEvent *event)
+void ColorPickerWidget::mouseMoveEvent(QMouseEvent* event)
 {
     if (m_filterActive) {
-        // "special keys" (non letter, numeral) do not work, so close for every key
-        //if (event->key() == Qt::Key_Escape)
-        closeEventFilter();
-        event->accept();
-        return;
+        m_grabRect.setWidth(event->globalX() - m_grabRect.x());
+        m_grabRect.setHeight(event->globalY() - m_grabRect.y());
+        m_grabRectFrame->setGeometry(m_grabRect.normalized());
     }
-    QWidget::keyPressEvent(event);
+    QWidget::mouseMoveEvent(event);
 }
 
 void ColorPickerWidget::slotSetupEventFilter()
 {
+    emit disableCurrentFilter(true);
     m_filterActive = true;
-#ifdef Q_WS_X11
-    m_filter = new KCDPickerFilter(this);
-    kapp->installX11EventFilter(m_filter);
-#endif
-    if (m_size->value() == 1)
-        grabMouse(QCursor(KIcon("color-picker").pixmap(22, 22), 0, 21));
-    else
-        grabMouse(Qt::CrossCursor);
+    setFocus();
+    installEventFilter(this);
+    grabMouse(QCursor(KIcon("color-picker").pixmap(22, 22), 0, 21));
     grabKeyboard();
 }
 
 void ColorPickerWidget::closeEventFilter()
 {
     m_filterActive = false;
-#ifdef Q_WS_X11
-    kapp->removeX11EventFilter(m_filter);
-    delete m_filter;
-    m_filter = 0;
-#endif
     releaseMouse();
     releaseKeyboard();
+    removeEventFilter(this);
+}
+
+bool ColorPickerWidget::eventFilter(QObject *object, QEvent *event)
+{
+    // Close color picker on any key press
+    if (event->type() == QEvent::KeyPress || event->type() == QEvent::ShortcutOverride) {
+        closeEventFilter();
+       emit disableCurrentFilter(false);
+        event->setAccepted(true);
+        return true;
+    }
+    return QObject::eventFilter(object, event);
+
 }
 
 QColor ColorPickerWidget::grabColor(const QPoint &p, bool destroyImage)
@@ -207,7 +230,7 @@ QColor ColorPickerWidget::grabColor(const QPoint &p, bool destroyImage)
     if( !qApp->desktop()->geometry().contains( p ))
         return QColor();
     unsigned long xpixel;
-    if (m_image == 0) {
+    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);
@@ -226,10 +249,14 @@ QColor ColorPickerWidget::grabColor(const QPoint &p, bool destroyImage)
                 &xcol);
     return QColor::fromRgbF(xcol.red / 65535.0, xcol.green / 65535.0, xcol.blue / 65535.0);
 #else
-    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);
+    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
 }