1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the examples of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:BSD$ |
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 https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** BSD License Usage |
18 | ** Alternatively, you may use this file under the terms of the BSD license |
19 | ** as follows: |
20 | ** |
21 | ** "Redistribution and use in source and binary forms, with or without |
22 | ** modification, are permitted provided that the following conditions are |
23 | ** met: |
24 | ** * Redistributions of source code must retain the above copyright |
25 | ** notice, this list of conditions and the following disclaimer. |
26 | ** * Redistributions in binary form must reproduce the above copyright |
27 | ** notice, this list of conditions and the following disclaimer in |
28 | ** the documentation and/or other materials provided with the |
29 | ** distribution. |
30 | ** * Neither the name of The Qt Company Ltd nor the names of its |
31 | ** contributors may be used to endorse or promote products derived |
32 | ** from this software without specific prior written permission. |
33 | ** |
34 | ** |
35 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
36 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
37 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
38 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
39 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
40 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
41 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
42 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
43 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
44 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
45 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
46 | ** |
47 | ** $QT_END_LICENSE$ |
48 | ** |
49 | ****************************************************************************/ |
50 | |
51 | #include "norwegianwoodstyle.h" |
52 | |
53 | #include <QComboBox> |
54 | #include <QPainter> |
55 | #include <QPainterPath> |
56 | #include <QPushButton> |
57 | #include <QStyleFactory> |
58 | |
59 | NorwegianWoodStyle::NorwegianWoodStyle() : |
60 | QProxyStyle(QStyleFactory::create("windows" )) |
61 | { |
62 | setObjectName("NorwegianWood" ); |
63 | } |
64 | |
65 | //! [0] |
66 | QPalette NorwegianWoodStyle::standardPalette() const |
67 | { |
68 | if (!m_standardPalette.isBrushSet(cg: QPalette::Disabled, cr: QPalette::Mid)) { |
69 | QColor brown(212, 140, 95); |
70 | QColor beige(236, 182, 120); |
71 | QColor slightlyOpaqueBlack(0, 0, 0, 63); |
72 | |
73 | QImage backgroundImage(":/images/woodbackground.png" ); |
74 | QImage buttonImage(":/images/woodbutton.png" ); |
75 | QImage midImage = buttonImage.convertToFormat(f: QImage::Format_RGB32); |
76 | |
77 | QPainter painter; |
78 | painter.begin(&midImage); |
79 | painter.setPen(Qt::NoPen); |
80 | painter.fillRect(midImage.rect(), color: slightlyOpaqueBlack); |
81 | painter.end(); |
82 | //! [0] |
83 | |
84 | //! [1] |
85 | QPalette palette(brown); |
86 | |
87 | palette.setBrush(acr: QPalette::BrightText, abrush: Qt::white); |
88 | palette.setBrush(acr: QPalette::Base, abrush: beige); |
89 | palette.setBrush(acr: QPalette::Highlight, abrush: Qt::darkGreen); |
90 | setTexture(palette, role: QPalette::Button, image: buttonImage); |
91 | setTexture(palette, role: QPalette::Mid, image: midImage); |
92 | setTexture(palette, role: QPalette::Window, image: backgroundImage); |
93 | |
94 | QBrush brush = palette.window(); |
95 | brush.setColor(brush.color().darker()); |
96 | |
97 | palette.setBrush(cg: QPalette::Disabled, cr: QPalette::WindowText, brush); |
98 | palette.setBrush(cg: QPalette::Disabled, cr: QPalette::Text, brush); |
99 | palette.setBrush(cg: QPalette::Disabled, cr: QPalette::ButtonText, brush); |
100 | palette.setBrush(cg: QPalette::Disabled, cr: QPalette::Base, brush); |
101 | palette.setBrush(cg: QPalette::Disabled, cr: QPalette::Button, brush); |
102 | palette.setBrush(cg: QPalette::Disabled, cr: QPalette::Mid, brush); |
103 | |
104 | m_standardPalette = palette; |
105 | } |
106 | |
107 | return m_standardPalette; |
108 | } |
109 | //! [1] |
110 | |
111 | //! [3] |
112 | void NorwegianWoodStyle::polish(QWidget *widget) |
113 | //! [3] //! [4] |
114 | { |
115 | if (qobject_cast<QPushButton *>(object: widget) |
116 | || qobject_cast<QComboBox *>(object: widget)) |
117 | widget->setAttribute(Qt::WA_Hover, on: true); |
118 | } |
119 | //! [4] |
120 | |
121 | //! [5] |
122 | void NorwegianWoodStyle::unpolish(QWidget *widget) |
123 | //! [5] //! [6] |
124 | { |
125 | if (qobject_cast<QPushButton *>(object: widget) |
126 | || qobject_cast<QComboBox *>(object: widget)) |
127 | widget->setAttribute(Qt::WA_Hover, on: false); |
128 | } |
129 | //! [6] |
130 | |
131 | //! [7] |
132 | int NorwegianWoodStyle::pixelMetric(PixelMetric metric, |
133 | //! [7] //! [8] |
134 | const QStyleOption *option, |
135 | const QWidget *widget) const |
136 | { |
137 | switch (metric) { |
138 | case PM_ComboBoxFrameWidth: |
139 | return 8; |
140 | case PM_ScrollBarExtent: |
141 | return QProxyStyle::pixelMetric(metric, option, widget) + 4; |
142 | default: |
143 | return QProxyStyle::pixelMetric(metric, option, widget); |
144 | } |
145 | } |
146 | //! [8] |
147 | |
148 | //! [9] |
149 | int NorwegianWoodStyle::styleHint(StyleHint hint, const QStyleOption *option, |
150 | //! [9] //! [10] |
151 | const QWidget *widget, |
152 | QStyleHintReturn *returnData) const |
153 | { |
154 | switch (hint) { |
155 | case SH_DitherDisabledText: |
156 | return int(false); |
157 | case SH_EtchDisabledText: |
158 | return int(true); |
159 | default: |
160 | return QProxyStyle::styleHint(hint, option, widget, returnData); |
161 | } |
162 | } |
163 | //! [10] |
164 | |
165 | //! [11] |
166 | void NorwegianWoodStyle::drawPrimitive(PrimitiveElement element, |
167 | //! [11] //! [12] |
168 | const QStyleOption *option, |
169 | QPainter *painter, |
170 | const QWidget *widget) const |
171 | { |
172 | switch (element) { |
173 | case PE_PanelButtonCommand: |
174 | { |
175 | int delta = (option->state & State_MouseOver) ? 64 : 0; |
176 | QColor slightlyOpaqueBlack(0, 0, 0, 63); |
177 | QColor semiTransparentWhite(255, 255, 255, 127 + delta); |
178 | QColor semiTransparentBlack(0, 0, 0, 127 - delta); |
179 | |
180 | int x, y, width, height; |
181 | option->rect.getRect(ax: &x, ay: &y, aw: &width, ah: &height); |
182 | //! [12] |
183 | |
184 | //! [13] |
185 | QPainterPath roundRect = roundRectPath(rect: option->rect); |
186 | //! [13] //! [14] |
187 | int radius = qMin(a: width, b: height) / 2; |
188 | //! [14] |
189 | |
190 | //! [15] |
191 | QBrush brush; |
192 | //! [15] //! [16] |
193 | bool darker; |
194 | |
195 | const QStyleOptionButton *buttonOption = |
196 | qstyleoption_cast<const QStyleOptionButton *>(opt: option); |
197 | if (buttonOption |
198 | && (buttonOption->features & QStyleOptionButton::Flat)) { |
199 | brush = option->palette.window(); |
200 | darker = (option->state & (State_Sunken | State_On)); |
201 | } else { |
202 | if (option->state & (State_Sunken | State_On)) { |
203 | brush = option->palette.mid(); |
204 | darker = !(option->state & State_Sunken); |
205 | } else { |
206 | brush = option->palette.button(); |
207 | darker = false; |
208 | //! [16] //! [17] |
209 | } |
210 | //! [17] //! [18] |
211 | } |
212 | //! [18] |
213 | |
214 | //! [19] |
215 | painter->save(); |
216 | //! [19] //! [20] |
217 | painter->setRenderHint(hint: QPainter::Antialiasing, on: true); |
218 | //! [20] //! [21] |
219 | painter->fillPath(path: roundRect, brush); |
220 | //! [21] //! [22] |
221 | if (darker) |
222 | //! [22] //! [23] |
223 | painter->fillPath(path: roundRect, brush: slightlyOpaqueBlack); |
224 | //! [23] |
225 | |
226 | //! [24] |
227 | int penWidth; |
228 | //! [24] //! [25] |
229 | if (radius < 10) |
230 | penWidth = 3; |
231 | else if (radius < 20) |
232 | penWidth = 5; |
233 | else |
234 | penWidth = 7; |
235 | |
236 | QPen topPen(semiTransparentWhite, penWidth); |
237 | QPen bottomPen(semiTransparentBlack, penWidth); |
238 | |
239 | if (option->state & (State_Sunken | State_On)) |
240 | qSwap(value1&: topPen, value2&: bottomPen); |
241 | //! [25] |
242 | |
243 | //! [26] |
244 | int x1 = x; |
245 | int x2 = x + radius; |
246 | int x3 = x + width - radius; |
247 | int x4 = x + width; |
248 | |
249 | if (option->direction == Qt::RightToLeft) { |
250 | qSwap(value1&: x1, value2&: x4); |
251 | qSwap(value1&: x2, value2&: x3); |
252 | } |
253 | |
254 | QPolygon topHalf; |
255 | topHalf << QPoint(x1, y) |
256 | << QPoint(x4, y) |
257 | << QPoint(x3, y + radius) |
258 | << QPoint(x2, y + height - radius) |
259 | << QPoint(x1, y + height); |
260 | |
261 | painter->setClipPath(path: roundRect); |
262 | painter->setClipRegion(topHalf, op: Qt::IntersectClip); |
263 | painter->setPen(topPen); |
264 | painter->drawPath(path: roundRect); |
265 | //! [26] //! [32] |
266 | |
267 | QPolygon bottomHalf = topHalf; |
268 | bottomHalf[0] = QPoint(x4, y + height); |
269 | |
270 | painter->setClipPath(path: roundRect); |
271 | painter->setClipRegion(bottomHalf, op: Qt::IntersectClip); |
272 | painter->setPen(bottomPen); |
273 | painter->drawPath(path: roundRect); |
274 | |
275 | painter->setPen(option->palette.windowText().color()); |
276 | painter->setClipping(false); |
277 | painter->drawPath(path: roundRect); |
278 | |
279 | painter->restore(); |
280 | } |
281 | break; |
282 | //! [32] //! [33] |
283 | default: |
284 | //! [33] //! [34] |
285 | QProxyStyle::drawPrimitive(element, option, painter, widget); |
286 | } |
287 | } |
288 | //! [34] |
289 | |
290 | //! [35] |
291 | void NorwegianWoodStyle::drawControl(ControlElement element, |
292 | //! [35] //! [36] |
293 | const QStyleOption *option, |
294 | QPainter *painter, |
295 | const QWidget *widget) const |
296 | { |
297 | switch (element) { |
298 | case CE_PushButtonLabel: |
299 | { |
300 | QStyleOptionButton myButtonOption; |
301 | const QStyleOptionButton *buttonOption = |
302 | qstyleoption_cast<const QStyleOptionButton *>(opt: option); |
303 | if (buttonOption) { |
304 | myButtonOption = *buttonOption; |
305 | if (myButtonOption.palette.currentColorGroup() |
306 | != QPalette::Disabled) { |
307 | if (myButtonOption.state & (State_Sunken | State_On)) { |
308 | myButtonOption.palette.setBrush(acr: QPalette::ButtonText, |
309 | abrush: myButtonOption.palette.brightText()); |
310 | } |
311 | } |
312 | } |
313 | QProxyStyle::drawControl(element, option: &myButtonOption, painter, widget); |
314 | } |
315 | break; |
316 | default: |
317 | QProxyStyle::drawControl(element, option, painter, widget); |
318 | } |
319 | } |
320 | //! [36] |
321 | |
322 | //! [37] |
323 | void NorwegianWoodStyle::setTexture(QPalette &palette, QPalette::ColorRole role, |
324 | //! [37] //! [38] |
325 | const QImage &image) |
326 | { |
327 | for (int i = 0; i < QPalette::NColorGroups; ++i) { |
328 | QBrush brush(image); |
329 | brush.setColor(palette.brush(cg: QPalette::ColorGroup(i), cr: role).color()); |
330 | palette.setBrush(cg: QPalette::ColorGroup(i), cr: role, brush); |
331 | } |
332 | } |
333 | //! [38] |
334 | |
335 | //! [39] |
336 | QPainterPath NorwegianWoodStyle::roundRectPath(const QRect &rect) |
337 | //! [39] //! [40] |
338 | { |
339 | int radius = qMin(a: rect.width(), b: rect.height()) / 2; |
340 | int diam = 2 * radius; |
341 | |
342 | int x1, y1, x2, y2; |
343 | rect.getCoords(xp1: &x1, yp1: &y1, xp2: &x2, yp2: &y2); |
344 | |
345 | QPainterPath path; |
346 | path.moveTo(x: x2, y: y1 + radius); |
347 | path.arcTo(rect: QRect(x2 - diam, y1, diam, diam), startAngle: 0.0, arcLength: +90.0); |
348 | path.lineTo(x: x1 + radius, y: y1); |
349 | path.arcTo(rect: QRect(x1, y1, diam, diam), startAngle: 90.0, arcLength: +90.0); |
350 | path.lineTo(x: x1, y: y2 - radius); |
351 | path.arcTo(rect: QRect(x1, y2 - diam, diam, diam), startAngle: 180.0, arcLength: +90.0); |
352 | path.lineTo(x: x1 + radius, y: y2); |
353 | path.arcTo(rect: QRect(x2 - diam, y2 - diam, diam, diam), startAngle: 270.0, arcLength: +90.0); |
354 | path.closeSubpath(); |
355 | return path; |
356 | } |
357 | //! [40] |
358 | |