1 /*
2  *  Copyright (c) 2007 Cyrille Berger <cberger@cberger.net>
3  *  Copyright (c) 2008 Boudewijn Rempt <boud@valdyas.org>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include "kis_popup_button.h"
22 
23 #include <QPointer>
24 #include <QApplication>
25 #include <QDesktopWidget>
26 #include <QFrame>
27 #include <QHBoxLayout>
28 #include <QStyleOption>
29 #include <QStylePainter>
30 
31 #include "kis_global.h"
32 #include <kis_debug.h>
33 
34 struct KisPopupButton::Private {
PrivateKisPopupButton::Private35     Private()
36         : frameLayout(0)
37     {}
38     QScopedPointer<QFrame> frame;
39     QPointer<QWidget> popupWidget;
40     QPointer<QHBoxLayout> frameLayout;
41 };
42 
KisPopupButton(QWidget * parent)43 KisPopupButton::KisPopupButton(QWidget* parent)
44         : QPushButton(parent)
45         , m_d(new Private)
46 {
47     setObjectName("KisPopupButton");
48     connect(this, SIGNAL(released()), SLOT(showPopupWidget()));
49 }
50 
~KisPopupButton()51 KisPopupButton::~KisPopupButton()
52 {
53     delete m_d;
54 }
55 
setAlwaysVisible(bool v)56 void KisPopupButton::setAlwaysVisible(bool v)
57 {
58     if (v) {
59         m_d->frame->setFrameStyle(Qt::SubWindow);
60         showPopupWidget();
61     } else {
62         m_d->frame->setFrameStyle(Qt::Popup);
63     }
64 }
65 
setPopupWidget(QWidget * widget)66 void KisPopupButton::setPopupWidget(QWidget* widget)
67 {
68     if (widget) {
69         /**
70          * Set parent explicitly to null to avoid propagation of the
71          * ignored events (specifically, QEvent::ShortcutOverride) to
72          * the view object. This avoids starting global actions while
73          * the PopUp is active. See bug 329842.
74          */
75         m_d->frame.reset(new QFrame(0));
76         m_d->frame->setObjectName("popup frame");
77         m_d->frame->setFrameStyle(QFrame::Box | QFrame::Plain);
78         m_d->frame->setWindowFlags(Qt::Popup);
79         m_d->frameLayout = new QHBoxLayout(m_d->frame.data());
80         m_d->frameLayout->setMargin(0);
81         m_d->frameLayout->setSizeConstraint(QLayout::SetFixedSize);
82         m_d->frame->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
83         m_d->popupWidget = widget;
84         m_d->popupWidget->setParent(m_d->frame.data());
85         m_d->frameLayout->addWidget(m_d->popupWidget);
86     }
87 }
88 
setPopupWidgetWidth(int w)89 void KisPopupButton::setPopupWidgetWidth(int w)
90 {
91     m_d->frame->resize(w, m_d->frame->height());
92 }
93 
showPopupWidget()94 void KisPopupButton::showPopupWidget()
95 {
96     if (m_d->popupWidget && !m_d->frame->isVisible()) {
97         m_d->frame->raise();
98         m_d->frame->show();
99         m_d->frame->activateWindow();
100         adjustPosition();
101     }
102     else {
103         hidePopupWidget();
104     }
105 }
106 
hidePopupWidget()107 void KisPopupButton::hidePopupWidget()
108 {
109     if (m_d->popupWidget) {
110         m_d->frame->setVisible(false);
111     }
112 }
113 
paintEvent(QPaintEvent * event)114 void KisPopupButton::paintEvent ( QPaintEvent * event  )
115 {
116     QPushButton::paintEvent(event);
117     paintPopupArrow();
118 }
119 
paintPopupArrow()120 void KisPopupButton::paintPopupArrow()
121 {
122     QStylePainter p(this);
123     QStyleOption option;
124     option.rect = QRect(rect().right() - 15, rect().bottom() - 15, 14, 14);
125     option.palette = palette();
126     option.palette.setBrush(QPalette::ButtonText, Qt::black); // Force color to black
127     option.state = QStyle::State_Enabled;
128     p.setBrush(Qt::black); // work around some theme that don't use QPalette::ButtonText like they  should, but instead the QPainter brushes and pen
129     p.setPen(Qt::black);
130     p.drawPrimitive(QStyle::PE_IndicatorArrowDown, option);
131 }
132 
adjustPosition()133 void KisPopupButton::adjustPosition()
134 {
135     QSize popSize = m_d->popupWidget->size();
136     QRect popupRect(this->mapToGlobal(QPoint(0, this->size().height())), popSize);
137 
138     // Get the available geometry of the screen which contains this KisPopupButton
139     QDesktopWidget* desktopWidget = QApplication::desktop();
140     QRect screenRect = desktopWidget->availableGeometry(this);
141     popupRect = kisEnsureInRect(popupRect, screenRect);
142 
143     m_d->frame->setGeometry(popupRect);
144 }
145 
146