X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fcolorpickerwidget.cpp;h=a9b8ce860973cb5aa22c3ad999bbf04efcb15664;hb=d679fbf19a2511b181570418dc7fa7c815728bcb;hp=a6bafd9387b852288653f32bd3120e93fb73da52;hpb=982c0be69cef7f936a6a6899c681f4ddeb389f29;p=kdenlive diff --git a/src/colorpickerwidget.cpp b/src/colorpickerwidget.cpp index a6bafd93..a9b8ce86 100644 --- a/src/colorpickerwidget.cpp +++ b/src/colorpickerwidget.cpp @@ -22,35 +22,38 @@ #include #include -#include +#include #include #include #include +#include #include #include +#include #include #ifdef Q_WS_X11 #include #include +#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,87 +61,98 @@ ColorPickerWidget::ColorPickerWidget(QWidget *parent) : m_filterActive(false) { #ifdef Q_WS_X11 - m_filter = 0; + m_image = NULL; #endif - m_image = 0; 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("

" + 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.") + "

"); + button->setAutoRaise(true); 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); + 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 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); + m_image = XGetImage(QX11Info::display(), root, m_grabRect.x(), m_grabRect.y(), m_grabRect.width(), m_grabRect.height(), -1, ZPixmap); #else QWidget *desktop = QApplication::desktop(); - m_image = QPixmap::grabWindow(desktop->winId(), x0, y0, x1 - x0, y1 - y0).toImage(); + m_image = QPixmap::grabWindow(desktop->winId(), m_grabRect.x(), m_grabRect.y(), m_grabRect.width(), m_grabRect.height()).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); + 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 = NULL; #endif - m_image = 0; - 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); } @@ -147,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() < 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()))); + 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) @@ -206,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); @@ -225,7 +249,7 @@ 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 - if (m_image == 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();