1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <qapplication.h>
43 #include <qwidget.h>
44 #include <qpainter.h>
45 #include <qdrawutil.h>
46 #include "qdecorationstyled_qws.h"
47 #include "qstyle.h"
48 #include "qstyleoption.h"
49 #include "qpaintengine.h"
50 
51 QT_BEGIN_NAMESPACE
52 
53 #if !defined(QT_NO_QWS_DECORATION_STYLED) || defined(QT_PLUGIN)
54 
QDecorationStyled()55 QDecorationStyled::QDecorationStyled()
56     : QDecorationDefault()
57 {
58 }
59 
~QDecorationStyled()60 QDecorationStyled::~QDecorationStyled()
61 {
62 }
63 
titleBarHeight(const QWidget * widget)64 int QDecorationStyled::titleBarHeight(const QWidget *widget)
65 {
66     QStyleOptionTitleBar opt;
67     opt.subControls = QStyle::SC_TitleBarLabel
68                       | QStyle::SC_TitleBarSysMenu
69                       | QStyle::SC_TitleBarNormalButton
70                       | QStyle::SC_TitleBarContextHelpButton
71                       | QStyle::SC_TitleBarMinButton
72                       | QStyle::SC_TitleBarMaxButton
73                       | QStyle::SC_TitleBarCloseButton;
74     opt.titleBarFlags = widget->windowFlags();
75     opt.direction = QApplication::layoutDirection();
76     opt.text = windowTitleFor(widget);
77     opt.icon = widget->windowIcon();
78     opt.rect = widget->rect();
79 
80     QStyle *style = QApplication::style();
81     if (!style)
82         return 18;
83 
84     return style->pixelMetric(QStyle::PM_TitleBarHeight, &opt, 0);
85 }
86 
paint(QPainter * painter,const QWidget * widget,int decorationRegion,DecorationState state)87 bool QDecorationStyled::paint(QPainter *painter, const QWidget *widget, int decorationRegion,
88                             DecorationState state)
89 {
90     if (decorationRegion == None)
91         return false;
92 
93     bool isActive = (widget == qApp->activeWindow());
94     QPalette pal = qApp->palette();
95     //ideally, the difference between Active and Inactive should be enough, so we shouldn't need to test this
96     if (!isActive) {
97         //pal.setCurrentColorGroup(QPalette::Disabled); //Can't do this either, because of palette limitations
98         //copied from Q3TitleBar:
99 	pal.setColor(QPalette::Inactive, QPalette::Highlight,
100 		     pal.color(QPalette::Inactive, QPalette::Dark));
101         pal.setColor(QPalette::Inactive, QPalette::Base,
102                       pal.color(QPalette::Inactive, QPalette::Dark));
103         pal.setColor(QPalette::Inactive, QPalette::HighlightedText,
104                       pal.color(QPalette::Inactive, QPalette::Window));
105     }
106 
107     Qt::WindowFlags flags = widget->windowFlags();
108     bool hasBorder = !widget->isMaximized();
109     bool hasTitle = flags & Qt::WindowTitleHint;
110     bool hasSysMenu = flags & Qt::WindowSystemMenuHint;
111     bool hasContextHelp = flags & Qt::WindowContextHelpButtonHint;
112     bool hasMinimize = flags & Qt::WindowMinimizeButtonHint;
113     bool hasMaximize = flags & Qt::WindowMaximizeButtonHint;
114 
115     bool paintAll = (DecorationRegion(decorationRegion) == All);
116     bool handled = false;
117 
118     QStyle *style = QApplication::style();
119 
120     // In the case of a borderless title bar, the title bar must be expanded one
121     // borderWidth to the left, right and up.
122     bool noTitleBorder = style->styleHint(QStyle::SH_TitleBar_NoBorder, 0, widget);
123     int borderWidth = style->pixelMetric(QStyle::PM_MDIFrameWidth, 0, 0);
124     int titleHeight = titleBarHeight(widget) + (noTitleBorder ? borderWidth : 0);
125     int titleExtra = noTitleBorder ? borderWidth : 0;
126 
127     if ((paintAll || decorationRegion & Borders) && state == Normal && hasBorder) {
128         QRegion newClip = painter->clipRegion();
129         if (hasTitle) { // reduce flicker
130             QRect rect(widget->rect());
131             QRect r(rect.left() - titleExtra, rect.top() - titleHeight,
132                     rect.width() + 2 * titleExtra, titleHeight);
133             newClip -= r;
134         }
135         if (!newClip.isEmpty()) {
136             QRect br = QDecoration::region(widget).boundingRect();
137             painter->save();
138             painter->setClipRegion(newClip);
139 
140             QStyleOptionFrame opt;
141             opt.palette = pal;
142             opt.rect = br;
143             opt.lineWidth = borderWidth;
144 
145             if (isActive)
146                 opt.state |= QStyle::State_Active;
147             bool porterDuff = painter->paintEngine()->hasFeature(QPaintEngine::PorterDuff);
148             if (porterDuff)
149                 painter->setCompositionMode(QPainter::CompositionMode_Source);
150             painter->fillRect(br, pal.window());
151             if (porterDuff)
152                 painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
153             style->drawPrimitive(QStyle::PE_FrameWindow, &opt, painter, 0);
154             painter->restore();
155 
156             decorationRegion &= (~Borders);
157             handled |= true;
158         }
159     }
160 
161     if (hasTitle) {
162         painter->save();
163 
164         QStyleOptionTitleBar opt;
165         opt.subControls = (decorationRegion & Title
166                               ? QStyle::SC_TitleBarLabel : QStyle::SubControl(0))
167                           | (decorationRegion & Menu
168                               ? QStyle::SC_TitleBarSysMenu : QStyle::SubControl(0))
169                           | (decorationRegion & Help
170                               ? QStyle::SC_TitleBarContextHelpButton : QStyle::SubControl(0))
171                           | (decorationRegion & Minimize
172                               ? QStyle::SC_TitleBarMinButton : QStyle::SubControl(0))
173                           | (decorationRegion & Maximize
174                               ? QStyle::SC_TitleBarMaxButton : QStyle::SubControl(0))
175                           | (decorationRegion & (Minimize | Maximize)
176                               ? QStyle::SC_TitleBarNormalButton : QStyle::SubControl(0))
177                           | (decorationRegion & Close
178                               ? QStyle::SC_TitleBarCloseButton : QStyle::SubControl(0));
179         opt.titleBarFlags = widget->windowFlags();
180         opt.titleBarState = widget->windowState();
181         if (isActive)
182             opt.titleBarState |= QStyle::State_Active;
183         opt.text = windowTitleFor(widget);
184         opt.icon = widget->windowIcon();
185         opt.palette = pal;
186         opt.rect = QRect(widget->rect().x() - titleExtra, -titleHeight,
187                          widget->rect().width() + 2 * titleExtra, titleHeight);
188 
189         if (paintAll) {
190             painter->setClipRegion(opt.rect);
191         } else {
192             const QRect widgetRect = widget->rect();
193             QRegion newClip = opt.rect;
194             if (!(decorationRegion & Menu) && hasSysMenu)
195                 newClip -= region(widget, widgetRect, Menu);
196             if (!(decorationRegion & Title) && hasTitle)
197                 newClip -= region(widget, widgetRect, Title);
198             if (!(decorationRegion & Help) && hasContextHelp)
199                 newClip -= region(widget, widgetRect, Help);
200             if (!(decorationRegion & Minimize) && hasMinimize)
201                 newClip -= region(widget, widgetRect, Minimize);
202             if (!(decorationRegion & Maximize) && hasMaximize)
203                 newClip -= region(widget, widgetRect, Maximize);
204             if (!(decorationRegion & (Minimize | Maximize)) && (hasMaximize | hasMinimize))
205                 newClip -= region(widget, widgetRect, Normal);
206             if (!(decorationRegion & Close))
207                 newClip -= region(widget, widgetRect, Close);
208             painter->setClipRegion(newClip);
209         }
210 
211         if (state == Pressed)
212             opt.activeSubControls = opt.subControls;
213 
214         style->drawComplexControl(QStyle::CC_TitleBar, &opt, painter, 0);
215         painter->restore();
216 
217         decorationRegion &= ~(Title | Menu | Help | Normalize | Minimize | Maximize | Close);
218         handled |= true;
219     }
220 
221     return handled;
222 }
223 
region(const QWidget * widget,const QRect & rect,int decorationRegion)224 QRegion QDecorationStyled::region(const QWidget *widget, const QRect &rect, int decorationRegion)
225 {
226     QStyle *style = QApplication::style();
227 
228     // In the case of a borderless title bar, the title bar must be expanded one
229     // borderWidth to the left, right and up.
230     bool noTitleBorder = style->styleHint(QStyle::SH_TitleBar_NoBorder, 0, widget);
231     int borderWidth = style->pixelMetric(QStyle::PM_MDIFrameWidth, 0, 0);
232     int titleHeight = titleBarHeight(widget) + (noTitleBorder ? borderWidth : 0);
233     int titleExtra = noTitleBorder ? borderWidth : 0;
234 
235     QRect inside = QRect(rect.x() - titleExtra, rect.top() - titleHeight,
236                          rect.width() + 2 * titleExtra, titleHeight);
237 
238     Qt::WindowFlags flags = widget->windowFlags();
239     bool hasSysMenu = flags & Qt::WindowSystemMenuHint;
240     bool hasContextHelp = flags & Qt::WindowContextHelpButtonHint;
241     bool hasMinimize = flags & Qt::WindowMinimizeButtonHint;
242     bool hasMaximize = flags & Qt::WindowMaximizeButtonHint;
243 
244     QStyleOptionTitleBar opt;
245     opt.subControls = QStyle::SC_TitleBarLabel
246                       | QStyle::SC_TitleBarSysMenu
247                       | QStyle::SC_TitleBarNormalButton
248                       | QStyle::SC_TitleBarMinButton
249                       | QStyle::SC_TitleBarMaxButton
250                       | QStyle::SC_TitleBarCloseButton;
251     opt.titleBarFlags = widget->windowFlags();
252     opt.direction = QApplication::layoutDirection();
253     opt.text = windowTitleFor(widget);
254     opt.icon = widget->windowIcon();
255     opt.rect = inside;
256 
257     QRegion region;
258     switch (decorationRegion) {
259     case Title:
260         region = style->subControlRect(QStyle::CC_TitleBar, &opt,
261                                        QStyle::SC_TitleBarLabel, 0);
262         break;
263     case Menu:
264         if (hasSysMenu)
265             region = style->subControlRect(QStyle::CC_TitleBar, &opt,
266                                            QStyle::SC_TitleBarSysMenu, 0);
267         break;
268     case Help:
269         if (hasContextHelp)
270             region = style->subControlRect(QStyle::CC_TitleBar, &opt,
271                                            QStyle::SC_TitleBarContextHelpButton,
272                                            0);
273         break;
274     case Normalize:
275         if (hasMaximize | hasMinimize)
276             region = style->subControlRect(QStyle::CC_TitleBar, &opt,
277                                            QStyle::SC_TitleBarNormalButton,
278                                            0);
279         break;
280     case Minimize:
281         if (hasMinimize)
282             region = style->subControlRect(QStyle::CC_TitleBar, &opt,
283                                            QStyle::SC_TitleBarMinButton,
284                                            0);
285         break;
286     case Maximize:
287         if (hasMaximize)
288             region = style->subControlRect(QStyle::CC_TitleBar, &opt,
289                                            QStyle::SC_TitleBarMaxButton,
290                                            0);
291         break;
292     case Close:
293         region = style->subControlRect(QStyle::CC_TitleBar, &opt,
294                                        QStyle::SC_TitleBarCloseButton, 0);
295         break;
296 
297     default:
298         region = QDecorationDefault::region(widget, rect, decorationRegion);
299     }
300 
301     opt.rect = QRect(rect.x() - titleExtra, rect.top() - titleHeight,
302                          rect.width() + 2 * titleExtra,
303                          rect.height() + titleHeight + titleExtra);
304 
305     QStyleHintReturnMask mask;
306     style->styleHint(QStyle::SH_WindowFrame_Mask, &opt, 0, &mask);
307 
308     return (mask.region.isEmpty() ? region : (region & mask.region));
309 }
310 
311 #endif // QT_NO_QWS_DECORATION_STYLED
312 
313 QT_END_NAMESPACE
314