Changeset 50843 in vbox for trunk/src/VBox/Frontends/VirtualBox
- Timestamp:
- Mar 21, 2014 2:52:02 PM (11 years ago)
- Location:
- trunk/src/VBox/Frontends/VirtualBox
- Files:
-
- 5 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk
r50463 r50843 396 396 src/widgets/graphics/UIGraphicsZoomButton.h \ 397 397 src/widgets/graphics/UIGraphicsToolBar.h \ 398 src/widgets/graphics/UIGraphicsTextPane.h \ 398 399 src/wizards/UIWizard.h \ 399 400 src/wizards/UIWizardPage.h \ … … 680 681 src/widgets/graphics/UIGraphicsZoomButton.cpp \ 681 682 src/widgets/graphics/UIGraphicsToolBar.cpp \ 683 src/widgets/graphics/UIGraphicsTextPane.cpp \ 682 684 src/wizards/UIWizard.cpp \ 683 685 src/wizards/UIWizardPage.cpp \ -
trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp
r50041 r50843 23 23 #include <QPropertyAnimation> 24 24 #include <QSignalTransition> 25 #include <QTextLayout>26 25 #include <QStyleOptionGraphicsItem> 27 26 #include <QGraphicsSceneMouseEvent> … … 32 31 #include "UIGDetailsModel.h" 33 32 #include "UIGraphicsRotatorButton.h" 33 #include "UIGraphicsTextPane.h" 34 34 #include "UIIconPool.h" 35 35 #include "UIConverter.h" … … 42 42 , m_iMinimumHeaderWidth(0) 43 43 , m_iMinimumHeaderHeight(0) 44 , m_iMinimumTextWidth(0) 45 , m_iMinimumTextHeight(0) 44 , m_pButton(0) 46 45 , m_fClosed(!fOpened) 47 , m_pButton(0)48 46 , m_iAdditionalHeight(0) 49 47 , m_fAnimationRunning(false) 48 , m_pTextPane(0) 50 49 , m_fHovered(false) 51 50 , m_fNameHovered(false) … … 62 61 /* Prepare button: */ 63 62 prepareButton(); 63 /* Prepare text-pane: */ 64 prepareTextPane(); 64 65 65 66 /* Setup size-policy: */ … … 130 131 /* Notify about finishing: */ 131 132 emit sigToggleElementFinished(); 133 } 134 135 void UIGDetailsElement::resizeEvent(QGraphicsSceneResizeEvent*) 136 { 137 /* Update layout: */ 138 updateLayout(); 132 139 } 133 140 … … 165 172 } 166 173 167 void UIGDetailsElement::updateMinimumTextWidth()168 {169 /* Prepare variables: */170 int iSpacing = data(ElementData_Spacing).toInt();171 int iMinimumTextColumnWidth = data(ElementData_MinimumTextColumnWidth).toInt();172 QFontMetrics fm(m_textFont, model()->paintDevice());173 174 /* Search for the maximum line widths: */175 int iMaximumLeftLineWidth = 0;176 int iMaximumRightLineWidth = 0;177 bool fSingleColumnText = true;178 foreach (const UITextTableLine line, m_text)179 {180 bool fRightColumnPresent = !line.second.isEmpty();181 if (fRightColumnPresent)182 fSingleColumnText = false;183 QString strLeftLine = fRightColumnPresent ? line.first + ":" : line.first;184 QString strRightLine = line.second;185 iMaximumLeftLineWidth = qMax(iMaximumLeftLineWidth, fm.width(strLeftLine));186 iMaximumRightLineWidth = qMax(iMaximumRightLineWidth, fm.width(strRightLine));187 }188 iMaximumLeftLineWidth += 1;189 iMaximumRightLineWidth += 1;190 191 /* Calculate minimum-text-width: */192 int iMinimumTextWidth = 0;193 if (fSingleColumnText)194 {195 /* Take into account only left column: */196 int iMinimumLeftColumnWidth = qMin(iMaximumLeftLineWidth, iMinimumTextColumnWidth);197 iMinimumTextWidth = iMinimumLeftColumnWidth;198 }199 else200 {201 /* Take into account both columns, but wrap only right one: */202 int iMinimumLeftColumnWidth = iMaximumLeftLineWidth;203 int iMinimumRightColumnWidth = qMin(iMaximumRightLineWidth, iMinimumTextColumnWidth);204 iMinimumTextWidth = iMinimumLeftColumnWidth + iSpacing + iMinimumRightColumnWidth;205 }206 207 /* Is there something changed? */208 if (m_iMinimumTextWidth != iMinimumTextWidth)209 {210 /* Remember new value: */211 m_iMinimumTextWidth = iMinimumTextWidth;212 /* Recursively update size-hint: */213 updateGeometry();214 }215 }216 217 void UIGDetailsElement::updateMinimumTextHeight()218 {219 /* Prepare variables: */220 int iMargin = data(ElementData_Margin).toInt();221 int iSpacing = data(ElementData_Spacing).toInt();222 int iMinimumTextColumnWidth = data(ElementData_MinimumTextColumnWidth).toInt();223 int iMaximumTextWidth = (int)geometry().width() - 3 * iMargin - iSpacing;224 QPaintDevice *pPaintDevice = model()->paintDevice();225 QFontMetrics fm(m_textFont, pPaintDevice);226 227 /* Search for the maximum line widths: */228 int iMaximumLeftLineWidth = 0;229 int iMaximumRightLineWidth = 0;230 bool fSingleColumnText = true;231 foreach (const UITextTableLine line, m_text)232 {233 bool fRightColumnPresent = !line.second.isEmpty();234 if (fRightColumnPresent)235 fSingleColumnText = false;236 QString strFirstLine = fRightColumnPresent ? line.first + ":" : line.first;237 QString strSecondLine = line.second;238 iMaximumLeftLineWidth = qMax(iMaximumLeftLineWidth, fm.width(strFirstLine));239 iMaximumRightLineWidth = qMax(iMaximumRightLineWidth, fm.width(strSecondLine));240 }241 iMaximumLeftLineWidth += 1;242 iMaximumRightLineWidth += 1;243 244 /* Calculate column widths: */245 int iLeftColumnWidth = 0;246 int iRightColumnWidth = 0;247 if (fSingleColumnText)248 {249 /* Take into account only left column: */250 iLeftColumnWidth = qMax(iMinimumTextColumnWidth, iMaximumTextWidth);251 }252 else253 {254 /* Take into account both columns, but wrap only right one: */255 iLeftColumnWidth = iMaximumLeftLineWidth;256 iRightColumnWidth = iMaximumTextWidth - iLeftColumnWidth;257 }258 259 /* Calculate minimum-text-height: */260 int iMinimumTextHeight = 0;261 foreach (const UITextTableLine line, m_text)262 {263 /* First layout: */264 int iLeftColumnHeight = 0;265 if (!line.first.isEmpty())266 {267 bool fRightColumnPresent = !line.second.isEmpty();268 QTextLayout *pTextLayout = prepareTextLayout(m_textFont, pPaintDevice,269 fRightColumnPresent ? line.first + ":" : line.first,270 iLeftColumnWidth, iLeftColumnHeight);271 delete pTextLayout;272 }273 274 /* Second layout: */275 int iRightColumnHeight = 0;276 if (!line.second.isEmpty())277 {278 QTextLayout *pTextLayout = prepareTextLayout(m_textFont, pPaintDevice, line.second,279 iRightColumnWidth, iRightColumnHeight);280 delete pTextLayout;281 }282 283 /* Append summary text height: */284 iMinimumTextHeight += qMax(iLeftColumnHeight, iRightColumnHeight);285 }286 287 /* Is there something changed? */288 if (m_iMinimumTextHeight != iMinimumTextHeight)289 {290 /* Remember new value: */291 m_iMinimumTextHeight = iMinimumTextHeight;292 /* Recursively update size-hint: */293 updateGeometry();294 }295 }296 297 174 void UIGDetailsElement::setIcon(const QIcon &icon) 298 175 { … … 318 195 } 319 196 197 const UITextTable& UIGDetailsElement::text() const 198 { 199 /* Retrieve text from text-pane: */ 200 return m_pTextPane->text(); 201 } 202 320 203 void UIGDetailsElement::setText(const UITextTable &text) 321 204 { 322 /* Clear first: */ 323 m_text.clear(); 324 /* For each the line of the passed table: */ 325 foreach (const UITextTableLine &line, text) 326 { 327 /* Get lines: */ 328 QString strLeftLine = line.first; 329 QString strRightLine = line.second; 330 /* If 2nd line is empty: */ 331 if (strRightLine.isEmpty()) 332 { 333 /* Parse the 1st one: */ 334 QStringList subLines = strLeftLine.split(QRegExp("\\n")); 335 foreach (const QString &strSubLine, subLines) 336 m_text << UITextTableLine(strSubLine, QString()); 337 } 338 else 339 m_text << UITextTableLine(strLeftLine, strRightLine); 340 } 341 342 /* Update linked values: */ 343 updateMinimumTextWidth(); 344 updateMinimumTextHeight(); 205 /* Pass text to text-pane: */ 206 m_pTextPane->setText(text); 345 207 } 346 208 … … 357 219 358 220 /* Maximum width: */ 359 iMinimumWidthHint = qMax(m_iMinimumHeaderWidth, m_iMinimumTextWidth);221 iMinimumWidthHint = qMax(m_iMinimumHeaderWidth, (int)m_pTextPane->minimumSizeHint().width()); 360 222 361 223 /* And 4 margins: 2 left and 2 right: */ … … 382 244 { 383 245 /* Add text height: */ 384 if (!m_ text.isEmpty())385 iMinimumHeightHint += 2 * iMargin + m_iMinimumTextHeight;246 if (!m_pTextPane->isEmpty()) 247 iMinimumHeightHint += 2 * iMargin + (int)m_pTextPane->minimumSizeHint().height(); 386 248 } 387 249 … … 404 266 QSize size = geometry().size().toSize(); 405 267 int iMargin = data(ElementData_Margin).toInt(); 268 269 /* Layout button: */ 406 270 int iButtonWidth = m_buttonSize.width(); 407 271 int iButtonHeight = m_buttonSize.height(); 408 409 /* Layout button: */410 272 int iButtonX = size.width() - 2 * iMargin - iButtonWidth; 411 273 int iButtonY = iButtonHeight == m_iMinimumHeaderHeight ? iMargin : 412 274 iMargin + (m_iMinimumHeaderHeight - iButtonHeight) / 2; 413 275 m_pButton->setPos(iButtonX, iButtonY); 276 277 /* If closed: */ 278 if (closed()) 279 { 280 /* Hide text-pane if still visible: */ 281 if (m_pTextPane->isVisible()) 282 m_pTextPane->hide(); 283 } 284 /* If opened: */ 285 else 286 { 287 /* Layout text-pane: */ 288 int iTextPaneX = 2 * iMargin; 289 int iTextPaneY = iMargin + m_iMinimumHeaderHeight + 2 * iMargin; 290 m_pTextPane->setPos(iTextPaneX, iTextPaneY); 291 m_pTextPane->resize(size.width() - 4 * iMargin, 292 size.height() - 4 * iMargin - m_iMinimumHeaderHeight); 293 /* Show text-pane if still invisible and animation finished: */ 294 if (!m_pTextPane->isVisible() && !isAnimationRunning()) 295 m_pTextPane->show(); 296 } 414 297 } 415 298 … … 504 387 } 505 388 389 void UIGDetailsElement::prepareTextPane() 390 { 391 /* Create text-pane: */ 392 m_pTextPane = new UIGraphicsTextPane(this, model()->paintDevice()); 393 } 394 506 395 void UIGDetailsElement::paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget*) 507 396 { … … 540 429 QColor buttonTextColor = pal.color(QPalette::Active, QPalette::ButtonText); 541 430 QColor linkTextColor = pal.color(QPalette::Active, QPalette::Link); 542 QColor baseTextColor = pal.color(QPalette::Active, QPalette::Text);543 431 544 432 /* Paint pixmap: */ 545 int i MachinePixmapX = 2 * iMargin;546 int i MachinePixmapY = iPixmapHeight == iMaximumHeight ?433 int iElementPixmapX = 2 * iMargin; 434 int iElementPixmapY = iPixmapHeight == iMaximumHeight ? 547 435 iMargin : iMargin + (iMaximumHeight - iPixmapHeight) / 2; 548 436 paintPixmap(/* Painter: */ 549 437 pPainter, 550 438 /* Rectangle to paint in: */ 551 QRect(QPoint(i MachinePixmapX, iMachinePixmapY), m_pixmapSize),439 QRect(QPoint(iElementPixmapX, iElementPixmapY), m_pixmapSize), 552 440 /* Pixmap to paint: */ 553 441 m_pixmap); 554 442 555 443 /* Paint name: */ 556 int iMachineNameX = i MachinePixmapX +444 int iMachineNameX = iElementPixmapX + 557 445 m_pixmapSize.width() + 558 446 iSpacing; … … 571 459 /* Name hovered? */ 572 460 m_fNameHovered ? linkTextColor : buttonTextColor); 573 574 /* Paint text: */575 if (!m_fClosed && !m_text.isEmpty() && !m_fAnimationRunning)576 {577 /* Prepare painter: */578 pPainter->save();579 pPainter->setPen(baseTextColor);580 581 /* Prepare variables: */582 int iMinimumTextColumnWidth = data(ElementData_MinimumTextColumnWidth).toInt();583 int iMaximumTextWidth = geometry().width() - 3 * iMargin - iSpacing;584 QPaintDevice *pPaintDevice = model()->paintDevice();585 QFontMetrics fm(m_textFont, pPaintDevice);586 587 /* Search for the maximum line widths: */588 int iMaximumLeftLineWidth = 0;589 int iMaximumRightLineWidth = 0;590 bool fSingleColumnText = true;591 foreach (const UITextTableLine line, m_text)592 {593 bool fRightColumnPresent = !line.second.isEmpty();594 if (fRightColumnPresent)595 fSingleColumnText = false;596 QString strFirstLine = fRightColumnPresent ? line.first + ":" : line.first;597 QString strSecondLine = line.second;598 iMaximumLeftLineWidth = qMax(iMaximumLeftLineWidth, fm.width(strFirstLine));599 iMaximumRightLineWidth = qMax(iMaximumRightLineWidth, fm.width(strSecondLine));600 }601 iMaximumLeftLineWidth += 1;602 iMaximumRightLineWidth += 1;603 604 /* Calculate column widths: */605 int iLeftColumnWidth = 0;606 int iRightColumnWidth = 0;607 if (fSingleColumnText)608 {609 /* Take into account only left column: */610 iLeftColumnWidth = qMax(iMinimumTextColumnWidth, iMaximumTextWidth);611 }612 else613 {614 /* Take into account both columns, but wrap only right one: */615 iLeftColumnWidth = iMaximumLeftLineWidth;616 iRightColumnWidth = iMaximumTextWidth - iLeftColumnWidth;617 }618 619 /* Where to paint? */620 int iMachineTextX = iMachinePixmapX;621 int iMachineTextY = iMargin + m_iMinimumHeaderHeight + 2 * iMargin;622 623 /* For each the line: */624 foreach (const UITextTableLine line, m_text)625 {626 /* First layout: */627 int iLeftColumnHeight = 0;628 if (!line.first.isEmpty())629 {630 bool fRightColumnPresent = !line.second.isEmpty();631 QTextLayout *pTextLayout = prepareTextLayout(m_textFont, pPaintDevice,632 fRightColumnPresent ? line.first + ":" : line.first,633 iLeftColumnWidth, iLeftColumnHeight);634 pTextLayout->draw(pPainter, QPointF(iMachineTextX, iMachineTextY));635 delete pTextLayout;636 }637 638 /* Second layout: */639 int iRightColumnHeight = 0;640 if (!line.second.isEmpty())641 {642 QTextLayout *pTextLayout = prepareTextLayout(m_textFont, pPaintDevice,643 line.second, iRightColumnWidth, iRightColumnHeight);644 pTextLayout->draw(pPainter, QPointF(iMachineTextX + iLeftColumnWidth + iSpacing, iMachineTextY));645 delete pTextLayout;646 }647 648 /* Indent Y: */649 iMachineTextY += qMax(iLeftColumnHeight, iRightColumnHeight);650 }651 652 /* Restore painter: */653 pPainter->restore();654 }655 461 } 656 462 … … 782 588 int iSpacing = data(ElementData_Spacing).toInt(); 783 589 int iNameHeight = m_nameSize.height(); 784 int i MachineNameX = 2 * iMargin + m_pixmapSize.width() + iSpacing;785 int i MachineNameY = iNameHeight == m_iMinimumHeaderHeight ?590 int iElementNameX = 2 * iMargin + m_pixmapSize.width() + iSpacing; 591 int iElementNameY = iNameHeight == m_iMinimumHeaderHeight ? 786 592 iMargin : iMargin + (m_iMinimumHeaderHeight - iNameHeight) / 2; 787 593 788 594 /* Simulate hyperlink hovering: */ 789 595 QPoint point = pEvent->pos().toPoint(); 790 bool fNameHovered = QRect(QPoint(i MachineNameX, iMachineNameY), m_nameSize).contains(point);596 bool fNameHovered = QRect(QPoint(iElementNameX, iElementNameY), m_nameSize).contains(point); 791 597 if (m_pSet->elementNameHoverable() && m_fNameHovered != fNameHovered) 792 598 { … … 803 609 unsetCursor(); 804 610 update(); 805 }806 807 /* static */808 QTextLayout* UIGDetailsElement::prepareTextLayout(const QFont &font, QPaintDevice *pPaintDevice,809 const QString &strText, int iWidth, int &iHeight)810 {811 /* Prepare variables: */812 QFontMetrics fm(font, pPaintDevice);813 int iLeading = fm.leading();814 815 /* Only bold sub-strings are currently handled: */816 QString strModifiedText(strText);817 QRegExp boldRegExp("<b>([\\s\\S]+)</b>");818 QList<QTextLayout::FormatRange> formatRangeList;819 while (boldRegExp.indexIn(strModifiedText) != -1)820 {821 /* Prepare format: */822 QTextLayout::FormatRange formatRange;823 QFont font = formatRange.format.font();824 font.setBold(true);825 formatRange.format.setFont(font);826 formatRange.start = boldRegExp.pos(0);827 formatRange.length = boldRegExp.cap(1).size();828 /* Add format range to list: */829 formatRangeList << formatRange;830 /* Replace sub-string: */831 strModifiedText.replace(boldRegExp.cap(0), boldRegExp.cap(1));832 }833 834 /* Create layout; */835 QTextLayout *pTextLayout = new QTextLayout(strModifiedText, font, pPaintDevice);836 pTextLayout->setAdditionalFormats(formatRangeList);837 838 /* Configure layout: */839 QTextOption textOption;840 textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);841 pTextLayout->setTextOption(textOption);842 843 /* Build layout: */844 pTextLayout->beginLayout();845 while (1)846 {847 QTextLine line = pTextLayout->createLine();848 if (!line.isValid())849 break;850 851 line.setLineWidth(iWidth);852 iHeight += iLeading;853 line.setPosition(QPointF(0, iHeight));854 iHeight += line.height();855 }856 pTextLayout->endLayout();857 858 /* Return layout: */859 return pTextLayout;860 611 } 861 612 -
trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.h
r50041 r50843 31 31 class CMachine; 32 32 class UIGraphicsRotatorButton; 33 class UIGraphicsTextPane; 33 34 class QTextLayout; 34 35 class QStateMachine; … … 38 39 typedef QPair<QString, QString> UITextTableLine; 39 40 typedef QList<UITextTableLine> UITextTable; 40 Q_DECLARE_METATYPE(UITextTable);41 41 42 42 /* Details element … … 104 104 }; 105 105 106 /** This event handler is delivered after the widget has been resized. */ 107 void resizeEvent(QGraphicsSceneResizeEvent *pEvent); 108 106 109 /* Data provider: */ 107 110 QVariant data(int iKey) const; … … 110 113 void updateMinimumHeaderWidth(); 111 114 void updateMinimumHeaderHeight(); 112 void updateMinimumTextWidth();113 void updateMinimumTextHeight();114 115 115 116 /* API: Icon stuff: */ … … 120 121 121 122 /* API: Text stuff: */ 122 UITextTable text() const { return m_text; }123 const UITextTable& text() const; 123 124 void setText(const UITextTable &text); 124 125 … … 156 157 void prepareElement(); 157 158 void prepareButton(); 159 void prepareTextPane(); 158 160 159 161 /* Helpers: Paint stuff: */ … … 174 176 void updateNameHoverLink(); 175 177 176 /* Helper: Layout stuff: */177 static QTextLayout* prepareTextLayout(const QFont &font, QPaintDevice *pPaintDevice,178 const QString &strText, int iWidth, int &iHeight);179 180 178 /* Helper: Animation stuff: */ 181 179 void updateAnimationParameters(); … … 186 184 QPixmap m_pixmap; 187 185 QString m_strName; 188 UITextTable m_text;189 186 int m_iCornerRadius; 190 187 QFont m_nameFont; … … 195 192 int m_iMinimumHeaderWidth; 196 193 int m_iMinimumHeaderHeight; 197 int m_iMinimumTextWidth; 198 int m_iMinimumTextHeight; 199 200 /* Variables: Toggle stuff: */ 194 195 /* Variables: Toggle-button stuff: */ 196 UIGraphicsRotatorButton *m_pButton; 201 197 bool m_fClosed; 202 UIGraphicsRotatorButton *m_pButton;203 198 int m_iAdditionalHeight; 204 199 bool m_fAnimationRunning; 200 201 /* Variables: Text-pane stuff: */ 202 UIGraphicsTextPane *m_pTextPane; 205 203 206 204 /* Variables: Hover stuff: */ -
trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElements.cpp
r50041 r50843 29 29 #include "UIIconPool.h" 30 30 #include "UIConverter.h" 31 #include "UIGraphicsTextPane.h" 31 32 32 33 /* COM includes: */ -
trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsSet.cpp
r50041 r50843 515 515 /* Resize element to required width: */ 516 516 pElement->resize(iWidth, pElement->geometry().height()); 517 /* Update minimum-height-hint: */518 pElement->updateMinimumTextHeight();519 517 } 520 518 /* Acquire required height: */ -
trunk/src/VBox/Frontends/VirtualBox/src/widgets/graphics/UIGraphicsTextPane.cpp
r50824 r50843 1 1 /* $Id$ */ 2 2 /** @file 3 * 4 * VBox frontends: Qt GUI ("VirtualBox"): 5 * UIGDetailsElement class implementation 3 * VBox Qt GUI - UIGraphicsTextPane and UITask class implementation. 6 4 */ 7 5 8 6 /* 9 * Copyright (C) 2012 Oracle Corporation7 * Copyright (C) 2012-2014 Oracle Corporation 10 8 * 11 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 19 17 20 18 /* Qt includes: */ 21 #include <QGraphicsView> 22 #include <QStateMachine> 23 #include <QPropertyAnimation> 24 #include <QSignalTransition> 19 #include <QFontMetrics> 25 20 #include <QTextLayout> 26 #include <QStyleOptionGraphicsItem> 27 #include <QGraphicsSceneMouseEvent> 21 #include <QPainter> 28 22 29 23 /* GUI includes: */ 30 #include "UIGDetailsElement.h" 31 #include "UIGDetailsSet.h" 32 #include "UIGDetailsModel.h" 33 #include "UIGraphicsRotatorButton.h" 34 #include "UIIconPool.h" 35 #include "UIConverter.h" 36 37 UIGDetailsElement::UIGDetailsElement(UIGDetailsSet *pParent, DetailsElementType type, bool fOpened) 38 : UIGDetailsItem(pParent) 39 , m_pSet(pParent) 40 , m_type(type) 41 , m_iCornerRadius(10) 42 , m_iMinimumHeaderWidth(0) 43 , m_iMinimumHeaderHeight(0) 24 #include "UIGraphicsTextPane.h" 25 26 UIGraphicsTextPane::UIGraphicsTextPane(QIGraphicsWidget *pParent, QPaintDevice *pPaintDevice) 27 : QIGraphicsWidget(pParent) 28 , m_pPaintDevice(pPaintDevice) 29 , m_iMargin(0) 30 , m_iSpacing(10) 31 , m_iMinimumTextColumnWidth(100) 44 32 , m_iMinimumTextWidth(0) 45 33 , m_iMinimumTextHeight(0) 46 , m_fClosed(!fOpened) 47 , m_pButton(0) 48 , m_iAdditionalHeight(0) 49 , m_fAnimationRunning(false) 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 { 60 /* Prepare element: */ 61 prepareElement(); 62 /* Prepare button: */ 63 prepareButton(); 64 65 /* Setup size-policy: */ 66 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); 67 68 /* Add item to the parent: */ 69 AssertMsg(parentItem(), ("No parent set for details element!")); 70 parentItem()->addItem(this); 71 } 72 73 UIGDetailsElement::~UIGDetailsElement() 74 { 75 /* Remove item from the parent: */ 76 AssertMsg(parentItem(), ("No parent set for details element!")); 77 parentItem()->removeItem(this); 78 } 79 80 void UIGDetailsElement::close(bool fAnimated /* = true */) 81 { 82 m_pButton->setToggled(false, fAnimated); 83 } 84 85 void UIGDetailsElement::open(bool fAnimated /* = true */) 86 { 87 m_pButton->setToggled(true, fAnimated); 88 } 89 90 void UIGDetailsElement::updateAppearance() 91 { 92 /* Reset name hover state: */ 93 m_fNameHovered = false; 94 updateNameHoverLink(); 95 } 96 97 void UIGDetailsElement::markAnimationFinished() 98 { 99 /* Mark animation as non-running: */ 100 m_fAnimationRunning = false; 101 102 /* Recursively update size-hint: */ 103 updateGeometry(); 104 /* Repaint: */ 105 update(); 106 } 107 108 void UIGDetailsElement::sltToggleButtonClicked() 109 { 110 emit sigToggleElement(m_type, closed()); 111 } 112 113 void UIGDetailsElement::sltElementToggleStart() 114 { 115 /* Mark animation running: */ 116 m_fAnimationRunning = true; 117 118 /* Setup animation: */ 119 updateAnimationParameters(); 120 121 /* Invert toggle-state: */ 122 m_fClosed = !m_fClosed; 123 } 124 125 void UIGDetailsElement::sltElementToggleFinish(bool fToggled) 126 { 127 /* Update toggle-state: */ 128 m_fClosed = !fToggled; 129 130 /* Notify about finishing: */ 131 emit sigToggleElementFinished(); 132 } 133 134 QVariant UIGDetailsElement::data(int iKey) const 135 { 136 /* Provide other members with required data: */ 137 switch (iKey) 138 { 139 /* Hints: */ 140 case ElementData_Margin: return 5; 141 case ElementData_Spacing: return 10; 142 case ElementData_MinimumTextColumnWidth: return 100; 143 /* Default: */ 144 default: break; 145 } 146 return QVariant(); 147 } 148 149 void UIGDetailsElement::updateMinimumHeaderWidth() 34 { 35 } 36 37 void UIGraphicsTextPane::setText(const UITextTable &text) 38 { 39 /* Clear text: */ 40 m_text.clear(); 41 42 /* For each the line of the passed table: */ 43 foreach (const UITextTableLine &line, text) 44 { 45 /* Lines: */ 46 QString strLeftLine = line.first; 47 QString strRightLine = line.second; 48 49 /* If 2nd line is NOT empty: */ 50 if (!strRightLine.isEmpty()) 51 { 52 /* Take both lines 'as is': */ 53 m_text << UITextTableLine(strLeftLine, strRightLine); 54 } 55 /* If 2nd line is empty: */ 56 else 57 { 58 /* Parse the 1st one to sub-lines: */ 59 QStringList subLines = strLeftLine.split(QRegExp("\\n")); 60 foreach (const QString &strSubLine, subLines) 61 m_text << UITextTableLine(strSubLine, QString()); 62 } 63 } 64 65 /* Update minimum text size-hint: */ 66 updateMinimumTextWidthHint(); 67 updateMinimumTextHeightHint(); 68 } 69 70 void UIGraphicsTextPane::updateMinimumTextWidthHint() 150 71 { 151 72 /* Prepare variables: */ 152 int iSpacing = data(ElementData_Spacing).toInt(); 153 154 /* Update minimum-header-width: */ 155 m_iMinimumHeaderWidth = m_pixmapSize.width() + 156 iSpacing + m_nameSize.width() + 157 iSpacing + m_buttonSize.width(); 158 } 159 160 void UIGDetailsElement::updateMinimumHeaderHeight() 161 { 162 /* Update minimum-header-height: */ 163 m_iMinimumHeaderHeight = qMax(m_pixmapSize.height(), m_nameSize.height()); 164 m_iMinimumHeaderHeight = qMax(m_iMinimumHeaderHeight, m_buttonSize.height()); 165 } 166 167 void UIGDetailsElement::updateMinimumTextWidth() 168 { 169 /* Prepare variables: */ 170 int iSpacing = data(ElementData_Spacing).toInt(); 171 int iMinimumTextColumnWidth = data(ElementData_MinimumTextColumnWidth).toInt(); 172 QFontMetrics fm(m_textFont, model()->paintDevice()); 73 QFontMetrics fm(font(), m_pPaintDevice); 173 74 174 75 /* Search for the maximum line widths: */ … … 176 77 int iMaximumRightLineWidth = 0; 177 78 bool fSingleColumnText = true; 178 foreach (const UITextTableLine line, m_text)79 foreach (const UITextTableLine &line, m_text) 179 80 { 180 81 bool fRightColumnPresent = !line.second.isEmpty(); … … 194 95 { 195 96 /* Take into account only left column: */ 196 int iMinimumLeftColumnWidth = qMin(iMaximumLeftLineWidth, iMinimumTextColumnWidth);97 int iMinimumLeftColumnWidth = qMin(iMaximumLeftLineWidth, m_iMinimumTextColumnWidth); 197 98 iMinimumTextWidth = iMinimumLeftColumnWidth; 198 99 } … … 201 102 /* Take into account both columns, but wrap only right one: */ 202 103 int iMinimumLeftColumnWidth = iMaximumLeftLineWidth; 203 int iMinimumRightColumnWidth = qMin(iMaximumRightLineWidth, iMinimumTextColumnWidth); 204 iMinimumTextWidth = iMinimumLeftColumnWidth + iSpacing + iMinimumRightColumnWidth; 205 } 206 207 /* Is there something changed? */ 208 if (m_iMinimumTextWidth != iMinimumTextWidth) 209 { 210 /* Remember new value: */ 211 m_iMinimumTextWidth = iMinimumTextWidth; 212 /* Recursively update size-hint: */ 213 updateGeometry(); 214 } 215 } 216 217 void UIGDetailsElement::updateMinimumTextHeight() 104 int iMinimumRightColumnWidth = qMin(iMaximumRightLineWidth, m_iMinimumTextColumnWidth); 105 iMinimumTextWidth = iMinimumLeftColumnWidth + m_iSpacing + iMinimumRightColumnWidth; 106 } 107 108 /* Make sure something changed: */ 109 if (m_iMinimumTextWidth == iMinimumTextWidth) 110 return; 111 112 /* Remember new value: */ 113 m_iMinimumTextWidth = iMinimumTextWidth; 114 115 /* Notify layout if any: */ 116 updateGeometry(); 117 } 118 119 void UIGraphicsTextPane::updateMinimumTextHeightHint() 218 120 { 219 121 /* Prepare variables: */ 220 int iMargin = data(ElementData_Margin).toInt(); 221 int iSpacing = data(ElementData_Spacing).toInt(); 222 int iMinimumTextColumnWidth = data(ElementData_MinimumTextColumnWidth).toInt(); 223 int iMaximumTextWidth = (int)geometry().width() - 3 * iMargin - iSpacing; 224 QPaintDevice *pPaintDevice = model()->paintDevice(); 225 QFontMetrics fm(m_textFont, pPaintDevice); 122 int iMaximumTextWidth = (int)size().width() - 2 * m_iMargin - m_iSpacing; 123 QFontMetrics fm(font(), m_pPaintDevice); 226 124 227 125 /* Search for the maximum line widths: */ … … 229 127 int iMaximumRightLineWidth = 0; 230 128 bool fSingleColumnText = true; 231 foreach (const UITextTableLine line, m_text)129 foreach (const UITextTableLine &line, m_text) 232 130 { 233 131 bool fRightColumnPresent = !line.second.isEmpty(); … … 248 146 { 249 147 /* Take into account only left column: */ 250 iLeftColumnWidth = qMax( iMinimumTextColumnWidth, iMaximumTextWidth);148 iLeftColumnWidth = qMax(m_iMinimumTextColumnWidth, iMaximumTextWidth); 251 149 } 252 150 else … … 266 164 { 267 165 bool fRightColumnPresent = !line.second.isEmpty(); 268 QTextLayout *pTextLayout = prepareTextLayout(m_textFont,pPaintDevice,269 270 166 QTextLayout *pTextLayout = buildTextLayout(font(), m_pPaintDevice, 167 fRightColumnPresent ? line.first + ":" : line.first, 168 iLeftColumnWidth, iLeftColumnHeight); 271 169 delete pTextLayout; 272 170 } … … 276 174 if (!line.second.isEmpty()) 277 175 { 278 QTextLayout *pTextLayout = prepareTextLayout(m_textFont,pPaintDevice, line.second,279 176 QTextLayout *pTextLayout = buildTextLayout(font(), m_pPaintDevice, line.second, 177 iRightColumnWidth, iRightColumnHeight); 280 178 delete pTextLayout; 281 179 } … … 285 183 } 286 184 287 /* Is there something changed? */ 288 if (m_iMinimumTextHeight != iMinimumTextHeight) 289 { 290 /* Remember new value: */ 291 m_iMinimumTextHeight = iMinimumTextHeight; 292 /* Recursively update size-hint: */ 293 updateGeometry(); 294 } 295 } 296 297 void UIGDetailsElement::setIcon(const QIcon &icon) 298 { 299 /* Cache icon: */ 300 m_pixmapSize = icon.isNull() ? QSize(0, 0) : icon.availableSizes().first(); 301 m_pixmap = icon.pixmap(m_pixmapSize); 302 303 /* Update linked values: */ 304 updateMinimumHeaderWidth(); 305 updateMinimumHeaderHeight(); 306 } 307 308 void UIGDetailsElement::setName(const QString &strName) 309 { 310 /* Cache name: */ 311 m_strName = strName; 312 QFontMetrics fm(m_nameFont, model()->paintDevice()); 313 m_nameSize = QSize(fm.width(m_strName), fm.height()); 314 315 /* Update linked values: */ 316 updateMinimumHeaderWidth(); 317 updateMinimumHeaderHeight(); 318 } 319 320 void UIGDetailsElement::setText(const UITextTable &text) 321 { 322 /* Clear first: */ 323 m_text.clear(); 324 /* For each the line of the passed table: */ 325 foreach (const UITextTableLine &line, text) 326 { 327 /* Get lines: */ 328 QString strLeftLine = line.first; 329 QString strRightLine = line.second; 330 /* If 2nd line is empty: */ 331 if (strRightLine.isEmpty()) 332 { 333 /* Parse the 1st one: */ 334 QStringList subLines = strLeftLine.split(QRegExp("\\n")); 335 foreach (const QString &strSubLine, subLines) 336 m_text << UITextTableLine(strSubLine, QString()); 337 } 338 else 339 m_text << UITextTableLine(strLeftLine, strRightLine); 340 } 341 342 /* Update linked values: */ 343 updateMinimumTextWidth(); 344 updateMinimumTextHeight(); 345 } 346 347 const CMachine& UIGDetailsElement::machine() 348 { 349 return m_pSet->machine(); 350 } 351 352 int UIGDetailsElement::minimumWidthHint() const 185 /* Make sure something changed: */ 186 if (m_iMinimumTextHeight == iMinimumTextHeight) 187 return; 188 189 /* Remember new value: */ 190 m_iMinimumTextHeight = iMinimumTextHeight; 191 192 /* Notify layout if any: */ 193 updateGeometry(); 194 } 195 196 QSizeF UIGraphicsTextPane::sizeHint(Qt::SizeHint which, const QSizeF &constraint /* = QSizeF() */) const 197 { 198 /* Calculate minimum size-hint: */ 199 if (which == Qt::MinimumSize) 200 { 201 int iWidth = 2 * m_iMargin + m_iMinimumTextWidth; 202 int iHeight = 2 * m_iMargin + m_iMinimumTextHeight; 203 return QSize(iWidth, iHeight); 204 } 205 /* Call to base-class: */ 206 return QIGraphicsWidget::sizeHint(which, constraint); 207 } 208 209 void UIGraphicsTextPane::resizeEvent(QGraphicsSceneResizeEvent*) 210 { 211 /* Update minimum text height-hint: */ 212 updateMinimumTextHeightHint(); 213 } 214 215 void UIGraphicsTextPane::paint(QPainter *pPainter, const QStyleOptionGraphicsItem*, QWidget*) 353 216 { 354 217 /* Prepare variables: */ 355 int iMargin = data(ElementData_Margin).toInt(); 356 int iMinimumWidthHint = 0; 357 358 /* Maximum width: */ 359 iMinimumWidthHint = qMax(m_iMinimumHeaderWidth, m_iMinimumTextWidth); 360 361 /* And 4 margins: 2 left and 2 right: */ 362 iMinimumWidthHint += 4 * iMargin; 363 364 /* Return result: */ 365 return iMinimumWidthHint; 366 } 367 368 int UIGDetailsElement::minimumHeightHint(bool fClosed) const 369 { 370 /* Prepare variables: */ 371 int iMargin = data(ElementData_Margin).toInt(); 372 int iMinimumHeightHint = 0; 373 374 /* Two margins: */ 375 iMinimumHeightHint += 2 * iMargin; 376 377 /* Header height: */ 378 iMinimumHeightHint += m_iMinimumHeaderHeight; 379 380 /* Element is opened? */ 381 if (!fClosed) 382 { 383 /* Add text height: */ 384 if (!m_text.isEmpty()) 385 iMinimumHeightHint += 2 * iMargin + m_iMinimumTextHeight; 386 } 387 388 /* Additional height during animation: */ 389 if (m_fAnimationRunning) 390 iMinimumHeightHint += m_iAdditionalHeight; 391 392 /* Return value: */ 393 return iMinimumHeightHint; 394 } 395 396 int UIGDetailsElement::minimumHeightHint() const 397 { 398 return minimumHeightHint(m_fClosed); 399 } 400 401 void UIGDetailsElement::updateLayout() 402 { 403 /* Prepare variables: */ 404 QSize size = geometry().size().toSize(); 405 int iMargin = data(ElementData_Margin).toInt(); 406 int iButtonWidth = m_buttonSize.width(); 407 int iButtonHeight = m_buttonSize.height(); 408 409 /* Layout button: */ 410 int iButtonX = size.width() - 2 * iMargin - iButtonWidth; 411 int iButtonY = iButtonHeight == m_iMinimumHeaderHeight ? iMargin : 412 iMargin + (m_iMinimumHeaderHeight - iButtonHeight) / 2; 413 m_pButton->setPos(iButtonX, iButtonY); 414 } 415 416 void UIGDetailsElement::setAdditionalHeight(int iAdditionalHeight) 417 { 418 /* Cache new value: */ 419 m_iAdditionalHeight = iAdditionalHeight; 420 /* Update layout: */ 421 updateLayout(); 422 /* Repaint: */ 423 update(); 424 } 425 426 void UIGDetailsElement::addItem(UIGDetailsItem*) 427 { 428 AssertMsgFailed(("Details element do NOT support children!")); 429 } 430 431 void UIGDetailsElement::removeItem(UIGDetailsItem*) 432 { 433 AssertMsgFailed(("Details element do NOT support children!")); 434 } 435 436 QList<UIGDetailsItem*> UIGDetailsElement::items(UIGDetailsItemType) const 437 { 438 AssertMsgFailed(("Details element do NOT support children!")); 439 return QList<UIGDetailsItem*>(); 440 } 441 442 bool UIGDetailsElement::hasItems(UIGDetailsItemType) const 443 { 444 AssertMsgFailed(("Details element do NOT support children!")); 445 return false; 446 } 447 448 void UIGDetailsElement::clearItems(UIGDetailsItemType) 449 { 450 AssertMsgFailed(("Details element do NOT support children!")); 451 } 452 453 void UIGDetailsElement::prepareElement() 454 { 455 /* Initialization: */ 456 m_nameFont = font(); 457 m_nameFont.setWeight(QFont::Bold); 458 m_textFont = font(); 459 460 /* Create highlight machine: */ 461 m_pHighlightMachine = new QStateMachine(this); 462 /* Create 'default' state: */ 463 QState *pStateDefault = new QState(m_pHighlightMachine); 464 /* Create 'highlighted' state: */ 465 QState *pStateHighlighted = new QState(m_pHighlightMachine); 466 467 /* Forward animation: */ 468 m_pForwardAnimation = new QPropertyAnimation(this, "animationDarkness", this); 469 m_pForwardAnimation->setDuration(m_iAnimationDuration); 470 m_pForwardAnimation->setStartValue(m_iDefaultDarkness); 471 m_pForwardAnimation->setEndValue(m_iHighlightDarkness); 472 473 /* Backward animation: */ 474 m_pBackwardAnimation = new QPropertyAnimation(this, "animationDarkness", this); 475 m_pBackwardAnimation->setDuration(m_iAnimationDuration); 476 m_pBackwardAnimation->setStartValue(m_iHighlightDarkness); 477 m_pBackwardAnimation->setEndValue(m_iDefaultDarkness); 478 479 /* Add state transitions: */ 480 QSignalTransition *pDefaultToHighlighted = pStateDefault->addTransition(this, SIGNAL(sigHoverEnter()), pStateHighlighted); 481 pDefaultToHighlighted->addAnimation(m_pForwardAnimation); 482 QSignalTransition *pHighlightedToDefault = pStateHighlighted->addTransition(this, SIGNAL(sigHoverLeave()), pStateDefault); 483 pHighlightedToDefault->addAnimation(m_pBackwardAnimation); 484 485 /* Initial state is 'default': */ 486 m_pHighlightMachine->setInitialState(pStateDefault); 487 /* Start state-machine: */ 488 m_pHighlightMachine->start(); 489 490 connect(this, SIGNAL(sigToggleElement(DetailsElementType, bool)), model(), SLOT(sltToggleElements(DetailsElementType, bool))); 491 connect(this, SIGNAL(sigLinkClicked(const QString&, const QString&, const QString&)), 492 model(), SIGNAL(sigLinkClicked(const QString&, const QString&, const QString&))); 493 } 494 495 void UIGDetailsElement::prepareButton() 496 { 497 /* Setup toggle-button: */ 498 m_pButton = new UIGraphicsRotatorButton(this, "additionalHeight", !m_fClosed, true /* reflected */); 499 m_pButton->setAutoHandleButtonClick(false); 500 connect(m_pButton, SIGNAL(sigButtonClicked()), this, SLOT(sltToggleButtonClicked())); 501 connect(m_pButton, SIGNAL(sigRotationStart()), this, SLOT(sltElementToggleStart())); 502 connect(m_pButton, SIGNAL(sigRotationFinish(bool)), this, SLOT(sltElementToggleFinish(bool))); 503 m_buttonSize = m_pButton->minimumSizeHint().toSize(); 504 } 505 506 void UIGDetailsElement::paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget*) 507 { 508 /* Update button visibility: */ 509 updateButtonVisibility(); 510 511 /* Configure painter shape: */ 512 configurePainterShape(pPainter, pOption, m_iCornerRadius); 513 514 /* Paint decorations: */ 515 paintDecorations(pPainter, pOption); 516 517 /* Paint element info: */ 518 paintElementInfo(pPainter, pOption); 519 } 520 521 void UIGDetailsElement::paintDecorations(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption) 522 { 523 /* Paint background: */ 524 paintBackground(pPainter, pOption); 525 } 526 527 void UIGDetailsElement::paintElementInfo(QPainter *pPainter, const QStyleOptionGraphicsItem*) 528 { 529 /* Initialize some necessary variables: */ 530 int iMargin = data(ElementData_Margin).toInt(); 531 int iSpacing = data(ElementData_Spacing).toInt(); 532 533 /* Calculate attributes: */ 534 int iPixmapHeight = m_pixmapSize.height(); 535 int iNameHeight = m_nameSize.height(); 536 int iMaximumHeight = qMax(iPixmapHeight, iNameHeight); 537 538 /* Prepare color: */ 539 QPalette pal = palette(); 540 QColor buttonTextColor = pal.color(QPalette::Active, QPalette::ButtonText); 541 QColor linkTextColor = pal.color(QPalette::Active, QPalette::Link); 542 QColor baseTextColor = pal.color(QPalette::Active, QPalette::Text); 543 544 /* Paint pixmap: */ 545 int iMachinePixmapX = 2 * iMargin; 546 int iMachinePixmapY = iPixmapHeight == iMaximumHeight ? 547 iMargin : iMargin + (iMaximumHeight - iPixmapHeight) / 2; 548 paintPixmap(/* Painter: */ 549 pPainter, 550 /* Rectangle to paint in: */ 551 QRect(QPoint(iMachinePixmapX, iMachinePixmapY), m_pixmapSize), 552 /* Pixmap to paint: */ 553 m_pixmap); 554 555 /* Paint name: */ 556 int iMachineNameX = iMachinePixmapX + 557 m_pixmapSize.width() + 558 iSpacing; 559 int iMachineNameY = iNameHeight == iMaximumHeight ? 560 iMargin : iMargin + (iMaximumHeight - iNameHeight) / 2; 561 paintText(/* Painter: */ 562 pPainter, 563 /* Rectangle to paint in: */ 564 QPoint(iMachineNameX, iMachineNameY), 565 /* Font to paint text: */ 566 m_nameFont, 567 /* Paint device: */ 568 model()->paintDevice(), 569 /* Text to paint: */ 570 m_strName, 571 /* Name hovered? */ 572 m_fNameHovered ? linkTextColor : buttonTextColor); 573 574 /* Paint text: */ 575 if (!m_fClosed && !m_text.isEmpty() && !m_fAnimationRunning) 576 { 577 /* Prepare painter: */ 578 pPainter->save(); 579 pPainter->setPen(baseTextColor); 580 581 /* Prepare variables: */ 582 int iMinimumTextColumnWidth = data(ElementData_MinimumTextColumnWidth).toInt(); 583 int iMaximumTextWidth = geometry().width() - 3 * iMargin - iSpacing; 584 QPaintDevice *pPaintDevice = model()->paintDevice(); 585 QFontMetrics fm(m_textFont, pPaintDevice); 586 587 /* Search for the maximum line widths: */ 588 int iMaximumLeftLineWidth = 0; 589 int iMaximumRightLineWidth = 0; 590 bool fSingleColumnText = true; 591 foreach (const UITextTableLine line, m_text) 218 int iMaximumTextWidth = (int)size().width() - 2 * m_iMargin - m_iSpacing; 219 QFontMetrics fm(font(), m_pPaintDevice); 220 221 /* Where to paint? */ 222 int iTextX = m_iMargin; 223 int iTextY = m_iMargin; 224 225 /* Search for the maximum line widths: */ 226 int iMaximumLeftLineWidth = 0; 227 int iMaximumRightLineWidth = 0; 228 bool fSingleColumnText = true; 229 foreach (const UITextTableLine line, m_text) 230 { 231 bool fRightColumnPresent = !line.second.isEmpty(); 232 if (fRightColumnPresent) 233 fSingleColumnText = false; 234 QString strFirstLine = fRightColumnPresent ? line.first + ":" : line.first; 235 QString strSecondLine = line.second; 236 iMaximumLeftLineWidth = qMax(iMaximumLeftLineWidth, fm.width(strFirstLine)); 237 iMaximumRightLineWidth = qMax(iMaximumRightLineWidth, fm.width(strSecondLine)); 238 } 239 iMaximumLeftLineWidth += 1; 240 iMaximumRightLineWidth += 1; 241 242 /* Calculate column widths: */ 243 int iLeftColumnWidth = 0; 244 int iRightColumnWidth = 0; 245 if (fSingleColumnText) 246 { 247 /* Take into account only left column: */ 248 iLeftColumnWidth = qMax(m_iMinimumTextColumnWidth, iMaximumTextWidth); 249 } 250 else 251 { 252 /* Take into account both columns, but wrap only right one: */ 253 iLeftColumnWidth = iMaximumLeftLineWidth; 254 iRightColumnWidth = iMaximumTextWidth - iLeftColumnWidth; 255 } 256 257 /* For each the line: */ 258 foreach (const UITextTableLine line, m_text) 259 { 260 /* First layout: */ 261 int iLeftColumnHeight = 0; 262 if (!line.first.isEmpty()) 592 263 { 593 264 bool fRightColumnPresent = !line.second.isEmpty(); 594 if (fRightColumnPresent) 595 fSingleColumnText = false; 596 QString strFirstLine = fRightColumnPresent ? line.first + ":" : line.first; 597 QString strSecondLine = line.second; 598 iMaximumLeftLineWidth = qMax(iMaximumLeftLineWidth, fm.width(strFirstLine)); 599 iMaximumRightLineWidth = qMax(iMaximumRightLineWidth, fm.width(strSecondLine)); 600 } 601 iMaximumLeftLineWidth += 1; 602 iMaximumRightLineWidth += 1; 603 604 /* Calculate column widths: */ 605 int iLeftColumnWidth = 0; 606 int iRightColumnWidth = 0; 607 if (fSingleColumnText) 608 { 609 /* Take into account only left column: */ 610 iLeftColumnWidth = qMax(iMinimumTextColumnWidth, iMaximumTextWidth); 611 } 612 else 613 { 614 /* Take into account both columns, but wrap only right one: */ 615 iLeftColumnWidth = iMaximumLeftLineWidth; 616 iRightColumnWidth = iMaximumTextWidth - iLeftColumnWidth; 617 } 618 619 /* Where to paint? */ 620 int iMachineTextX = iMachinePixmapX; 621 int iMachineTextY = iMargin + m_iMinimumHeaderHeight + 2 * iMargin; 622 623 /* For each the line: */ 624 foreach (const UITextTableLine line, m_text) 625 { 626 /* First layout: */ 627 int iLeftColumnHeight = 0; 628 if (!line.first.isEmpty()) 629 { 630 bool fRightColumnPresent = !line.second.isEmpty(); 631 QTextLayout *pTextLayout = prepareTextLayout(m_textFont, pPaintDevice, 632 fRightColumnPresent ? line.first + ":" : line.first, 633 iLeftColumnWidth, iLeftColumnHeight); 634 pTextLayout->draw(pPainter, QPointF(iMachineTextX, iMachineTextY)); 635 delete pTextLayout; 636 } 637 638 /* Second layout: */ 639 int iRightColumnHeight = 0; 640 if (!line.second.isEmpty()) 641 { 642 QTextLayout *pTextLayout = prepareTextLayout(m_textFont, pPaintDevice, 643 line.second, iRightColumnWidth, iRightColumnHeight); 644 pTextLayout->draw(pPainter, QPointF(iMachineTextX + iLeftColumnWidth + iSpacing, iMachineTextY)); 645 delete pTextLayout; 646 } 647 648 /* Indent Y: */ 649 iMachineTextY += qMax(iLeftColumnHeight, iRightColumnHeight); 650 } 651 652 /* Restore painter: */ 653 pPainter->restore(); 654 } 655 } 656 657 void UIGDetailsElement::paintBackground(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption) 658 { 659 /* Save painter: */ 660 pPainter->save(); 661 662 /* Prepare variables: */ 663 int iMargin = data(ElementData_Margin).toInt(); 664 int iHeaderHeight = 2 * iMargin + m_iMinimumHeaderHeight; 665 QRect optionRect = pOption->rect; 666 QRect fullRect = !m_fAnimationRunning ? optionRect : 667 QRect(optionRect.topLeft(), QSize(optionRect.width(), iHeaderHeight + m_iAdditionalHeight)); 668 int iFullHeight = fullRect.height(); 669 670 /* Prepare color: */ 671 QPalette pal = palette(); 672 QColor headerColor = pal.color(QPalette::Active, QPalette::Button); 673 QColor strokeColor = pal.color(QPalette::Active, QPalette::Mid); 674 QColor bodyColor = pal.color(QPalette::Active, QPalette::Base); 675 676 /* Add clipping: */ 677 QPainterPath path; 678 path.moveTo(m_iCornerRadius, 0); 679 path.arcTo(QRectF(path.currentPosition(), QSizeF(2 * m_iCornerRadius, 2 * m_iCornerRadius)).translated(-m_iCornerRadius, 0), 90, 90); 680 path.lineTo(path.currentPosition().x(), iFullHeight - m_iCornerRadius); 681 path.arcTo(QRectF(path.currentPosition(), QSizeF(2 * m_iCornerRadius, 2 * m_iCornerRadius)).translated(0, -m_iCornerRadius), 180, 90); 682 path.lineTo(fullRect.width() - m_iCornerRadius, path.currentPosition().y()); 683 path.arcTo(QRectF(path.currentPosition(), QSizeF(2 * m_iCornerRadius, 2 * m_iCornerRadius)).translated(-m_iCornerRadius, -2 * m_iCornerRadius), 270, 90); 684 path.lineTo(path.currentPosition().x(), m_iCornerRadius); 685 path.arcTo(QRectF(path.currentPosition(), QSizeF(2 * m_iCornerRadius, 2 * m_iCornerRadius)).translated(-2 * m_iCornerRadius, -m_iCornerRadius), 0, 90); 686 path.closeSubpath(); 687 pPainter->setClipPath(path); 688 689 /* Calculate top rectangle: */ 690 QRect tRect = fullRect; 691 tRect.setBottom(tRect.top() + iHeaderHeight); 692 /* Calculate bottom rectangle: */ 693 QRect bRect = fullRect; 694 bRect.setTop(tRect.bottom()); 695 696 /* Prepare top gradient: */ 697 QLinearGradient tGradient(tRect.bottomLeft(), tRect.topLeft()); 698 tGradient.setColorAt(0, headerColor.darker(110)); 699 tGradient.setColorAt(1, headerColor.darker(animationDarkness())); 700 701 /* Paint all the stuff: */ 702 pPainter->fillRect(tRect, tGradient); 703 pPainter->fillRect(bRect, bodyColor); 704 705 /* Stroke path: */ 706 pPainter->setClipping(false); 707 pPainter->strokePath(path, strokeColor); 708 709 /* Restore painter: */ 710 pPainter->restore(); 711 } 712 713 void UIGDetailsElement::hoverMoveEvent(QGraphicsSceneHoverEvent *pEvent) 714 { 715 /* Update hover state: */ 716 if (!m_fHovered) 717 { 718 m_fHovered = true; 719 emit sigHoverEnter(); 720 } 721 722 /* Update name-hover state: */ 723 handleHoverEvent(pEvent); 724 } 725 726 void UIGDetailsElement::hoverLeaveEvent(QGraphicsSceneHoverEvent *pEvent) 727 { 728 /* Update hover state: */ 729 if (m_fHovered) 730 { 731 m_fHovered = false; 732 emit sigHoverLeave(); 733 } 734 735 /* Update name-hover state: */ 736 handleHoverEvent(pEvent); 737 } 738 739 void UIGDetailsElement::mousePressEvent(QGraphicsSceneMouseEvent *pEvent) 740 { 741 /* Only for hovered header: */ 742 if (!m_fNameHovered) 743 return; 744 745 /* Process link click: */ 746 pEvent->accept(); 747 QString strCategory; 748 if (m_type >= DetailsElementType_General && 749 m_type <= DetailsElementType_SF) 750 strCategory = QString("#%1").arg(gpConverter->toInternalString(m_type)); 751 else if (m_type == DetailsElementType_Description) 752 strCategory = QString("#%1%%mTeDescription").arg(gpConverter->toInternalString(m_type)); 753 emit sigLinkClicked(strCategory, QString(), machine().GetId()); 754 } 755 756 void UIGDetailsElement::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *pEvent) 757 { 758 /* Only for left-button: */ 759 if (pEvent->button() != Qt::LeftButton) 760 return; 761 762 /* Process left-button double-click: */ 763 emit sigToggleElement(m_type, closed()); 764 } 765 766 void UIGDetailsElement::updateButtonVisibility() 767 { 768 if (m_fHovered && !m_pButton->isVisible()) 769 m_pButton->show(); 770 else if (!m_fHovered && m_pButton->isVisible()) 771 m_pButton->hide(); 772 } 773 774 void UIGDetailsElement::handleHoverEvent(QGraphicsSceneHoverEvent *pEvent) 775 { 776 /* Not for 'preview' element type: */ 777 if (m_type == DetailsElementType_Preview) 778 return; 779 780 /* Prepare variables: */ 781 int iMargin = data(ElementData_Margin).toInt(); 782 int iSpacing = data(ElementData_Spacing).toInt(); 783 int iNameHeight = m_nameSize.height(); 784 int iMachineNameX = 2 * iMargin + m_pixmapSize.width() + iSpacing; 785 int iMachineNameY = iNameHeight == m_iMinimumHeaderHeight ? 786 iMargin : iMargin + (m_iMinimumHeaderHeight - iNameHeight) / 2; 787 788 /* Simulate hyperlink hovering: */ 789 QPoint point = pEvent->pos().toPoint(); 790 bool fNameHovered = QRect(QPoint(iMachineNameX, iMachineNameY), m_nameSize).contains(point); 791 if (m_pSet->elementNameHoverable() && m_fNameHovered != fNameHovered) 792 { 793 m_fNameHovered = fNameHovered; 794 updateNameHoverLink(); 795 } 796 } 797 798 void UIGDetailsElement::updateNameHoverLink() 799 { 800 if (m_fNameHovered) 801 setCursor(Qt::PointingHandCursor); 802 else 803 unsetCursor(); 804 update(); 265 QTextLayout *pTextLayout = buildTextLayout(font(), m_pPaintDevice, 266 fRightColumnPresent ? line.first + ":" : line.first, 267 iLeftColumnWidth, iLeftColumnHeight); 268 pTextLayout->draw(pPainter, QPointF(iTextX, iTextY)); 269 delete pTextLayout; 270 } 271 272 /* Second layout: */ 273 int iRightColumnHeight = 0; 274 if (!line.second.isEmpty()) 275 { 276 QTextLayout *pTextLayout = buildTextLayout(font(), m_pPaintDevice, 277 line.second, iRightColumnWidth, iRightColumnHeight); 278 pTextLayout->draw(pPainter, QPointF(iTextX + iLeftColumnWidth + m_iSpacing, iTextY)); 279 delete pTextLayout; 280 } 281 282 /* Indent Y: */ 283 iTextY += qMax(iLeftColumnHeight, iRightColumnHeight); 284 } 805 285 } 806 286 807 287 /* static */ 808 QTextLayout* UIG DetailsElement::prepareTextLayout(const QFont &font, QPaintDevice *pPaintDevice,809 288 QTextLayout* UIGraphicsTextPane::buildTextLayout(const QFont &font, QPaintDevice *pPaintDevice, 289 const QString &strText, int iWidth, int &iHeight) 810 290 { 811 291 /* Prepare variables: */ … … 860 340 } 861 341 862 void UIGDetailsElement::updateAnimationParameters()863 {864 /* Recalculate animation parameters: */865 int iOpenedHeight = minimumHeightHint(false);866 int iClosedHeight = minimumHeightHint(true);867 int iAdditionalHeight = iOpenedHeight - iClosedHeight;868 if (m_fClosed)869 m_iAdditionalHeight = 0;870 else871 m_iAdditionalHeight = iAdditionalHeight;872 m_pButton->setAnimationRange(0, iAdditionalHeight);873 }874 -
trunk/src/VBox/Frontends/VirtualBox/src/widgets/graphics/UIGraphicsTextPane.h
r50824 r50843 1 1 /** @file 2 * 3 * VBox frontends: Qt GUI ("VirtualBox"): 4 * UIGDetailsElement class declaration 2 * VBox Qt GUI - UIGraphicsTextPane class declaration. 5 3 */ 6 4 7 5 /* 8 * Copyright (C) 2012 Oracle Corporation6 * Copyright (C) 2012-2014 Oracle Corporation 9 7 * 10 8 * This file is part of VirtualBox Open Source Edition (OSE), as … … 17 15 */ 18 16 19 #ifndef __UIGDetailsElement_h__ 20 #define __UIGDetailsElement_h__ 21 22 /* Qt includes: */ 23 #include <QIcon> 17 #ifndef ___UIGraphicsTextPane_h___ 18 #define ___UIGraphicsTextPane_h___ 24 19 25 20 /* GUI includes: */ 26 #include "UIGDetailsItem.h" 27 #include "UIDefs.h" 28 29 /* Forward declarations: */ 30 class UIGDetailsSet; 31 class CMachine; 32 class UIGraphicsRotatorButton; 33 class QTextLayout; 34 class QStateMachine; 35 class QPropertyAnimation; 21 #include "QIGraphicsWidget.h" 36 22 37 23 /* Typedefs: */ … … 40 26 Q_DECLARE_METATYPE(UITextTable); 41 27 42 /* Details element 43 * for graphics details model/view architecture: */ 44 class UIGDetailsElement : public UIGDetailsItem 28 /** QIGraphicsWidget reimplementation to draw QTextLayout content. */ 29 class UIGraphicsTextPane : public QIGraphicsWidget 45 30 { 46 31 Q_OBJECT; 47 Q_PROPERTY(int animationDarkness READ animationDarkness WRITE setAnimationDarkness);48 Q_PROPERTY(int additionalHeight READ additionalHeight WRITE setAdditionalHeight);49 50 signals:51 52 /* Notifiers: Hover stuff: */53 void sigHoverEnter();54 void sigHoverLeave();55 56 /* Notifiers: Toggle stuff: */57 void sigToggleElement(DetailsElementType type, bool fToggled);58 void sigToggleElementFinished();59 60 /* Notifier: Link-click stuff: */61 void sigLinkClicked(const QString &strCategory, const QString &strControl, const QString &strId);62 32 63 33 public: 64 34 65 /* Graphics-item type: */ 66 enum { Type = UIGDetailsItemType_Element }; 67 int type() const { return Type; } 35 /** Graphics text-pane constructor. */ 36 UIGraphicsTextPane(QIGraphicsWidget *pParent, QPaintDevice *pPaintDevice); 68 37 69 /* Constructor/destructor: */ 70 UIGDetailsElement(UIGDetailsSet *pParent, DetailsElementType type, bool fOpened); 71 ~UIGDetailsElement(); 72 73 /* API: Element type: */ 74 DetailsElementType elementType() const { return m_type; } 75 76 /* API: Open/close stuff: */ 77 bool closed() const { return m_fClosed; } 78 bool opened() const { return !m_fClosed; } 79 void close(bool fAnimated = true); 80 void open(bool fAnimated = true); 81 82 /* API: Update stuff: */ 83 virtual void updateAppearance(); 84 85 /* API: Animation stuff: */ 86 void markAnimationFinished(); 87 88 protected slots: 89 90 /* Handlers: Toggle stuff: */ 91 void sltToggleButtonClicked(); 92 void sltElementToggleStart(); 93 void sltElementToggleFinish(bool fToggled); 94 95 protected: 96 97 /* Data enumerator: */ 98 enum ElementData 99 { 100 /* Hints: */ 101 ElementData_Margin, 102 ElementData_Spacing, 103 ElementData_MinimumTextColumnWidth 104 }; 105 106 /* Data provider: */ 107 QVariant data(int iKey) const; 108 109 /* Helpers: Update stuff: */ 110 void updateMinimumHeaderWidth(); 111 void updateMinimumHeaderHeight(); 112 void updateMinimumTextWidth(); 113 void updateMinimumTextHeight(); 114 115 /* API: Icon stuff: */ 116 void setIcon(const QIcon &icon); 117 118 /* API: Name stuff: */ 119 void setName(const QString &strName); 120 121 /* API: Text stuff: */ 122 UITextTable text() const { return m_text; } 38 /** Returns whether contained text is empty. */ 39 bool isEmpty() const { return m_text.isEmpty(); } 40 /** Returns contained text. */ 41 const UITextTable& text() const { return m_text; } 42 /** Defines contained text. */ 123 43 void setText(const UITextTable &text); 124 125 /* API: Machine stuff: */126 const CMachine& machine();127 128 /* Helpers: Layout stuff: */129 int minimumHeaderWidth() const { return m_iMinimumHeaderWidth; }130 int minimumHeaderHeight() const { return m_iMinimumHeaderHeight; }131 int minimumWidthHint() const;132 virtual int minimumHeightHint(bool fClosed) const;133 int minimumHeightHint() const;134 void updateLayout();135 136 /* Helpers: Hover stuff: */137 int animationDarkness() const { return m_iAnimationDarkness; }138 void setAnimationDarkness(int iAnimationDarkness) { m_iAnimationDarkness = iAnimationDarkness; update(); }139 140 /* Helpers: Animation stuff: */141 void setAdditionalHeight(int iAdditionalHeight);142 int additionalHeight() const { return m_iAdditionalHeight; }143 UIGraphicsRotatorButton* button() const { return m_pButton; }144 bool isAnimationRunning() const { return m_fAnimationRunning; }145 44 146 45 private: 147 46 148 /* API: Children stuff:*/149 void addItem(UIGDetailsItem *pItem);150 void removeItem(UIGDetailsItem *pItem);151 QList<UIGDetailsItem*> items(UIGDetailsItemType type) const;152 bool hasItems(UIGDetailsItemType type) const;153 void clearItems(UIGDetailsItemType type);47 /** Updates minimum text width hint. */ 48 void updateMinimumTextWidthHint(); 49 /** Updates minimum text height hint. */ 50 void updateMinimumTextHeightHint(); 51 /** Returns the size-hint to constrain the content. */ 52 QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const; 154 53 155 /* Helpers: Prepare stuff: */ 156 void prepareElement(); 157 void prepareButton(); 54 /** This event handler is delivered after the widget has been resized. */ 55 void resizeEvent(QGraphicsSceneResizeEvent *pEvent); 158 56 159 /* Helpers: Paint stuff:*/57 /** Paints the contents in local coordinates. */ 160 58 void paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget *pWidget = 0); 161 void paintDecorations(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption);162 void paintElementInfo(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption);163 void paintBackground(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption);164 59 165 /* Handlers: Mouse stuff: */ 166 void hoverMoveEvent(QGraphicsSceneHoverEvent *pEvent); 167 void hoverLeaveEvent(QGraphicsSceneHoverEvent *pEvent); 168 void mousePressEvent(QGraphicsSceneMouseEvent *pEvent); 169 void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *pEvent); 60 /** Builds new text-layout. */ 61 static QTextLayout* buildTextLayout(const QFont &font, QPaintDevice *pPaintDevice, 62 const QString &strText, int iWidth, int &iHeight); 170 63 171 /* Helpers: Mouse stuff: */ 172 void updateButtonVisibility(); 173 void handleHoverEvent(QGraphicsSceneHoverEvent *pEvent); 174 void updateNameHoverLink(); 64 /** Margin. */ 65 const int m_iMargin; 66 /** Spacing. */ 67 const int m_iSpacing; 68 /** Minimum text-column width: */ 69 const int m_iMinimumTextColumnWidth; 175 70 176 /* Helper: Layout stuff: */ 177 static QTextLayout* prepareTextLayout(const QFont &font, QPaintDevice *pPaintDevice, 178 const QString &strText, int iWidth, int &iHeight); 179 180 /* Helper: Animation stuff: */ 181 void updateAnimationParameters(); 182 183 /* Variables: */ 184 UIGDetailsSet *m_pSet; 185 DetailsElementType m_type; 186 QPixmap m_pixmap; 187 QString m_strName; 188 UITextTable m_text; 189 int m_iCornerRadius; 190 QFont m_nameFont; 191 QFont m_textFont; 192 QSize m_pixmapSize; 193 QSize m_nameSize; 194 QSize m_buttonSize; 195 int m_iMinimumHeaderWidth; 196 int m_iMinimumHeaderHeight; 71 /** Minimum text-width. */ 197 72 int m_iMinimumTextWidth; 73 /** Minimum text-height. */ 198 74 int m_iMinimumTextHeight; 199 75 200 /* Variables: Toggle stuff: */ 201 bool m_fClosed; 202 UIGraphicsRotatorButton *m_pButton; 203 int m_iAdditionalHeight; 204 bool m_fAnimationRunning; 76 /** Paint-device to scale to. */ 77 QPaintDevice *m_pPaintDevice; 205 78 206 /* Variables: Hover stuff: */ 207 bool m_fHovered; 208 bool m_fNameHovered; 209 QStateMachine *m_pHighlightMachine; 210 QPropertyAnimation *m_pForwardAnimation; 211 QPropertyAnimation *m_pBackwardAnimation; 212 int m_iAnimationDuration; 213 int m_iDefaultDarkness; 214 int m_iHighlightDarkness; 215 int m_iAnimationDarkness; 216 217 /* Friends: */ 218 friend class UIGDetailsSet; 79 /** Contained text. */ 80 UITextTable m_text; 219 81 }; 220 82 221 #endif /* __UIGDetailsElement_h__ */ 222 83 #endif /* !___UIGraphicsTextPane_h___ */
Note:
See TracChangeset
for help on using the changeset viewer.