1 | /* $Id: UIChooserItemGlobal.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * VBox Qt GUI - UIChooserItemGlobal class implementation.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2012-2024 Oracle and/or its affiliates.
|
---|
8 | *
|
---|
9 | * This file is part of VirtualBox base platform packages, as
|
---|
10 | * available from https://www.virtualbox.org.
|
---|
11 | *
|
---|
12 | * This program is free software; you can redistribute it and/or
|
---|
13 | * modify it under the terms of the GNU General Public License
|
---|
14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
15 | * License.
|
---|
16 | *
|
---|
17 | * This program is distributed in the hope that it will be useful, but
|
---|
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
20 | * General Public License for more details.
|
---|
21 | *
|
---|
22 | * You should have received a copy of the GNU General Public License
|
---|
23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
24 | *
|
---|
25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
26 | */
|
---|
27 |
|
---|
28 | /* Qt includes: */
|
---|
29 | #include <QApplication>
|
---|
30 | #include <QGraphicsSceneMouseEvent>
|
---|
31 | #include <QGraphicsView>
|
---|
32 | #include <QPainter>
|
---|
33 | #include <QStyleOptionGraphicsItem>
|
---|
34 | #include <QWindow>
|
---|
35 |
|
---|
36 | /* GUI includes: */
|
---|
37 | #include "UIChooserItemGlobal.h"
|
---|
38 | #include "UIChooserModel.h"
|
---|
39 | #include "UIChooserNodeGlobal.h"
|
---|
40 | #include "UIIconPool.h"
|
---|
41 | #include "UIImageTools.h"
|
---|
42 | #include "UITranslationEventListener.h"
|
---|
43 | #include "UIVirtualBoxManager.h"
|
---|
44 |
|
---|
45 |
|
---|
46 | UIChooserItemGlobal::UIChooserItemGlobal(UIChooserItem *pParent, UIChooserNodeGlobal *pNode)
|
---|
47 | : UIChooserItem(pParent, pNode)
|
---|
48 | #ifdef VBOX_WS_MAC
|
---|
49 | , m_iDefaultColorDeviation(0)
|
---|
50 | #endif
|
---|
51 | , m_iHoverLightnessStart(0)
|
---|
52 | , m_iHoverLightnessFinal(0)
|
---|
53 | , m_iHighlightLightnessStart(0)
|
---|
54 | , m_iHighlightLightnessFinal(0)
|
---|
55 | , m_iMinimumNameWidth(0)
|
---|
56 | , m_iMaximumNameWidth(0)
|
---|
57 | , m_iHeightHint(0)
|
---|
58 | {
|
---|
59 | prepare();
|
---|
60 | }
|
---|
61 |
|
---|
62 | UIChooserItemGlobal::~UIChooserItemGlobal()
|
---|
63 | {
|
---|
64 | cleanup();
|
---|
65 | }
|
---|
66 |
|
---|
67 | UIChooserNodeGlobal *UIChooserItemGlobal::nodeToGlobalType() const
|
---|
68 | {
|
---|
69 | return node() ? node()->toGlobalNode() : 0;
|
---|
70 | }
|
---|
71 |
|
---|
72 | bool UIChooserItemGlobal::isToolButtonArea(const QPoint &position, int iMarginMultiplier /* = 1 */) const
|
---|
73 | {
|
---|
74 | const int iFullWidth = geometry().width();
|
---|
75 | const int iFullHeight = geometry().height();
|
---|
76 | const int iMarginHR = data(GlobalItemData_MarginHR).toInt();
|
---|
77 | const int iButtonMargin = data(GlobalItemData_ButtonMargin).toInt();
|
---|
78 | const int iToolPixmapX = iFullWidth - iMarginHR - 1
|
---|
79 | - m_toolPixmap.width() / m_toolPixmap.devicePixelRatio();
|
---|
80 | const int iToolPixmapY = (iFullHeight - m_toolPixmap.height() / m_toolPixmap.devicePixelRatio()) / 2;
|
---|
81 | QRect rect = QRect(iToolPixmapX,
|
---|
82 | iToolPixmapY,
|
---|
83 | m_toolPixmap.width() / m_toolPixmap.devicePixelRatio(),
|
---|
84 | m_toolPixmap.height() / m_toolPixmap.devicePixelRatio());
|
---|
85 | rect.adjust(-iMarginMultiplier * iButtonMargin, -iMarginMultiplier * iButtonMargin,
|
---|
86 | iMarginMultiplier * iButtonMargin, iMarginMultiplier * iButtonMargin);
|
---|
87 | return rect.contains(position);
|
---|
88 | }
|
---|
89 |
|
---|
90 | bool UIChooserItemGlobal::isPinButtonArea(const QPoint &position, int iMarginMultiplier /* = 1 */) const
|
---|
91 | {
|
---|
92 | const int iFullWidth = geometry().width();
|
---|
93 | const int iFullHeight = geometry().height();
|
---|
94 | const int iMarginHR = data(GlobalItemData_MarginHR).toInt();
|
---|
95 | const int iSpacing = data(GlobalItemData_Spacing).toInt();
|
---|
96 | const int iButtonMargin = data(GlobalItemData_ButtonMargin).toInt();
|
---|
97 | const int iPinPixmapX = iFullWidth - iMarginHR - 1
|
---|
98 | - m_toolPixmap.width() / m_toolPixmap.devicePixelRatio()
|
---|
99 | - iSpacing
|
---|
100 | - m_pinPixmap.width() / m_pinPixmap.devicePixelRatio();
|
---|
101 | const int iPinPixmapY = (iFullHeight - m_pinPixmap.height() / m_pinPixmap.devicePixelRatio()) / 2;
|
---|
102 | QRect rect = QRect(iPinPixmapX,
|
---|
103 | iPinPixmapY,
|
---|
104 | m_pinPixmap.width() / m_pinPixmap.devicePixelRatio(),
|
---|
105 | m_pinPixmap.height() / m_pinPixmap.devicePixelRatio());
|
---|
106 | rect.adjust(-iMarginMultiplier * iButtonMargin, -iMarginMultiplier * iButtonMargin,
|
---|
107 | iMarginMultiplier * iButtonMargin, iMarginMultiplier * iButtonMargin);
|
---|
108 | return rect.contains(position);
|
---|
109 | }
|
---|
110 |
|
---|
111 | int UIChooserItemGlobal::heightHint() const
|
---|
112 | {
|
---|
113 | return m_iHeightHint;
|
---|
114 | }
|
---|
115 |
|
---|
116 | void UIChooserItemGlobal::setHeightHint(int iHint)
|
---|
117 | {
|
---|
118 | /* Remember a new hint: */
|
---|
119 | m_iHeightHint = iHint;
|
---|
120 |
|
---|
121 | /* Update geometry and the model layout: */
|
---|
122 | updateGeometry();
|
---|
123 | model()->updateLayout();
|
---|
124 | }
|
---|
125 |
|
---|
126 | void UIChooserItemGlobal::sltRetranslateUI()
|
---|
127 | {
|
---|
128 | }
|
---|
129 |
|
---|
130 | void UIChooserItemGlobal::showEvent(QShowEvent *pEvent)
|
---|
131 | {
|
---|
132 | /* Call to base-class: */
|
---|
133 | UIChooserItem::showEvent(pEvent);
|
---|
134 |
|
---|
135 | /* Update pixmaps: */
|
---|
136 | updatePixmaps();
|
---|
137 | }
|
---|
138 |
|
---|
139 | void UIChooserItemGlobal::resizeEvent(QGraphicsSceneResizeEvent *pEvent)
|
---|
140 | {
|
---|
141 | /* Call to base-class: */
|
---|
142 | UIChooserItem::resizeEvent(pEvent);
|
---|
143 |
|
---|
144 | /* What is the new geometry? */
|
---|
145 | const QRectF newGeometry = geometry();
|
---|
146 |
|
---|
147 | /* Should we update visible name? */
|
---|
148 | if (previousGeometry().width() != newGeometry.width())
|
---|
149 | updateMaximumNameWidth();
|
---|
150 |
|
---|
151 | /* Remember the new geometry: */
|
---|
152 | setPreviousGeometry(newGeometry);
|
---|
153 | }
|
---|
154 |
|
---|
155 | void UIChooserItemGlobal::mousePressEvent(QGraphicsSceneMouseEvent *pEvent)
|
---|
156 | {
|
---|
157 | /* Call to base-class: */
|
---|
158 | UIChooserItem::mousePressEvent(pEvent);
|
---|
159 | /* No drag at all: */
|
---|
160 | pEvent->ignore();
|
---|
161 | }
|
---|
162 |
|
---|
163 | void UIChooserItemGlobal::paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOptions, QWidget * /* pWidget = 0 */)
|
---|
164 | {
|
---|
165 | /* Acquire rectangle: */
|
---|
166 | const QRect rectangle = pOptions->rect;
|
---|
167 |
|
---|
168 | /* Paint background: */
|
---|
169 | paintBackground(pPainter, rectangle);
|
---|
170 | /* Paint frame: */
|
---|
171 | paintFrame(pPainter, rectangle);
|
---|
172 | /* Paint global info: */
|
---|
173 | paintGlobalInfo(pPainter, rectangle);
|
---|
174 | }
|
---|
175 |
|
---|
176 | void UIChooserItemGlobal::setFavorite(bool fFavorite)
|
---|
177 | {
|
---|
178 | /* Call to base-class: */
|
---|
179 | UIChooserItem::setFavorite(fFavorite);
|
---|
180 |
|
---|
181 | /* Update pin-pixmap: */
|
---|
182 | updatePinPixmap();
|
---|
183 | }
|
---|
184 |
|
---|
185 | void UIChooserItemGlobal::startEditing()
|
---|
186 | {
|
---|
187 | AssertMsgFailed(("Global graphics item do NOT support editing yet!"));
|
---|
188 | }
|
---|
189 |
|
---|
190 | void UIChooserItemGlobal::updateItem()
|
---|
191 | {
|
---|
192 | /* Update this global-item: */
|
---|
193 | updatePixmaps();
|
---|
194 | updateMinimumNameWidth();
|
---|
195 | updateVisibleName();
|
---|
196 | updateToolTip();
|
---|
197 | update();
|
---|
198 |
|
---|
199 | /* Update parent group-item: */
|
---|
200 | parentItem()->updateToolTip();
|
---|
201 | parentItem()->update();
|
---|
202 | }
|
---|
203 |
|
---|
204 | void UIChooserItemGlobal::updateToolTip()
|
---|
205 | {
|
---|
206 | // Nothing for now..
|
---|
207 | }
|
---|
208 |
|
---|
209 | QList<UIChooserItem*> UIChooserItemGlobal::items(UIChooserNodeType) const
|
---|
210 | {
|
---|
211 | AssertMsgFailedReturn(("Global graphics item do NOT support children!"), QList<UIChooserItem*>());
|
---|
212 | }
|
---|
213 |
|
---|
214 | void UIChooserItemGlobal::addItem(UIChooserItem *, bool, int)
|
---|
215 | {
|
---|
216 | AssertMsgFailed(("Global graphics item do NOT support children!"));
|
---|
217 | }
|
---|
218 |
|
---|
219 | void UIChooserItemGlobal::removeItem(UIChooserItem *)
|
---|
220 | {
|
---|
221 | AssertMsgFailed(("Global graphics item do NOT support children!"));
|
---|
222 | }
|
---|
223 |
|
---|
224 | UIChooserItem *UIChooserItemGlobal::searchForItem(const QString &, int iSearchFlags)
|
---|
225 | {
|
---|
226 | /* Ignore if we are not searching for the global-item: */
|
---|
227 | if (!(iSearchFlags & UIChooserItemSearchFlag_Global))
|
---|
228 | return 0;
|
---|
229 |
|
---|
230 | /* Returning this: */
|
---|
231 | return this;
|
---|
232 | }
|
---|
233 |
|
---|
234 | UIChooserItem *UIChooserItemGlobal::firstMachineItem()
|
---|
235 | {
|
---|
236 | return 0;
|
---|
237 | }
|
---|
238 |
|
---|
239 | void UIChooserItemGlobal::updateLayout()
|
---|
240 | {
|
---|
241 | // Just do nothing ..
|
---|
242 | }
|
---|
243 |
|
---|
244 | int UIChooserItemGlobal::minimumWidthHint() const
|
---|
245 | {
|
---|
246 | /* Prepare variables: */
|
---|
247 | const int iMarginHL = data(GlobalItemData_MarginHL).toInt();
|
---|
248 | const int iMarginHR = data(GlobalItemData_MarginHR).toInt();
|
---|
249 | const int iSpacing = data(GlobalItemData_Spacing).toInt();
|
---|
250 |
|
---|
251 | /* Calculating proposed width: */
|
---|
252 | int iProposedWidth = 0;
|
---|
253 |
|
---|
254 | /* Two margins: */
|
---|
255 | iProposedWidth += iMarginHL + iMarginHR;
|
---|
256 | /* And global-item content width: */
|
---|
257 | iProposedWidth += (m_pixmapSize.width() +
|
---|
258 | iSpacing +
|
---|
259 | m_iMinimumNameWidth +
|
---|
260 | iSpacing +
|
---|
261 | m_toolPixmapSize.width() +
|
---|
262 | iSpacing +
|
---|
263 | m_pinPixmapSize.width());
|
---|
264 |
|
---|
265 | /* Return result: */
|
---|
266 | return iProposedWidth;
|
---|
267 | }
|
---|
268 |
|
---|
269 | int UIChooserItemGlobal::minimumHeightHint() const
|
---|
270 | {
|
---|
271 | /* Prepare variables: */
|
---|
272 | const int iMarginV = data(GlobalItemData_MarginV).toInt();
|
---|
273 |
|
---|
274 | /* Calculating proposed height: */
|
---|
275 | int iProposedHeight = 0;
|
---|
276 |
|
---|
277 | /* Global-item content height: */
|
---|
278 | int iContentHeight = qMax(m_pixmapSize.height(), m_visibleNameSize.height());
|
---|
279 | iContentHeight = qMax(iContentHeight, m_toolPixmapSize.height());
|
---|
280 | iContentHeight = qMax(iContentHeight, m_pinPixmapSize.height());
|
---|
281 |
|
---|
282 | /* If we have height hint: */
|
---|
283 | if (m_iHeightHint)
|
---|
284 | {
|
---|
285 | /* Take the largest value between height hint and content height: */
|
---|
286 | iProposedHeight += qMax(m_iHeightHint, iContentHeight);
|
---|
287 | }
|
---|
288 | /* Otherwise: */
|
---|
289 | else
|
---|
290 | {
|
---|
291 | /* Two margins: */
|
---|
292 | iProposedHeight += 2 * iMarginV;
|
---|
293 | /* And content height: */
|
---|
294 | iProposedHeight += iContentHeight;
|
---|
295 | }
|
---|
296 |
|
---|
297 | /* Return result: */
|
---|
298 | return iProposedHeight;
|
---|
299 | }
|
---|
300 |
|
---|
301 | QSizeF UIChooserItemGlobal::sizeHint(Qt::SizeHint which, const QSizeF &constraint /* = QSizeF() */) const
|
---|
302 | {
|
---|
303 | /* If Qt::MinimumSize requested: */
|
---|
304 | if (which == Qt::MinimumSize)
|
---|
305 | return QSizeF(minimumWidthHint(), minimumHeightHint());
|
---|
306 | /* Else call to base-class: */
|
---|
307 | return UIChooserItem::sizeHint(which, constraint);
|
---|
308 | }
|
---|
309 |
|
---|
310 | QPixmap UIChooserItemGlobal::toPixmap()
|
---|
311 | {
|
---|
312 | AssertFailedReturn(QPixmap());
|
---|
313 | }
|
---|
314 |
|
---|
315 | bool UIChooserItemGlobal::isDropAllowed(QGraphicsSceneDragDropEvent *, UIChooserItemDragToken) const
|
---|
316 | {
|
---|
317 | /* No drops at all: */
|
---|
318 | return false;
|
---|
319 | }
|
---|
320 |
|
---|
321 | void UIChooserItemGlobal::processDrop(QGraphicsSceneDragDropEvent *, UIChooserItem *, UIChooserItemDragToken)
|
---|
322 | {
|
---|
323 | /* Nothing to process: */
|
---|
324 | }
|
---|
325 |
|
---|
326 | void UIChooserItemGlobal::resetDragToken()
|
---|
327 | {
|
---|
328 | /* Nothing to process: */
|
---|
329 | }
|
---|
330 |
|
---|
331 | QMimeData *UIChooserItemGlobal::createMimeData()
|
---|
332 | {
|
---|
333 | /* Nothing to return: */
|
---|
334 | return 0;
|
---|
335 | }
|
---|
336 |
|
---|
337 | void UIChooserItemGlobal::sltHandleWindowRemapped()
|
---|
338 | {
|
---|
339 | updatePixmaps();
|
---|
340 | }
|
---|
341 |
|
---|
342 | void UIChooserItemGlobal::prepare()
|
---|
343 | {
|
---|
344 | /* Color tones: */
|
---|
345 | #if defined(VBOX_WS_MAC)
|
---|
346 | m_iDefaultColorDeviation = 105;
|
---|
347 | m_iHoverLightnessStart = 125;
|
---|
348 | m_iHoverLightnessFinal = 115;
|
---|
349 | m_iHighlightLightnessStart = 115;
|
---|
350 | m_iHighlightLightnessFinal = 105;
|
---|
351 | #elif defined(VBOX_WS_WIN)
|
---|
352 | m_iHoverLightnessStart = 220;
|
---|
353 | m_iHoverLightnessFinal = 210;
|
---|
354 | m_iHighlightLightnessStart = 190;
|
---|
355 | m_iHighlightLightnessFinal = 180;
|
---|
356 | #else /* !VBOX_WS_MAC && !VBOX_WS_WIN */
|
---|
357 | m_iHoverLightnessStart = 125;
|
---|
358 | m_iHoverLightnessFinal = 115;
|
---|
359 | m_iHighlightLightnessStart = 110;
|
---|
360 | m_iHighlightLightnessFinal = 100;
|
---|
361 | #endif /* !VBOX_WS_MAC && !VBOX_WS_WIN */
|
---|
362 |
|
---|
363 | /* Fonts: */
|
---|
364 | m_nameFont = font();
|
---|
365 | m_nameFont.setWeight(QFont::Bold);
|
---|
366 |
|
---|
367 | /* Sizes: */
|
---|
368 | m_iMinimumNameWidth = 0;
|
---|
369 | m_iMaximumNameWidth = 0;
|
---|
370 |
|
---|
371 | /* Add item to the parent: */
|
---|
372 | AssertPtrReturnVoid(parentItem());
|
---|
373 | parentItem()->addItem(this, isFavorite(), position());
|
---|
374 |
|
---|
375 | /* Configure connections: */
|
---|
376 | connect(gpManager, &UIVirtualBoxManager::sigWindowRemapped,
|
---|
377 | this, &UIChooserItemGlobal::sltHandleWindowRemapped);
|
---|
378 |
|
---|
379 | /* Init: */
|
---|
380 | updatePixmaps();
|
---|
381 |
|
---|
382 | /* Apply language settings: */
|
---|
383 | sltRetranslateUI();
|
---|
384 | connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
|
---|
385 | this, &UIChooserItemGlobal::sltRetranslateUI);
|
---|
386 | }
|
---|
387 |
|
---|
388 | void UIChooserItemGlobal::cleanup()
|
---|
389 | {
|
---|
390 | /* If that item is current: */
|
---|
391 | if (model()->currentItem() == this)
|
---|
392 | {
|
---|
393 | /* Unset current-item: */
|
---|
394 | model()->setCurrentItem(0);
|
---|
395 | }
|
---|
396 | /* If that item is in selection list: */
|
---|
397 | if (model()->selectedItems().contains(this))
|
---|
398 | {
|
---|
399 | /* Remove item from the selection list: */
|
---|
400 | model()->removeFromSelectedItems(this);
|
---|
401 | }
|
---|
402 | /* If that item is in navigation list: */
|
---|
403 | if (model()->navigationItems().contains(this))
|
---|
404 | {
|
---|
405 | /* Remove item from the navigation list: */
|
---|
406 | model()->removeFromNavigationItems(this);
|
---|
407 | }
|
---|
408 |
|
---|
409 | /* Remove item from the parent: */
|
---|
410 | AssertPtrReturnVoid(parentItem());
|
---|
411 | parentItem()->removeItem(this);
|
---|
412 | }
|
---|
413 |
|
---|
414 | QVariant UIChooserItemGlobal::data(int iKey) const
|
---|
415 | {
|
---|
416 | /* Provide other members with required data: */
|
---|
417 | switch (iKey)
|
---|
418 | {
|
---|
419 | /* Layout hints: */
|
---|
420 | case GlobalItemData_MarginHL: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
|
---|
421 | case GlobalItemData_MarginHR: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 4 * 5;
|
---|
422 | case GlobalItemData_MarginV: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 4 * 3;
|
---|
423 | case GlobalItemData_Spacing: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 2;
|
---|
424 | case GlobalItemData_ButtonMargin: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 4;
|
---|
425 |
|
---|
426 | /* Default: */
|
---|
427 | default: break;
|
---|
428 | }
|
---|
429 | return QVariant();
|
---|
430 | }
|
---|
431 |
|
---|
432 | void UIChooserItemGlobal::updatePixmaps()
|
---|
433 | {
|
---|
434 | /* Update pixmap: */
|
---|
435 | updatePixmap();
|
---|
436 | /* Update tool-pixmap: */
|
---|
437 | updateToolPixmap();
|
---|
438 | /* Update pin-pixmap: */
|
---|
439 | updatePinPixmap();
|
---|
440 | }
|
---|
441 |
|
---|
442 | void UIChooserItemGlobal::updatePixmap()
|
---|
443 | {
|
---|
444 | /* Acquire new metric, then compose pixmap-size: */
|
---|
445 | const int iMetric = QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize);
|
---|
446 | const QSize pixmapSize = QSize(iMetric, iMetric);
|
---|
447 |
|
---|
448 | /* Create new icon, then acquire pixmap: */
|
---|
449 | const QIcon icon = UIIconPool::iconSet(":/tools_global_32px.png");
|
---|
450 | const qreal fDevicePixelRatio = gpManager->windowHandle() ? gpManager->windowHandle()->devicePixelRatio() : 1;
|
---|
451 | const QPixmap pixmap = icon.pixmap(pixmapSize, fDevicePixelRatio);
|
---|
452 |
|
---|
453 | /* Update linked values: */
|
---|
454 | if (m_pixmapSize != pixmapSize)
|
---|
455 | {
|
---|
456 | m_pixmapSize = pixmapSize;
|
---|
457 | updateMaximumNameWidth();
|
---|
458 | updateGeometry();
|
---|
459 | }
|
---|
460 | if (m_pixmap.toImage() != pixmap.toImage())
|
---|
461 | {
|
---|
462 | m_pixmap = pixmap;
|
---|
463 | update();
|
---|
464 | }
|
---|
465 | }
|
---|
466 |
|
---|
467 | void UIChooserItemGlobal::updateToolPixmap()
|
---|
468 | {
|
---|
469 | /* Determine icon metric: */
|
---|
470 | const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize) * .75;
|
---|
471 | /* Create new tool-pixmap and tool-pixmap size: */
|
---|
472 | const QIcon toolIcon = UIIconPool::iconSet(":/tools_menu_24px.png");
|
---|
473 | AssertReturnVoid(!toolIcon.isNull());
|
---|
474 | const QSize toolPixmapSize = QSize(iIconMetric, iIconMetric);
|
---|
475 | const qreal fDevicePixelRatio = gpManager->windowHandle() ? gpManager->windowHandle()->devicePixelRatio() : 1;
|
---|
476 | const QPixmap toolPixmap = toolIcon.pixmap(toolPixmapSize, fDevicePixelRatio);
|
---|
477 | /* Update linked values: */
|
---|
478 | if (m_toolPixmapSize != toolPixmapSize)
|
---|
479 | {
|
---|
480 | m_toolPixmapSize = toolPixmapSize;
|
---|
481 | updateGeometry();
|
---|
482 | }
|
---|
483 | if (m_toolPixmap.toImage() != toolPixmap.toImage())
|
---|
484 | {
|
---|
485 | m_toolPixmap = toolPixmap;
|
---|
486 | update();
|
---|
487 | }
|
---|
488 | }
|
---|
489 |
|
---|
490 | void UIChooserItemGlobal::updatePinPixmap()
|
---|
491 | {
|
---|
492 | /* Determine icon metric: */
|
---|
493 | const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize) * .75;
|
---|
494 | /* Create new tool-pixmap and tool-pixmap size: */
|
---|
495 | const QIcon pinIcon = UIIconPool::iconSet(isFavorite() ? ":/favorite_pressed_24px.png" : ":/favorite_24px.png");
|
---|
496 | AssertReturnVoid(!pinIcon.isNull());
|
---|
497 | const QSize pinPixmapSize = QSize(iIconMetric, iIconMetric);
|
---|
498 | const qreal fDevicePixelRatio = gpManager->windowHandle() ? gpManager->windowHandle()->devicePixelRatio() : 1;
|
---|
499 | const QPixmap pinPixmap = pinIcon.pixmap(pinPixmapSize, fDevicePixelRatio);
|
---|
500 | /* Update linked values: */
|
---|
501 | if (m_pinPixmapSize != pinPixmapSize)
|
---|
502 | {
|
---|
503 | m_pinPixmapSize = pinPixmapSize;
|
---|
504 | updateGeometry();
|
---|
505 | }
|
---|
506 | if (m_pinPixmap.toImage() != pinPixmap.toImage())
|
---|
507 | {
|
---|
508 | m_pinPixmap = pinPixmap;
|
---|
509 | update();
|
---|
510 | }
|
---|
511 | }
|
---|
512 |
|
---|
513 | void UIChooserItemGlobal::updateMinimumNameWidth()
|
---|
514 | {
|
---|
515 | /* Calculate new minimum name width: */
|
---|
516 | QPaintDevice *pPaintDevice = model()->paintDevice();
|
---|
517 | const QFontMetrics fm(m_nameFont, pPaintDevice);
|
---|
518 | const int iMinimumNameWidth = fm.horizontalAdvance(compressText(m_nameFont, pPaintDevice, name(),
|
---|
519 | textWidth(m_nameFont, pPaintDevice, 15)));
|
---|
520 |
|
---|
521 | /* Is there something changed? */
|
---|
522 | if (m_iMinimumNameWidth == iMinimumNameWidth)
|
---|
523 | return;
|
---|
524 |
|
---|
525 | /* Update linked values: */
|
---|
526 | m_iMinimumNameWidth = iMinimumNameWidth;
|
---|
527 | updateGeometry();
|
---|
528 | }
|
---|
529 |
|
---|
530 | void UIChooserItemGlobal::updateMaximumNameWidth()
|
---|
531 | {
|
---|
532 | /* Prepare variables: */
|
---|
533 | const int iMarginHL = data(GlobalItemData_MarginHL).toInt();
|
---|
534 | const int iMarginHR = data(GlobalItemData_MarginHR).toInt();
|
---|
535 | const int iSpacing = data(GlobalItemData_Spacing).toInt();
|
---|
536 |
|
---|
537 | /* Calculate new maximum name width: */
|
---|
538 | int iMaximumNameWidth = (int)geometry().width();
|
---|
539 | iMaximumNameWidth -= iMarginHL; /* left margin */
|
---|
540 | iMaximumNameWidth -= m_pixmapSize.width(); /* pixmap width */
|
---|
541 | iMaximumNameWidth -= iSpacing; /* spacing between pixmap and name */
|
---|
542 | iMaximumNameWidth -= iMarginHR; /* right margin */
|
---|
543 |
|
---|
544 | /* Is there something changed? */
|
---|
545 | if (m_iMaximumNameWidth == iMaximumNameWidth)
|
---|
546 | return;
|
---|
547 |
|
---|
548 | /* Update linked values: */
|
---|
549 | m_iMaximumNameWidth = iMaximumNameWidth;
|
---|
550 | updateVisibleName();
|
---|
551 | }
|
---|
552 |
|
---|
553 | void UIChooserItemGlobal::updateVisibleName()
|
---|
554 | {
|
---|
555 | /* Prepare variables: */
|
---|
556 | QPaintDevice *pPaintDevice = model()->paintDevice();
|
---|
557 |
|
---|
558 | /* Calculate new visible name and name-size: */
|
---|
559 | const QString strVisibleName = compressText(m_nameFont, pPaintDevice, name(), m_iMaximumNameWidth);
|
---|
560 | const QSize visibleNameSize = textSize(m_nameFont, pPaintDevice, strVisibleName);
|
---|
561 |
|
---|
562 | /* Update linked values: */
|
---|
563 | if (m_visibleNameSize != visibleNameSize)
|
---|
564 | {
|
---|
565 | m_visibleNameSize = visibleNameSize;
|
---|
566 | updateGeometry();
|
---|
567 | }
|
---|
568 | if (m_strVisibleName != strVisibleName)
|
---|
569 | {
|
---|
570 | m_strVisibleName = strVisibleName;
|
---|
571 | update();
|
---|
572 | }
|
---|
573 | }
|
---|
574 |
|
---|
575 | void UIChooserItemGlobal::paintBackground(QPainter *pPainter, const QRect &rectangle)
|
---|
576 | {
|
---|
577 | /* Save painter: */
|
---|
578 | pPainter->save();
|
---|
579 |
|
---|
580 | /* Prepare color: */
|
---|
581 | const QPalette pal = QApplication::palette();
|
---|
582 |
|
---|
583 | /* Selected-item background: */
|
---|
584 | if (model()->selectedItems().contains(this))
|
---|
585 | {
|
---|
586 | /* Prepare color: */
|
---|
587 | const QColor backgroundColor = pal.color(QPalette::Active, QPalette::Highlight);
|
---|
588 | /* Draw gradient: */
|
---|
589 | QLinearGradient bgGrad(rectangle.topLeft(), rectangle.bottomLeft());
|
---|
590 | bgGrad.setColorAt(0, backgroundColor.lighter(m_iHighlightLightnessStart));
|
---|
591 | bgGrad.setColorAt(1, backgroundColor.lighter(m_iHighlightLightnessFinal));
|
---|
592 | pPainter->fillRect(rectangle, bgGrad);
|
---|
593 |
|
---|
594 | if (isHovered())
|
---|
595 | {
|
---|
596 | /* Prepare color: */
|
---|
597 | QColor animationColor1 = QColor(Qt::white);
|
---|
598 | QColor animationColor2 = QColor(Qt::white);
|
---|
599 | #ifdef VBOX_WS_MAC
|
---|
600 | animationColor1.setAlpha(90);
|
---|
601 | #else
|
---|
602 | animationColor1.setAlpha(30);
|
---|
603 | #endif
|
---|
604 | animationColor2.setAlpha(0);
|
---|
605 | /* Draw hovered-item animated gradient: */
|
---|
606 | QRect animatedRect = rectangle;
|
---|
607 | animatedRect.setWidth(animatedRect.height());
|
---|
608 | const int iLength = 2 * animatedRect.width() + rectangle.width();
|
---|
609 | const int iShift = - animatedRect.width() + iLength * animatedValue() / 100;
|
---|
610 | animatedRect.moveLeft(iShift);
|
---|
611 | QLinearGradient bgAnimatedGrad(animatedRect.topLeft(), animatedRect.bottomRight());
|
---|
612 | bgAnimatedGrad.setColorAt(0, animationColor2);
|
---|
613 | bgAnimatedGrad.setColorAt(0.1, animationColor2);
|
---|
614 | bgAnimatedGrad.setColorAt(0.5, animationColor1);
|
---|
615 | bgAnimatedGrad.setColorAt(0.9, animationColor2);
|
---|
616 | bgAnimatedGrad.setColorAt(1, animationColor2);
|
---|
617 | pPainter->fillRect(rectangle, bgAnimatedGrad);
|
---|
618 | }
|
---|
619 | }
|
---|
620 | /* Hovered-item background: */
|
---|
621 | else if (isHovered())
|
---|
622 | {
|
---|
623 | /* Prepare color: */
|
---|
624 | const QColor backgroundColor = pal.color(QPalette::Active, QPalette::Highlight);
|
---|
625 | /* Draw gradient: */
|
---|
626 | QLinearGradient bgGrad(rectangle.topLeft(), rectangle.bottomLeft());
|
---|
627 | bgGrad.setColorAt(0, backgroundColor.lighter(m_iHoverLightnessStart));
|
---|
628 | bgGrad.setColorAt(1, backgroundColor.lighter(m_iHoverLightnessFinal));
|
---|
629 | pPainter->fillRect(rectangle, bgGrad);
|
---|
630 |
|
---|
631 | /* Prepare color: */
|
---|
632 | QColor animationColor1 = QColor(Qt::white);
|
---|
633 | QColor animationColor2 = QColor(Qt::white);
|
---|
634 | #ifdef VBOX_WS_MAC
|
---|
635 | animationColor1.setAlpha(120);
|
---|
636 | #else
|
---|
637 | animationColor1.setAlpha(50);
|
---|
638 | #endif
|
---|
639 | animationColor2.setAlpha(0);
|
---|
640 | /* Draw hovered-item animated gradient: */
|
---|
641 | QRect animatedRect = rectangle;
|
---|
642 | animatedRect.setWidth(animatedRect.height());
|
---|
643 | const int iLength = 2 * animatedRect.width() + rectangle.width();
|
---|
644 | const int iShift = - animatedRect.width() + iLength * animatedValue() / 100;
|
---|
645 | animatedRect.moveLeft(iShift);
|
---|
646 | QLinearGradient bgAnimatedGrad(animatedRect.topLeft(), animatedRect.bottomRight());
|
---|
647 | bgAnimatedGrad.setColorAt(0, animationColor2);
|
---|
648 | bgAnimatedGrad.setColorAt(0.1, animationColor2);
|
---|
649 | bgAnimatedGrad.setColorAt(0.5, animationColor1);
|
---|
650 | bgAnimatedGrad.setColorAt(0.9, animationColor2);
|
---|
651 | bgAnimatedGrad.setColorAt(1, animationColor2);
|
---|
652 | pPainter->fillRect(rectangle, bgAnimatedGrad);
|
---|
653 | }
|
---|
654 | /* Default background: */
|
---|
655 | else
|
---|
656 | {
|
---|
657 | #ifdef VBOX_WS_MAC
|
---|
658 | /* Prepare color: */
|
---|
659 | const QColor backgroundColor = pal.color(QPalette::Active, QPalette::Window);
|
---|
660 | /* Draw gradient: */
|
---|
661 | QLinearGradient bgGrad(rectangle.topLeft(), rectangle.bottomLeft());
|
---|
662 | bgGrad.setColorAt(0, backgroundColor.lighter(m_iDefaultColorDeviation));
|
---|
663 | bgGrad.setColorAt(1, backgroundColor.darker(m_iDefaultColorDeviation));
|
---|
664 | pPainter->fillRect(rectangle, bgGrad);
|
---|
665 | #else
|
---|
666 | /* Draw simple background: */
|
---|
667 | pPainter->fillRect(rectangle, pal.color(QPalette::Active, QPalette::Window));
|
---|
668 | #endif
|
---|
669 | }
|
---|
670 |
|
---|
671 | /* Restore painter: */
|
---|
672 | pPainter->restore();
|
---|
673 | }
|
---|
674 |
|
---|
675 | void UIChooserItemGlobal::paintFrame(QPainter *pPainter, const QRect &rectangle)
|
---|
676 | {
|
---|
677 | /* Only selected and/or hovered item should have a frame: */
|
---|
678 | if (!model()->selectedItems().contains(this) && !isHovered())
|
---|
679 | return;
|
---|
680 |
|
---|
681 | /* Save painter: */
|
---|
682 | pPainter->save();
|
---|
683 |
|
---|
684 | /* Prepare color: */
|
---|
685 | const QPalette pal = QApplication::palette();
|
---|
686 | QColor strokeColor;
|
---|
687 |
|
---|
688 | /* Selected-item frame: */
|
---|
689 | if (model()->selectedItems().contains(this))
|
---|
690 | strokeColor = pal.color(QPalette::Active, QPalette::Highlight).lighter(m_iHighlightLightnessStart - 40);
|
---|
691 | /* Hovered-item frame: */
|
---|
692 | else if (isHovered())
|
---|
693 | strokeColor = pal.color(QPalette::Active, QPalette::Highlight).lighter(m_iHoverLightnessStart - 40);
|
---|
694 |
|
---|
695 | /* Create/assign pen: */
|
---|
696 | QPen pen(strokeColor);
|
---|
697 | pen.setWidth(0);
|
---|
698 | pPainter->setPen(pen);
|
---|
699 |
|
---|
700 | /* Draw borders: */
|
---|
701 | pPainter->drawLine(rectangle.topLeft(), rectangle.topRight() + QPoint(1, 0));
|
---|
702 | pPainter->drawLine(rectangle.bottomLeft(), rectangle.bottomRight() + QPoint(1, 0));
|
---|
703 | pPainter->drawLine(rectangle.topLeft(), rectangle.bottomLeft());
|
---|
704 |
|
---|
705 | /* Restore painter: */
|
---|
706 | pPainter->restore();
|
---|
707 | }
|
---|
708 |
|
---|
709 | void UIChooserItemGlobal::paintGlobalInfo(QPainter *pPainter, const QRect &rectangle)
|
---|
710 | {
|
---|
711 | /* Prepare variables: */
|
---|
712 | const int iFullWidth = rectangle.width();
|
---|
713 | const int iFullHeight = rectangle.height();
|
---|
714 | const int iMarginHL = data(GlobalItemData_MarginHL).toInt();
|
---|
715 | const int iMarginHR = data(GlobalItemData_MarginHR).toInt();
|
---|
716 | const int iSpacing = data(GlobalItemData_Spacing).toInt();
|
---|
717 | const int iButtonMargin = data(GlobalItemData_ButtonMargin).toInt();
|
---|
718 |
|
---|
719 | /* Selected or hovered item foreground: */
|
---|
720 | if (model()->selectedItems().contains(this) || isHovered())
|
---|
721 | {
|
---|
722 | /* Prepare palette: */
|
---|
723 | const QPalette pal = QApplication::palette();
|
---|
724 |
|
---|
725 | /* Get background color: */
|
---|
726 | const QColor highlight = pal.color(QPalette::Active, QPalette::Highlight);
|
---|
727 | const QColor background = model()->selectedItems().contains(this)
|
---|
728 | ? highlight.lighter(m_iHighlightLightnessStart)
|
---|
729 | : highlight.lighter(m_iHoverLightnessStart);
|
---|
730 |
|
---|
731 | /* Gather foreground color for background one: */
|
---|
732 | const QColor foreground = suitableForegroundColor(pal, background);
|
---|
733 | pPainter->setPen(foreground);
|
---|
734 | }
|
---|
735 |
|
---|
736 | /* Calculate indents: */
|
---|
737 | int iLeftColumnIndent = iMarginHL;
|
---|
738 |
|
---|
739 | /* Paint left column: */
|
---|
740 | {
|
---|
741 | /* Prepare variables: */
|
---|
742 | const int iGlobalPixmapX = iLeftColumnIndent;
|
---|
743 | const int iGlobalPixmapY = (iFullHeight - m_pixmap.height() / m_pixmap.devicePixelRatio()) / 2;
|
---|
744 |
|
---|
745 | /* Paint pixmap: */
|
---|
746 | paintPixmap(/* Painter: */
|
---|
747 | pPainter,
|
---|
748 | /* Point to paint in: */
|
---|
749 | QPoint(iGlobalPixmapX, iGlobalPixmapY),
|
---|
750 | /* Pixmap to paint: */
|
---|
751 | m_pixmap);
|
---|
752 | }
|
---|
753 |
|
---|
754 | /* Calculate indents: */
|
---|
755 | const int iMiddleColumnIndent = iLeftColumnIndent +
|
---|
756 | m_pixmapSize.width() +
|
---|
757 | iSpacing;
|
---|
758 |
|
---|
759 | /* Paint middle column: */
|
---|
760 | {
|
---|
761 | /* Prepare variables: */
|
---|
762 | const int iNameX = iMiddleColumnIndent;
|
---|
763 | const int iNameY = (iFullHeight - m_visibleNameSize.height()) / 2;
|
---|
764 |
|
---|
765 | /* Paint name: */
|
---|
766 | paintText(/* Painter: */
|
---|
767 | pPainter,
|
---|
768 | /* Point to paint in: */
|
---|
769 | QPoint(iNameX, iNameY),
|
---|
770 | /* Font to paint text: */
|
---|
771 | m_nameFont,
|
---|
772 | /* Paint device: */
|
---|
773 | model()->paintDevice(),
|
---|
774 | /* Text to paint: */
|
---|
775 | m_strVisibleName);
|
---|
776 | }
|
---|
777 |
|
---|
778 | /* Calculate indents: */
|
---|
779 | QGraphicsView *pView = model()->scene()->views().first();
|
---|
780 | const QPointF sceneCursorPosition = pView->mapToScene(pView->mapFromGlobal(QCursor::pos()));
|
---|
781 | const QPoint itemCursorPosition = mapFromScene(sceneCursorPosition).toPoint();
|
---|
782 | int iRightColumnIndent = iFullWidth - iMarginHR - 1 - m_toolPixmap.width() / m_toolPixmap.devicePixelRatio();
|
---|
783 |
|
---|
784 | /* Paint right column: */
|
---|
785 | if ( model()->firstSelectedItem() == this
|
---|
786 | || isHovered())
|
---|
787 | {
|
---|
788 | /* Prepare variables: */
|
---|
789 | const int iToolPixmapX = iRightColumnIndent;
|
---|
790 | const int iToolPixmapY = (iFullHeight - m_toolPixmap.height() / m_toolPixmap.devicePixelRatio()) / 2;
|
---|
791 | QRect toolButtonRectangle = QRect(iToolPixmapX,
|
---|
792 | iToolPixmapY,
|
---|
793 | m_toolPixmap.width() / m_toolPixmap.devicePixelRatio(),
|
---|
794 | m_toolPixmap.height() / m_toolPixmap.devicePixelRatio());
|
---|
795 | toolButtonRectangle.adjust(- iButtonMargin, -iButtonMargin, iButtonMargin, iButtonMargin);
|
---|
796 |
|
---|
797 | /* Paint tool button: */
|
---|
798 | if ( isHovered()
|
---|
799 | && isToolButtonArea(itemCursorPosition, 4))
|
---|
800 | paintFlatButton(/* Painter: */
|
---|
801 | pPainter,
|
---|
802 | /* Button rectangle: */
|
---|
803 | toolButtonRectangle,
|
---|
804 | /* Cursor position: */
|
---|
805 | itemCursorPosition);
|
---|
806 |
|
---|
807 | /* Paint pixmap: */
|
---|
808 | paintPixmap(/* Painter: */
|
---|
809 | pPainter,
|
---|
810 | /* Point to paint in: */
|
---|
811 | QPoint(iToolPixmapX, iToolPixmapY),
|
---|
812 | /* Pixmap to paint: */
|
---|
813 | m_toolPixmap);
|
---|
814 | }
|
---|
815 |
|
---|
816 | /* Calculate indents: */
|
---|
817 | iRightColumnIndent = iRightColumnIndent - m_toolPixmap.width() / m_toolPixmap.devicePixelRatio() - iSpacing;
|
---|
818 |
|
---|
819 | /* Paint right column: */
|
---|
820 | if ( model()->firstSelectedItem() == this
|
---|
821 | || isHovered())
|
---|
822 | {
|
---|
823 | /* Prepare variables: */
|
---|
824 | const int iPinPixmapX = iRightColumnIndent;
|
---|
825 | const int iPinPixmapY = (iFullHeight - m_pinPixmap.height() / m_pinPixmap.devicePixelRatio()) / 2;
|
---|
826 | QRect pinButtonRectangle = QRect(iPinPixmapX,
|
---|
827 | iPinPixmapY,
|
---|
828 | m_pinPixmap.width() / m_pinPixmap.devicePixelRatio(),
|
---|
829 | m_pinPixmap.height() / m_pinPixmap.devicePixelRatio());
|
---|
830 | pinButtonRectangle.adjust(- iButtonMargin, -iButtonMargin, iButtonMargin, iButtonMargin);
|
---|
831 |
|
---|
832 | /* Paint pin button: */
|
---|
833 | if ( isHovered()
|
---|
834 | && isPinButtonArea(itemCursorPosition, 4))
|
---|
835 | paintFlatButton(/* Painter: */
|
---|
836 | pPainter,
|
---|
837 | /* Button rectangle: */
|
---|
838 | pinButtonRectangle,
|
---|
839 | /* Cursor position: */
|
---|
840 | itemCursorPosition);
|
---|
841 |
|
---|
842 | /* Paint pixmap: */
|
---|
843 | paintPixmap(/* Painter: */
|
---|
844 | pPainter,
|
---|
845 | /* Point to paint in: */
|
---|
846 | QPoint(iPinPixmapX, iPinPixmapY),
|
---|
847 | /* Pixmap to paint: */
|
---|
848 | m_pinPixmap);
|
---|
849 | }
|
---|
850 | }
|
---|