VirtualBox

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

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

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
  • Property svn:mergeinfo set to (toggle deleted branches)
    /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
    /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp79225,​79271
File size: 25.0 KB
Line 
1/* $Id: UIDetailsElement.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIDetailsElement class implementation.
4 */
5
6/*
7 * Copyright (C) 2012-2019 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 "UIExtraDataManager.h"
37# include "UIGraphicsRotatorButton.h"
38# include "UIGraphicsTextPane.h"
39# include "UIIconPool.h"
40# include "UIVirtualBoxManager.h"
41# include "VBoxGlobal.h"
42
43#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
44
45
46UIDetailsElement::UIDetailsElement(UIDetailsSet *pParent, DetailsElementType enmType, bool fOpened)
47 : UIDetailsItem(pParent)
48 , m_pSet(pParent)
49 , m_enmType(enmType)
50#ifdef VBOX_WS_MAC
51 , m_iDefaultToneStart(145)
52 , m_iDefaultToneFinal(155)
53 , m_iHoverToneStart(115)
54 , m_iHoverToneFinal(125)
55#else
56 , m_iDefaultToneStart(160)
57 , m_iDefaultToneFinal(190)
58 , m_iHoverToneStart(160)
59 , m_iHoverToneFinal(190)
60#endif
61 , m_fHovered(false)
62 , m_fNameHovered(false)
63 , m_pHoveringMachine(0)
64 , m_pHoveringAnimationForward(0)
65 , m_pHoveringAnimationBackward(0)
66 , m_iAnimationDuration(300)
67 , m_iDefaultValue(0)
68 , m_iHoveredValue(255)
69 , m_iAnimatedValue(m_iDefaultValue)
70 , m_pButton(0)
71 , m_fClosed(!fOpened)
72 , m_fAnimationRunning(false)
73 , m_iAdditionalHeight(0)
74 , m_pTextPane(0)
75 , m_iMinimumHeaderWidth(0)
76 , m_iMinimumHeaderHeight(0)
77{
78 /* Prepare element: */
79 prepareElement();
80 /* Prepare button: */
81 prepareButton();
82 /* Prepare text-pane: */
83 prepareTextPane();
84
85 /* Setup size-policy: */
86 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
87
88 /* Add item to the parent: */
89 AssertMsg(parentItem(), ("No parent set for details element!"));
90 parentItem()->addItem(this);
91}
92
93UIDetailsElement::~UIDetailsElement()
94{
95 /* Remove item from the parent: */
96 AssertMsg(parentItem(), ("No parent set for details element!"));
97 parentItem()->removeItem(this);
98}
99
100void UIDetailsElement::setText(const UITextTable &text)
101{
102 /* Pass text to text-pane: */
103 m_pTextPane->setText(text);
104}
105
106UITextTable &UIDetailsElement::text() const
107{
108 /* Retrieve text from text-pane: */
109 return m_pTextPane->text();
110}
111
112void UIDetailsElement::close(bool fAnimated /* = true */)
113{
114 m_pButton->setToggled(false, fAnimated);
115}
116
117void UIDetailsElement::open(bool fAnimated /* = true */)
118{
119 m_pButton->setToggled(true, fAnimated);
120}
121
122void UIDetailsElement::markAnimationFinished()
123{
124 /* Mark animation as non-running: */
125 m_fAnimationRunning = false;
126
127 /* Recursively update size-hint: */
128 updateGeometry();
129 /* Repaint: */
130 update();
131}
132
133void UIDetailsElement::updateAppearance()
134{
135 /* Reset name hover state: */
136 m_fNameHovered = false;
137 updateNameHoverLink();
138
139 /* Update anchor role restrictions: */
140 ConfigurationAccessLevel cal = m_pSet->configurationAccessLevel();
141 m_pTextPane->setAnchorRoleRestricted("#mount", cal == ConfigurationAccessLevel_Null);
142 m_pTextPane->setAnchorRoleRestricted("#attach", cal != ConfigurationAccessLevel_Full);
143}
144
145int UIDetailsElement::minimumWidthHint() const
146{
147 /* Prepare variables: */
148 int iMargin = data(ElementData_Margin).toInt();
149 int iMinimumWidthHint = 0;
150
151 /* Maximum width: */
152 iMinimumWidthHint = qMax(m_iMinimumHeaderWidth, (int)m_pTextPane->minimumSizeHint().width());
153
154 /* And 4 margins: 2 left and 2 right: */
155 iMinimumWidthHint += 4 * iMargin;
156
157 /* Return result: */
158 return iMinimumWidthHint;
159}
160
161int UIDetailsElement::minimumHeightHint() const
162{
163 return minimumHeightHintForElement(m_fClosed);
164}
165
166void UIDetailsElement::showEvent(QShowEvent *pEvent)
167{
168 /* Call to base-class: */
169 UIDetailsItem::showEvent(pEvent);
170
171 /* Update icon: */
172 updateIcon();
173}
174
175void UIDetailsElement::resizeEvent(QGraphicsSceneResizeEvent*)
176{
177 /* Update layout: */
178 updateLayout();
179}
180
181void UIDetailsElement::hoverMoveEvent(QGraphicsSceneHoverEvent *pEvent)
182{
183 /* Update hover state: */
184 if (!m_fHovered)
185 {
186 m_fHovered = true;
187 emit sigHoverEnter();
188 }
189
190 /* Update name-hover state: */
191 handleHoverEvent(pEvent);
192}
193
194void UIDetailsElement::hoverLeaveEvent(QGraphicsSceneHoverEvent *pEvent)
195{
196 /* Update hover state: */
197 if (m_fHovered)
198 {
199 m_fHovered = false;
200 emit sigHoverLeave();
201 }
202
203 /* Update name-hover state: */
204 handleHoverEvent(pEvent);
205}
206
207void UIDetailsElement::mousePressEvent(QGraphicsSceneMouseEvent *pEvent)
208{
209 /* Only for hovered header: */
210 if (!m_fNameHovered)
211 return;
212
213 /* Process link click: */
214 pEvent->accept();
215 QString strCategory;
216 if (m_enmType >= DetailsElementType_General &&
217 m_enmType < DetailsElementType_Description)
218 strCategory = QString("#%1").arg(gpConverter->toInternalString(m_enmType));
219 else if (m_enmType == DetailsElementType_Description)
220 strCategory = QString("#%1%%mTeDescription").arg(gpConverter->toInternalString(m_enmType));
221 emit sigLinkClicked(strCategory, QString(), machine().GetId());
222}
223
224void UIDetailsElement::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *pEvent)
225{
226 /* Only for left-button: */
227 if (pEvent->button() != Qt::LeftButton)
228 return;
229
230 /* Process left-button double-click: */
231 emit sigToggleElement(m_enmType, isClosed());
232}
233
234void UIDetailsElement::paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOptions, QWidget *)
235{
236 /* Update button visibility: */
237 updateButtonVisibility();
238
239 /* Paint background: */
240 paintBackground(pPainter, pOptions);
241 /* Paint frame: */
242 paintFrame(pPainter, pOptions);
243 /* Paint element info: */
244 paintElementInfo(pPainter, pOptions);
245}
246
247QString UIDetailsElement::description() const
248{
249 return tr("%1 details", "like 'General details' or 'Storage details'").arg(m_strName);
250}
251
252const CMachine &UIDetailsElement::machine()
253{
254 return m_pSet->machine();
255}
256
257void UIDetailsElement::setName(const QString &strName)
258{
259 /* Cache name: */
260 m_strName = strName;
261 QFontMetrics fm(m_nameFont, model()->paintDevice());
262 m_nameSize = QSize(fm.width(m_strName), fm.height());
263
264 /* Update linked values: */
265 updateMinimumHeaderWidth();
266 updateMinimumHeaderHeight();
267}
268
269void UIDetailsElement::setAdditionalHeight(int iAdditionalHeight)
270{
271 /* Cache new value: */
272 m_iAdditionalHeight = iAdditionalHeight;
273 /* Update layout: */
274 updateLayout();
275 /* Repaint: */
276 update();
277}
278
279QVariant UIDetailsElement::data(int iKey) const
280{
281 /* Provide other members with required data: */
282 switch (iKey)
283 {
284 /* Hints: */
285 case ElementData_Margin: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 4;
286 case ElementData_Spacing: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 2;
287 /* Default: */
288 default: break;
289 }
290 return QVariant();
291}
292
293void UIDetailsElement::addItem(UIDetailsItem*)
294{
295 AssertMsgFailed(("Details element do NOT support children!"));
296}
297
298void UIDetailsElement::removeItem(UIDetailsItem*)
299{
300 AssertMsgFailed(("Details element do NOT support children!"));
301}
302
303QList<UIDetailsItem*> UIDetailsElement::items(UIDetailsItemType) const
304{
305 AssertMsgFailed(("Details element do NOT support children!"));
306 return QList<UIDetailsItem*>();
307}
308
309bool UIDetailsElement::hasItems(UIDetailsItemType) const
310{
311 AssertMsgFailed(("Details element do NOT support children!"));
312 return false;
313}
314
315void UIDetailsElement::clearItems(UIDetailsItemType)
316{
317 AssertMsgFailed(("Details element do NOT support children!"));
318}
319
320void UIDetailsElement::updateLayout()
321{
322 /* Prepare variables: */
323 QSize size = geometry().size().toSize();
324 int iMargin = data(ElementData_Margin).toInt();
325
326 /* Layout button: */
327 int iButtonWidth = m_buttonSize.width();
328 int iButtonHeight = m_buttonSize.height();
329 int iButtonX = size.width() - 2 * iMargin - iButtonWidth;
330 int iButtonY = iButtonHeight == m_iMinimumHeaderHeight ? iMargin :
331 iMargin + (m_iMinimumHeaderHeight - iButtonHeight) / 2;
332 m_pButton->setPos(iButtonX, iButtonY);
333
334 /* If closed: */
335 if (isClosed())
336 {
337 /* Hide text-pane if still visible: */
338 if (m_pTextPane->isVisible())
339 m_pTextPane->hide();
340 }
341 /* If opened: */
342 else
343 {
344 /* Layout text-pane: */
345 int iTextPaneX = 2 * iMargin;
346 int iTextPaneY = iMargin + m_iMinimumHeaderHeight + 2 * iMargin;
347 m_pTextPane->setPos(iTextPaneX, iTextPaneY);
348 m_pTextPane->resize(size.width() - 4 * iMargin,
349 size.height() - 4 * iMargin - m_iMinimumHeaderHeight);
350 /* Show text-pane if still invisible and animation finished: */
351 if (!m_pTextPane->isVisible() && !isAnimationRunning())
352 m_pTextPane->show();
353 }
354}
355
356int UIDetailsElement::minimumHeightHintForElement(bool fClosed) const
357{
358 /* Prepare variables: */
359 int iMargin = data(ElementData_Margin).toInt();
360 int iMinimumHeightHint = 0;
361
362 /* Two margins: */
363 iMinimumHeightHint += 2 * iMargin;
364
365 /* Header height: */
366 iMinimumHeightHint += m_iMinimumHeaderHeight;
367
368 /* Element is opened? */
369 if (!fClosed)
370 {
371 /* Add text height: */
372 if (!m_pTextPane->isEmpty())
373 iMinimumHeightHint += 2 * iMargin + (int)m_pTextPane->minimumSizeHint().height();
374 }
375
376 /* Additional height during animation: */
377 if (m_fAnimationRunning)
378 iMinimumHeightHint += m_iAdditionalHeight;
379
380 /* Return value: */
381 return iMinimumHeightHint;
382}
383
384void UIDetailsElement::sltHandleWindowRemapped()
385{
386 /* Update icon: */
387 updateIcon();
388}
389
390void UIDetailsElement::sltToggleButtonClicked()
391{
392 emit sigToggleElement(m_enmType, isClosed());
393}
394
395void UIDetailsElement::sltElementToggleStart()
396{
397 /* Mark animation running: */
398 m_fAnimationRunning = true;
399
400 /* Setup animation: */
401 updateAnimationParameters();
402
403 /* Invert toggle-state: */
404 m_fClosed = !m_fClosed;
405}
406
407void UIDetailsElement::sltElementToggleFinish(bool fToggled)
408{
409 /* Update toggle-state: */
410 m_fClosed = !fToggled;
411
412 /* Notify about finishing: */
413 emit sigToggleElementFinished();
414}
415
416void UIDetailsElement::sltHandleAnchorClicked(const QString &strAnchor)
417{
418 /* Current anchor role: */
419 const QString strRole = strAnchor.section(',', 0, 0);
420 const QString strData = strAnchor.section(',', 1);
421
422 /* Handle known anchor roles: */
423 if ( strRole == "#mount" // Optical and floppy attachments..
424 || strRole == "#attach" // Hard-drive attachments..
425 )
426 {
427 /* Prepare storage-menu: */
428 UIMenu menu;
429 menu.setShowToolTip(true);
430
431 /* Storage-controller name: */
432 QString strControllerName = strData.section(',', 0, 0);
433 /* Storage-slot: */
434 StorageSlot storageSlot = gpConverter->fromString<StorageSlot>(strData.section(',', 1));
435
436 /* Fill storage-menu: */
437 vboxGlobal().prepareStorageMenu(menu, this, SLOT(sltMountStorageMedium()),
438 machine(), strControllerName, storageSlot);
439
440 /* Exec menu: */
441 menu.exec(QCursor::pos());
442 }
443}
444
445void UIDetailsElement::sltMountStorageMedium()
446{
447 /* Sender action: */
448 QAction *pAction = qobject_cast<QAction*>(sender());
449 AssertMsgReturnVoid(pAction, ("This slot should only be called by menu action!\n"));
450
451 /* Current mount-target: */
452 const UIMediumTarget target = pAction->data().value<UIMediumTarget>();
453
454 /* Update current machine mount-target: */
455 vboxGlobal().updateMachineStorage(machine(), target);
456}
457
458void UIDetailsElement::prepareElement()
459{
460 /* Initialization: */
461 m_nameFont = font();
462 m_nameFont.setWeight(QFont::Bold);
463 m_textFont = font();
464
465 /* Update icon: */
466 updateIcon();
467
468 /* Create hovering animation machine: */
469 m_pHoveringMachine = new QStateMachine(this);
470 if (m_pHoveringMachine)
471 {
472 /* Create 'default' state: */
473 QState *pStateDefault = new QState(m_pHoveringMachine);
474 /* Create 'hovered' state: */
475 QState *pStateHovered = new QState(m_pHoveringMachine);
476
477 /* Configure 'default' state: */
478 if (pStateDefault)
479 {
480 /* When we entering default state => we assigning animatedValue to m_iDefaultValue: */
481 pStateDefault->assignProperty(this, "animatedValue", m_iDefaultValue);
482
483 /* Add state transition: */
484 QSignalTransition *pDefaultToHovered = pStateDefault->addTransition(this, SIGNAL(sigHoverEnter()), pStateHovered);
485 if (pDefaultToHovered)
486 {
487 /* Create forward animation: */
488 m_pHoveringAnimationForward = new QPropertyAnimation(this, "animatedValue", this);
489 if (m_pHoveringAnimationForward)
490 {
491 m_pHoveringAnimationForward->setDuration(m_iAnimationDuration);
492 m_pHoveringAnimationForward->setStartValue(m_iDefaultValue);
493 m_pHoveringAnimationForward->setEndValue(m_iHoveredValue);
494
495 /* Add to transition: */
496 pDefaultToHovered->addAnimation(m_pHoveringAnimationForward);
497 }
498 }
499 }
500
501 /* Configure 'hovered' state: */
502 if (pStateHovered)
503 {
504 /* When we entering hovered state => we assigning animatedValue to m_iHoveredValue: */
505 pStateHovered->assignProperty(this, "animatedValue", m_iHoveredValue);
506
507 /* Add state transition: */
508 QSignalTransition *pHoveredToDefault = pStateHovered->addTransition(this, SIGNAL(sigHoverLeave()), pStateDefault);
509 if (pHoveredToDefault)
510 {
511 /* Create backward animation: */
512 m_pHoveringAnimationBackward = new QPropertyAnimation(this, "animatedValue", this);
513 if (m_pHoveringAnimationBackward)
514 {
515 m_pHoveringAnimationBackward->setDuration(m_iAnimationDuration);
516 m_pHoveringAnimationBackward->setStartValue(m_iHoveredValue);
517 m_pHoveringAnimationBackward->setEndValue(m_iDefaultValue);
518
519 /* Add to transition: */
520 pHoveredToDefault->addAnimation(m_pHoveringAnimationBackward);
521 }
522 }
523 }
524
525 /* Initial state is 'default': */
526 m_pHoveringMachine->setInitialState(pStateDefault);
527 /* Start state-machine: */
528 m_pHoveringMachine->start();
529 }
530
531 /* Configure connections: */
532 connect(gpManager, &UIVirtualBoxManager::sigWindowRemapped,
533 this, &UIDetailsElement::sltHandleWindowRemapped);
534 connect(this, SIGNAL(sigToggleElement(DetailsElementType, bool)),
535 model(), SLOT(sltToggleElements(DetailsElementType, bool)));
536 connect(this, SIGNAL(sigLinkClicked(const QString&, const QString&, const QUuid &)),
537 model(), SIGNAL(sigLinkClicked(const QString&, const QString&, const QUuid &)));
538}
539
540void UIDetailsElement::prepareButton()
541{
542 /* Setup toggle-button: */
543 m_pButton = new UIGraphicsRotatorButton(this, "additionalHeight", !m_fClosed, true /* reflected */);
544 m_pButton->setAutoHandleButtonClick(false);
545 connect(m_pButton, SIGNAL(sigButtonClicked()), this, SLOT(sltToggleButtonClicked()));
546 connect(m_pButton, SIGNAL(sigRotationStart()), this, SLOT(sltElementToggleStart()));
547 connect(m_pButton, SIGNAL(sigRotationFinish(bool)), this, SLOT(sltElementToggleFinish(bool)));
548 m_buttonSize = m_pButton->minimumSizeHint().toSize();
549}
550
551void UIDetailsElement::prepareTextPane()
552{
553 /* Create text-pane: */
554 m_pTextPane = new UIGraphicsTextPane(this, model()->paintDevice());
555 connect(m_pTextPane, SIGNAL(sigGeometryChanged()), this, SLOT(sltUpdateGeometry()));
556 connect(m_pTextPane, SIGNAL(sigAnchorClicked(const QString&)), this, SLOT(sltHandleAnchorClicked(const QString&)));
557}
558
559void UIDetailsElement::updateIcon()
560{
561 /* Prepare whole icon first of all: */
562 const QIcon icon = gpConverter->toIcon(elementType());
563
564 /* Cache icon: */
565 if (icon.isNull())
566 {
567 /* No icon provided: */
568 m_pixmapSize = QSize();
569 m_pixmap = QPixmap();
570 }
571 else
572 {
573 /* Determine default icon size: */
574 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
575 m_pixmapSize = QSize(iIconMetric, iIconMetric);
576 /* Acquire the icon of corresponding size (taking top-level widget DPI into account): */
577 m_pixmap = icon.pixmap(gpManager->windowHandle(), m_pixmapSize);
578 }
579
580 /* Update linked values: */
581 updateMinimumHeaderWidth();
582 updateMinimumHeaderHeight();
583}
584
585void UIDetailsElement::handleHoverEvent(QGraphicsSceneHoverEvent *pEvent)
586{
587 /* Not for 'preview' element type: */
588 if (m_enmType == DetailsElementType_Preview)
589 return;
590
591 /* Prepare variables: */
592 int iMargin = data(ElementData_Margin).toInt();
593 int iSpacing = data(ElementData_Spacing).toInt();
594 int iNameHeight = m_nameSize.height();
595 int iElementNameX = 2 * iMargin + m_pixmapSize.width() + iSpacing;
596 int iElementNameY = iNameHeight == m_iMinimumHeaderHeight ?
597 iMargin : iMargin + (m_iMinimumHeaderHeight - iNameHeight) / 2;
598
599 /* Simulate hyperlink hovering: */
600 QPoint point = pEvent->pos().toPoint();
601 bool fNameHovered = QRect(QPoint(iElementNameX, iElementNameY), m_nameSize).contains(point);
602 if ( m_pSet->configurationAccessLevel() != ConfigurationAccessLevel_Null
603 && m_fNameHovered != fNameHovered)
604 {
605 m_fNameHovered = fNameHovered;
606 updateNameHoverLink();
607 }
608}
609
610void UIDetailsElement::updateNameHoverLink()
611{
612 if (m_fNameHovered)
613 VBoxGlobal::setCursor(this, Qt::PointingHandCursor);
614 else
615 VBoxGlobal::unsetCursor(this);
616 update();
617}
618
619void UIDetailsElement::updateAnimationParameters()
620{
621 /* Recalculate animation parameters: */
622 int iOpenedHeight = minimumHeightHintForElement(false);
623 int iClosedHeight = minimumHeightHintForElement(true);
624 int iAdditionalHeight = iOpenedHeight - iClosedHeight;
625 if (m_fClosed)
626 m_iAdditionalHeight = 0;
627 else
628 m_iAdditionalHeight = iAdditionalHeight;
629 m_pButton->setAnimationRange(0, iAdditionalHeight);
630}
631
632void UIDetailsElement::updateButtonVisibility()
633{
634 if (m_fHovered && !m_pButton->isVisible())
635 m_pButton->show();
636 else if (!m_fHovered && m_pButton->isVisible())
637 m_pButton->hide();
638}
639
640void UIDetailsElement::updateMinimumHeaderWidth()
641{
642 /* Prepare variables: */
643 int iSpacing = data(ElementData_Spacing).toInt();
644
645 /* Update minimum-header-width: */
646 m_iMinimumHeaderWidth = m_pixmapSize.width() +
647 iSpacing + m_nameSize.width() +
648 iSpacing + m_buttonSize.width();
649}
650
651void UIDetailsElement::updateMinimumHeaderHeight()
652{
653 /* Update minimum-header-height: */
654 m_iMinimumHeaderHeight = qMax(m_pixmapSize.height(), m_nameSize.height());
655 m_iMinimumHeaderHeight = qMax(m_iMinimumHeaderHeight, m_buttonSize.height());
656}
657
658void UIDetailsElement::paintBackground(QPainter *pPainter, const QStyleOptionGraphicsItem *pOptions) const
659{
660 /* Save painter: */
661 pPainter->save();
662
663 /* Prepare variables: */
664 const int iMargin = data(ElementData_Margin).toInt();
665 const int iHeadHeight = 2 * iMargin + m_iMinimumHeaderHeight;
666 const QRect optionRect = pOptions->rect;
667 const QRect headRect = QRect(optionRect.topLeft(), QSize(optionRect.width(), iHeadHeight));
668 const QRect fullRect = m_fAnimationRunning
669 ? QRect(optionRect.topLeft(), QSize(optionRect.width(), iHeadHeight + m_iAdditionalHeight))
670 : optionRect;
671
672 /* Acquire palette: */
673 const QPalette pal = palette();
674
675 /* Paint default background: */
676 const QColor defaultColor = pal.color(QPalette::Active, QPalette::Mid);
677 const QColor dcTone1 = defaultColor.lighter(m_iDefaultToneFinal);
678 const QColor dcTone2 = defaultColor.lighter(m_iDefaultToneStart);
679 QLinearGradient gradientDefault(fullRect.topLeft(), fullRect.bottomLeft());
680 gradientDefault.setColorAt(0, dcTone1);
681 gradientDefault.setColorAt(1, dcTone2);
682 pPainter->fillRect(fullRect, gradientDefault);
683
684 /* If element is hovered: */
685 if (m_fHovered)
686 {
687 /* Paint hovered background: */
688 const QColor hoveredColor = pal.color(QPalette::Active, QPalette::Highlight);
689 QColor hcTone1 = hoveredColor.lighter(m_iHoverToneFinal);
690 QColor hcTone2 = hoveredColor.lighter(m_iHoverToneStart);
691 hcTone1.setAlpha(m_iAnimatedValue);
692 hcTone2.setAlpha(m_iAnimatedValue);
693 QLinearGradient gradientHovered(headRect.topLeft(), headRect.bottomLeft());
694 gradientHovered.setColorAt(0, hcTone1);
695 gradientHovered.setColorAt(1, hcTone2);
696 pPainter->fillRect(headRect, gradientHovered);
697 }
698
699 /* Restore painter: */
700 pPainter->restore();
701}
702
703void UIDetailsElement::paintFrame(QPainter *pPainter, const QStyleOptionGraphicsItem *pOptions) const
704{
705 /* Save painter: */
706 pPainter->save();
707
708 /* Prepare variables: */
709 const int iMargin = data(ElementData_Margin).toInt();
710 const int iHeadHeight = 2 * iMargin + m_iMinimumHeaderHeight;
711 const QRect optionRect = pOptions->rect;
712 const QRect rectangle = m_fAnimationRunning
713 ? QRect(optionRect.topLeft(), QSize(optionRect.width(), iHeadHeight + m_iAdditionalHeight))
714 : optionRect;
715
716 /* Paint frame: */
717 const QColor strokeColor = palette().color(QPalette::Active, QPalette::Mid).lighter(m_iDefaultToneStart);
718 QPen pen(strokeColor);
719 pen.setWidth(0);
720 pPainter->setPen(pen);
721 pPainter->drawLine(rectangle.topLeft(), rectangle.topRight());
722 pPainter->drawLine(rectangle.bottomLeft(), rectangle.bottomRight());
723 pPainter->drawLine(rectangle.topLeft(), rectangle.bottomLeft());
724 pPainter->drawLine(rectangle.topRight(), rectangle.bottomRight());
725
726 /* Restore painter: */
727 pPainter->restore();
728}
729
730void UIDetailsElement::paintElementInfo(QPainter *pPainter, const QStyleOptionGraphicsItem *) const
731{
732 /* Initialize some necessary variables: */
733 const int iMargin = data(ElementData_Margin).toInt();
734 const int iSpacing = data(ElementData_Spacing).toInt();
735
736 /* Calculate attributes: */
737 const int iPixmapHeight = m_pixmapSize.height();
738 const int iNameHeight = m_nameSize.height();
739 const int iMaximumHeight = qMax(iPixmapHeight, iNameHeight);
740
741 /* Prepare color: */
742 const QPalette pal = palette();
743 const QColor buttonTextColor = pal.color(QPalette::Active, QPalette::ButtonText);
744 const QColor linkTextColor = pal.color(QPalette::Active, QPalette::Link);
745
746 /* Paint pixmap: */
747 int iElementPixmapX = 2 * iMargin;
748 int iElementPixmapY = iPixmapHeight == iMaximumHeight ?
749 iMargin : iMargin + (iMaximumHeight - iPixmapHeight) / 2;
750 paintPixmap(/* Painter: */
751 pPainter,
752 /* Rectangle to paint in: */
753 QRect(QPoint(iElementPixmapX, iElementPixmapY), m_pixmapSize),
754 /* Pixmap to paint: */
755 m_pixmap);
756
757 /* Paint name: */
758 int iMachineNameX = iElementPixmapX +
759 m_pixmapSize.width() +
760 iSpacing;
761 int iMachineNameY = iNameHeight == iMaximumHeight ?
762 iMargin : iMargin + (iMaximumHeight - iNameHeight) / 2;
763 paintText(/* Painter: */
764 pPainter,
765 /* Rectangle to paint in: */
766 QPoint(iMachineNameX, iMachineNameY),
767 /* Font to paint text: */
768 m_nameFont,
769 /* Paint device: */
770 model()->paintDevice(),
771 /* Text to paint: */
772 m_strName,
773 /* Name hovered? */
774 m_fNameHovered ? linkTextColor : buttonTextColor);
775}
776
777/* static */
778void UIDetailsElement::paintPixmap(QPainter *pPainter, const QRect &rect, const QPixmap &pixmap)
779{
780 pPainter->drawPixmap(rect, pixmap);
781}
782
783/* static */
784void UIDetailsElement::paintText(QPainter *pPainter, QPoint point,
785 const QFont &font, QPaintDevice *pPaintDevice,
786 const QString &strText, const QColor &color)
787{
788 /* Prepare variables: */
789 QFontMetrics fm(font, pPaintDevice);
790 point += QPoint(0, fm.ascent());
791
792 /* Draw text: */
793 pPainter->save();
794 pPainter->setFont(font);
795 pPainter->setPen(color);
796 pPainter->drawText(point, strText);
797 pPainter->restore();
798}
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