[26714] | 1 | /* $Id: UIPopupPaneDetails.cpp 100064 2023-06-04 09:10:01Z vboxsync $ */
|
---|
[25177] | 2 | /** @file
|
---|
[68540] | 3 | * VBox Qt GUI - UIPopupPaneDetails class implementation.
|
---|
[25177] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2013-2023 Oracle and/or its affiliates.
|
---|
[25177] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[25177] | 26 | */
|
---|
| 27 |
|
---|
[41587] | 28 | /* Qt includes: */
|
---|
[76606] | 29 | #include <QCheckBox>
|
---|
| 30 | #include <QTextDocument>
|
---|
| 31 | #include <QTextEdit>
|
---|
[34736] | 32 |
|
---|
[41587] | 33 | /* GUI includes: */
|
---|
[76606] | 34 | #include "UIAnimationFramework.h"
|
---|
[80914] | 35 | #include "UIPopupPane.h"
|
---|
[76606] | 36 | #include "UIPopupPaneDetails.h"
|
---|
[25177] | 37 |
|
---|
[80914] | 38 | /* Other VBox includes: */
|
---|
| 39 | #include <iprt/assert.h>
|
---|
[52730] | 40 |
|
---|
[68540] | 41 | UIPopupPaneDetails::UIPopupPaneDetails(QWidget *pParent, const QString &strText, bool fFocused)
|
---|
[50138] | 42 | : QWidget(pParent)
|
---|
[68807] | 43 | , m_iLayoutMargin(5)
|
---|
[45691] | 44 | , m_iLayoutSpacing(10)
|
---|
[47031] | 45 | , m_strText(strText)
|
---|
[68540] | 46 | , m_pTextEdit(0)
|
---|
| 47 | , m_iDesiredTextEditWidth(-1)
|
---|
[68807] | 48 | , m_iMaximumPaneHeight(-1)
|
---|
| 49 | , m_iMaximumTextEditHeight(0)
|
---|
| 50 | , m_iTextContentMargin(5)
|
---|
[47694] | 51 | , m_fFocused(fFocused)
|
---|
[45592] | 52 | , m_pAnimation(0)
|
---|
[45522] | 53 | {
|
---|
| 54 | /* Prepare: */
|
---|
| 55 | prepare();
|
---|
| 56 | }
|
---|
| 57 |
|
---|
[68540] | 58 | void UIPopupPaneDetails::setText(const QString &strText)
|
---|
[45522] | 59 | {
|
---|
[47031] | 60 | /* Make sure the text has changed: */
|
---|
[68540] | 61 | if (m_strText == strText)
|
---|
[45522] | 62 | return;
|
---|
[47031] | 63 |
|
---|
| 64 | /* Fetch new text: */
|
---|
| 65 | m_strText = strText;
|
---|
[68540] | 66 | m_pTextEdit->setText(m_strText);
|
---|
[47031] | 67 |
|
---|
[68540] | 68 | /* Update size-hint/visibility: */
|
---|
[45658] | 69 | updateSizeHint();
|
---|
[68540] | 70 | updateVisibility();
|
---|
[45522] | 71 | }
|
---|
| 72 |
|
---|
[68540] | 73 | QSize UIPopupPaneDetails::minimumSizeHint() const
|
---|
[45522] | 74 | {
|
---|
| 75 | /* Check if desired-width set: */
|
---|
[68540] | 76 | if (m_iDesiredTextEditWidth >= 0)
|
---|
[45691] | 77 | /* Dependent size-hint: */
|
---|
[45592] | 78 | return m_minimumSizeHint;
|
---|
[45691] | 79 | /* Golden-rule size-hint by default: */
|
---|
| 80 | return QWidget::minimumSizeHint();
|
---|
[45522] | 81 | }
|
---|
| 82 |
|
---|
[68540] | 83 | void UIPopupPaneDetails::setMinimumSizeHint(const QSize &minimumSizeHint)
|
---|
[45592] | 84 | {
|
---|
[47031] | 85 | /* Make sure the size-hint has changed: */
|
---|
[45658] | 86 | if (m_minimumSizeHint == minimumSizeHint)
|
---|
| 87 | return;
|
---|
[47031] | 88 |
|
---|
| 89 | /* Fetch new size-hint: */
|
---|
[45658] | 90 | m_minimumSizeHint = minimumSizeHint;
|
---|
[47031] | 91 |
|
---|
[45658] | 92 | /* Notify parent popup-pane: */
|
---|
| 93 | emit sigSizeHintChanged();
|
---|
[45592] | 94 | }
|
---|
| 95 |
|
---|
[68540] | 96 | void UIPopupPaneDetails::layoutContent()
|
---|
[45592] | 97 | {
|
---|
[45691] | 98 | /* Variables: */
|
---|
| 99 | const int iWidth = width();
|
---|
| 100 | const int iHeight = height();
|
---|
[68540] | 101 | const int iTextEditWidth = m_textEditSizeHint.width();
|
---|
| 102 | const int iTextEditHeight = m_textEditSizeHint.height();
|
---|
[47031] | 103 |
|
---|
[68540] | 104 | /* TextEdit: */
|
---|
| 105 | m_pTextEdit->move(m_iLayoutMargin, m_iLayoutMargin);
|
---|
| 106 | m_pTextEdit->resize(qMin(iWidth, iTextEditWidth), qMin(iHeight, iTextEditHeight));
|
---|
[68807] | 107 | /* Text-document: */
|
---|
| 108 | QTextDocument *pTextDocument = m_pTextEdit->document();
|
---|
| 109 | if (pTextDocument)
|
---|
| 110 | {
|
---|
| 111 | pTextDocument->adjustSize();
|
---|
| 112 | pTextDocument->setTextWidth(m_pTextEdit->width() - m_iTextContentMargin);
|
---|
| 113 | }
|
---|
[45592] | 114 | }
|
---|
| 115 |
|
---|
[68540] | 116 | void UIPopupPaneDetails::sltHandleProposalForWidth(int iWidth)
|
---|
| 117 | {
|
---|
[47455] | 118 | /* Make sure the desired-width has changed: */
|
---|
[68540] | 119 | if (m_iDesiredTextEditWidth == iWidth)
|
---|
[47455] | 120 | return;
|
---|
| 121 |
|
---|
| 122 | /* Fetch new desired-width: */
|
---|
[68540] | 123 | m_iDesiredTextEditWidth = iWidth;
|
---|
[47455] | 124 |
|
---|
| 125 | /* Update size-hint: */
|
---|
| 126 | updateSizeHint();
|
---|
| 127 | }
|
---|
| 128 |
|
---|
[68540] | 129 | void UIPopupPaneDetails::sltHandleProposalForHeight(int iHeight)
|
---|
[45592] | 130 | {
|
---|
[68540] | 131 | /* Make sure the desired-height has changed: */
|
---|
[68807] | 132 | if (m_iMaximumPaneHeight == iHeight)
|
---|
[68540] | 133 | return;
|
---|
| 134 |
|
---|
| 135 | /* Fetch new desired-height: */
|
---|
[68807] | 136 | m_iMaximumPaneHeight = iHeight;
|
---|
| 137 | m_iMaximumTextEditHeight = m_iMaximumPaneHeight - 2 * m_iLayoutMargin;
|
---|
[68540] | 138 |
|
---|
| 139 | /* Update size-hint: */
|
---|
| 140 | updateSizeHint();
|
---|
| 141 | }
|
---|
| 142 |
|
---|
| 143 | void UIPopupPaneDetails::sltFocusEnter()
|
---|
| 144 | {
|
---|
[45691] | 145 | /* Ignore if already focused: */
|
---|
[45592] | 146 | if (m_fFocused)
|
---|
[45691] | 147 | return;
|
---|
| 148 |
|
---|
| 149 | /* Update focus state: */
|
---|
| 150 | m_fFocused = true;
|
---|
| 151 |
|
---|
[68540] | 152 | /* Update visibility: */
|
---|
| 153 | updateVisibility();
|
---|
| 154 |
|
---|
[45691] | 155 | /* Notify listeners: */
|
---|
| 156 | emit sigFocusEnter();
|
---|
[45592] | 157 | }
|
---|
| 158 |
|
---|
[68540] | 159 | void UIPopupPaneDetails::sltFocusLeave()
|
---|
[45691] | 160 | {
|
---|
| 161 | /* Ignore if already unfocused: */
|
---|
| 162 | if (!m_fFocused)
|
---|
| 163 | return;
|
---|
| 164 |
|
---|
| 165 | /* Update focus state: */
|
---|
| 166 | m_fFocused = false;
|
---|
| 167 |
|
---|
[68540] | 168 | /* Update visibility: */
|
---|
| 169 | updateVisibility();
|
---|
| 170 |
|
---|
[45691] | 171 | /* Notify listeners: */
|
---|
| 172 | emit sigFocusLeave();
|
---|
| 173 | }
|
---|
| 174 |
|
---|
[68540] | 175 | void UIPopupPaneDetails::prepare()
|
---|
[45522] | 176 | {
|
---|
| 177 | /* Prepare content: */
|
---|
| 178 | prepareContent();
|
---|
[47031] | 179 | /* Prepare animation: */
|
---|
| 180 | prepareAnimation();
|
---|
| 181 |
|
---|
[68540] | 182 | /* Update size-hint/visibility: */
|
---|
[47031] | 183 | updateSizeHint();
|
---|
[68540] | 184 | updateVisibility();
|
---|
[45522] | 185 | }
|
---|
| 186 |
|
---|
[68540] | 187 | void UIPopupPaneDetails::prepareContent()
|
---|
[45522] | 188 | {
|
---|
[68540] | 189 | /* Create text-editor: */
|
---|
| 190 | m_pTextEdit = new QTextEdit(this);
|
---|
[71515] | 191 | if (m_pTextEdit)
|
---|
[45522] | 192 | {
|
---|
[68540] | 193 | /* Configure text-editor: */
|
---|
| 194 | m_pTextEdit->setFont(tuneFont(m_pTextEdit->font()));
|
---|
| 195 | m_pTextEdit->setText(m_strText);
|
---|
| 196 | m_pTextEdit->setFocusProxy(this);
|
---|
[45522] | 197 | }
|
---|
| 198 | }
|
---|
| 199 |
|
---|
[68540] | 200 | void UIPopupPaneDetails::prepareAnimation()
|
---|
[47031] | 201 | {
|
---|
[80914] | 202 | UIPopupPane *pPopupPane = qobject_cast<UIPopupPane*>(parent());
|
---|
| 203 | AssertReturnVoid(pPopupPane);
|
---|
| 204 | {
|
---|
| 205 | /* Propagate parent signals: */
|
---|
| 206 | connect(pPopupPane, &UIPopupPane::sigFocusEnter, this, &UIPopupPaneDetails::sltFocusEnter);
|
---|
| 207 | connect(pPopupPane, &UIPopupPane::sigFocusLeave, this, &UIPopupPaneDetails::sltFocusLeave);
|
---|
| 208 | }
|
---|
[47031] | 209 | /* Install geometry animation for 'minimumSizeHint' property: */
|
---|
| 210 | m_pAnimation = UIAnimation::installPropertyAnimation(this, "minimumSizeHint", "collapsedSizeHint", "expandedSizeHint",
|
---|
[47694] | 211 | SIGNAL(sigFocusEnter()), SIGNAL(sigFocusLeave()), m_fFocused);
|
---|
[47031] | 212 | }
|
---|
| 213 |
|
---|
[68540] | 214 | void UIPopupPaneDetails::updateSizeHint()
|
---|
[45522] | 215 | {
|
---|
[45691] | 216 | /* Recalculate collapsed size-hint: */
|
---|
| 217 | {
|
---|
[68540] | 218 | /* Collapsed size-hint with 0 height: */
|
---|
| 219 | m_collapsedSizeHint = QSize(m_iDesiredTextEditWidth, 0);
|
---|
[45691] | 220 | }
|
---|
| 221 |
|
---|
| 222 | /* Recalculate expanded size-hint: */
|
---|
| 223 | {
|
---|
[68807] | 224 | int iNewHeight = m_iMaximumPaneHeight;
|
---|
[68540] | 225 | QTextDocument *pTextDocument = m_pTextEdit->document();
|
---|
[70474] | 226 | if (pTextDocument)
|
---|
[68540] | 227 | {
|
---|
| 228 | /* Adjust text-edit size: */
|
---|
| 229 | pTextDocument->adjustSize();
|
---|
| 230 | /* Get corresponding QTextDocument size: */
|
---|
| 231 | QSize textSize = pTextDocument->size().toSize();
|
---|
| 232 | /* Make sure the text edits height is no larger than that of container widget: */
|
---|
[68807] | 233 | iNewHeight = qMin(m_iMaximumTextEditHeight, textSize.height() + 2 * m_iLayoutMargin);
|
---|
[68540] | 234 | }
|
---|
[45691] | 235 | /* Recalculate label size-hint: */
|
---|
[68540] | 236 | m_textEditSizeHint = QSize(m_iDesiredTextEditWidth, iNewHeight);
|
---|
[45691] | 237 | /* Expanded size-hint contains full-size label: */
|
---|
[68540] | 238 | m_expandedSizeHint = m_textEditSizeHint;
|
---|
[45691] | 239 | }
|
---|
| 240 |
|
---|
| 241 | /* Update current size-hint: */
|
---|
[45658] | 242 | m_minimumSizeHint = m_fFocused ? m_expandedSizeHint : m_collapsedSizeHint;
|
---|
[45691] | 243 |
|
---|
[46242] | 244 | /* Update animation: */
|
---|
[47031] | 245 | if (m_pAnimation)
|
---|
| 246 | m_pAnimation->update();
|
---|
| 247 |
|
---|
| 248 | /* Notify parent popup-pane: */
|
---|
| 249 | emit sigSizeHintChanged();
|
---|
[45522] | 250 | }
|
---|
| 251 |
|
---|
[71515] | 252 | void UIPopupPaneDetails::updateVisibility()
|
---|
| 253 | {
|
---|
| 254 | if (m_fFocused && !m_strText.isEmpty())
|
---|
| 255 | show();
|
---|
| 256 | else
|
---|
| 257 | hide();
|
---|
| 258 | }
|
---|
| 259 |
|
---|
[47042] | 260 | /* static */
|
---|
[68540] | 261 | QFont UIPopupPaneDetails::tuneFont(QFont font)
|
---|
[47042] | 262 | {
|
---|
[60362] | 263 | #if defined(VBOX_WS_MAC)
|
---|
[47043] | 264 | font.setPointSize(font.pointSize() - 2);
|
---|
[100064] | 265 | #elif defined(VBOX_WS_NIX)
|
---|
[47043] | 266 | font.setPointSize(font.pointSize() - 1);
|
---|
[47042] | 267 | #endif
|
---|
| 268 | return font;
|
---|
| 269 | }
|
---|