Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qappleiconengine.mm
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#if defined(Q_OS_MACOS)
7# include <AppKit/AppKit.h>
8#elif defined(QT_PLATFORM_UIKIT)
9# include <UIKit/UIKit.h>
10#endif
11
12#include <QtGui/qguiapplication.h>
13#include <QtGui/qpainter.h>
14#include <QtGui/qpalette.h>
15#include <QtGui/qstylehints.h>
16
17#include <QtGui/private/qcoregraphics_p.h>
18
20
21using namespace Qt::StringLiterals;
22
23namespace {
24auto *loadImage(const QString &iconName)
25{
26 static constexpr std::pair<QLatin1StringView, NSString *> iconMap[] = {
27 {"address-book-new"_L1, @"book.closed"},
28 {"application-exit"_L1, @"xmark.circle"},
29 {"appointment-new"_L1, @"calendar.badge.plus"},
30 {"call-start"_L1, @"phone.arrow.up.right"},
31 {"call-stop"_L1, @"phone.down"},
32 {"contact-new"_L1, @"person.crop.circle.badge.plus"},
33 {"document-new"_L1, @"plus"},
34 {"document-open"_L1, @"arrow.up.forward"},
35 {"document-open-recent"_L1, @"clock"},
36 {"document-page-setup"_L1, @"text.page"},
37 {"document-print"_L1, @"printer"},
38 {"document-print-preview"_L1, @"richtext.page"},
39 {"document-properties"_L1, @"info.circle.text.page"},
40 {"document-revert"_L1, @"arrow.counterclockwise"},
41 {"document-save"_L1, @"square.and.arrow.down"},
42 {"document-save-as"_L1, @"square.and.arrow.down.on.square"},
43 {"document-send"_L1, @"paperplane"},
44 {"document-export"_L1, @"square.and.arrow.up"},
45 {"edit-clear"_L1, @"xmark.circle"},
46 {"edit-copy"_L1, @"doc.on.doc"},
47 {"edit-cut"_L1, @"scissors"},
48 {"edit-delete"_L1, @"trash"},
49 {"edit-find"_L1, @"text.page.badge.magnifyingglass"},
50 //{"edit-find-replace"_L1, @"arrow.up.left.and.down.right.magnifyingglass"},
51 {"edit-paste"_L1, @"document.on.clipboard"},
52 {"edit-redo"_L1, @"arrow.uturn.forward"},
53 {"edit-select-all"_L1, @"character.textbox"},
54 {"edit-undo"_L1, @"arrow.uturn.backward"},
55 {"folder-new"_L1, @"folder.badge.plus"},
56 {"format-indent-less"_L1, @"decrease.indent"},
57 {"format-indent-more"_L1, @"increase.indent"},
58 {"format-justify-center"_L1, @"text.aligncenter"},
59 {"format-justify-fill"_L1, @"text.justify"},
60 {"format-justify-left"_L1, @"text.justify.left"},
61 {"format-justify-right"_L1, @"text.justify.right"},
62 {"format-text-direction-ltr"_L1, @"text.justify.leading"},
63 {"format-text-direction-rtl"_L1, @"text.justify.trailing"},
64 {"format-text-bold"_L1, @"bold"},
65 {"format-text-italic"_L1, @"italic"},
66 {"format-text-underline"_L1, @"underline"},
67 {"format-text-strikethrough"_L1, @"strikethrough"},
68 //{"go-bottom"_L1, @""},
69 {"go-down"_L1, @"chevron.down"},
70 //{"go-first"_L1, @""},
71 {"go-home"_L1, @"house"},
72 //{"go-jump"_L1, @""},
73 //{"go-last"_L1, @""},
74 {"go-next"_L1, @"chevron.right"},
75 {"go-previous"_L1, @"chevron.left"},
76 //{"go-top"_L1, @""},
77 {"go-up"_L1, @"chevron.up"},
78 {"help-about"_L1, @"info.circle"},
79 //{"help-contents"_L1, @""},
80 {"help-faq"_L1, @"questionmark.app"},
81 {"insert-image"_L1, @"photo.badge.plus"},
82 {"insert-link"_L1, @"link.badge.plus"},
83 {"insert-object"_L1, @"widget.small.badge.plus"},
84 {"insert-text"_L1, @"text.badge.plus"},
85 {"list-add"_L1, @"plus.circle"},
86 {"list-remove"_L1, @"minus.circle"},
87 {"mail-forward"_L1, @"arrowshape.turn.up.right"},
88 {"mail-mark-important"_L1, @"star"},
89 {"mail-mark-junk"_L1, @"xmark.bin"},
90 {"mail-mark-notjunk"_L1, @"arrow.up.bin"},
91 {"mail-mark-read"_L1, @"envelope.open"},
92 {"mail-mark-unread"_L1, @"envelope.badge"},
93 {"mail-message-new"_L1, @"square.and.pencil"},
94 {"mail-reply-all"_L1, @"arrowshape.turn.up.left.2"},
95 {"mail-reply-sender"_L1, @"arrowshape.turn.up.left"},
96 {"mail-send"_L1, @"arrow.up.circle.fill"},
97 {"mail-send-receive"_L1, @"arrow.trianglehead.2.clockwise.rotate.90"},
98 {"mail-replied"_L1, @"envelope.and.arrow.trianglehead.branch"},
99 {"media-eject"_L1, @"eject"},
100 {"media-playback-pause"_L1, @"pause"},
101 {"media-playback-start"_L1, @"play"},
102 {"media-playback-stop"_L1, @"stop"},
103 {"media-record"_L1, @"record.circle"},
104 {"media-seek-backward"_L1, @"backward"},
105 {"media-seek-forward"_L1, @"forward"},
106 {"media-skip-backward"_L1, @"backward.end.alt"},
107 {"media-skip-forward"_L1, @"forward.end.alt"},
108 {"object-flip-horizontal"_L1, @"rectangle.landscape.rotate"},
109 {"object-flip-vertical"_L1, @"rectangle.portrait.rotate"},
110 {"object-rotate-left"_L1, @"rotate.left"},
111 {"object-rotate-right"_L1, @"rotate.right"},
112 {"process-stop"_L1, @"stop.circle"},
113 {"system-lock-screen"_L1, @"lock"},
114 {"system-log-out"_L1, @"person.crop.circle"},
115 //{"system-run"_L1, @""},
116 {"system-search"_L1, @"magnifyingglass"},
117 {"system-reboot"_L1, @"restart"},
118 {"system-shutdown"_L1, @"power"},
119 {"tools-check-spelling"_L1, @"textformat.characters.dottedunderline"},
120 {"view-fullscreen"_L1, @"arrow.up.left.and.arrow.down.right"},
121 {"view-refresh"_L1, @"arrow.clockwise"},
122 {"view-restore"_L1, @"arrow.down.right.and.arrow.up.left"},
123 {"view-sort-ascending"_L1, @"arrow.up"},
124 {"view-sort-descending"_L1, @"arrow.down"},
125 {"window-close"_L1, @"xmark.circle"},
126 {"window-new"_L1, @"macwindow.badge.plus"},
127 {"zoom-fit-best"_L1, @"square.arrowtriangle.4.outward"},
128 {"zoom-in"_L1, @"plus.magnifyingglass"},
129 {"zoom-original"_L1, @"1.magnifyingglass"},
130 {"zoom-out"_L1, @"minus.magnifyingglass"},
131 {"process-working"_L1, @"circle.dotted"},
132 {"accessories-calculator"_L1, @"plus.forwardslash.minus"},
133 {"accessories-character-map"_L1, @"keyboard.macwindow"},
134 {"accessories-dictionary"_L1, @"character.book.closed"},
135 {"accessories-text-editor"_L1, @"textformat"},
136 {"help-browser"_L1, @"folder.badge.questionmark"},
137 {"multimedia-volume-control"_L1, @"speaker.wave.3"},
138 {"preferences-desktop-accessibility"_L1, @"accessibility"},
139 {"preferences-desktop-font"_L1, @"textformat.characters"},
140 {"preferences-desktop-keyboard"_L1, @"keyboard"},
141 {"preferences-desktop-locale"_L1, @"mappin.and.ellipse"},
142 {"preferences-desktop-multimedia"_L1, @"music.note.tv"},
143 {"preferences-desktop-screensaver"_L1, @"display"},
144 {"preferences-desktop-theme"_L1, @"paintpalette"},
145 {"preferences-desktop-wallpaper"_L1, @"photo.tv"},
146 {"system-file-manager"_L1, @"folder.badge.gearshape"},
147 {"system-software-install"_L1, @"laptopcomputer.and.arrow.down"},
148 {"system-software-update"_L1, @"laptopcomputer.badge.checkmark"},
149 {"utilities-system-monitor"_L1, @"chart.bar.xaxis"},
150 {"utilities-terminal"_L1, @"apple.terminal"},
151 {"applications-accessories"_L1, @"scanner"},
152 {"applications-development"_L1, @"hammer"},
153 {"applications-engineering"_L1, @"wrench.and.screwdriver"},
154 {"applications-games"_L1, @"gamecontroller.circle"},
155 {"applications-graphics"_L1, @"theatermask.and.paintbrush"},
156 {"applications-internet"_L1, @"network"},
157 {"applications-multimedia"_L1, @"tv.and.mediabox"},
158 {"applications-office"_L1, @"square.and.pencil.circle"},
159 {"applications-other"_L1, @"app.grid"},
160 {"applications-science"_L1, @"atom"},
161 {"applications-system"_L1, @"gear"},
162 {"applications-utilities"_L1, @"wrench.and.screwdriver"},
163 {"preferences-desktop"_L1, @"menubar.dock.rectangle"},
164 {"preferences-desktop-peripherals"_L1, @"iphone.and.ipod"},
165 {"preferences-desktop-personal"_L1, @"person.badge.key"},
166 {"preferences-other"_L1, @"gear"},
167 {"preferences-system"_L1, @"gear"},
168 {"preferences-system-network"_L1, @"network"},
169 {"system-help"_L1, @"questionmark.diamond"},
170 {"audio-card"_L1, @"waveform.circle"},
171 {"audio-input-microphone"_L1, @"mic"},
172 {"battery"_L1, @"battery.100percent"},
173 {"camera-photo"_L1, @"camera"},
174 {"camera-video"_L1, @"video"},
175 {"camera-web"_L1, @"web.camera"},
176 {"computer"_L1, @"desktopcomputer"},
177 {"drive-harddisk"_L1, @"internaldrive"},
178 {"drive-optical"_L1, @"opticaldiscdrive"},
179 {"drive-removable-media"_L1, @"externaldrive"},
180 {"input-gaming"_L1, @"gamecontroller"},
181 {"input-keyboard"_L1, @"keyboard"},
182 {"input-mouse"_L1, @"computermouse"},
183 {"input-tablet"_L1, @"ipad"},
184 {"media-flash"_L1, @"mediastick"},
185 //{"media-floppy"_L1, @""},
186 {"media-optical"_L1, @"opticaldisc"},
187 {"media-tape"_L1, @"recordingtape"},
188 {"modem"_L1, @"phone.connection"},
189 {"multimedia-player"_L1, @"ipod"},
190 {"network-wired"_L1, @"app.connected.to.app.below.fill"},
191 {"network-wireless"_L1, @"wifi"},
192 {"network-workgroup"_L1, @"network"},
193 {"pda"_L1, @"flipphone"},
194 {"phone"_L1, @"iphone"},
195 {"printer"_L1, @"printer"},
196 {"scanner"_L1, @"scanner"},
197 {"video-display"_L1, @"play.display"},
198 {"emblem-default"_L1, @"circle"},
199 {"emblem-documents"_L1, @"doc.circle"},
200 {"emblem-downloads"_L1, @"arrow.down.circle"},
201 {"emblem-favorite"_L1, @"star.circle"},
202 {"emblem-important"_L1, @"exclamationmark.circle"},
203 {"emblem-mail"_L1, @"envelope.circle"},
204 {"emblem-photos"_L1, @"photo.circle"},
205 {"emblem-readonly"_L1, @"eye.circle"},
206 {"emblem-shared"_L1, @"person.2.circle"},
207 {"emblem-symbolic-link"_L1, @"link.circle"},
208 {"emblem-synchronized"_L1, @"arrow.triangle.2.circlepath.circle"},
209 {"emblem-system"_L1, @"gear.circle"},
210 {"emblem-unreadable"_L1, @"eye.slash.circle"},
211 {"text-x-generic"_L1, @"doc"}, // until iOS 18/macOS 15; @"document" after that
212 {"folder"_L1, @"folder"},
213 {"folder-remote"_L1, @"icloud"},
214 {"network-server"_L1, @"server.rack"},
215 //{"start-here"_L1, @""},
216 {"user-bookmarks"_L1, @"bookmark.circle"},
217 {"user-desktop"_L1, @"menubar.dock.rectangle"}, // used by finder
218 {"user-home"_L1, @"house"}, //"go-home" also using this one
219 {"user-trash"_L1, @"trash"},
220 {"appointment-missed"_L1, @"calendar.badge.exclamationmark"},
221 {"appointment-soon"_L1, @"calendar.badge.clock"},
222 {"audio-volume-high"_L1, @"speaker.wave.3"},
223 {"audio-volume-low"_L1, @"speaker.wave.1"},
224 {"audio-volume-medium"_L1, @"speaker.wave.2"},
225 {"audio-volume-muted"_L1, @"speaker.slash"},
226 {"battery-caution"_L1, @"minus.plus.batteryblock.exclamationmark"},
227 {"battery-low"_L1, @"battery.25percent"}, // there are different levels that can be low battery
228 {"dialog-error"_L1, @"exclamationmark.bubble"},
229 {"dialog-information"_L1, @"info.circle"},
230 {"dialog-password"_L1, @"lock"},
231 {"dialog-question"_L1, @"questionmark.circle"},
232 {"dialog-warning"_L1, @"exclamationmark.octagon"},
233 {"folder-drag-accept"_L1, @"plus.rectangle.on.folder"},
234 {"folder-open"_L1, @"arrow.forward.folder"},
235 {"folder-visiting"_L1, @"folder.circle"},
236 {"image-loading"_L1, @"photo.badge.arrow.down"},
237 {"image-missing"_L1, @"photo.badge.exclamationmark"},
238 {"mail-attachment"_L1, @"paperclip"},
239 {"mail-unread"_L1, @"envelope.badge"},
240 {"mail-read"_L1, @"envelope.open"},
241 //{"mail-replied"_L1, @""},
242 //{"mail-signed"_L1, @""},
243 {"mail-signed-verified"_L1, @"envelope.badge.shield.half.filled"},
244 {"media-playlist-repeat"_L1, @"repeat"},
245 {"media-playlist-shuffle"_L1, @"shuffle"},
246 {"network-error"_L1, @"xmark.icloud"},
247 {"network-idle"_L1, @"icloud"},
248 {"network-offline"_L1, @"icloud.slash"},
249 {"network-receive"_L1, @"icloud.and.arrow.down"},
250 {"network-transmit"_L1, @"icloud.and.arrow.up"},
251 {"network-transmit-receive"_L1, @"arrow.trianglehead.2.clockwise.rotate.90.icloud"},
252 //{"printer-error"_L1, @""},
253 {"printer-printing"_L1, @"printer.dotmatrix"},
254 {"security-high"_L1, @"lock.badge.checkmark"},
255 {"security-medium"_L1, @"lock"},
256 {"security-low"_L1, @"lock.trianglebadge.exclamationmark"},
257 {"software-update-available"_L1, @"arrowshape.up.circle"},
258 {"software-update-urgent"_L1, @"exclamationmark.transmission"},
259 {"sync-error"_L1, @"exclamationmark.arrow.triangle.2.circlepath"},
260 {"sync-synchronizing"_L1, @"arrow.triangle.2.circlepath"},
261 {"task-due"_L1, @"clock.badge.exclamationmark"},
262 {"task-past-due"_L1, @"clock.badge.xmark"},
263 {"user-available"_L1, @"person.crop.circle.badge"},
264 {"user-away"_L1, @"person.crop.circle.badge.moon"},
265 {"user-idle"_L1, @"person.crop.circle.badge.clock"},
266 {"user-offline"_L1, @"person.crop.circle.badge.xmark"},
267 //{"user-trash-full"_L1, @""},
268 {"weather-clear"_L1, @"sun.max"},
269 {"weather-clear-night"_L1, @"moon"},
270 {"weather-few-clouds"_L1, @"cloud.sun"},
271 {"weather-few-clouds-night"_L1, @"cloud.moon"},
272 {"weather-fog"_L1, @"cloud.fog"},
273 {"weather-overcast"_L1, @"cloud"},
274 {"weather-severe-alert"_L1, @"cloud.bolt.rain"},
275 {"weather-showers"_L1, @"cloud.heavyrain"},
276 {"weather-showers-scattered"_L1, @"cloud.drizzle"},
277 {"weather-snow"_L1, @"cloud.snow"},
278 {"weather-storm"_L1, @"tropicalstorm"},
279 };
280 const auto it = std::find_if(std::begin(iconMap), std::end(iconMap), [iconName](const auto &c){
281 return c.first == iconName;
282 });
283 NSString *systemIconName = it != std::end(iconMap) ? it->second : iconName.toNSString();
284#if defined(Q_OS_MACOS)
285 return [NSImage imageWithSystemSymbolName:systemIconName accessibilityDescription:nil];
286#elif defined(QT_PLATFORM_UIKIT)
287 return [UIImage systemImageNamed:systemIconName];
288#endif
289}
290}
291
292QAppleIconEngine::QAppleIconEngine(const QString &iconName)
293 : m_iconName(iconName), m_image(loadImage(iconName))
294{
295 if (m_image)
296 [m_image retain];
297}
298
299QAppleIconEngine::~QAppleIconEngine()
300{
301 if (m_image)
302 [m_image release];
303}
304
305QIconEngine *QAppleIconEngine::clone() const
306{
307 return new QAppleIconEngine(m_iconName);
308}
309
310QString QAppleIconEngine::key() const
311{
312 return u"QAppleIconEngine"_s;
313}
314
315QString QAppleIconEngine::iconName()
316{
317 return m_iconName;
318}
319
320bool QAppleIconEngine::isNull()
321{
322 return m_image == nullptr;
323}
324
325QList<QSize> QAppleIconEngine::availableIconSizes(double aspectRatio)
326{
327 const qreal devicePixelRatio = qGuiApp->devicePixelRatio();
328 const QList<QSize> sizes = {
329 {qRound(16 * devicePixelRatio), qRound(16. * devicePixelRatio / aspectRatio)},
330 {qRound(32 * devicePixelRatio), qRound(32. * devicePixelRatio / aspectRatio)},
331 {qRound(64 * devicePixelRatio), qRound(64. * devicePixelRatio / aspectRatio)},
332 {qRound(128 * devicePixelRatio), qRound(128. * devicePixelRatio / aspectRatio)},
333 {qRound(256 * devicePixelRatio), qRound(256. * devicePixelRatio / aspectRatio)},
334 };
335 return sizes;
336}
337
338QList<QSize> QAppleIconEngine::availableSizes(QIcon::Mode, QIcon::State)
339{
340 const double aspectRatio = isNull() ? 1.0 : m_image.size.width / m_image.size.height;
341 return availableIconSizes(aspectRatio);
342}
343
344QSize QAppleIconEngine::actualSize(const QSize &size, QIcon::Mode /*mode*/, QIcon::State /*state*/)
345{
346 const double inputAspectRatio = isNull() ? 1.0 : m_image.size.width / m_image.size.height;
347 const double outputAspectRatio = size.width() / size.height();
348 QSize result = size;
349 if (outputAspectRatio > inputAspectRatio)
350 result.rwidth() = result.height() * inputAspectRatio;
351 else
352 result.rheight() = result.width() / inputAspectRatio;
353 return result;
354}
355
356QPixmap QAppleIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
357{
358 return scaledPixmap(size, mode, state, 1.0);
359}
360
361namespace {
362#if defined(Q_OS_MACOS)
363auto *configuredImage(const NSImage *image, const QColor &color)
364{
365 auto *config = [NSImageSymbolConfiguration configurationWithPointSize:48
366 weight:NSFontWeightRegular
367 scale:NSImageSymbolScaleLarge];
368
369 // Apply tint color first, which switches the configuration to palette mode
370 config = [config configurationByApplyingConfiguration:
371 [NSImageSymbolConfiguration configurationWithPaletteColors:@[
372 [NSColor colorWithSRGBRed:color.redF() green:color.greenF()
373 blue:color.blueF() alpha:color.alphaF()]
374 ]]];
375
376 // Then switch back to monochrome, as palette mode gives a different look
377 // than monochrome, even with a single color.
378 config = [config configurationByApplyingConfiguration:
379 [NSImageSymbolConfiguration configurationPreferringMonochrome]];
380
381 return [image imageWithSymbolConfiguration:config];
382}
383#elif defined(QT_PLATFORM_UIKIT)
384auto *configuredImage(const UIImage *image, const QColor &color)
385{
386 auto *config = [UIImageSymbolConfiguration configurationWithPointSize:48
387 weight:UIImageSymbolWeightRegular
388 scale:UIImageSymbolScaleLarge];
389
390 auto *primaryColor = [UIColor colorWithRed:color.redF()
391 green:color.greenF()
392 blue:color.blueF()
393 alpha:color.alphaF()];
394
395 return [[image imageByApplyingSymbolConfiguration:config] imageWithTintColor:primaryColor];
396}
397#endif
398}
399
400QPixmap QAppleIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
401{
402 const CacheKey key(mode, state, size, scale);
403 QPixmap pixmap = m_cache.value(key);
404 if (pixmap.isNull()) {
405 const QSize paintSize = actualSize(size, mode, state);
406 const QSize paintOffset = paintSize != size
407 ? (QSizeF(size - paintSize) * 0.5).toSize()
408 : QSize();
409
410 pixmap = QPixmap(size * scale);
411 pixmap.setDevicePixelRatio(scale);
412 pixmap.fill(Qt::transparent);
413
414 if (!pixmap.isNull()) {
415 QPainter painter(&pixmap);
416 paint(&painter, QRect(paintOffset.width(), paintOffset.height(),
417 paintSize.width(), paintSize.height()), mode, state);
418 m_cache.insert(key, pixmap);
419 }
420 }
421 return pixmap;
422}
423
424void QAppleIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
425{
426 Q_UNUSED(state);
427
428 QColor color;
429 const QPalette palette;
430 switch (mode) {
431 case QIcon::Normal:
432 color = palette.color(QPalette::Inactive, QPalette::Text);
433 break;
434 case QIcon::Disabled:
435 color = palette.color(QPalette::Disabled, QPalette::Text);
436 break;
437 case QIcon::Active:
438 color = palette.color(QPalette::Active, QPalette::Text);
439 break;
440 case QIcon::Selected:
441 color = palette.color(QPalette::Active, QPalette::HighlightedText);
442 break;
443 }
444 const auto *image = configuredImage(m_image, color);
445
446 QMacCGContext ctx(painter);
447
448#if defined(Q_OS_MACOS)
449 NSGraphicsContext *gc = [NSGraphicsContext graphicsContextWithCGContext:ctx flipped:YES];
450 [NSGraphicsContext saveGraphicsState];
451 [NSGraphicsContext setCurrentContext:gc];
452
453 const NSSize pixmapSize = NSMakeSize(rect.width(), rect.height());
454 [image setSize:pixmapSize];
455 const NSRect sourceRect = NSMakeRect(0, 0, pixmapSize.width, pixmapSize.height);
456 const NSRect iconRect = NSMakeRect(rect.x(), rect.y(), pixmapSize.width, pixmapSize.height);
457
458 [image drawInRect:iconRect fromRect:sourceRect operation:NSCompositingOperationSourceOver
459 fraction:1.0 respectFlipped:YES hints:@{
460 NSImageHintUserInterfaceLayoutDirection: painter->layoutDirection() == Qt::RightToLeft ?
461 @(NSUserInterfaceLayoutDirectionRightToLeft) : @(NSUserInterfaceLayoutDirectionLeftToRight)
462 }];
463 [NSGraphicsContext restoreGraphicsState];
464#elif defined(QT_PLATFORM_UIKIT)
465 auto *layoutDirectionTrait = [UITraitCollection traitCollectionWithLayoutDirection:
466 painter->layoutDirection() == Qt::RightToLeft ?
467 UITraitEnvironmentLayoutDirectionRightToLeft :
468 UITraitEnvironmentLayoutDirectionLeftToRight];
469
470 image = [image imageWithConfiguration:layoutDirectionTrait.imageConfiguration];
471
472 UIGraphicsPushContext(ctx);
473 const CGRect cgrect = CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
474 [image drawInRect:cgrect];
475 UIGraphicsPopContext();
476#endif
477}
478
479QT_END_NAMESPACE
Combined button and popup list for selecting options.