VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/manager/details/UIDetailsElement.cpp@ 74049

Last change on this file since 74049 was 74049, checked in by vboxsync, 6 years ago

FE/Qt: VirtualBox Manager UI: Large cleanup for UIDetailsElement, doxygen + style fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
  • Property svn:mergeinfo set to (toggle deleted branches)
    /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cppmergedeligible
    /branches/VBox-3.0/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp58652,​70973
    /branches/VBox-3.2/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp66309,​66318
    /branches/VBox-4.0/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp70873
    /branches/VBox-4.1/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp74233
    /branches/VBox-4.2/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp91503-91504,​91506-91508,​91510,​91514-91515,​91521
    /branches/VBox-4.3/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp91223
    /branches/VBox-4.3/trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp91223
    /branches/dsen/gui/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp79076-79078,​79089,​79109-79110,​79112-79113,​79127-79130,​79134,​79141,​79151,​79155,​79157-79159,​79193,​79197
    /branches/dsen/gui2/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp79562-79569,​79572-79573,​79578,​79581-79582,​79590-79591,​79598-79599,​79602-79603,​79605-79606,​79632,​79635,​79637,​79644
    /branches/dsen/gui3/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp79645-79692
File size: 22.7 KB
Line 
1/* $Id: UIDetailsElement.cpp 74049 2018-09-03 16:45:09Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIDetailsElement class implementation.
4 */
5
6/*
7 * Copyright (C) 2012-2018 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifdef VBOX_WITH_PRECOMPILED_HEADERS
19# include <precomp.h>
20#else /* !VBOX_WITH_PRECOMPILED_HEADERS */
21
22/* Qt includes: */
23# include <QGraphicsSceneMouseEvent>
24# include <QGraphicsView>
25# include <QPropertyAnimation>
26# include <QSignalTransition>
27# include <QStateMachine>
28# include <QStyleOptionGraphicsItem>
29
30/* GUI includes: */
31# include "UIActionPool.h"
32# include "UIConverter.h"
33# include "UIDetailsElement.h"
34# include "UIDetailsSet.h"
35# include "UIDetailsModel.h"
36# include "UIGraphicsRotatorButton.h"
37# include "UIGraphicsTextPane.h"
38# include "UIIconPool.h"
39# include "UIVirtualBoxManager.h"
40# include "VBoxGlobal.h"
41
42#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
43
44
45UIDetailsElement::UIDetailsElement(UIDetailsSet *pParent, DetailsElementType enmType, bool fOpened)
46 : UIDetailsItem(pParent)
47 , m_pSet(pParent)
48 , m_enmType(enmType)
49 , m_iCornerRadius(QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 2)
50 , m_fHovered(false)
51 , m_fNameHovered(false)
52 , m_pHighlightMachine(0)
53 , m_pForwardAnimation(0)
54 , m_pBackwardAnimation(0)
55 , m_iAnimationDuration(400)
56 , m_iDefaultDarkness(100)
57 , m_iHighlightDarkness(90)
58 , m_iAnimationDarkness(m_iDefaultDarkness)
59 , m_pButton(0)
60 , m_fClosed(!fOpened)
61 , m_fAnimationRunning(false)
62 , m_iAdditionalHeight(0)
63 , m_pTextPane(0)
64 , m_iMinimumHeaderWidth(0)
65 , m_iMinimumHeaderHeight(0)
66{
67 /* Prepare element: */
68 prepareElement();
69 /* Prepare button: */
70 prepareButton();
71 /* Prepare text-pane: */
72 prepareTextPane();
73
74 /* Setup size-policy: */
75 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
76
77 /* Add item to the parent: */
78 AssertMsg(parentItem(), ("No parent set for details element!"));
79 parentItem()->addItem(this);
80}
81
82UIDetailsElement::~UIDetailsElement()
83{
84 /* Remove item from the parent: */
85 AssertMsg(parentItem(), ("No parent set for details element!"));
86 parentItem()->removeItem(this);
87}
88
89void UIDetailsElement::setText(const UITextTable &text)
90{
91 /* Pass text to text-pane: */
92 m_pTextPane->setText(text);
93}
94
95UITextTable &UIDetailsElement::text() const
96{
97 /* Retrieve text from text-pane: */
98 return m_pTextPane->text();
99}
100
101void UIDetailsElement::close(bool fAnimated /* = true */)
102{
103 m_pButton->setToggled(false, fAnimated);
104}
105
106void UIDetailsElement::open(bool fAnimated /* = true */)
107{
108 m_pButton->setToggled(true, fAnimated);
109}
110
111void UIDetailsElement::markAnimationFinished()
112{
113 /* Mark animation as non-running: */
114 m_fAnimationRunning = false;
115
116 /* Recursively update size-hint: */
117 updateGeometry();
118 /* Repaint: */
119 update();
120}
121
122void UIDetailsElement::updateAppearance()
123{
124 /* Reset name hover state: */
125 m_fNameHovered = false;
126 updateNameHoverLink();
127
128 /* Update anchor role restrictions: */
129 ConfigurationAccessLevel cal = m_pSet->configurationAccessLevel();
130 m_pTextPane->setAnchorRoleRestricted("#mount", cal == ConfigurationAccessLevel_Null);
131 m_pTextPane->setAnchorRoleRestricted("#attach", cal != ConfigurationAccessLevel_Full);
132}
133
134int UIDetailsElement::minimumWidthHint() const
135{
136 /* Prepare variables: */
137 int iMargin = data(ElementData_Margin).toInt();
138 int iMinimumWidthHint = 0;
139
140 /* Maximum width: */
141 iMinimumWidthHint = qMax(m_iMinimumHeaderWidth, (int)m_pTextPane->minimumSizeHint().width());
142
143 /* And 4 margins: 2 left and 2 right: */
144 iMinimumWidthHint += 4 * iMargin;
145
146 /* Return result: */
147 return iMinimumWidthHint;
148}
149
150int UIDetailsElement::minimumHeightHint() const
151{
152 return minimumHeightHintForElement(m_fClosed);
153}
154
155void UIDetailsElement::showEvent(QShowEvent *pEvent)
156{
157 /* Call to base-class: */
158 UIDetailsItem::showEvent(pEvent);
159
160 /* Update icon: */
161 updateIcon();
162}
163
164void UIDetailsElement::resizeEvent(QGraphicsSceneResizeEvent*)
165{
166 /* Update layout: */
167 updateLayout();
168}
169
170void UIDetailsElement::hoverMoveEvent(QGraphicsSceneHoverEvent *pEvent)
171{
172 /* Update hover state: */
173 if (!m_fHovered)
174 {
175 m_fHovered = true;
176 emit sigHoverEnter();
177 }
178
179 /* Update name-hover state: */
180 handleHoverEvent(pEvent);
181}
182
183void UIDetailsElement::hoverLeaveEvent(QGraphicsSceneHoverEvent *pEvent)
184{
185 /* Update hover state: */
186 if (m_fHovered)
187 {
188 m_fHovered = false;
189 emit sigHoverLeave();
190 }
191
192 /* Update name-hover state: */
193 handleHoverEvent(pEvent);
194}
195
196void UIDetailsElement::mousePressEvent(QGraphicsSceneMouseEvent *pEvent)
197{
198 /* Only for hovered header: */
199 if (!m_fNameHovered)
200 return;
201
202 /* Process link click: */
203 pEvent->accept();
204 QString strCategory;
205 if (m_enmType >= DetailsElementType_General &&
206 m_enmType < DetailsElementType_Description)
207 strCategory = QString("#%1").arg(gpConverter->toInternalString(m_enmType));
208 else if (m_enmType == DetailsElementType_Description)
209 strCategory = QString("#%1%%mTeDescription").arg(gpConverter->toInternalString(m_enmType));
210 emit sigLinkClicked(strCategory, QString(), machine().GetId());
211}
212
213void UIDetailsElement::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *pEvent)
214{
215 /* Only for left-button: */
216 if (pEvent->button() != Qt::LeftButton)
217 return;
218
219 /* Process left-button double-click: */
220 emit sigToggleElement(m_enmType, isClosed());
221}
222
223void UIDetailsElement::paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOptions, QWidget *)
224{
225 /* Update button visibility: */
226 updateButtonVisibility();
227
228 /* Configure painter shape: */
229 configurePainterShape(pPainter, pOptions, m_iCornerRadius);
230
231 /* Paint decorations: */
232 paintDecorations(pPainter, pOptions);
233
234 /* Paint element info: */
235 paintElementInfo(pPainter, pOptions);
236}
237
238QString UIDetailsElement::description() const
239{
240 return tr("%1 details", "like 'General details' or 'Storage details'").arg(m_strName);
241}
242
243const CMachine &UIDetailsElement::machine()
244{
245 return m_pSet->machine();
246}
247
248void UIDetailsElement::setName(const QString &strName)
249{
250 /* Cache name: */
251 m_strName = strName;
252 QFontMetrics fm(m_nameFont, model()->paintDevice());
253 m_nameSize = QSize(fm.width(m_strName), fm.height());
254
255 /* Update linked values: */
256 updateMinimumHeaderWidth();
257 updateMinimumHeaderHeight();
258}
259
260void UIDetailsElement::setAdditionalHeight(int iAdditionalHeight)
261{
262 /* Cache new value: */
263 m_iAdditionalHeight = iAdditionalHeight;
264 /* Update layout: */
265 updateLayout();
266 /* Repaint: */
267 update();
268}
269
270QVariant UIDetailsElement::data(int iKey) const
271{
272 /* Provide other members with required data: */
273 switch (iKey)
274 {
275 /* Hints: */
276 case ElementData_Margin: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 4;
277 case ElementData_Spacing: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 2;
278 /* Default: */
279 default: break;
280 }
281 return QVariant();
282}
283
284void UIDetailsElement::addItem(UIDetailsItem*)
285{
286 AssertMsgFailed(("Details element do NOT support children!"));
287}
288
289void UIDetailsElement::removeItem(UIDetailsItem*)
290{
291 AssertMsgFailed(("Details element do NOT support children!"));
292}
293
294QList<UIDetailsItem*> UIDetailsElement::items(UIDetailsItemType) const
295{
296 AssertMsgFailed(("Details element do NOT support children!"));
297 return QList<UIDetailsItem*>();
298}
299
300bool UIDetailsElement::hasItems(UIDetailsItemType) const
301{
302 AssertMsgFailed(("Details element do NOT support children!"));
303 return false;
304}
305
306void UIDetailsElement::clearItems(UIDetailsItemType)
307{
308 AssertMsgFailed(("Details element do NOT support children!"));
309}
310
311void UIDetailsElement::updateLayout()
312{
313 /* Prepare variables: */
314 QSize size = geometry().size().toSize();
315 int iMargin = data(ElementData_Margin).toInt();
316
317 /* Layout button: */
318 int iButtonWidth = m_buttonSize.width();
319 int iButtonHeight = m_buttonSize.height();
320 int iButtonX = size.width() - 2 * iMargin - iButtonWidth;
321 int iButtonY = iButtonHeight == m_iMinimumHeaderHeight ? iMargin :
322 iMargin + (m_iMinimumHeaderHeight - iButtonHeight) / 2;
323 m_pButton->setPos(iButtonX, iButtonY);
324
325 /* If closed: */
326 if (isClosed())
327 {
328 /* Hide text-pane if still visible: */
329 if (m_pTextPane->isVisible())
330 m_pTextPane->hide();
331 }
332 /* If opened: */
333 else
334 {
335 /* Layout text-pane: */
336 int iTextPaneX = 2 * iMargin;
337 int iTextPaneY = iMargin + m_iMinimumHeaderHeight + 2 * iMargin;
338 m_pTextPane->setPos(iTextPaneX, iTextPaneY);
339 m_pTextPane->resize(size.width() - 4 * iMargin,
340 size.height() - 4 * iMargin - m_iMinimumHeaderHeight);
341 /* Show text-pane if still invisible and animation finished: */
342 if (!m_pTextPane->isVisible() && !isAnimationRunning())
343 m_pTextPane->show();
344 }
345}
346
347int UIDetailsElement::minimumHeightHintForElement(bool fClosed) const
348{
349 /* Prepare variables: */
350 int iMargin = data(ElementData_Margin).toInt();
351 int iMinimumHeightHint = 0;
352
353 /* Two margins: */
354 iMinimumHeightHint += 2 * iMargin;
355
356 /* Header height: */
357 iMinimumHeightHint += m_iMinimumHeaderHeight;
358
359 /* Element is opened? */
360 if (!fClosed)
361 {
362 /* Add text height: */
363 if (!m_pTextPane->isEmpty())
364 iMinimumHeightHint += 2 * iMargin + (int)m_pTextPane->minimumSizeHint().height();
365 }
366
367 /* Additional height during animation: */
368 if (m_fAnimationRunning)
369 iMinimumHeightHint += m_iAdditionalHeight;
370
371 /* Return value: */
372 return iMinimumHeightHint;
373}
374
375void UIDetailsElement::sltHandleWindowRemapped()
376{
377 /* Update icon: */
378 updateIcon();
379}
380
381void UIDetailsElement::sltToggleButtonClicked()
382{
383 emit sigToggleElement(m_enmType, isClosed());
384}
385
386void UIDetailsElement::sltElementToggleStart()
387{
388 /* Mark animation running: */
389 m_fAnimationRunning = true;
390
391 /* Setup animation: */
392 updateAnimationParameters();
393
394 /* Invert toggle-state: */
395 m_fClosed = !m_fClosed;
396}
397
398void UIDetailsElement::sltElementToggleFinish(bool fToggled)
399{
400 /* Update toggle-state: */
401 m_fClosed = !fToggled;
402
403 /* Notify about finishing: */
404 emit sigToggleElementFinished();
405}
406
407void UIDetailsElement::sltHandleAnchorClicked(const QString &strAnchor)
408{
409 /* Current anchor role: */
410 const QString strRole = strAnchor.section(',', 0, 0);
411 const QString strData = strAnchor.section(',', 1);
412
413 /* Handle known anchor roles: */
414 if ( strRole == "#mount" // Optical and floppy attachments..
415 || strRole == "#attach" // Hard-drive attachments..
416 )
417 {
418 /* Prepare storage-menu: */
419 UIMenu menu;
420 menu.setShowToolTip(true);
421
422 /* Storage-controller name: */
423 QString strControllerName = strData.section(',', 0, 0);
424 /* Storage-slot: */
425 StorageSlot storageSlot = gpConverter->fromString<StorageSlot>(strData.section(',', 1));
426
427 /* Fill storage-menu: */
428 vboxGlobal().prepareStorageMenu(menu, this, SLOT(sltMountStorageMedium()),
429 machine(), strControllerName, storageSlot);
430
431 /* Exec menu: */
432 menu.exec(QCursor::pos());
433 }
434}
435
436void UIDetailsElement::sltMountStorageMedium()
437{
438 /* Sender action: */
439 QAction *pAction = qobject_cast<QAction*>(sender());
440 AssertMsgReturnVoid(pAction, ("This slot should only be called by menu action!\n"));
441
442 /* Current mount-target: */
443 const UIMediumTarget target = pAction->data().value<UIMediumTarget>();
444
445 /* Update current machine mount-target: */
446 vboxGlobal().updateMachineStorage(machine(), target);
447}
448
449void UIDetailsElement::prepareElement()
450{
451 /* Initialization: */
452 m_nameFont = font();
453 m_nameFont.setWeight(QFont::Bold);
454 m_textFont = font();
455
456 /* Update icon: */
457 updateIcon();
458
459 /* Create highlight machine: */
460 m_pHighlightMachine = new QStateMachine(this);
461 /* Create 'default' state: */
462 QState *pStateDefault = new QState(m_pHighlightMachine);
463 pStateDefault->assignProperty(this, "animationDarkness", m_iDefaultDarkness);
464 /* Create 'highlighted' state: */
465 QState *pStateHighlighted = new QState(m_pHighlightMachine);
466 pStateHighlighted->assignProperty(this, "animationDarkness", m_iHighlightDarkness);
467
468 /* Forward animation: */
469 m_pForwardAnimation = new QPropertyAnimation(this, "animationDarkness", this);
470 m_pForwardAnimation->setDuration(m_iAnimationDuration);
471 m_pForwardAnimation->setStartValue(m_iDefaultDarkness);
472 m_pForwardAnimation->setEndValue(m_iHighlightDarkness);
473
474 /* Backward animation: */
475 m_pBackwardAnimation = new QPropertyAnimation(this, "animationDarkness", this);
476 m_pBackwardAnimation->setDuration(m_iAnimationDuration);
477 m_pBackwardAnimation->setStartValue(m_iHighlightDarkness);
478 m_pBackwardAnimation->setEndValue(m_iDefaultDarkness);
479
480 /* Add state transitions: */
481 QSignalTransition *pDefaultToHighlighted = pStateDefault->addTransition(this, SIGNAL(sigHoverEnter()), pStateHighlighted);
482 pDefaultToHighlighted->addAnimation(m_pForwardAnimation);
483 QSignalTransition *pHighlightedToDefault = pStateHighlighted->addTransition(this, SIGNAL(sigHoverLeave()), pStateDefault);
484 pHighlightedToDefault->addAnimation(m_pBackwardAnimation);
485
486 /* Initial state is 'default': */
487 m_pHighlightMachine->setInitialState(pStateDefault);
488 /* Start state-machine: */
489 m_pHighlightMachine->start();
490
491 /* Configure connections: */
492 connect(gpManager, &UIVirtualBoxManager::sigWindowRemapped,
493 this, &UIDetailsElement::sltHandleWindowRemapped);
494 connect(this, SIGNAL(sigToggleElement(DetailsElementType, bool)),
495 model(), SLOT(sltToggleElements(DetailsElementType, bool)));
496 connect(this, SIGNAL(sigLinkClicked(const QString&, const QString&, const QString&)),
497 model(), SIGNAL(sigLinkClicked(const QString&, const QString&, const QString&)));
498}
499
500void UIDetailsElement::prepareButton()
501{
502 /* Setup toggle-button: */
503 m_pButton = new UIGraphicsRotatorButton(this, "additionalHeight", !m_fClosed, true /* reflected */);
504 m_pButton->setAutoHandleButtonClick(false);
505 connect(m_pButton, SIGNAL(sigButtonClicked()), this, SLOT(sltToggleButtonClicked()));
506 connect(m_pButton, SIGNAL(sigRotationStart()), this, SLOT(sltElementToggleStart()));
507 connect(m_pButton, SIGNAL(sigRotationFinish(bool)), this, SLOT(sltElementToggleFinish(bool)));
508 m_buttonSize = m_pButton->minimumSizeHint().toSize();
509}
510
511void UIDetailsElement::prepareTextPane()
512{
513 /* Create text-pane: */
514 m_pTextPane = new UIGraphicsTextPane(this, model()->paintDevice());
515 connect(m_pTextPane, SIGNAL(sigGeometryChanged()), this, SLOT(sltUpdateGeometry()));
516 connect(m_pTextPane, SIGNAL(sigAnchorClicked(const QString&)), this, SLOT(sltHandleAnchorClicked(const QString&)));
517}
518
519void UIDetailsElement::updateIcon()
520{
521 /* Prepare whole icon first of all: */
522 const QIcon icon = gpConverter->toIcon(elementType());
523
524 /* Cache icon: */
525 if (icon.isNull())
526 {
527 /* No icon provided: */
528 m_pixmapSize = QSize();
529 m_pixmap = QPixmap();
530 }
531 else
532 {
533 /* Determine default icon size: */
534 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
535 m_pixmapSize = QSize(iIconMetric, iIconMetric);
536 /* Acquire the icon of corresponding size (taking top-level widget DPI into account): */
537 m_pixmap = icon.pixmap(gpManager->windowHandle(), m_pixmapSize);
538 }
539
540 /* Update linked values: */
541 updateMinimumHeaderWidth();
542 updateMinimumHeaderHeight();
543}
544
545void UIDetailsElement::handleHoverEvent(QGraphicsSceneHoverEvent *pEvent)
546{
547 /* Not for 'preview' element type: */
548 if (m_enmType == DetailsElementType_Preview)
549 return;
550
551 /* Prepare variables: */
552 int iMargin = data(ElementData_Margin).toInt();
553 int iSpacing = data(ElementData_Spacing).toInt();
554 int iNameHeight = m_nameSize.height();
555 int iElementNameX = 2 * iMargin + m_pixmapSize.width() + iSpacing;
556 int iElementNameY = iNameHeight == m_iMinimumHeaderHeight ?
557 iMargin : iMargin + (m_iMinimumHeaderHeight - iNameHeight) / 2;
558
559 /* Simulate hyperlink hovering: */
560 QPoint point = pEvent->pos().toPoint();
561 bool fNameHovered = QRect(QPoint(iElementNameX, iElementNameY), m_nameSize).contains(point);
562 if ( m_pSet->configurationAccessLevel() != ConfigurationAccessLevel_Null
563 && m_fNameHovered != fNameHovered)
564 {
565 m_fNameHovered = fNameHovered;
566 updateNameHoverLink();
567 }
568}
569
570void UIDetailsElement::updateNameHoverLink()
571{
572 if (m_fNameHovered)
573 VBoxGlobal::setCursor(this, Qt::PointingHandCursor);
574 else
575 VBoxGlobal::unsetCursor(this);
576 update();
577}
578
579void UIDetailsElement::updateAnimationParameters()
580{
581 /* Recalculate animation parameters: */
582 int iOpenedHeight = minimumHeightHintForElement(false);
583 int iClosedHeight = minimumHeightHintForElement(true);
584 int iAdditionalHeight = iOpenedHeight - iClosedHeight;
585 if (m_fClosed)
586 m_iAdditionalHeight = 0;
587 else
588 m_iAdditionalHeight = iAdditionalHeight;
589 m_pButton->setAnimationRange(0, iAdditionalHeight);
590}
591
592void UIDetailsElement::updateButtonVisibility()
593{
594 if (m_fHovered && !m_pButton->isVisible())
595 m_pButton->show();
596 else if (!m_fHovered && m_pButton->isVisible())
597 m_pButton->hide();
598}
599
600void UIDetailsElement::updateMinimumHeaderWidth()
601{
602 /* Prepare variables: */
603 int iSpacing = data(ElementData_Spacing).toInt();
604
605 /* Update minimum-header-width: */
606 m_iMinimumHeaderWidth = m_pixmapSize.width() +
607 iSpacing + m_nameSize.width() +
608 iSpacing + m_buttonSize.width();
609}
610
611void UIDetailsElement::updateMinimumHeaderHeight()
612{
613 /* Update minimum-header-height: */
614 m_iMinimumHeaderHeight = qMax(m_pixmapSize.height(), m_nameSize.height());
615 m_iMinimumHeaderHeight = qMax(m_iMinimumHeaderHeight, m_buttonSize.height());
616}
617
618void UIDetailsElement::paintDecorations(QPainter *pPainter, const QStyleOptionGraphicsItem *pOptions)
619{
620 /* Paint background: */
621 paintBackground(pPainter, pOptions);
622}
623
624void UIDetailsElement::paintElementInfo(QPainter *pPainter, const QStyleOptionGraphicsItem*)
625{
626 /* Initialize some necessary variables: */
627 int iMargin = data(ElementData_Margin).toInt();
628 int iSpacing = data(ElementData_Spacing).toInt();
629
630 /* Calculate attributes: */
631 int iPixmapHeight = m_pixmapSize.height();
632 int iNameHeight = m_nameSize.height();
633 int iMaximumHeight = qMax(iPixmapHeight, iNameHeight);
634
635 /* Prepare color: */
636 QPalette pal = palette();
637 QColor buttonTextColor = pal.color(QPalette::Active, QPalette::ButtonText);
638 QColor linkTextColor = pal.color(QPalette::Active, QPalette::Link);
639
640 /* Paint pixmap: */
641 int iElementPixmapX = 2 * iMargin;
642 int iElementPixmapY = iPixmapHeight == iMaximumHeight ?
643 iMargin : iMargin + (iMaximumHeight - iPixmapHeight) / 2;
644 paintPixmap(/* Painter: */
645 pPainter,
646 /* Rectangle to paint in: */
647 QRect(QPoint(iElementPixmapX, iElementPixmapY), m_pixmapSize),
648 /* Pixmap to paint: */
649 m_pixmap);
650
651 /* Paint name: */
652 int iMachineNameX = iElementPixmapX +
653 m_pixmapSize.width() +
654 iSpacing;
655 int iMachineNameY = iNameHeight == iMaximumHeight ?
656 iMargin : iMargin + (iMaximumHeight - iNameHeight) / 2;
657 paintText(/* Painter: */
658 pPainter,
659 /* Rectangle to paint in: */
660 QPoint(iMachineNameX, iMachineNameY),
661 /* Font to paint text: */
662 m_nameFont,
663 /* Paint device: */
664 model()->paintDevice(),
665 /* Text to paint: */
666 m_strName,
667 /* Name hovered? */
668 m_fNameHovered ? linkTextColor : buttonTextColor);
669}
670
671void UIDetailsElement::paintBackground(QPainter *pPainter, const QStyleOptionGraphicsItem *pOptions)
672{
673 /* Save painter: */
674 pPainter->save();
675
676 /* Prepare variables: */
677 int iMargin = data(ElementData_Margin).toInt();
678 int iHeaderHeight = 2 * iMargin + m_iMinimumHeaderHeight;
679 QRect optionRect = pOptions->rect;
680 QRect fullRect = !m_fAnimationRunning ? optionRect :
681 QRect(optionRect.topLeft(), QSize(optionRect.width(), iHeaderHeight + m_iAdditionalHeight));
682 int iFullHeight = fullRect.height();
683
684 /* Prepare color: */
685 QPalette pal = palette();
686 QColor headerColor = pal.color(QPalette::Active, QPalette::Button);
687 QColor strokeColor = pal.color(QPalette::Active, QPalette::Mid);
688 QColor bodyColor = pal.color(QPalette::Active, QPalette::Base);
689
690 /* Add clipping: */
691 QPainterPath path;
692 path.moveTo(m_iCornerRadius, 0);
693 path.arcTo(QRectF(path.currentPosition(), QSizeF(2 * m_iCornerRadius, 2 * m_iCornerRadius)).translated(-m_iCornerRadius, 0), 90, 90);
694 path.lineTo(path.currentPosition().x(), iFullHeight - m_iCornerRadius);
695 path.arcTo(QRectF(path.currentPosition(), QSizeF(2 * m_iCornerRadius, 2 * m_iCornerRadius)).translated(0, -m_iCornerRadius), 180, 90);
696 path.lineTo(fullRect.width() - m_iCornerRadius, path.currentPosition().y());
697 path.arcTo(QRectF(path.currentPosition(), QSizeF(2 * m_iCornerRadius, 2 * m_iCornerRadius)).translated(-m_iCornerRadius, -2 * m_iCornerRadius), 270, 90);
698 path.lineTo(path.currentPosition().x(), m_iCornerRadius);
699 path.arcTo(QRectF(path.currentPosition(), QSizeF(2 * m_iCornerRadius, 2 * m_iCornerRadius)).translated(-2 * m_iCornerRadius, -m_iCornerRadius), 0, 90);
700 path.closeSubpath();
701 pPainter->setClipPath(path);
702
703 /* Calculate top rectangle: */
704 QRect tRect = fullRect;
705 tRect.setBottom(tRect.top() + iHeaderHeight);
706 /* Calculate bottom rectangle: */
707 QRect bRect = fullRect;
708 bRect.setTop(tRect.bottom());
709
710 /* Prepare top gradient: */
711 QLinearGradient tGradient(tRect.bottomLeft(), tRect.topLeft());
712 tGradient.setColorAt(0, headerColor.darker(110));
713 tGradient.setColorAt(1, headerColor.darker(animationDarkness()));
714
715 /* Paint all the stuff: */
716 pPainter->fillRect(tRect, tGradient);
717 pPainter->fillRect(bRect, bodyColor);
718
719 /* Stroke path: */
720 pPainter->setClipping(false);
721 pPainter->strokePath(path, strokeColor);
722
723 /* Restore painter: */
724 pPainter->restore();
725}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette