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 Qt Quick Controls 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 https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://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 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qquickstyleitem_p.h" |
41 | |
42 | #include <qstringbuilder.h> |
43 | #include <qpainter.h> |
44 | #include <qpixmapcache.h> |
45 | #include <qstyle.h> |
46 | #include <qstyleoption.h> |
47 | #include <qapplication.h> |
48 | #include <qquickwindow.h> |
49 | #include "private/qguiapplication_p.h" |
50 | #include <QtQuick/private/qquickwindow_p.h> |
51 | #include <QtQuick/private/qquickitem_p.h> |
52 | #include <QtGui/qpa/qplatformtheme.h> |
53 | #include <QtQuick/qsgninepatchnode.h> |
54 | #include "../qquickmenuitem_p.h" |
55 | |
56 | QT_BEGIN_NAMESPACE |
57 | |
58 | #ifdef Q_OS_OSX |
59 | #include <Carbon/Carbon.h> |
60 | |
61 | static inline HIRect qt_hirectForQRect(const QRect &convertRect, const QRect &rect = QRect()) |
62 | { |
63 | return CGRectMake(convertRect.x() + rect.x(), convertRect.y() + rect.y(), |
64 | convertRect.width() - rect.width(), convertRect.height() - rect.height()); |
65 | } |
66 | |
67 | /*! \internal |
68 | |
69 | Returns the CoreGraphics CGContextRef of the paint device. 0 is |
70 | returned if it can't be obtained. It is the caller's responsibility to |
71 | CGContextRelease the context when finished using it. |
72 | |
73 | \warning This function is only available on \macos. |
74 | \warning This function is duplicated in qmacstyle_mac.mm |
75 | */ |
76 | CGContextRef qt_mac_cg_context(const QPaintDevice *pdev) |
77 | { |
78 | |
79 | if (pdev->devType() == QInternal::Image) { |
80 | const QImage *i = static_cast<const QImage*>(pdev); |
81 | QImage *image = const_cast< QImage*>(i); |
82 | CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); |
83 | uint flags = kCGImageAlphaPremultipliedFirst; |
84 | flags |= kCGBitmapByteOrder32Host; |
85 | CGContextRef ret = 0; |
86 | |
87 | ret = CGBitmapContextCreate(image->bits(), image->width(), image->height(), |
88 | 8, image->bytesPerLine(), colorspace, flags); |
89 | |
90 | CGContextTranslateCTM(ret, 0, image->height()); |
91 | CGContextScaleCTM(ret, 1, -1); |
92 | return ret; |
93 | } |
94 | return 0; |
95 | } |
96 | |
97 | #endif |
98 | |
99 | QQuickStyleItem1::QQuickStyleItem1(QQuickItem *parent) |
100 | : QQuickItem(parent), |
101 | m_styleoption(0), |
102 | m_itemType(Undefined), |
103 | m_sunken(false), |
104 | m_raised(false), |
105 | m_active(true), |
106 | m_selected(false), |
107 | m_focus(false), |
108 | m_hover(false), |
109 | m_on(false), |
110 | m_horizontal(true), |
111 | m_transient(false), |
112 | m_sharedWidget(false), |
113 | m_minimum(0), |
114 | m_maximum(100), |
115 | m_value(0), |
116 | m_step(0), |
117 | m_paintMargins(0), |
118 | m_contentWidth(0), |
119 | m_contentHeight(0), |
120 | m_textureWidth(0), |
121 | m_textureHeight(0) |
122 | { |
123 | m_font = qApp->font(); |
124 | setFlag(flag: QQuickItem::ItemHasContents, enabled: true); |
125 | setSmooth(false); |
126 | |
127 | connect(sender: this, SIGNAL(visibleChanged()), receiver: this, SLOT(updateItem())); |
128 | connect(sender: this, SIGNAL(widthChanged()), receiver: this, SLOT(updateItem())); |
129 | connect(sender: this, SIGNAL(heightChanged()), receiver: this, SLOT(updateItem())); |
130 | connect(sender: this, SIGNAL(enabledChanged()), receiver: this, SLOT(updateItem())); |
131 | connect(sender: this, SIGNAL(infoChanged()), receiver: this, SLOT(updateItem())); |
132 | connect(sender: this, SIGNAL(onChanged()), receiver: this, SLOT(updateItem())); |
133 | connect(sender: this, SIGNAL(selectedChanged()), receiver: this, SLOT(updateItem())); |
134 | connect(sender: this, SIGNAL(activeChanged()), receiver: this, SLOT(updateItem())); |
135 | connect(sender: this, SIGNAL(textChanged()), receiver: this, SLOT(updateSizeHint())); |
136 | connect(sender: this, SIGNAL(textChanged()), receiver: this, SLOT(updateItem())); |
137 | connect(sender: this, SIGNAL(activeChanged()), receiver: this, SLOT(updateItem())); |
138 | connect(sender: this, SIGNAL(raisedChanged()), receiver: this, SLOT(updateItem())); |
139 | connect(sender: this, SIGNAL(sunkenChanged()), receiver: this, SLOT(updateItem())); |
140 | connect(sender: this, SIGNAL(hoverChanged()), receiver: this, SLOT(updateItem())); |
141 | connect(sender: this, SIGNAL(maximumChanged()), receiver: this, SLOT(updateItem())); |
142 | connect(sender: this, SIGNAL(minimumChanged()), receiver: this, SLOT(updateItem())); |
143 | connect(sender: this, SIGNAL(valueChanged()), receiver: this, SLOT(updateItem())); |
144 | connect(sender: this, SIGNAL(horizontalChanged()), receiver: this, SLOT(updateItem())); |
145 | connect(sender: this, SIGNAL(transientChanged()), receiver: this, SLOT(updateItem())); |
146 | connect(sender: this, SIGNAL(activeControlChanged()), receiver: this, SLOT(updateItem())); |
147 | connect(sender: this, SIGNAL(hasFocusChanged()), receiver: this, SLOT(updateItem())); |
148 | connect(sender: this, SIGNAL(activeControlChanged()), receiver: this, SLOT(updateItem())); |
149 | connect(sender: this, SIGNAL(hintChanged()), receiver: this, SLOT(updateItem())); |
150 | connect(sender: this, SIGNAL(propertiesChanged()), receiver: this, SLOT(updateSizeHint())); |
151 | connect(sender: this, SIGNAL(propertiesChanged()), receiver: this, SLOT(updateItem())); |
152 | connect(sender: this, SIGNAL(elementTypeChanged()), receiver: this, SLOT(updateItem())); |
153 | connect(sender: this, SIGNAL(contentWidthChanged(int)), receiver: this, SLOT(updateSizeHint())); |
154 | connect(sender: this, SIGNAL(contentHeightChanged(int)), receiver: this, SLOT(updateSizeHint())); |
155 | connect(sender: this, SIGNAL(widthChanged()), receiver: this, SLOT(updateRect())); |
156 | connect(sender: this, SIGNAL(heightChanged()), receiver: this, SLOT(updateRect())); |
157 | |
158 | connect(sender: this, SIGNAL(heightChanged()), receiver: this, SLOT(updateBaselineOffset())); |
159 | connect(sender: this, SIGNAL(contentHeightChanged(int)), receiver: this, SLOT(updateBaselineOffset())); |
160 | } |
161 | |
162 | QQuickStyleItem1::~QQuickStyleItem1() |
163 | { |
164 | if (const QStyleOptionButton *aux = qstyleoption_cast<const QStyleOptionButton*>(opt: m_styleoption)) |
165 | delete aux; |
166 | #if QT_CONFIG(itemviews) |
167 | else if (const QStyleOptionViewItem *aux = qstyleoption_cast<const QStyleOptionViewItem*>(opt: m_styleoption)) |
168 | delete aux; |
169 | #endif |
170 | else if (const QStyleOptionHeader *aux = qstyleoption_cast<const QStyleOptionHeader*>(opt: m_styleoption)) |
171 | delete aux; |
172 | else if (const QStyleOptionToolButton *aux = qstyleoption_cast<const QStyleOptionToolButton*>(opt: m_styleoption)) |
173 | delete aux; |
174 | #if QT_CONFIG(toolbar) |
175 | else if (const QStyleOptionToolBar *aux = qstyleoption_cast<const QStyleOptionToolBar*>(opt: m_styleoption)) |
176 | delete aux; |
177 | #endif |
178 | #if QT_CONFIG(tabbar) |
179 | else if (const QStyleOptionTab *aux = qstyleoption_cast<const QStyleOptionTab*>(opt: m_styleoption)) |
180 | delete aux; |
181 | #endif |
182 | else if (const QStyleOptionFrame *aux = qstyleoption_cast<const QStyleOptionFrame*>(opt: m_styleoption)) |
183 | delete aux; |
184 | else if (const QStyleOptionFocusRect *aux = qstyleoption_cast<const QStyleOptionFocusRect*>(opt: m_styleoption)) |
185 | delete aux; |
186 | #if QT_CONFIG(tabwidget) |
187 | else if (const QStyleOptionTabWidgetFrame *aux = qstyleoption_cast<const QStyleOptionTabWidgetFrame*>(opt: m_styleoption)) |
188 | delete aux; |
189 | #endif |
190 | else if (const QStyleOptionMenuItem *aux = qstyleoption_cast<const QStyleOptionMenuItem*>(opt: m_styleoption)) |
191 | delete aux; |
192 | else if (const QStyleOptionComboBox *aux = qstyleoption_cast<const QStyleOptionComboBox*>(opt: m_styleoption)) |
193 | delete aux; |
194 | #if QT_CONFIG(spinbox) |
195 | else if (const QStyleOptionSpinBox *aux = qstyleoption_cast<const QStyleOptionSpinBox*>(opt: m_styleoption)) |
196 | delete aux; |
197 | #endif |
198 | #if QT_CONFIG(slider) |
199 | else if (const QStyleOptionSlider *aux = qstyleoption_cast<const QStyleOptionSlider*>(opt: m_styleoption)) |
200 | delete aux; |
201 | #endif |
202 | else if (const QStyleOptionProgressBar *aux = qstyleoption_cast<const QStyleOptionProgressBar*>(opt: m_styleoption)) |
203 | delete aux; |
204 | else if (const QStyleOptionGroupBox *aux = qstyleoption_cast<const QStyleOptionGroupBox*>(opt: m_styleoption)) |
205 | delete aux; |
206 | else |
207 | delete m_styleoption; |
208 | |
209 | m_styleoption = 0; |
210 | } |
211 | |
212 | void QQuickStyleItem1::initStyleOption() |
213 | { |
214 | if (m_styleoption) |
215 | m_styleoption->state = {}; |
216 | |
217 | QString sizeHint = m_hints.value(QStringLiteral("size" )).toString(); |
218 | QPlatformTheme::Font platformFont = (sizeHint == QLatin1String("mini" )) ? QPlatformTheme::MiniFont : |
219 | (sizeHint == QLatin1String("small" )) ? QPlatformTheme::SmallFont : |
220 | QPlatformTheme::SystemFont; |
221 | |
222 | bool needsResolvePalette = true; |
223 | |
224 | switch (m_itemType) { |
225 | case Button: { |
226 | if (!m_styleoption) |
227 | m_styleoption = new QStyleOptionButton(); |
228 | |
229 | QStyleOptionButton *opt = qstyleoption_cast<QStyleOptionButton*>(opt: m_styleoption); |
230 | opt->text = text(); |
231 | opt->icon = m_properties[QStringLiteral("icon" )].value<QIcon>(); |
232 | int e = qApp->style()->pixelMetric(metric: QStyle::PM_ButtonIconSize, option: m_styleoption, widget: 0); |
233 | opt->iconSize = QSize(e, e); |
234 | opt->features = activeControl() == QLatin1String("default" ) ? |
235 | QStyleOptionButton::DefaultButton : |
236 | QStyleOptionButton::None; |
237 | if (platformFont == QPlatformTheme::SystemFont) |
238 | platformFont = QPlatformTheme::PushButtonFont; |
239 | const QFont *font = QGuiApplicationPrivate::platformTheme()->font(type: platformFont); |
240 | if (font) |
241 | opt->fontMetrics = QFontMetrics(*font); |
242 | QObject * = m_properties[QStringLiteral("menu" )].value<QObject *>(); |
243 | if (menu) { |
244 | opt->features |= QStyleOptionButton::HasMenu; |
245 | #ifdef Q_OS_OSX |
246 | if (style() == QLatin1String("mac" )) { |
247 | if (platformFont == QPlatformTheme::PushButtonFont) |
248 | menu->setProperty("__xOffset" , 12); |
249 | else |
250 | menu->setProperty("__xOffset" , 11); |
251 | if (platformFont == QPlatformTheme::MiniFont) |
252 | menu->setProperty("__yOffset" , 5); |
253 | else if (platformFont == QPlatformTheme::SmallFont) |
254 | menu->setProperty("__yOffset" , 6); |
255 | else |
256 | menu->setProperty("__yOffset" , 3); |
257 | if (font) |
258 | menu->setProperty("__font" , *font); |
259 | } |
260 | #endif |
261 | } |
262 | } |
263 | break; |
264 | #if QT_CONFIG(itemviews) |
265 | case ItemRow: { |
266 | if (!m_styleoption) |
267 | m_styleoption = new QStyleOptionViewItem(); |
268 | |
269 | QStyleOptionViewItem *opt = qstyleoption_cast<QStyleOptionViewItem*>(opt: m_styleoption); |
270 | opt->features = {}; |
271 | if (activeControl() == QLatin1String("alternate" )) |
272 | opt->features |= QStyleOptionViewItem::Alternate; |
273 | } |
274 | break; |
275 | #endif // QT_CONFIG(itemviews) |
276 | case Splitter: { |
277 | if (!m_styleoption) { |
278 | m_styleoption = new QStyleOption; |
279 | } |
280 | } |
281 | break; |
282 | #if QT_CONFIG(itemviews) |
283 | case Item: { |
284 | if (!m_styleoption) { |
285 | m_styleoption = new QStyleOptionViewItem(); |
286 | } |
287 | QStyleOptionViewItem *opt = qstyleoption_cast<QStyleOptionViewItem*>(opt: m_styleoption); |
288 | opt->features = QStyleOptionViewItem::HasDisplay; |
289 | opt->text = text(); |
290 | opt->textElideMode = Qt::ElideRight; |
291 | opt->displayAlignment = Qt::AlignLeft | Qt::AlignVCenter; |
292 | opt->decorationAlignment = Qt::AlignCenter; |
293 | resolvePalette(); |
294 | needsResolvePalette = false; |
295 | QPalette pal = m_styleoption->palette; |
296 | pal.setBrush(acr: QPalette::Base, abrush: Qt::NoBrush); |
297 | m_styleoption->palette = pal; |
298 | if (const QFont *font = QGuiApplicationPrivate::platformTheme()->font(type: QPlatformTheme::ItemViewFont)) { |
299 | opt->fontMetrics = QFontMetrics(*font); |
300 | opt->font = *font; |
301 | } |
302 | } |
303 | break; |
304 | #endif // QT_CONFIG(itemviews) |
305 | case ItemBranchIndicator: { |
306 | if (!m_styleoption) |
307 | m_styleoption = new QStyleOption; |
308 | |
309 | m_styleoption->state = QStyle::State_Item; // We don't want to fully support Win 95 |
310 | if (m_properties.value(QStringLiteral("hasChildren" )).toBool()) |
311 | m_styleoption->state |= QStyle::State_Children; |
312 | if (m_properties.value(QStringLiteral("hasSibling" )).toBool()) // Even this one could go away |
313 | m_styleoption->state |= QStyle::State_Sibling; |
314 | if (m_on) |
315 | m_styleoption->state |= QStyle::State_Open; |
316 | } |
317 | break; |
318 | case Header: { |
319 | if (!m_styleoption) |
320 | m_styleoption = new QStyleOptionHeader(); |
321 | |
322 | QStyleOptionHeader *opt = qstyleoption_cast<QStyleOptionHeader*>(opt: m_styleoption); |
323 | opt->text = text(); |
324 | opt->textAlignment = static_cast<Qt::AlignmentFlag>(m_properties.value(QStringLiteral("textalignment" )).toInt()); |
325 | opt->sortIndicator = activeControl() == QLatin1String("down" ) ? |
326 | QStyleOptionHeader::SortDown |
327 | : activeControl() == QLatin1String("up" ) ? |
328 | QStyleOptionHeader::SortUp : QStyleOptionHeader::None; |
329 | QString = m_properties.value(QStringLiteral("headerpos" )).toString(); |
330 | if (headerpos == QLatin1String("beginning" )) |
331 | opt->position = QStyleOptionHeader::Beginning; |
332 | else if (headerpos == QLatin1String("end" )) |
333 | opt->position = QStyleOptionHeader::End; |
334 | else if (headerpos == QLatin1String("only" )) |
335 | opt->position = QStyleOptionHeader::OnlyOneSection; |
336 | else |
337 | opt->position = QStyleOptionHeader::Middle; |
338 | if (const QFont *font = QGuiApplicationPrivate::platformTheme()->font(type: QPlatformTheme::HeaderViewFont)) |
339 | opt->fontMetrics = QFontMetrics(*font); |
340 | } |
341 | break; |
342 | case ToolButton: { |
343 | if (!m_styleoption) |
344 | m_styleoption = new QStyleOptionToolButton(); |
345 | |
346 | QStyleOptionToolButton *opt = |
347 | qstyleoption_cast<QStyleOptionToolButton*>(opt: m_styleoption); |
348 | opt->subControls = QStyle::SC_ToolButton; |
349 | opt->state |= QStyle::State_AutoRaise; |
350 | opt->activeSubControls = QStyle::SC_ToolButton; |
351 | opt->text = text(); |
352 | opt->icon = m_properties[QStringLiteral("icon" )].value<QIcon>(); |
353 | |
354 | if (m_properties.value(QStringLiteral("menu" )).toBool()) { |
355 | opt->subControls |= QStyle::SC_ToolButtonMenu; |
356 | opt->features = QStyleOptionToolButton::HasMenu; |
357 | } |
358 | |
359 | // For now icon only is displayed by default. |
360 | opt->toolButtonStyle = Qt::ToolButtonIconOnly; |
361 | if (opt->icon.isNull() && !opt->text.isEmpty()) |
362 | opt->toolButtonStyle = Qt::ToolButtonTextOnly; |
363 | |
364 | int e = qApp->style()->pixelMetric(metric: QStyle::PM_ToolBarIconSize, option: m_styleoption, widget: 0); |
365 | opt->iconSize = QSize(e, e); |
366 | |
367 | if (const QFont *font = QGuiApplicationPrivate::platformTheme()->font(type: QPlatformTheme::ToolButtonFont)) { |
368 | opt->fontMetrics = QFontMetrics(*font); |
369 | opt->font = *font; |
370 | } |
371 | |
372 | } |
373 | break; |
374 | #if QT_CONFIG(toolbar) |
375 | case ToolBar: { |
376 | if (!m_styleoption) |
377 | m_styleoption = new QStyleOptionToolBar(); |
378 | } |
379 | break; |
380 | #endif |
381 | #if QT_CONFIG(tabbar) |
382 | case Tab: { |
383 | if (!m_styleoption) |
384 | m_styleoption = new QStyleOptionTab(); |
385 | |
386 | QStyleOptionTab *opt = qstyleoption_cast<QStyleOptionTab*>(opt: m_styleoption); |
387 | opt->text = text(); |
388 | |
389 | if (m_properties.value(QStringLiteral("hasFrame" )).toBool()) |
390 | opt->features |= QStyleOptionTab::HasFrame; |
391 | |
392 | QString orientation = m_properties.value(QStringLiteral("orientation" )).toString(); |
393 | QString position = m_properties.value(QStringLiteral("tabpos" )).toString(); |
394 | QString selectedPosition = m_properties.value(QStringLiteral("selectedpos" )).toString(); |
395 | |
396 | opt->shape = orientation == QLatin1String("Bottom" ) ? QTabBar::RoundedSouth : QTabBar::RoundedNorth; |
397 | if (position == QLatin1String("beginning" )) |
398 | opt->position = QStyleOptionTab::Beginning; |
399 | else if (position == QLatin1String("end" )) |
400 | opt->position = QStyleOptionTab::End; |
401 | else if (position == QLatin1String("only" )) |
402 | opt->position = QStyleOptionTab::OnlyOneTab; |
403 | else |
404 | opt->position = QStyleOptionTab::Middle; |
405 | |
406 | if (selectedPosition == QLatin1String("next" )) |
407 | opt->selectedPosition = QStyleOptionTab::NextIsSelected; |
408 | else if (selectedPosition == QLatin1String("previous" )) |
409 | opt->selectedPosition = QStyleOptionTab::PreviousIsSelected; |
410 | else |
411 | opt->selectedPosition = QStyleOptionTab::NotAdjacent; |
412 | |
413 | |
414 | } break; |
415 | #endif // QT_CONFIG(tabbar) |
416 | case Frame: { |
417 | if (!m_styleoption) |
418 | m_styleoption = new QStyleOptionFrame(); |
419 | |
420 | QStyleOptionFrame *opt = qstyleoption_cast<QStyleOptionFrame*>(opt: m_styleoption); |
421 | opt->frameShape = QFrame::StyledPanel; |
422 | opt->lineWidth = 1; |
423 | opt->midLineWidth = 1; |
424 | } |
425 | break; |
426 | case FocusRect: { |
427 | if (!m_styleoption) |
428 | m_styleoption = new QStyleOptionFocusRect(); |
429 | // Needed on windows |
430 | m_styleoption->state |= QStyle::State_KeyboardFocusChange; |
431 | } |
432 | break; |
433 | #if QT_CONFIG(tabwidget) |
434 | case TabFrame: { |
435 | if (!m_styleoption) |
436 | m_styleoption = new QStyleOptionTabWidgetFrame(); |
437 | QStyleOptionTabWidgetFrame *opt = qstyleoption_cast<QStyleOptionTabWidgetFrame*>(opt: m_styleoption); |
438 | |
439 | opt->selectedTabRect = m_properties[QStringLiteral("selectedTabRect" )].toRect(); |
440 | opt->shape = m_properties[QStringLiteral("orientation" )] == Qt::BottomEdge ? QTabBar::RoundedSouth : QTabBar::RoundedNorth; |
441 | if (minimum()) |
442 | opt->selectedTabRect = QRect(value(), 0, minimum(), height()); |
443 | opt->tabBarSize = QSize(minimum() , height()); |
444 | // oxygen style needs this hack |
445 | opt->leftCornerWidgetSize = QSize(value(), 0); |
446 | } |
447 | break; |
448 | #endif // QT_CONFIG(tabwidget) |
449 | case MenuBar: |
450 | if (!m_styleoption) { |
451 | QStyleOptionMenuItem * = new QStyleOptionMenuItem(); |
452 | menuOpt->menuItemType = QStyleOptionMenuItem::EmptyArea; |
453 | m_styleoption = menuOpt; |
454 | } |
455 | |
456 | break; |
457 | case MenuBarItem: |
458 | { |
459 | if (!m_styleoption) |
460 | m_styleoption = new QStyleOptionMenuItem(); |
461 | |
462 | QStyleOptionMenuItem *opt = qstyleoption_cast<QStyleOptionMenuItem*>(opt: m_styleoption); |
463 | opt->text = text(); |
464 | opt->menuItemType = QStyleOptionMenuItem::Normal; |
465 | setProperty(name: "_q_showUnderlined" , value: m_hints[QStringLiteral("showUnderlined" )].toBool()); |
466 | |
467 | if (const QFont *font = QGuiApplicationPrivate::platformTheme()->font(type: QPlatformTheme::MenuBarFont)) { |
468 | opt->font = *font; |
469 | opt->fontMetrics = QFontMetrics(opt->font); |
470 | m_font = opt->font; |
471 | } |
472 | } |
473 | break; |
474 | case Menu: { |
475 | if (!m_styleoption) |
476 | m_styleoption = new QStyleOptionMenuItem(); |
477 | } |
478 | break; |
479 | case MenuItem: |
480 | case ComboBoxItem: |
481 | { |
482 | if (!m_styleoption) |
483 | m_styleoption = new QStyleOptionMenuItem(); |
484 | |
485 | QStyleOptionMenuItem *opt = qstyleoption_cast<QStyleOptionMenuItem*>(opt: m_styleoption); |
486 | // For GTK style. See below, in setElementType() |
487 | setProperty(name: "_q_isComboBoxPopupItem" , value: m_itemType == ComboBoxItem); |
488 | |
489 | QQuickMenuItemType1::MenuItemType type = |
490 | static_cast<QQuickMenuItemType1::MenuItemType>(m_properties[QStringLiteral("type" )].toInt()); |
491 | if (type == QQuickMenuItemType1::ScrollIndicator) { |
492 | int scrollerDirection = m_properties[QStringLiteral("scrollerDirection" )].toInt(); |
493 | opt->menuItemType = QStyleOptionMenuItem::Scroller; |
494 | opt->state |= scrollerDirection == Qt::UpArrow ? |
495 | QStyle::State_UpArrow : QStyle::State_DownArrow; |
496 | } else if (type == QQuickMenuItemType1::Separator) { |
497 | opt->menuItemType = QStyleOptionMenuItem::Separator; |
498 | } else { |
499 | opt->text = text(); |
500 | |
501 | if (type == QQuickMenuItemType1::Menu) { |
502 | opt->menuItemType = QStyleOptionMenuItem::SubMenu; |
503 | } else { |
504 | opt->menuItemType = QStyleOptionMenuItem::Normal; |
505 | |
506 | QString shortcut = m_properties[QStringLiteral("shortcut" )].toString(); |
507 | if (!shortcut.isEmpty()) { |
508 | opt->text += QLatin1Char('\t') + shortcut; |
509 | opt->tabWidth = qMax(a: opt->tabWidth, b: qRound(d: textWidth(shortcut))); |
510 | } |
511 | |
512 | if (m_properties[QStringLiteral("checkable" )].toBool()) { |
513 | opt->checked = on(); |
514 | QVariant exclusive = m_properties[QStringLiteral("exclusive" )]; |
515 | opt->checkType = exclusive.toBool() ? QStyleOptionMenuItem::Exclusive : |
516 | QStyleOptionMenuItem::NonExclusive; |
517 | } |
518 | } |
519 | if (m_properties[QStringLiteral("icon" )].canConvert<QIcon>()) |
520 | opt->icon = m_properties[QStringLiteral("icon" )].value<QIcon>(); |
521 | setProperty(name: "_q_showUnderlined" , value: m_hints["showUnderlined" ].toBool()); |
522 | |
523 | if (const QFont *font = QGuiApplicationPrivate::platformTheme()->font(type: m_itemType == ComboBoxItem ? QPlatformTheme::ComboMenuItemFont : QPlatformTheme::MenuFont)) { |
524 | opt->font = *font; |
525 | opt->fontMetrics = QFontMetrics(opt->font); |
526 | m_font = opt->font; |
527 | } |
528 | } |
529 | } |
530 | break; |
531 | case CheckBox: |
532 | case RadioButton: |
533 | { |
534 | if (!m_styleoption) |
535 | m_styleoption = new QStyleOptionButton(); |
536 | |
537 | QStyleOptionButton *opt = qstyleoption_cast<QStyleOptionButton*>(opt: m_styleoption); |
538 | if (!on()) |
539 | opt->state |= QStyle::State_Off; |
540 | if (m_properties.value(QStringLiteral("partiallyChecked" )).toBool()) |
541 | opt->state |= QStyle::State_NoChange; |
542 | opt->text = text(); |
543 | } |
544 | break; |
545 | case Edit: { |
546 | if (!m_styleoption) |
547 | m_styleoption = new QStyleOptionFrame(); |
548 | |
549 | QStyleOptionFrame *opt = qstyleoption_cast<QStyleOptionFrame*>(opt: m_styleoption); |
550 | opt->lineWidth = 1; // this must be non-zero |
551 | } |
552 | break; |
553 | case ComboBox :{ |
554 | if (!m_styleoption) |
555 | m_styleoption = new QStyleOptionComboBox(); |
556 | |
557 | QStyleOptionComboBox *opt = qstyleoption_cast<QStyleOptionComboBox*>(opt: m_styleoption); |
558 | |
559 | if (platformFont == QPlatformTheme::SystemFont) |
560 | platformFont = QPlatformTheme::PushButtonFont; |
561 | const QFont *font = QGuiApplicationPrivate::platformTheme()->font(type: platformFont); |
562 | if (font) |
563 | opt->fontMetrics = QFontMetrics(*font); |
564 | opt->currentText = text(); |
565 | opt->editable = m_properties[QStringLiteral("editable" )].toBool(); |
566 | #ifdef Q_OS_OSX |
567 | if (m_properties[QStringLiteral("popup" )].canConvert<QObject *>() |
568 | && style() == QLatin1String("mac" )) { |
569 | QObject *popup = m_properties[QStringLiteral("popup" )].value<QObject *>(); |
570 | if (platformFont == QPlatformTheme::MiniFont) { |
571 | popup->setProperty("__xOffset" , -2); |
572 | popup->setProperty("__yOffset" , 5); |
573 | } else { |
574 | if (platformFont == QPlatformTheme::SmallFont) |
575 | popup->setProperty("__xOffset" , -1); |
576 | popup->setProperty("__yOffset" , 6); |
577 | } |
578 | if (font) |
579 | popup->setProperty("__font" , *font); |
580 | } |
581 | #endif |
582 | } |
583 | break; |
584 | #if QT_CONFIG(spinbox) |
585 | case SpinBox: { |
586 | if (!m_styleoption) |
587 | m_styleoption = new QStyleOptionSpinBox(); |
588 | |
589 | QStyleOptionSpinBox *opt = qstyleoption_cast<QStyleOptionSpinBox*>(opt: m_styleoption); |
590 | opt->frame = true; |
591 | opt->subControls = QStyle::SC_SpinBoxFrame | QStyle::SC_SpinBoxEditField; |
592 | if (value() & 0x1) |
593 | opt->activeSubControls = QStyle::SC_SpinBoxUp; |
594 | else if (value() & (1<<1)) |
595 | opt->activeSubControls = QStyle::SC_SpinBoxDown; |
596 | opt->subControls = QStyle::SC_All; |
597 | opt->stepEnabled = {}; |
598 | if (value() & (1<<2)) |
599 | opt->stepEnabled |= QAbstractSpinBox::StepUpEnabled; |
600 | if (value() & (1<<3)) |
601 | opt->stepEnabled |= QAbstractSpinBox::StepDownEnabled; |
602 | } |
603 | break; |
604 | #endif // QT_CONFIG(spinbox) |
605 | #if QT_CONFIG(slider) |
606 | case Slider: |
607 | case Dial: |
608 | { |
609 | if (!m_styleoption) |
610 | m_styleoption = new QStyleOptionSlider(); |
611 | |
612 | QStyleOptionSlider *opt = qstyleoption_cast<QStyleOptionSlider*>(opt: m_styleoption); |
613 | opt->orientation = horizontal() ? Qt::Horizontal : Qt::Vertical; |
614 | opt->upsideDown = !horizontal(); |
615 | opt->minimum = minimum(); |
616 | opt->maximum = maximum(); |
617 | opt->sliderPosition = value(); |
618 | opt->singleStep = step(); |
619 | |
620 | if (opt->singleStep) { |
621 | qreal numOfSteps = (opt->maximum - opt->minimum) / opt->singleStep; |
622 | // at least 5 pixels between tick marks |
623 | qreal extent = horizontal() ? width() : height(); |
624 | if (numOfSteps && (extent / numOfSteps < 5)) |
625 | opt->tickInterval = qRound(d: (5 * numOfSteps / extent) + 0.5) * step(); |
626 | else |
627 | opt->tickInterval = opt->singleStep; |
628 | |
629 | } else // default Qt-components implementation |
630 | opt->tickInterval = opt->maximum != opt->minimum ? 1200 / (opt->maximum - opt->minimum) : 0; |
631 | |
632 | opt->sliderValue = value(); |
633 | opt->subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderHandle; |
634 | opt->tickPosition = activeControl() == QLatin1String("ticks" ) ? |
635 | QSlider::TicksBelow : QSlider::NoTicks; |
636 | if (opt->tickPosition != QSlider::NoTicks) |
637 | opt->subControls |= QStyle::SC_SliderTickmarks; |
638 | |
639 | opt->activeSubControls = QStyle::SC_SliderHandle; |
640 | } |
641 | break; |
642 | #endif // QT_CONFIG(slider) |
643 | case ProgressBar: { |
644 | if (!m_styleoption) |
645 | m_styleoption = new QStyleOptionProgressBar(); |
646 | |
647 | QStyleOptionProgressBar *opt = qstyleoption_cast<QStyleOptionProgressBar*>(opt: m_styleoption); |
648 | opt->orientation = horizontal() ? Qt::Horizontal : Qt::Vertical; |
649 | opt->minimum = minimum(); |
650 | opt->maximum = maximum(); |
651 | opt->progress = value(); |
652 | } |
653 | break; |
654 | case GroupBox: { |
655 | if (!m_styleoption) |
656 | m_styleoption = new QStyleOptionGroupBox(); |
657 | |
658 | QStyleOptionGroupBox *opt = qstyleoption_cast<QStyleOptionGroupBox*>(opt: m_styleoption); |
659 | opt->text = text(); |
660 | opt->lineWidth = 1; |
661 | opt->subControls = QStyle::SC_GroupBoxLabel; |
662 | opt->features = {}; |
663 | if (m_properties[QStringLiteral("sunken" )].toBool()) { // Qt draws an ugly line here so I ignore it |
664 | opt->subControls |= QStyle::SC_GroupBoxFrame; |
665 | } else { |
666 | opt->features |= QStyleOptionFrame::Flat; |
667 | } |
668 | if (m_properties[QStringLiteral("checkable" )].toBool()) |
669 | opt->subControls |= QStyle::SC_GroupBoxCheckBox; |
670 | |
671 | } |
672 | break; |
673 | #if QT_CONFIG(slider) |
674 | case ScrollBar: { |
675 | if (!m_styleoption) |
676 | m_styleoption = new QStyleOptionSlider(); |
677 | |
678 | QStyleOptionSlider *opt = qstyleoption_cast<QStyleOptionSlider*>(opt: m_styleoption); |
679 | opt->minimum = minimum(); |
680 | opt->maximum = maximum(); |
681 | opt->pageStep = qMax(a: 0, b: int(horizontal() ? width() : height())); |
682 | opt->orientation = horizontal() ? Qt::Horizontal : Qt::Vertical; |
683 | opt->sliderPosition = value(); |
684 | opt->sliderValue = value(); |
685 | opt->activeSubControls = (activeControl() == QLatin1String("up" )) |
686 | ? QStyle::SC_ScrollBarSubLine : (activeControl() == QLatin1String("down" )) ? |
687 | QStyle::SC_ScrollBarAddLine : |
688 | (activeControl() == QLatin1String("handle" )) ? |
689 | QStyle::SC_ScrollBarSlider : hover() ? QStyle::SC_ScrollBarGroove : QStyle::SC_None; |
690 | if (raised()) |
691 | opt->state |= QStyle::State_On; |
692 | |
693 | opt->sliderValue = value(); |
694 | opt->subControls = QStyle::SC_All; |
695 | |
696 | setTransient(qApp->style()->styleHint(stylehint: QStyle::SH_ScrollBar_Transient, opt: m_styleoption)); |
697 | break; |
698 | } |
699 | #endif // QT_CONFIG(slider) |
700 | default: |
701 | break; |
702 | } |
703 | |
704 | if (!m_styleoption) |
705 | m_styleoption = new QStyleOption(); |
706 | |
707 | if (needsResolvePalette) |
708 | resolvePalette(); |
709 | |
710 | m_styleoption->styleObject = this; |
711 | m_styleoption->direction = qApp->layoutDirection(); |
712 | |
713 | int w = m_textureWidth > 0 ? m_textureWidth : width(); |
714 | int h = m_textureHeight > 0 ? m_textureHeight : height(); |
715 | |
716 | m_styleoption->rect = QRect(m_paintMargins, 0, w - 2* m_paintMargins, h); |
717 | |
718 | if (isEnabled()) { |
719 | m_styleoption->state |= QStyle::State_Enabled; |
720 | m_styleoption->palette.setCurrentColorGroup(QPalette::Active); |
721 | } else { |
722 | m_styleoption->palette.setCurrentColorGroup(QPalette::Disabled); |
723 | } |
724 | if (m_active) |
725 | m_styleoption->state |= QStyle::State_Active; |
726 | else |
727 | m_styleoption->palette.setCurrentColorGroup(QPalette::Inactive); |
728 | if (m_sunken) |
729 | m_styleoption->state |= QStyle::State_Sunken; |
730 | if (m_raised) |
731 | m_styleoption->state |= QStyle::State_Raised; |
732 | if (m_selected) |
733 | m_styleoption->state |= QStyle::State_Selected; |
734 | if (m_focus) |
735 | m_styleoption->state |= QStyle::State_HasFocus; |
736 | if (m_on) |
737 | m_styleoption->state |= QStyle::State_On; |
738 | if (m_hover) |
739 | m_styleoption->state |= QStyle::State_MouseOver; |
740 | if (m_horizontal) |
741 | m_styleoption->state |= QStyle::State_Horizontal; |
742 | |
743 | // some styles don't draw a focus rectangle if |
744 | // QStyle::State_KeyboardFocusChange is not set |
745 | if (window()) { |
746 | Qt::FocusReason lastFocusReason = QQuickWindowPrivate::get(c: window())->lastFocusReason; |
747 | if (lastFocusReason == Qt::TabFocusReason || lastFocusReason == Qt::BacktabFocusReason) { |
748 | m_styleoption->state |= QStyle::State_KeyboardFocusChange; |
749 | } |
750 | } |
751 | |
752 | if (sizeHint == QLatin1String("mini" )) { |
753 | m_styleoption->state |= QStyle::State_Mini; |
754 | } else if (sizeHint == QLatin1String("small" )) { |
755 | m_styleoption->state |= QStyle::State_Small; |
756 | } |
757 | |
758 | } |
759 | |
760 | void QQuickStyleItem1::resolvePalette() |
761 | { |
762 | if (QCoreApplication::testAttribute(attribute: Qt::AA_SetPalette)) |
763 | return; |
764 | |
765 | QPlatformTheme::Palette paletteType = QPlatformTheme::SystemPalette; |
766 | switch (m_itemType) { |
767 | case Button: |
768 | paletteType = QPlatformTheme::ButtonPalette; |
769 | break; |
770 | case RadioButton: |
771 | paletteType = QPlatformTheme::RadioButtonPalette; |
772 | break; |
773 | case CheckBox: |
774 | paletteType = QPlatformTheme::CheckBoxPalette; |
775 | break; |
776 | case ComboBox: |
777 | case ComboBoxItem: |
778 | paletteType = QPlatformTheme::ComboBoxPalette; |
779 | break; |
780 | case ToolBar: |
781 | case ToolButton: |
782 | paletteType = QPlatformTheme::ToolButtonPalette; |
783 | break; |
784 | case Tab: |
785 | case TabFrame: |
786 | paletteType = QPlatformTheme::TabBarPalette; |
787 | break; |
788 | case Edit: |
789 | paletteType = QPlatformTheme::TextEditPalette; |
790 | break; |
791 | case GroupBox: |
792 | paletteType = QPlatformTheme::GroupBoxPalette; |
793 | break; |
794 | case Header: |
795 | paletteType = QPlatformTheme::HeaderPalette; |
796 | break; |
797 | case Item: |
798 | case ItemRow: |
799 | paletteType = QPlatformTheme::ItemViewPalette; |
800 | break; |
801 | case Menu: |
802 | case MenuItem: |
803 | paletteType = QPlatformTheme::MenuPalette; |
804 | break; |
805 | case MenuBar: |
806 | case MenuBarItem: |
807 | paletteType = QPlatformTheme::MenuBarPalette; |
808 | break; |
809 | default: |
810 | break; |
811 | } |
812 | |
813 | const QPalette *platformPalette = QGuiApplicationPrivate::platformTheme()->palette(type: paletteType); |
814 | if (platformPalette) |
815 | m_styleoption->palette = *platformPalette; |
816 | // Defaults to SystemPalette otherwise |
817 | } |
818 | |
819 | /* |
820 | * Property style |
821 | * |
822 | * Returns a simplified style name. |
823 | * |
824 | * QMacStyle = "mac" |
825 | * QWindowsXPStyle = "windowsxp" |
826 | * QFusionStyle = "fusion" |
827 | */ |
828 | |
829 | QString QQuickStyleItem1::style() const |
830 | { |
831 | QString style = qApp->style()->metaObject()->className(); |
832 | style = style.toLower(); |
833 | if (style.startsWith(c: QLatin1Char('q'))) |
834 | style = style.right(n: style.length() - 1); |
835 | if (style.endsWith(s: QLatin1String("style" ))) |
836 | style = style.left(n: style.length() - 5); |
837 | return style; |
838 | } |
839 | |
840 | QString QQuickStyleItem1::hitTest(int px, int py) |
841 | { |
842 | QStyle::SubControl subcontrol = QStyle::SC_All; |
843 | switch (m_itemType) { |
844 | case SpinBox :{ |
845 | subcontrol = qApp->style()->hitTestComplexControl(cc: QStyle::CC_SpinBox, |
846 | opt: qstyleoption_cast<QStyleOptionComplex*>(opt: m_styleoption), |
847 | pt: QPoint(px,py), widget: 0); |
848 | if (subcontrol == QStyle::SC_SpinBoxUp) |
849 | return QStringLiteral("up" ); |
850 | else if (subcontrol == QStyle::SC_SpinBoxDown) |
851 | return QStringLiteral("down" ); |
852 | } |
853 | break; |
854 | |
855 | case Slider: { |
856 | subcontrol = qApp->style()->hitTestComplexControl(cc: QStyle::CC_Slider, |
857 | opt: qstyleoption_cast<QStyleOptionComplex*>(opt: m_styleoption), |
858 | pt: QPoint(px,py), widget: 0); |
859 | if (subcontrol == QStyle::SC_SliderHandle) |
860 | return QStringLiteral("handle" ); |
861 | } |
862 | break; |
863 | |
864 | case ScrollBar: { |
865 | subcontrol = qApp->style()->hitTestComplexControl(cc: QStyle::CC_ScrollBar, |
866 | opt: qstyleoption_cast<QStyleOptionComplex*>(opt: m_styleoption), |
867 | pt: QPoint(px,py), widget: 0); |
868 | switch (subcontrol) { |
869 | case QStyle::SC_ScrollBarSlider: |
870 | return QStringLiteral("handle" ); |
871 | |
872 | case QStyle::SC_ScrollBarSubLine: |
873 | return QStringLiteral("up" ); |
874 | |
875 | case QStyle::SC_ScrollBarSubPage: |
876 | return QStringLiteral("upPage" ); |
877 | |
878 | case QStyle::SC_ScrollBarAddLine: |
879 | return QStringLiteral("down" ); |
880 | |
881 | case QStyle::SC_ScrollBarAddPage: |
882 | return QStringLiteral("downPage" ); |
883 | |
884 | default: |
885 | break; |
886 | } |
887 | } |
888 | break; |
889 | |
890 | default: |
891 | break; |
892 | } |
893 | return QStringLiteral("none" ); |
894 | } |
895 | |
896 | QSize QQuickStyleItem1::sizeFromContents(int width, int height) |
897 | { |
898 | initStyleOption(); |
899 | |
900 | QSize size; |
901 | switch (m_itemType) { |
902 | case RadioButton: |
903 | size = qApp->style()->sizeFromContents(ct: QStyle::CT_RadioButton, opt: m_styleoption, contentsSize: QSize(width,height)); |
904 | break; |
905 | case CheckBox: |
906 | size = qApp->style()->sizeFromContents(ct: QStyle::CT_CheckBox, opt: m_styleoption, contentsSize: QSize(width,height)); |
907 | break; |
908 | case ToolBar: |
909 | size = QSize(200, style().contains(s: QLatin1String("windows" )) ? 30 : 42); |
910 | break; |
911 | case ToolButton: { |
912 | QStyleOptionToolButton *btn = qstyleoption_cast<QStyleOptionToolButton*>(opt: m_styleoption); |
913 | int w = 0; |
914 | int h = 0; |
915 | if (btn->toolButtonStyle != Qt::ToolButtonTextOnly) { |
916 | QSize icon = btn->iconSize; |
917 | w = icon.width(); |
918 | h = icon.height(); |
919 | } |
920 | if (btn->toolButtonStyle != Qt::ToolButtonIconOnly) { |
921 | QSize textSize = btn->fontMetrics.size(flags: Qt::TextShowMnemonic, str: btn->text); |
922 | textSize.setWidth(textSize.width() + btn->fontMetrics.horizontalAdvance(QLatin1Char(' '))*2); |
923 | if (btn->toolButtonStyle == Qt::ToolButtonTextUnderIcon) { |
924 | h += 4 + textSize.height(); |
925 | if (textSize.width() > w) |
926 | w = textSize.width(); |
927 | } else if (btn->toolButtonStyle == Qt::ToolButtonTextBesideIcon) { |
928 | w += 4 + textSize.width(); |
929 | if (textSize.height() > h) |
930 | h = textSize.height(); |
931 | } else { // TextOnly |
932 | w = textSize.width(); |
933 | h = textSize.height(); |
934 | } |
935 | } |
936 | btn->rect.setSize(QSize(w, h)); |
937 | size = qApp->style()->sizeFromContents(ct: QStyle::CT_ToolButton, opt: m_styleoption, contentsSize: QSize(w, h)); } |
938 | break; |
939 | case Button: { |
940 | QStyleOptionButton *btn = qstyleoption_cast<QStyleOptionButton*>(opt: m_styleoption); |
941 | |
942 | int contentWidth = btn->fontMetrics.horizontalAdvance(btn->text); |
943 | int contentHeight = btn->fontMetrics.height(); |
944 | if (!btn->icon.isNull()) { |
945 | //+4 matches a hardcoded value in QStyle and acts as a margin between the icon and the text. |
946 | contentWidth += btn->iconSize.width() + 4; |
947 | contentHeight = qMax(a: btn->fontMetrics.height(), b: btn->iconSize.height()); |
948 | } |
949 | int newWidth = qMax(a: width, b: contentWidth); |
950 | int newHeight = qMax(a: height, b: contentHeight); |
951 | size = qApp->style()->sizeFromContents(ct: QStyle::CT_PushButton, opt: m_styleoption, contentsSize: QSize(newWidth, newHeight)); } |
952 | #ifdef Q_OS_OSX |
953 | if (style() == QLatin1String("mac" )) { |
954 | // Cancel out QMacStylePrivate::PushButton*Offset, or part of it |
955 | size -= QSize(7, 6); |
956 | } |
957 | #endif |
958 | break; |
959 | case ComboBox: { |
960 | QStyleOptionComboBox *btn = qstyleoption_cast<QStyleOptionComboBox*>(opt: m_styleoption); |
961 | int newWidth = qMax(a: width, b: btn->fontMetrics.horizontalAdvance(btn->currentText)); |
962 | int newHeight = qMax(a: height, b: btn->fontMetrics.height()); |
963 | size = qApp->style()->sizeFromContents(ct: QStyle::CT_ComboBox, opt: m_styleoption, contentsSize: QSize(newWidth, newHeight)); } |
964 | break; |
965 | case Tab: |
966 | size = qApp->style()->sizeFromContents(ct: QStyle::CT_TabBarTab, opt: m_styleoption, contentsSize: QSize(width,height)); |
967 | break; |
968 | case Slider: |
969 | size = qApp->style()->sizeFromContents(ct: QStyle::CT_Slider, opt: m_styleoption, contentsSize: QSize(width,height)); |
970 | break; |
971 | case ProgressBar: |
972 | size = qApp->style()->sizeFromContents(ct: QStyle::CT_ProgressBar, opt: m_styleoption, contentsSize: QSize(width,height)); |
973 | break; |
974 | case SpinBox: |
975 | #ifdef Q_OS_OSX |
976 | if (style() == QLatin1String("mac" )) { |
977 | size = qApp->style()->sizeFromContents(QStyle::CT_SpinBox, m_styleoption, QSize(width, height + 5)); |
978 | break; |
979 | } |
980 | #endif // fall through if not mac |
981 | case Edit: |
982 | #ifdef Q_OS_OSX |
983 | if (style() == QLatin1String("mac" )) { |
984 | QString sizeHint = m_hints.value(QStringLiteral("size" )).toString(); |
985 | if (sizeHint == QLatin1String("small" ) || sizeHint == QLatin1String("mini" )) |
986 | size = QSize(width, 19); |
987 | else |
988 | size = QSize(width, 22); |
989 | if (hints().value(QStringLiteral("rounded" )).toBool()) |
990 | size += QSize(4, 4); |
991 | |
992 | } else |
993 | #endif |
994 | { |
995 | // We have to create a new style option since we might be calling with a QStyleOptionSpinBox |
996 | QStyleOptionFrame frame; |
997 | frame.state = m_styleoption->state; |
998 | frame.lineWidth = qApp->style()->pixelMetric(metric: QStyle::PM_DefaultFrameWidth, option: m_styleoption, widget: 0); |
999 | frame.rect = m_styleoption->rect; |
1000 | frame.styleObject = this; |
1001 | size = qApp->style()->sizeFromContents(ct: QStyle::CT_LineEdit, opt: &frame, contentsSize: QSize(width, height)); |
1002 | if (m_itemType == SpinBox) |
1003 | size.setWidth(qApp->style()->sizeFromContents(ct: QStyle::CT_SpinBox, |
1004 | opt: m_styleoption, contentsSize: QSize(width + 2, height)).width()); |
1005 | } |
1006 | break; |
1007 | case GroupBox: { |
1008 | QStyleOptionGroupBox *box = qstyleoption_cast<QStyleOptionGroupBox*>(opt: m_styleoption); |
1009 | QFontMetrics metrics(box->fontMetrics); |
1010 | int baseWidth = metrics.horizontalAdvance(box->text) |
1011 | + metrics.horizontalAdvance(QLatin1Char(' ')); |
1012 | int baseHeight = metrics.height() + m_contentHeight; |
1013 | if (box->subControls & QStyle::SC_GroupBoxCheckBox) { |
1014 | baseWidth += qApp->style()->pixelMetric(metric: QStyle::PM_IndicatorWidth); |
1015 | baseWidth += qApp->style()->pixelMetric(metric: QStyle::PM_CheckBoxLabelSpacing); |
1016 | baseHeight = qMax(a: baseHeight, qApp->style()->pixelMetric(metric: QStyle::PM_IndicatorHeight)); |
1017 | } |
1018 | size = qApp->style()->sizeFromContents(ct: QStyle::CT_GroupBox, opt: m_styleoption, contentsSize: QSize(qMax(a: baseWidth, b: m_contentWidth), baseHeight)); |
1019 | } |
1020 | break; |
1021 | case Header: |
1022 | size = qApp->style()->sizeFromContents(ct: QStyle::CT_HeaderSection, opt: m_styleoption, contentsSize: QSize(width,height)); |
1023 | #ifdef Q_OS_OSX |
1024 | if (style() == QLatin1String("mac" )) |
1025 | size.setHeight(15); |
1026 | #endif |
1027 | break; |
1028 | case ItemRow: |
1029 | case Item: //fall through |
1030 | size = qApp->style()->sizeFromContents(ct: QStyle::CT_ItemViewItem, opt: m_styleoption, contentsSize: QSize(width,height)); |
1031 | break; |
1032 | case MenuBarItem: |
1033 | size = qApp->style()->sizeFromContents(ct: QStyle::CT_MenuBarItem, opt: m_styleoption, contentsSize: QSize(width,height)); |
1034 | break; |
1035 | case MenuBar: |
1036 | size = qApp->style()->sizeFromContents(ct: QStyle::CT_MenuBar, opt: m_styleoption, contentsSize: QSize(width,height)); |
1037 | break; |
1038 | case Menu: |
1039 | size = qApp->style()->sizeFromContents(ct: QStyle::CT_Menu, opt: m_styleoption, contentsSize: QSize(width,height)); |
1040 | break; |
1041 | case MenuItem: |
1042 | case ComboBoxItem: |
1043 | if (static_cast<QStyleOptionMenuItem *>(m_styleoption)->menuItemType == QStyleOptionMenuItem::Scroller) { |
1044 | size.setHeight(qMax(a: QApplication::globalStrut().height(), |
1045 | qApp->style()->pixelMetric(metric: QStyle::PM_MenuScrollerHeight, option: 0, widget: 0))); |
1046 | } else { |
1047 | size = qApp->style()->sizeFromContents(ct: QStyle::CT_MenuItem, opt: m_styleoption, contentsSize: QSize(width,height)); |
1048 | } |
1049 | break; |
1050 | default: |
1051 | break; |
1052 | } return size; |
1053 | } |
1054 | |
1055 | qreal QQuickStyleItem1::baselineOffset() |
1056 | { |
1057 | QRect r; |
1058 | bool ceilResult = true; // By default baseline offset rounding is done upwards |
1059 | switch (m_itemType) { |
1060 | case RadioButton: |
1061 | r = qApp->style()->subElementRect(subElement: QStyle::SE_RadioButtonContents, option: m_styleoption); |
1062 | break; |
1063 | case Button: |
1064 | r = qApp->style()->subElementRect(subElement: QStyle::SE_PushButtonContents, option: m_styleoption); |
1065 | break; |
1066 | case CheckBox: |
1067 | r = qApp->style()->subElementRect(subElement: QStyle::SE_CheckBoxContents, option: m_styleoption); |
1068 | break; |
1069 | case Edit: |
1070 | r = qApp->style()->subElementRect(subElement: QStyle::SE_LineEditContents, option: m_styleoption); |
1071 | break; |
1072 | case ComboBox: |
1073 | if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt: m_styleoption)) { |
1074 | r = qApp->style()->subControlRect(cc: QStyle::CC_ComboBox, opt: combo, sc: QStyle::SC_ComboBoxEditField); |
1075 | if (style() != QLatin1String("mac" )) |
1076 | r.adjust(dx1: 0,dy1: 0,dx2: 0,dy2: 1); |
1077 | } |
1078 | break; |
1079 | #if QT_CONFIG(spinbox) |
1080 | case SpinBox: |
1081 | if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(opt: m_styleoption)) { |
1082 | r = qApp->style()->subControlRect(cc: QStyle::CC_SpinBox, opt: spinbox, sc: QStyle::SC_SpinBoxEditField); |
1083 | ceilResult = false; |
1084 | } |
1085 | break; |
1086 | #endif |
1087 | default: |
1088 | break; |
1089 | } |
1090 | if (r.height() > 0) { |
1091 | const QFontMetrics &fm = m_styleoption->fontMetrics; |
1092 | int surplus = r.height() - fm.height(); |
1093 | if ((surplus & 1) && ceilResult) |
1094 | surplus++; |
1095 | int result = r.top() + surplus/2 + fm.ascent(); |
1096 | #ifdef Q_OS_OSX |
1097 | if (style() == QLatin1String("mac" )) { |
1098 | switch (m_itemType) { |
1099 | case Button: |
1100 | case Edit: |
1101 | result -= 1; |
1102 | break; |
1103 | case ComboBox: |
1104 | // adjust back the adjustments done in drawControl(CE_ComboBoxLabel) |
1105 | result += 1; |
1106 | break; |
1107 | default: |
1108 | break; |
1109 | } |
1110 | } |
1111 | #endif |
1112 | return result; |
1113 | } |
1114 | |
1115 | return 0.; |
1116 | } |
1117 | |
1118 | void QQuickStyleItem1::updateBaselineOffset() |
1119 | { |
1120 | const qreal baseline = baselineOffset(); |
1121 | if (baseline > 0) |
1122 | setBaselineOffset(baseline); |
1123 | } |
1124 | |
1125 | void QQuickStyleItem1::setContentWidth(int arg) |
1126 | { |
1127 | if (m_contentWidth != arg) { |
1128 | m_contentWidth = arg; |
1129 | emit contentWidthChanged(arg); |
1130 | } |
1131 | } |
1132 | |
1133 | void QQuickStyleItem1::setContentHeight(int arg) |
1134 | { |
1135 | if (m_contentHeight != arg) { |
1136 | m_contentHeight = arg; |
1137 | emit contentHeightChanged(arg); |
1138 | } |
1139 | } |
1140 | |
1141 | void QQuickStyleItem1::updateSizeHint() |
1142 | { |
1143 | QSize implicitSize = sizeFromContents(width: m_contentWidth, height: m_contentHeight); |
1144 | setImplicitSize(implicitSize.width(), implicitSize.height()); |
1145 | } |
1146 | |
1147 | void QQuickStyleItem1::updateRect() |
1148 | { |
1149 | initStyleOption(); |
1150 | m_styleoption->rect.setWidth(width()); |
1151 | m_styleoption->rect.setHeight(height()); |
1152 | } |
1153 | |
1154 | int QQuickStyleItem1::pixelMetric(const QString &metric) |
1155 | { |
1156 | |
1157 | if (metric == QLatin1String("scrollbarExtent" )) |
1158 | return qApp->style()->pixelMetric(metric: QStyle::PM_ScrollBarExtent, option: 0 ); |
1159 | else if (metric == QLatin1String("defaultframewidth" )) |
1160 | return qApp->style()->pixelMetric(metric: QStyle::PM_DefaultFrameWidth, option: m_styleoption); |
1161 | else if (metric == QLatin1String("taboverlap" )) |
1162 | return qApp->style()->pixelMetric(metric: QStyle::PM_TabBarTabOverlap, option: 0 ); |
1163 | else if (metric == QLatin1String("tabbaseoverlap" )) |
1164 | return qApp->style()->pixelMetric(metric: QStyle::PM_TabBarBaseOverlap, option: m_styleoption ); |
1165 | else if (metric == QLatin1String("tabhspace" )) |
1166 | return qApp->style()->pixelMetric(metric: QStyle::PM_TabBarTabHSpace, option: 0 ); |
1167 | else if (metric == QLatin1String("indicatorwidth" )) |
1168 | return qApp->style()->pixelMetric(metric: QStyle::PM_ExclusiveIndicatorWidth, option: 0 ); |
1169 | else if (metric == QLatin1String("tabvspace" )) |
1170 | return qApp->style()->pixelMetric(metric: QStyle::PM_TabBarTabVSpace, option: 0 ); |
1171 | else if (metric == QLatin1String("tabbaseheight" )) |
1172 | return qApp->style()->pixelMetric(metric: QStyle::PM_TabBarBaseHeight, option: 0 ); |
1173 | else if (metric == QLatin1String("tabvshift" )) |
1174 | return qApp->style()->pixelMetric(metric: QStyle::PM_TabBarTabShiftVertical, option: 0 ); |
1175 | else if (metric == QLatin1String("menubarhmargin" )) |
1176 | return qApp->style()->pixelMetric(metric: QStyle::PM_MenuBarHMargin, option: 0 ); |
1177 | else if (metric == QLatin1String("menubarvmargin" )) |
1178 | return qApp->style()->pixelMetric(metric: QStyle::PM_MenuBarVMargin, option: 0 ); |
1179 | else if (metric == QLatin1String("menubarpanelwidth" )) |
1180 | return qApp->style()->pixelMetric(metric: QStyle::PM_MenuBarPanelWidth, option: 0 ); |
1181 | else if (metric == QLatin1String("menubaritemspacing" )) |
1182 | return qApp->style()->pixelMetric(metric: QStyle::PM_MenuBarItemSpacing, option: 0 ); |
1183 | else if (metric == QLatin1String("spacebelowmenubar" )) |
1184 | return qApp->style()->styleHint(stylehint: QStyle::SH_MainWindow_SpaceBelowMenuBar, opt: m_styleoption); |
1185 | else if (metric == QLatin1String("menuhmargin" )) |
1186 | return qApp->style()->pixelMetric(metric: QStyle::PM_MenuHMargin, option: 0 ); |
1187 | else if (metric == QLatin1String("menuvmargin" )) |
1188 | return qApp->style()->pixelMetric(metric: QStyle::PM_MenuVMargin, option: 0 ); |
1189 | else if (metric == QLatin1String("menupanelwidth" )) |
1190 | return qApp->style()->pixelMetric(metric: QStyle::PM_MenuPanelWidth, option: 0 ); |
1191 | else if (metric == QLatin1String("submenuoverlap" )) |
1192 | return qApp->style()->pixelMetric(metric: QStyle::PM_SubMenuOverlap, option: 0 ); |
1193 | else if (metric == QLatin1String("splitterwidth" )) |
1194 | return qApp->style()->pixelMetric(metric: QStyle::PM_SplitterWidth, option: 0 ); |
1195 | else if (metric == QLatin1String("scrollbarspacing" )) |
1196 | return abs(qApp->style()->pixelMetric(metric: QStyle::PM_ScrollView_ScrollBarSpacing, option: 0 )); |
1197 | else if (metric == QLatin1String("treeviewindentation" )) |
1198 | return qApp->style()->pixelMetric(metric: QStyle::PM_TreeViewIndentation, option: 0 ); |
1199 | return 0; |
1200 | } |
1201 | |
1202 | QVariant QQuickStyleItem1::styleHint(const QString &metric) |
1203 | { |
1204 | initStyleOption(); |
1205 | if (metric == QLatin1String("comboboxpopup" )) { |
1206 | return qApp->style()->styleHint(stylehint: QStyle::SH_ComboBox_Popup, opt: m_styleoption); |
1207 | } else if (metric == QLatin1String("highlightedTextColor" )) { |
1208 | return m_styleoption->palette.highlightedText().color().name(); |
1209 | } else if (metric == QLatin1String("textColor" )) { |
1210 | QPalette pal = m_styleoption->palette; |
1211 | pal.setCurrentColorGroup(active()? QPalette::Active : QPalette::Inactive); |
1212 | return pal.text().color().name(); |
1213 | } else if (metric == QLatin1String("focuswidget" )) { |
1214 | return qApp->style()->styleHint(stylehint: QStyle::SH_FocusFrame_AboveWidget); |
1215 | } else if (metric == QLatin1String("tabbaralignment" )) { |
1216 | int result = qApp->style()->styleHint(stylehint: QStyle::SH_TabBar_Alignment); |
1217 | if (result == Qt::AlignCenter) |
1218 | return QStringLiteral("center" ); |
1219 | return QStringLiteral("left" ); |
1220 | } else if (metric == QLatin1String("externalScrollBars" )) { |
1221 | return qApp->style()->styleHint(stylehint: QStyle::SH_ScrollView_FrameOnlyAroundContents); |
1222 | } else if (metric == QLatin1String("scrollToClickPosition" )) |
1223 | return qApp->style()->styleHint(stylehint: QStyle::SH_ScrollBar_LeftClickAbsolutePosition); |
1224 | else if (metric == QLatin1String("activateItemOnSingleClick" )) |
1225 | return qApp->style()->styleHint(stylehint: QStyle::SH_ItemView_ActivateItemOnSingleClick); |
1226 | else if (metric == QLatin1String("submenupopupdelay" )) |
1227 | return qApp->style()->styleHint(stylehint: QStyle::SH_Menu_SubMenuPopupDelay, opt: m_styleoption); |
1228 | #if QT_CONFIG(wheelevent) |
1229 | else if (metric == QLatin1String("wheelScrollLines" )) |
1230 | return qApp->wheelScrollLines(); |
1231 | #endif |
1232 | return 0; |
1233 | |
1234 | // Add SH_Menu_SpaceActivatesItem |
1235 | } |
1236 | |
1237 | void QQuickStyleItem1::setHints(const QVariantMap &str) |
1238 | { |
1239 | if (m_hints != str) { |
1240 | m_hints = str; |
1241 | initStyleOption(); |
1242 | updateSizeHint(); |
1243 | if (m_styleoption->state & QStyle::State_Mini) { |
1244 | m_font.setPointSize(9.); |
1245 | emit fontChanged(); |
1246 | } else if (m_styleoption->state & QStyle::State_Small) { |
1247 | m_font.setPointSize(11.); |
1248 | emit fontChanged(); |
1249 | } else { |
1250 | emit hintChanged(); |
1251 | } |
1252 | } |
1253 | } |
1254 | |
1255 | void QQuickStyleItem1::resetHints() |
1256 | { |
1257 | m_hints.clear(); |
1258 | } |
1259 | |
1260 | |
1261 | void QQuickStyleItem1::setElementType(const QString &str) |
1262 | { |
1263 | if (m_type == str) |
1264 | return; |
1265 | |
1266 | m_type = str; |
1267 | |
1268 | emit elementTypeChanged(); |
1269 | if (m_styleoption) { |
1270 | delete m_styleoption; |
1271 | m_styleoption = 0; |
1272 | } |
1273 | |
1274 | // Only enable visible if the widget can animate |
1275 | if (str == QLatin1String("menu" )) { |
1276 | m_itemType = Menu; |
1277 | } else if (str == QLatin1String("menuitem" )) { |
1278 | m_itemType = MenuItem; |
1279 | } else if (str == QLatin1String("item" ) || str == QLatin1String("itemrow" ) || str == QLatin1String("header" )) { |
1280 | #ifdef Q_OS_OSX |
1281 | m_font.setPointSize(11.0); |
1282 | emit fontChanged(); |
1283 | #endif |
1284 | if (str == QLatin1String("header" )) { |
1285 | m_itemType = Header; |
1286 | } else { |
1287 | m_itemType = str == QLatin1String("item" ) ? Item : ItemRow; |
1288 | } |
1289 | } else if (str == QLatin1String("itembranchindicator" )) { |
1290 | m_itemType = ItemBranchIndicator; |
1291 | } else if (str == QLatin1String("groupbox" )) { |
1292 | m_itemType = GroupBox; |
1293 | } else if (str == QLatin1String("tab" )) { |
1294 | m_itemType = Tab; |
1295 | } else if (str == QLatin1String("tabframe" )) { |
1296 | m_itemType = TabFrame; |
1297 | } else if (str == QLatin1String("comboboxitem" )) { |
1298 | // Gtk uses qobject cast, hence we need to separate this from menuitem |
1299 | // On mac, we temporarily use the menu item because it has more accurate |
1300 | // palette. |
1301 | m_itemType = ComboBoxItem; |
1302 | } else if (str == QLatin1String("toolbar" )) { |
1303 | m_itemType = ToolBar; |
1304 | } else if (str == QLatin1String("toolbutton" )) { |
1305 | m_itemType = ToolButton; |
1306 | } else if (str == QLatin1String("slider" )) { |
1307 | m_itemType = Slider; |
1308 | } else if (str == QLatin1String("frame" )) { |
1309 | m_itemType = Frame; |
1310 | } else if (str == QLatin1String("combobox" )) { |
1311 | m_itemType = ComboBox; |
1312 | } else if (str == QLatin1String("splitter" )) { |
1313 | m_itemType = Splitter; |
1314 | } else if (str == QLatin1String("progressbar" )) { |
1315 | m_itemType = ProgressBar; |
1316 | } else if (str == QLatin1String("button" )) { |
1317 | m_itemType = Button; |
1318 | } else if (str == QLatin1String("checkbox" )) { |
1319 | m_itemType = CheckBox; |
1320 | } else if (str == QLatin1String("radiobutton" )) { |
1321 | m_itemType = RadioButton; |
1322 | } else if (str == QLatin1String("edit" )) { |
1323 | m_itemType = Edit; |
1324 | } else if (str == QLatin1String("spinbox" )) { |
1325 | m_itemType = SpinBox; |
1326 | } else if (str == QLatin1String("scrollbar" )) { |
1327 | m_itemType = ScrollBar; |
1328 | } else if (str == QLatin1String("widget" )) { |
1329 | m_itemType = Widget; |
1330 | } else if (str == QLatin1String("focusframe" )) { |
1331 | m_itemType = FocusFrame; |
1332 | } else if (str == QLatin1String("focusrect" )) { |
1333 | m_itemType = FocusRect; |
1334 | } else if (str == QLatin1String("dial" )) { |
1335 | m_itemType = Dial; |
1336 | } else if (str == QLatin1String("statusbar" )) { |
1337 | m_itemType = StatusBar; |
1338 | } else if (str == QLatin1String("machelpbutton" )) { |
1339 | m_itemType = MacHelpButton; |
1340 | } else if (str == QLatin1String("scrollareacorner" )) { |
1341 | m_itemType = ScrollAreaCorner; |
1342 | } else if (str == QLatin1String("menubar" )) { |
1343 | m_itemType = MenuBar; |
1344 | } else if (str == QLatin1String("menubaritem" )) { |
1345 | m_itemType = MenuBarItem; |
1346 | } else { |
1347 | m_itemType = Undefined; |
1348 | } |
1349 | updateSizeHint(); |
1350 | } |
1351 | |
1352 | QRectF QQuickStyleItem1::subControlRect(const QString &subcontrolString) |
1353 | { |
1354 | QStyle::SubControl subcontrol = QStyle::SC_None; |
1355 | initStyleOption(); |
1356 | switch (m_itemType) { |
1357 | case SpinBox: |
1358 | { |
1359 | QStyle::ComplexControl control = QStyle::CC_SpinBox; |
1360 | if (subcontrolString == QLatin1String("down" )) |
1361 | subcontrol = QStyle::SC_SpinBoxDown; |
1362 | else if (subcontrolString == QLatin1String("up" )) |
1363 | subcontrol = QStyle::SC_SpinBoxUp; |
1364 | else if (subcontrolString == QLatin1String("edit" )){ |
1365 | subcontrol = QStyle::SC_SpinBoxEditField; |
1366 | } |
1367 | return qApp->style()->subControlRect(cc: control, |
1368 | opt: qstyleoption_cast<QStyleOptionComplex*>(opt: m_styleoption), |
1369 | sc: subcontrol); |
1370 | |
1371 | } |
1372 | break; |
1373 | case Slider: |
1374 | { |
1375 | QStyle::ComplexControl control = QStyle::CC_Slider; |
1376 | if (subcontrolString == QLatin1String("handle" )) |
1377 | subcontrol = QStyle::SC_SliderHandle; |
1378 | else if (subcontrolString == QLatin1String("groove" )) |
1379 | subcontrol = QStyle::SC_SliderGroove; |
1380 | return qApp->style()->subControlRect(cc: control, |
1381 | opt: qstyleoption_cast<QStyleOptionComplex*>(opt: m_styleoption), |
1382 | sc: subcontrol); |
1383 | |
1384 | } |
1385 | break; |
1386 | case ScrollBar: |
1387 | { |
1388 | QStyle::ComplexControl control = QStyle::CC_ScrollBar; |
1389 | if (subcontrolString == QLatin1String("slider" )) |
1390 | subcontrol = QStyle::SC_ScrollBarSlider; |
1391 | if (subcontrolString == QLatin1String("groove" )) |
1392 | subcontrol = QStyle::SC_ScrollBarGroove; |
1393 | else if (subcontrolString == QLatin1String("handle" )) |
1394 | subcontrol = QStyle::SC_ScrollBarSlider; |
1395 | else if (subcontrolString == QLatin1String("add" )) |
1396 | subcontrol = QStyle::SC_ScrollBarAddPage; |
1397 | else if (subcontrolString == QLatin1String("sub" )) |
1398 | subcontrol = QStyle::SC_ScrollBarSubPage; |
1399 | return qApp->style()->subControlRect(cc: control, |
1400 | opt: qstyleoption_cast<QStyleOptionComplex*>(opt: m_styleoption), |
1401 | sc: subcontrol); |
1402 | } |
1403 | break; |
1404 | case ItemBranchIndicator: { |
1405 | QStyleOption opt; |
1406 | opt.rect = QRect(0, 0, implicitWidth(), implicitHeight()); |
1407 | return qApp->style()->subElementRect(subElement: QStyle::SE_TreeViewDisclosureItem, option: &opt, widget: 0); |
1408 | } |
1409 | default: |
1410 | break; |
1411 | } |
1412 | return QRectF(); |
1413 | } |
1414 | |
1415 | namespace { |
1416 | class QHighDpiPixmapsEnabler1 { |
1417 | public: |
1418 | QHighDpiPixmapsEnabler1() |
1419 | :wasEnabled(false) |
1420 | { |
1421 | if (!qApp->testAttribute(attribute: Qt::AA_UseHighDpiPixmaps)) { |
1422 | qApp->setAttribute(attribute: Qt::AA_UseHighDpiPixmaps); |
1423 | wasEnabled = true; |
1424 | } |
1425 | } |
1426 | |
1427 | ~QHighDpiPixmapsEnabler1() |
1428 | { |
1429 | if (wasEnabled) |
1430 | qApp->setAttribute(attribute: Qt::AA_UseHighDpiPixmaps, on: false); |
1431 | } |
1432 | private: |
1433 | bool wasEnabled; |
1434 | }; |
1435 | } |
1436 | |
1437 | void QQuickStyleItem1::paint(QPainter *painter) |
1438 | { |
1439 | initStyleOption(); |
1440 | if (QStyleOptionMenuItem *opt = qstyleoption_cast<QStyleOptionMenuItem*>(opt: m_styleoption)) |
1441 | painter->setFont(opt->font); |
1442 | else { |
1443 | QPlatformTheme::Font platformFont = (m_styleoption->state & QStyle::State_Mini) ? QPlatformTheme::MiniFont : |
1444 | (m_styleoption->state & QStyle::State_Small) ? QPlatformTheme::SmallFont : |
1445 | QPlatformTheme::NFonts; |
1446 | if (platformFont != QPlatformTheme::NFonts) |
1447 | if (const QFont *font = QGuiApplicationPrivate::platformTheme()->font(type: platformFont)) |
1448 | painter->setFont(*font); |
1449 | } |
1450 | |
1451 | // Set AA_UseHighDpiPixmaps when calling style code to make QIcon return |
1452 | // "retina" pixmaps. The flag is controlled by the application so we can't |
1453 | // set it unconditinally. |
1454 | QHighDpiPixmapsEnabler1 enabler; |
1455 | |
1456 | switch (m_itemType) { |
1457 | case Button: |
1458 | #ifdef Q_OS_OSX |
1459 | if (style() == QLatin1String("mac" )) { |
1460 | // Add back what was substracted in sizeFromContents() |
1461 | m_styleoption->rect.adjust(-4, -2, 3, 4); |
1462 | } |
1463 | #endif |
1464 | qApp->style()->drawControl(element: QStyle::CE_PushButton, opt: m_styleoption, p: painter); |
1465 | break; |
1466 | case ItemRow :{ |
1467 | QPixmap pixmap; |
1468 | // Only draw through style once |
1469 | const QString pmKey = QLatin1String("itemrow" ) % QString::number(m_styleoption->state,base: 16) % activeControl(); |
1470 | if (!QPixmapCache::find(key: pmKey, pixmap: &pixmap) || pixmap.width() < width() || height() != pixmap.height()) { |
1471 | int newSize = width(); |
1472 | pixmap = QPixmap(newSize, height()); |
1473 | pixmap.fill(fillColor: Qt::transparent); |
1474 | QPainter pixpainter(&pixmap); |
1475 | qApp->style()->drawPrimitive(pe: QStyle::PE_PanelItemViewRow, opt: m_styleoption, p: &pixpainter); |
1476 | if ((style() == QLatin1String("mac" ) || !qApp->style()->styleHint(stylehint: QStyle::SH_ItemView_ShowDecorationSelected)) && selected()) { |
1477 | QPalette pal = QApplication::palette(className: "QAbstractItemView" ); |
1478 | pal.setCurrentColorGroup(m_styleoption->palette.currentColorGroup()); |
1479 | pixpainter.fillRect(m_styleoption->rect, pal.highlight()); |
1480 | } |
1481 | QPixmapCache::insert(key: pmKey, pixmap); |
1482 | } |
1483 | painter->drawPixmap(x: 0, y: 0, pm: pixmap); |
1484 | } |
1485 | break; |
1486 | case Item: |
1487 | qApp->style()->drawControl(element: QStyle::CE_ItemViewItem, opt: m_styleoption, p: painter); |
1488 | break; |
1489 | case ItemBranchIndicator: |
1490 | qApp->style()->drawPrimitive(pe: QStyle::PE_IndicatorBranch, opt: m_styleoption, p: painter); |
1491 | break; |
1492 | case Header: |
1493 | qApp->style()->drawControl(element: QStyle::CE_Header, opt: m_styleoption, p: painter); |
1494 | break; |
1495 | case ToolButton: |
1496 | |
1497 | #ifdef Q_OS_OSX |
1498 | if (style() == QLatin1String("mac" ) && hints().value(QStringLiteral("segmented" )).toBool()) { |
1499 | const QPaintDevice *target = painter->device(); |
1500 | HIThemeSegmentDrawInfo sgi; |
1501 | sgi.version = 0; |
1502 | sgi.state = isEnabled() ? kThemeStateActive : kThemeStateDisabled; |
1503 | if (sunken()) sgi.state |= kThemeStatePressed; |
1504 | sgi.size = kHIThemeSegmentSizeNormal; |
1505 | sgi.kind = kHIThemeSegmentKindTextured; |
1506 | sgi.value = on() && !sunken() ? kThemeButtonOn : kThemeButtonOff; |
1507 | |
1508 | sgi.adornment |= kHIThemeSegmentAdornmentLeadingSeparator; |
1509 | if (sunken()) { |
1510 | sgi.adornment |= kHIThemeSegmentAdornmentTrailingSeparator; |
1511 | } |
1512 | SInt32 button_height; |
1513 | GetThemeMetric(kThemeMetricButtonRoundedHeight, &button_height); |
1514 | QString buttonPos = m_properties.value(QStringLiteral("position" )).toString(); |
1515 | sgi.position = buttonPos == QLatin1String("leftmost" ) ? kHIThemeSegmentPositionFirst : |
1516 | buttonPos == QLatin1String("rightmost" ) ? kHIThemeSegmentPositionLast : |
1517 | buttonPos == QLatin1String("h_middle" ) ? kHIThemeSegmentPositionMiddle : |
1518 | kHIThemeSegmentPositionOnly; |
1519 | QRect centered = m_styleoption->rect; |
1520 | centered.setHeight(button_height); |
1521 | centered.moveCenter(m_styleoption->rect.center()); |
1522 | HIRect hirect = qt_hirectForQRect(centered.translated(0, -1), QRect(0, 0, 0, 0)); |
1523 | HIThemeDrawSegment(&hirect, &sgi, qt_mac_cg_context(target), kHIThemeOrientationNormal); |
1524 | } else |
1525 | #endif |
1526 | qApp->style()->drawComplexControl(cc: QStyle::CC_ToolButton, opt: qstyleoption_cast<QStyleOptionComplex*>(opt: m_styleoption), p: painter); |
1527 | break; |
1528 | case Tab: |
1529 | #ifdef Q_OS_OSX |
1530 | if (style() == QLatin1String("mac" )) { |
1531 | m_styleoption->rect.translate(0, 1); // Unhack QMacStyle's hack |
1532 | qApp->style()->drawControl(QStyle::CE_TabBarTabShape, m_styleoption, painter); |
1533 | m_styleoption->rect.translate(0, -1); |
1534 | qApp->style()->drawControl(QStyle::CE_TabBarTabLabel, m_styleoption, painter); |
1535 | } else |
1536 | #endif |
1537 | { |
1538 | qApp->style()->drawControl(element: QStyle::CE_TabBarTab, opt: m_styleoption, p: painter); |
1539 | } |
1540 | break; |
1541 | case Frame: |
1542 | qApp->style()->drawControl(element: QStyle::CE_ShapedFrame, opt: m_styleoption, p: painter); |
1543 | break; |
1544 | case FocusFrame: |
1545 | qApp->style()->drawControl(element: QStyle::CE_FocusFrame, opt: m_styleoption, p: painter); |
1546 | break; |
1547 | case FocusRect: |
1548 | qApp->style()->drawPrimitive(pe: QStyle::PE_FrameFocusRect, opt: m_styleoption, p: painter); |
1549 | break; |
1550 | case TabFrame: |
1551 | qApp->style()->drawPrimitive(pe: QStyle::PE_FrameTabWidget, opt: m_styleoption, p: painter); |
1552 | break; |
1553 | case MenuBar: |
1554 | qApp->style()->drawControl(element: QStyle::CE_MenuBarEmptyArea, opt: m_styleoption, p: painter); |
1555 | break; |
1556 | case MenuBarItem: |
1557 | qApp->style()->drawControl(element: QStyle::CE_MenuBarItem, opt: m_styleoption, p: painter); |
1558 | break; |
1559 | case MenuItem: |
1560 | case ComboBoxItem: { // fall through |
1561 | QStyle::ControlElement = |
1562 | static_cast<QStyleOptionMenuItem *>(m_styleoption)->menuItemType == QStyleOptionMenuItem::Scroller ? |
1563 | QStyle::CE_MenuScroller : QStyle::CE_MenuItem; |
1564 | qApp->style()->drawControl(element: menuElement, opt: m_styleoption, p: painter); |
1565 | } |
1566 | break; |
1567 | case CheckBox: |
1568 | qApp->style()->drawControl(element: QStyle::CE_CheckBox, opt: m_styleoption, p: painter); |
1569 | break; |
1570 | case RadioButton: |
1571 | qApp->style()->drawControl(element: QStyle::CE_RadioButton, opt: m_styleoption, p: painter); |
1572 | break; |
1573 | case Edit: { |
1574 | #ifdef Q_OS_OSX |
1575 | if (style() == QLatin1String("mac" ) && hints().value(QStringLiteral("rounded" )).toBool()) { |
1576 | const QPaintDevice *target = painter->device(); |
1577 | HIThemeFrameDrawInfo fdi; |
1578 | fdi.version = 0; |
1579 | fdi.state = kThemeStateActive; |
1580 | SInt32 frame_size; |
1581 | GetThemeMetric(kThemeMetricEditTextFrameOutset, &frame_size); |
1582 | fdi.kind = kHIThemeFrameTextFieldRound; |
1583 | if ((m_styleoption->state & QStyle::State_ReadOnly) || !(m_styleoption->state & QStyle::State_Enabled)) |
1584 | fdi.state = kThemeStateInactive; |
1585 | fdi.isFocused = hasFocus(); |
1586 | HIRect hirect = qt_hirectForQRect(m_styleoption->rect.adjusted(2, 2, -2, 2), QRect(0, 0, 0, 0)); |
1587 | HIThemeDrawFrame(&hirect, &fdi, qt_mac_cg_context(target), kHIThemeOrientationNormal); |
1588 | } else |
1589 | #endif |
1590 | qApp->style()->drawPrimitive(pe: QStyle::PE_PanelLineEdit, opt: m_styleoption, p: painter); |
1591 | } |
1592 | break; |
1593 | case MacHelpButton: |
1594 | #ifdef Q_OS_OSX |
1595 | { |
1596 | const QPaintDevice *target = painter->device(); |
1597 | HIThemeButtonDrawInfo fdi; |
1598 | fdi.kind = kThemeRoundButtonHelp; |
1599 | fdi.version = 0; |
1600 | fdi.adornment = 0; |
1601 | fdi.state = sunken() ? kThemeStatePressed : kThemeStateActive; |
1602 | HIRect hirect = qt_hirectForQRect(m_styleoption->rect,QRect(0, 0, 0, 0)); |
1603 | HIThemeDrawButton(&hirect, &fdi, qt_mac_cg_context(target), kHIThemeOrientationNormal, NULL); |
1604 | } |
1605 | #endif |
1606 | break; |
1607 | case Widget: |
1608 | qApp->style()->drawPrimitive(pe: QStyle::PE_Widget, opt: m_styleoption, p: painter); |
1609 | break; |
1610 | case ScrollAreaCorner: |
1611 | qApp->style()->drawPrimitive(pe: QStyle::PE_PanelScrollAreaCorner, opt: m_styleoption, p: painter); |
1612 | break; |
1613 | case Splitter: |
1614 | if (m_styleoption->rect.width() == 1) |
1615 | painter->fillRect(x: 0, y: 0, w: width(), h: height(), b: m_styleoption->palette.dark().color()); |
1616 | else |
1617 | qApp->style()->drawControl(element: QStyle::CE_Splitter, opt: m_styleoption, p: painter); |
1618 | break; |
1619 | case ComboBox: |
1620 | { |
1621 | qApp->style()->drawComplexControl(cc: QStyle::CC_ComboBox, |
1622 | opt: qstyleoption_cast<QStyleOptionComplex*>(opt: m_styleoption), |
1623 | p: painter); |
1624 | // This is needed on mac as it will use the painter color and ignore the palette |
1625 | QPen pen = painter->pen(); |
1626 | painter->setPen(m_styleoption->palette.text().color()); |
1627 | qApp->style()->drawControl(element: QStyle::CE_ComboBoxLabel, opt: m_styleoption, p: painter); |
1628 | painter->setPen(pen); |
1629 | } break; |
1630 | case SpinBox: |
1631 | #ifdef Q_OS_MAC |
1632 | // macstyle depends on the embedded qlineedit to fill the editfield background |
1633 | if (style() == QLatin1String("mac" )) { |
1634 | QRect editRect = qApp->style()->subControlRect(QStyle::CC_SpinBox, |
1635 | qstyleoption_cast<QStyleOptionComplex*>(m_styleoption), |
1636 | QStyle::SC_SpinBoxEditField); |
1637 | painter->fillRect(editRect.adjusted(-1, -1, 1, 1), m_styleoption->palette.base()); |
1638 | } |
1639 | #endif |
1640 | qApp->style()->drawComplexControl(cc: QStyle::CC_SpinBox, |
1641 | opt: qstyleoption_cast<QStyleOptionComplex*>(opt: m_styleoption), |
1642 | p: painter); |
1643 | break; |
1644 | case Slider: |
1645 | qApp->style()->drawComplexControl(cc: QStyle::CC_Slider, |
1646 | opt: qstyleoption_cast<QStyleOptionComplex*>(opt: m_styleoption), |
1647 | p: painter); |
1648 | break; |
1649 | case Dial: |
1650 | qApp->style()->drawComplexControl(cc: QStyle::CC_Dial, |
1651 | opt: qstyleoption_cast<QStyleOptionComplex*>(opt: m_styleoption), |
1652 | p: painter); |
1653 | break; |
1654 | case ProgressBar: |
1655 | qApp->style()->drawControl(element: QStyle::CE_ProgressBar, opt: m_styleoption, p: painter); |
1656 | break; |
1657 | case ToolBar: |
1658 | painter->fillRect(m_styleoption->rect, color: m_styleoption->palette.window().color()); |
1659 | qApp->style()->drawControl(element: QStyle::CE_ToolBar, opt: m_styleoption, p: painter); |
1660 | painter->save(); |
1661 | painter->setPen(style() != QLatin1String("fusion" ) ? m_styleoption->palette.dark().color().darker(f: 120) : |
1662 | m_styleoption->palette.window().color().lighter(f: 107)); |
1663 | painter->drawLine(p1: m_styleoption->rect.bottomLeft(), p2: m_styleoption->rect.bottomRight()); |
1664 | painter->restore(); |
1665 | break; |
1666 | case StatusBar: |
1667 | #ifdef Q_OS_OSX |
1668 | if (style() == QLatin1String("mac" )) { |
1669 | qApp->style()->drawControl(QStyle::CE_ToolBar, m_styleoption, painter); |
1670 | painter->setPen(m_styleoption->palette.dark().color().darker(120)); |
1671 | painter->drawLine(m_styleoption->rect.topLeft(), m_styleoption->rect.topRight()); |
1672 | } else |
1673 | #endif |
1674 | { |
1675 | painter->fillRect(m_styleoption->rect, color: m_styleoption->palette.window().color()); |
1676 | painter->setPen(m_styleoption->palette.dark().color().darker(f: 120)); |
1677 | painter->drawLine(p1: m_styleoption->rect.topLeft(), p2: m_styleoption->rect.topRight()); |
1678 | qApp->style()->drawPrimitive(pe: QStyle::PE_PanelStatusBar, opt: m_styleoption, p: painter); |
1679 | } |
1680 | break; |
1681 | case GroupBox: |
1682 | qApp->style()->drawComplexControl(cc: QStyle::CC_GroupBox, opt: qstyleoption_cast<QStyleOptionComplex*>(opt: m_styleoption), p: painter); |
1683 | break; |
1684 | case ScrollBar: |
1685 | qApp->style()->drawComplexControl(cc: QStyle::CC_ScrollBar, opt: qstyleoption_cast<QStyleOptionComplex*>(opt: m_styleoption), p: painter); |
1686 | break; |
1687 | case Menu: { |
1688 | QStyleHintReturnMask val; |
1689 | qApp->style()->styleHint(stylehint: QStyle::SH_Menu_Mask, opt: m_styleoption, widget: 0, returnData: &val); |
1690 | painter->save(); |
1691 | painter->setClipRegion(val.region); |
1692 | painter->fillRect(m_styleoption->rect, m_styleoption->palette.window()); |
1693 | painter->restore(); |
1694 | qApp->style()->drawPrimitive(pe: QStyle::PE_PanelMenu, opt: m_styleoption, p: painter); |
1695 | |
1696 | if (int fw = qApp->style()->pixelMetric(metric: QStyle::PM_MenuPanelWidth)) { |
1697 | QStyleOptionFrame frame; |
1698 | frame.state = QStyle::State_None; |
1699 | frame.lineWidth = fw; |
1700 | frame.midLineWidth = 0; |
1701 | frame.rect = m_styleoption->rect; |
1702 | frame.styleObject = this; |
1703 | frame.palette = m_styleoption->palette; |
1704 | qApp->style()->drawPrimitive(pe: QStyle::PE_FrameMenu, opt: &frame, p: painter); |
1705 | } |
1706 | } |
1707 | break; |
1708 | default: |
1709 | break; |
1710 | } |
1711 | } |
1712 | |
1713 | qreal QQuickStyleItem1::textWidth(const QString &text) |
1714 | { |
1715 | QFontMetricsF fm = QFontMetricsF(m_styleoption->fontMetrics); |
1716 | return fm.boundingRect(string: text).width(); |
1717 | } |
1718 | |
1719 | qreal QQuickStyleItem1::textHeight(const QString &text) |
1720 | { |
1721 | QFontMetricsF fm = QFontMetricsF(m_styleoption->fontMetrics); |
1722 | return text.isEmpty() ? fm.height() : |
1723 | fm.boundingRect(string: text).height(); |
1724 | } |
1725 | |
1726 | QString QQuickStyleItem1::elidedText(const QString &text, int elideMode, int width) |
1727 | { |
1728 | return m_styleoption->fontMetrics.elidedText(text, mode: Qt::TextElideMode(elideMode), width); |
1729 | } |
1730 | |
1731 | bool QQuickStyleItem1::hasThemeIcon(const QString &icon) const |
1732 | { |
1733 | return QIcon::hasThemeIcon(name: icon); |
1734 | } |
1735 | |
1736 | bool QQuickStyleItem1::event(QEvent *ev) |
1737 | { |
1738 | if (ev->type() == QEvent::StyleAnimationUpdate) { |
1739 | if (isVisible()) { |
1740 | ev->accept(); |
1741 | polish(); |
1742 | } |
1743 | return true; |
1744 | } else if (ev->type() == QEvent::StyleChange) { |
1745 | if (m_itemType == ScrollBar) |
1746 | initStyleOption(); |
1747 | } |
1748 | return QQuickItem::event(ev); |
1749 | } |
1750 | |
1751 | void QQuickStyleItem1::setTextureWidth(int w) |
1752 | { |
1753 | if (m_textureWidth == w) |
1754 | return; |
1755 | m_textureWidth = w; |
1756 | emit textureWidthChanged(w: m_textureWidth); |
1757 | update(); |
1758 | } |
1759 | |
1760 | void QQuickStyleItem1::setTextureHeight(int h) |
1761 | { |
1762 | if (m_textureHeight == h) |
1763 | return; |
1764 | m_textureHeight = h; |
1765 | emit textureHeightChanged(h: m_textureHeight); |
1766 | update(); |
1767 | } |
1768 | |
1769 | QSGNode *QQuickStyleItem1::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) |
1770 | { |
1771 | if (m_image.isNull()) { |
1772 | delete node; |
1773 | return 0; |
1774 | } |
1775 | |
1776 | QSGNinePatchNode *styleNode = static_cast<QSGNinePatchNode *>(node); |
1777 | if (!styleNode) |
1778 | styleNode = window()->createNinePatchNode(); |
1779 | |
1780 | #ifdef QSG_RUNTIME_DESCRIPTION |
1781 | qsgnode_set_description(node: styleNode, |
1782 | description: QString::fromLatin1(str: "%1:%2, '%3'" ) |
1783 | .arg(a: style()) |
1784 | .arg(a: elementType()) |
1785 | .arg(a: text())); |
1786 | #endif |
1787 | |
1788 | styleNode->setTexture(window()->createTextureFromImage(image: m_image, options: QQuickWindow::TextureCanUseAtlas)); |
1789 | styleNode->setBounds(boundingRect()); |
1790 | styleNode->setDevicePixelRatio(window()->devicePixelRatio()); |
1791 | styleNode->setPadding(left: m_border.left(), top: m_border.top(), right: m_border.right(), bottom: m_border.bottom()); |
1792 | styleNode->update(); |
1793 | |
1794 | return styleNode; |
1795 | } |
1796 | |
1797 | void QQuickStyleItem1::updatePolish() |
1798 | { |
1799 | if (width() >= 1 && height() >= 1) { // Note these are reals so 1 pixel is minimum |
1800 | float devicePixelRatio = window() ? window()->devicePixelRatio() : qApp->devicePixelRatio(); |
1801 | int w = m_textureWidth > 0 ? m_textureWidth : width(); |
1802 | int h = m_textureHeight > 0 ? m_textureHeight : height(); |
1803 | m_image = QImage(w * devicePixelRatio, h * devicePixelRatio, QImage::Format_ARGB32_Premultiplied); |
1804 | m_image.setDevicePixelRatio(devicePixelRatio); |
1805 | m_image.fill(color: Qt::transparent); |
1806 | QPainter painter(&m_image); |
1807 | painter.setLayoutDirection(qApp->layoutDirection()); |
1808 | paint(painter: &painter); |
1809 | QQuickItem::update(); |
1810 | } else if (!m_image.isNull()) { |
1811 | m_image = QImage(); |
1812 | QQuickItem::update(); |
1813 | } |
1814 | } |
1815 | |
1816 | QPixmap QQuickTableRowImageProvider1::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) |
1817 | { |
1818 | Q_UNUSED (requestedSize); |
1819 | int width = 16; |
1820 | int height = 16; |
1821 | if (size) |
1822 | *size = QSize(width, height); |
1823 | |
1824 | QPixmap pixmap(width, height); |
1825 | #if QT_CONFIG(itemviews) |
1826 | QStyleOptionViewItem opt; |
1827 | opt.state |= QStyle::State_Enabled; |
1828 | opt.rect = QRect(0, 0, width, height); |
1829 | QString style = qApp->style()->metaObject()->className(); |
1830 | opt.features = {}; |
1831 | |
1832 | if (id.contains(s: QLatin1String("selected" ))) |
1833 | opt.state |= QStyle::State_Selected; |
1834 | |
1835 | if (id.contains(s: QLatin1String("active" ))) { |
1836 | opt.state |= QStyle::State_Active; |
1837 | opt.palette.setCurrentColorGroup(QPalette::Active); |
1838 | } else |
1839 | opt.palette.setCurrentColorGroup(QPalette::Inactive); |
1840 | |
1841 | if (id.contains(s: QLatin1String("alternate" ))) |
1842 | opt.features |= QStyleOptionViewItem::Alternate; |
1843 | |
1844 | QPalette pal = QApplication::palette(className: "QAbstractItemView" ); |
1845 | if (opt.state & QStyle::State_Selected && (style.contains(s: QLatin1String("Mac" )) || |
1846 | !qApp->style()->styleHint(stylehint: QStyle::SH_ItemView_ShowDecorationSelected))) { |
1847 | pal.setCurrentColorGroup(opt.palette.currentColorGroup()); |
1848 | pixmap.fill(fillColor: pal.highlight().color()); |
1849 | } else { |
1850 | pixmap.fill(fillColor: pal.base().color()); |
1851 | QPainter pixpainter(&pixmap); |
1852 | qApp->style()->drawPrimitive(pe: QStyle::PE_PanelItemViewRow, opt: &opt, p: &pixpainter); |
1853 | } |
1854 | #else |
1855 | Q_UNUSED(id); |
1856 | #endif |
1857 | return pixmap; |
1858 | } |
1859 | |
1860 | QT_END_NAMESPACE |
1861 | |