]> git.sesse.net Git - kdenlive/blob - src/colorpickerwidget.cpp
Merge branch 'master' into next
[kdenlive] / src / colorpickerwidget.cpp
1 /***************************************************************************
2  *   Copyright (C) 2010 by Till Theato (root@ttill.de)                     *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
18  ***************************************************************************/
19
20
21 #include "colorpickerwidget.h"
22
23 #include <QMouseEvent>
24 #include <QHBoxLayout>
25 #include <QToolButton>
26 #include <QLabel>
27 #include <QSpinBox>
28 #include <QDesktopWidget>
29 #include <QFrame>
30
31 #include <KApplication>
32 #include <KIcon>
33 #include <KDebug>
34 #include <KLocalizedString>
35
36 #ifdef Q_WS_X11
37 #include <X11/Xutil.h>
38 #include <fixx11h.h>
39 #endif 
40
41
42 ColorPickerWidget::ColorPickerWidget(QWidget *parent) :
43         QWidget(parent),
44         m_filterActive(false)
45 {
46 #ifdef Q_WS_X11
47     m_image = NULL;
48 #endif
49
50     QHBoxLayout *layout = new QHBoxLayout(this);
51     layout->setContentsMargins(0, 0, 0, 0);
52
53     QToolButton *button = new QToolButton(this);
54     button->setIcon(KIcon("color-picker"));
55     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>");
56     button->setAutoRaise(true);
57     connect(button, SIGNAL(clicked()), this, SLOT(slotSetupEventFilter()));
58
59     layout->addWidget(button);
60     setFocusPolicy(Qt::StrongFocus);
61
62     m_grabRectFrame = new QFrame();
63     m_grabRectFrame->setFrameStyle(QFrame::Box | QFrame::Plain);
64     m_grabRectFrame->setWindowOpacity(0.5);
65     m_grabRectFrame->setWindowFlags(Qt::FramelessWindowHint);
66     m_grabRectFrame->hide();
67 }
68
69 ColorPickerWidget::~ColorPickerWidget()
70 {
71     delete m_grabRectFrame;
72     if (m_filterActive) removeEventFilter(this);
73 }
74
75 void ColorPickerWidget::slotGetAverageColor()
76 {
77     m_grabRect = m_grabRect.normalized();
78
79     int numPixel = m_grabRect.width() * m_grabRect.height();
80
81     int sumR = 0;
82     int sumG = 0;
83     int sumB = 0;
84
85     // only show message for larger rects because of the overhead displayMessage creates
86     if (numPixel > 40000)
87         emit displayMessage(i18n("Requesting color information..."), 0);
88
89     /*
90      Only getting the image once for the whole rect
91      results in a vast speed improvement.
92     */
93 #ifdef Q_WS_X11
94     Window root = RootWindow(QX11Info::display(), QX11Info::appScreen());
95     m_image = XGetImage(QX11Info::display(), root, m_grabRect.x(), m_grabRect.y(), m_grabRect.width(), m_grabRect.height(), -1, ZPixmap);
96 #else
97     QWidget *desktop = QApplication::desktop();
98     m_image = QPixmap::grabWindow(desktop->winId(), m_grabRect.x(), m_grabRect.y(), m_grabRect.width(), m_grabRect.height()).toImage();
99 #endif
100
101     for (int x = 0; x < m_grabRect.width(); ++x) {
102         for (int y = 0; y < m_grabRect.height(); ++y) {
103             QColor color = grabColor(QPoint(x, y), false);
104             sumR += color.red();
105             sumG += color.green();
106             sumB += color.blue();
107         }
108
109         // Warning: slows things down, so don't do it for every pixel (the inner for loop)
110         if (numPixel > 40000)
111             emit displayMessage(i18n("Requesting color information..."), (int)(x * m_grabRect.height() / (qreal)numPixel * 100));
112     }
113
114 #ifdef Q_WS_X11
115     XDestroyImage(m_image);
116     m_image = NULL;
117 #endif
118
119     if (numPixel > 40000)
120         emit displayMessage(i18n("Calculated average color for rectangle."), -1);
121
122     emit colorPicked(QColor(sumR / numPixel, sumG / numPixel, sumB / numPixel));
123 }
124
125 void ColorPickerWidget::mousePressEvent(QMouseEvent* event)
126 {
127     if (event->button() != Qt::LeftButton) {
128         closeEventFilter();
129         event->accept();
130         return;
131     }
132
133     if (m_filterActive) {
134         m_grabRect = QRect(event->globalPos(), QSize(0, 0));
135         m_grabRectFrame->setGeometry(m_grabRect);
136         m_grabRectFrame->show();
137     }
138
139     QWidget::mousePressEvent(event);
140 }
141
142 void ColorPickerWidget::mouseReleaseEvent(QMouseEvent *event)
143 {
144     if (m_filterActive) {
145         m_grabRectFrame->hide();
146
147         closeEventFilter();
148
149         m_grabRect.setWidth(event->globalX() - m_grabRect.x());
150         m_grabRect.setHeight(event->globalY() - m_grabRect.y());
151
152         if (m_grabRect.width() * m_grabRect.height() == 0) {
153             emit colorPicked(grabColor(event->globalPos()));
154         } else {
155             // delay because m_grabRectFrame does not hide immediately
156             QTimer::singleShot(50, this, SLOT(slotGetAverageColor()));
157         }
158
159         return;
160     }
161     QWidget::mouseReleaseEvent(event);
162 }
163
164 void ColorPickerWidget::mouseMoveEvent(QMouseEvent* event)
165 {
166     if (m_filterActive) {
167         m_grabRect.setWidth(event->globalX() - m_grabRect.x());
168         m_grabRect.setHeight(event->globalY() - m_grabRect.y());
169         m_grabRectFrame->setGeometry(m_grabRect.normalized());
170     }
171     QWidget::mouseMoveEvent(event);
172 }
173
174 void ColorPickerWidget::slotSetupEventFilter()
175 {
176     m_filterActive = true;
177     setFocus();
178     installEventFilter(this);
179     grabMouse(QCursor(KIcon("color-picker").pixmap(22, 22), 0, 21));
180     grabKeyboard();
181 }
182
183 void ColorPickerWidget::closeEventFilter()
184 {
185     m_filterActive = false;
186     releaseMouse();
187     releaseKeyboard();
188     removeEventFilter(this);
189 }
190
191 bool ColorPickerWidget::eventFilter(QObject *object, QEvent *event)
192 {
193     // Close color picker on any key press
194     if (event->type() == QEvent::KeyPress || event->type() == QEvent::ShortcutOverride) {
195         closeEventFilter();
196         event->setAccepted(true);
197         return true;
198     }
199     return QObject::eventFilter(object, event);
200
201 }
202
203 QColor ColorPickerWidget::grabColor(const QPoint &p, bool destroyImage)
204 {
205 #ifdef Q_WS_X11
206     /*
207      we use the X11 API directly in this case as we are not getting back a valid
208      return from QPixmap::grabWindow in the case where the application is using
209      an argb visual
210     */
211     if( !qApp->desktop()->geometry().contains( p ))
212         return QColor();
213     unsigned long xpixel;
214     if (m_image == NULL) {
215         Window root = RootWindow(QX11Info::display(), QX11Info::appScreen());
216         m_image = XGetImage(QX11Info::display(), root, p.x(), p.y(), 1, 1, -1, ZPixmap);
217         xpixel = XGetPixel(m_image, 0, 0);
218     } else {
219         xpixel = XGetPixel(m_image, p.x(), p.y());
220     }
221     if (destroyImage) {
222         XDestroyImage(m_image);
223         m_image = 0;
224     }
225     XColor xcol;
226     xcol.pixel = xpixel;
227     xcol.flags = DoRed | DoGreen | DoBlue;
228     XQueryColor(QX11Info::display(),
229                 DefaultColormap(QX11Info::display(), QX11Info::appScreen()),
230                 &xcol);
231     return QColor::fromRgbF(xcol.red / 65535.0, xcol.green / 65535.0, xcol.blue / 65535.0);
232 #else
233     if (m_image.isNull()) {
234         QWidget *desktop = QApplication::desktop();
235         QPixmap pm = QPixmap::grabWindow(desktop->winId(), p.x(), p.y(), 1, 1);
236         QImage i = pm.toImage();
237         return i.pixel(0, 0);
238     } else {
239         return m_image.pixel(p.x(), p.y());
240     }
241 #endif
242 }
243
244 #include "colorpickerwidget.moc"