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