/* Copyright (C) 2014 * swift project Community / Contributors * * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated, * or distributed except according to the terms contained in the LICENSE file. */ #include "blackgui/enableforframelesswindow.h" #include "blackgui/guiutility.h" #include "blackgui/overlaymessagesframe.h" #include "blackmisc/icon.h" #include "blackmisc/verify.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace BlackMisc; namespace BlackGui { QWidget *CGuiUtility::s_mainApplicationWidget = nullptr; CEnableForFramelessWindow *CGuiUtility::mainFramelessEnabledWindow() { const QWidgetList tlw = topLevelApplicationWidgetsWithName(); for (QWidget *w : tlw) { // best choice is to check on frameless window CEnableForFramelessWindow *mw = dynamic_cast(w); if (!mw) { continue; } if (mw->isMainApplicationWindow()) { return mw; } } return nullptr; } namespace Private { QWidget *mainApplicationWidgetSearch() { CEnableForFramelessWindow *mw = CGuiUtility::mainFramelessEnabledWindow(); if (mw && mw->getWidget()) { return mw->getWidget(); } // second choice, try via QMainWindow const QWidgetList tlw = CGuiUtility::topLevelApplicationWidgetsWithName(); for (QWidget *w : tlw) { QMainWindow *qmw = qobject_cast(w); if (!qmw) { continue; } if (!qmw->parentWidget()) { return qmw; } } return nullptr; } } // ns void CGuiUtility::registerMainApplicationWidget(QWidget *mainWidget) { CGuiUtility::s_mainApplicationWidget = mainWidget; } QWidget *CGuiUtility::mainApplicationWidget() { if (!CGuiUtility::s_mainApplicationWidget) { CGuiUtility::s_mainApplicationWidget = Private::mainApplicationWidgetSearch(); } return CGuiUtility::s_mainApplicationWidget; } qreal CGuiUtility::mainApplicationWidgetPixelRatio() { const QWidget *mw = CGuiUtility::mainApplicationWidget(); if (mw) { return mw->devicePixelRatio(); } return 1.0; } QSize CGuiUtility::desktopSize() { const QWidget *mw = CGuiUtility::mainApplicationWidget(); if (mw) { return QApplication::desktop()->screenGeometry(mw).size(); } // main screen return QApplication::desktop()->screenGeometry(QApplication::desktop()).size(); } bool CGuiUtility::isMainWindowFrameless() { const CEnableForFramelessWindow *mw = CGuiUtility::mainFramelessEnabledWindow(); return (mw && mw->isFrameless()); } QString CGuiUtility::screenInformation(const QString &separator) { QString i = u"Number of screens: " % QString::number(QGuiApplication::screens().size()) % separator % u"Primary screen: " % QGuiApplication::primaryScreen()->name(); for (const QScreen *screen : QGuiApplication::screens()) { i += separator % u"Information for screen: " % screen->name() % separator % u"Available geometry: " % rectAsString(screen->availableGeometry()) % separator % u"Available size: " % sizeAsString(screen->availableSize()) % separator % u"Available virtual geometry: " % rectAsString(screen->availableVirtualGeometry()) % separator % u"Available virtual size: " % sizeAsString(screen->availableVirtualSize()) % separator % u"Device ratio: " % QString::number(screen->devicePixelRatio()) % separator % u"Depth: " % QString::number(screen->depth()) % u"bits" % separator % u"Geometry: " % rectAsString(screen->geometry()) % separator % u"Logical DPI: " % QString::number(screen->logicalDotsPerInch()) % separator % u"Logical DPI X: " % QString::number(screen->logicalDotsPerInchX()) % separator % u"Logical DPI Y: " % QString::number(screen->logicalDotsPerInchY()) % separator % u"Orientation: " % orientationAsString(screen->orientation()) % separator % u"Physical DPI: " % QString::number(screen->physicalDotsPerInch()) % separator % u"Physical DPI X: " % QString::number(screen->physicalDotsPerInchX()) % separator % u"Physical DPI Y: " % QString::number(screen->physicalDotsPerInchY()) % separator % u"Physical size: " % sizeAsString(screen->physicalSize()) % u"mm" % separator % u"Primary orientation: " % orientationAsString(screen->primaryOrientation()) % separator % u"Refresh rate: " % QString::number(screen->refreshRate()) % u"Hz" % u"Size: " % sizeAsString(screen->size()) % separator % u"Virtual geometry: " % rectAsString(screen->virtualGeometry()) % separator % u"Virtual size: " % sizeAsString(screen->virtualSize()); } return i; } const QString &CGuiUtility::orientationAsString(Qt::ScreenOrientation orientation) { static const QString pr("Primary"); static const QString la("Landscape"); static const QString po("Portrait"); static const QString il("Inverted landscape"); static const QString ip("Inverted portrait"); switch (orientation) { case Qt::PrimaryOrientation : return pr; case Qt::LandscapeOrientation : return la; case Qt::PortraitOrientation : return po; case Qt::InvertedLandscapeOrientation : return il; case Qt::InvertedPortraitOrientation : return ip; default : break; } static const QString unknown("Unknown"); return unknown; } const QString CGuiUtility::rectAsString(const QRect &rect) { return QStringLiteral("x: %1 y: %2 w: %3 h: %4").arg(rect.x()).arg(rect.y()).arg(rect.width()).arg(rect.height()); } const QString CGuiUtility::rectAsString(const QRectF &rect) { return QStringLiteral("x: %1 y: %2 w: %3 h: %4").arg(rect.x()).arg(rect.y()).arg(rect.width()).arg(rect.height()); } const QString CGuiUtility::sizeAsString(const QSize &size) { return QStringLiteral("w: %1 h: %2").arg(size.width()).arg(size.height()); } const QString CGuiUtility::sizeAsString(const QSizeF &size) { return QStringLiteral("w: %1 h: %2").arg(size.width()).arg(size.height()); } static QThreadStorage tsRegex; bool CGuiUtility::lenientTitleComparison(const QString &title, const QString &comparison) { if (title == comparison) { return true; } QString t(title.trimmed().toLower().simplified()); QString c(comparison.trimmed().toLower().simplified()); Q_ASSERT_X(!t.isEmpty(), Q_FUNC_INFO, "missing title"); Q_ASSERT_X(!c.isEmpty(), Q_FUNC_INFO, "missing value"); if (t == c) { return true; } // further unify if (! tsRegex.hasLocalData()) { tsRegex.setLocalData(QRegularExpression("[^a-z0-9\\s]")); } const QRegularExpression ®exp = tsRegex.localData(); t = t.remove(regexp); c = c.remove(regexp); return t == c; } bool CGuiUtility::setComboBoxValueByStartingString(QComboBox *box, const QString &candidate, const QString &unspecified) { if (!box) { return false; } if (!candidate.isEmpty()) { for (int i = 0; i < box->count(); i++) { const QString t(box->itemText(i)); if (t.startsWith(candidate, Qt::CaseInsensitive)) { box->setCurrentIndex(i); return true; } } } // not found if (unspecified.isEmpty()) { return false; } for (int i = 0; i < box->count(); i++) { const QString t(box->itemText(i)); if (t.startsWith(unspecified, Qt::CaseInsensitive)) { box->setCurrentIndex(i); return true; } } return false; } bool CGuiUtility::setComboBoxValueByContainingString(QComboBox *box, const QString &candidate, const QString &unspecified) { if (!box) { return false; } if (!candidate.isEmpty()) { const int ci = box->currentIndex(); for (int i = 0; i < box->count(); i++) { const QString t(box->itemText(i)); if (t.contains(candidate, Qt::CaseInsensitive)) { if (ci == i) { return true; } // avoid signals box->setCurrentIndex(i); return true; } } } // not found if (unspecified.isEmpty()) { return false; } const int ci = box->currentIndex(); for (int i = 0; i < box->count(); i++) { const QString t(box->itemText(i)); if (t.contains(unspecified, Qt::CaseInsensitive)) { if (ci == i) { return true; } // avoid signals box->setCurrentIndex(i); return true; } } return false; } bool CGuiUtility::hasSwiftVariantMimeType(const QMimeData *mime) { return mime && mime->hasFormat(swiftJsonDragAndDropMimeType()); } CVariant CGuiUtility::fromSwiftDragAndDropData(const QMimeData *mime) { if (!hasSwiftVariantMimeType(mime)) { return CVariant(); } return CGuiUtility::fromSwiftDragAndDropData(mime->data(swiftJsonDragAndDropMimeType())); } CVariant CGuiUtility::fromSwiftDragAndDropData(const QByteArray &utf8Data) { if (utf8Data.isEmpty()) { return CVariant(); } const QJsonDocument jsonDoc(QJsonDocument::fromJson(utf8Data)); const QJsonObject jsonObj(jsonDoc.object()); const QString typeName(jsonObj.value("type").toString()); const int typeId = QMetaType::type(qPrintable(typeName)); // check if a potential valid value object if (typeName.isEmpty() || typeId == QMetaType::UnknownType) { return CVariant(); } CVariant valueVariant; const CStatusMessage status = valueVariant.convertFromJsonNoThrow(jsonObj, {}, {}); if (status.isFailure()) { return CVariant(); } return valueVariant; } int CGuiUtility::metaTypeIdFromSwiftDragAndDropData(const QMimeData *mime) { constexpr int Unknown = static_cast(QMetaType::UnknownType); if (!hasSwiftVariantMimeType(mime)) { return Unknown; } static const QJsonObject jsonObj(QJsonDocument::fromJson(mime->data(swiftJsonDragAndDropMimeType())).object()); Q_ASSERT_X(!jsonObj.isEmpty(), Q_FUNC_INFO, "Empty JSON object"); const QString typeName(jsonObj.value("type").toString()); if (typeName.isEmpty()) { return Unknown; } const int typeId = QMetaType::type(qPrintable(typeName)); return typeId; } const QString &CGuiUtility::swiftJsonDragAndDropMimeType() { static const QString m("text/json/swift"); return m; } QFileInfo CGuiUtility::representedMimeFile(const QMimeData *mime) { if (!mime->hasText()) { return QFileInfo(); } const QString candidate = mime->text(); if (candidate.isEmpty()) { return QFileInfo(); } if (!candidate.contains("://")) { return QFileInfo(candidate); } QUrl url(candidate); const QString localFile = url.toLocalFile(); return QFileInfo(localFile); } bool CGuiUtility::isMimeRepresentingReadableFile(const QMimeData *mime) { const QFileInfo fi = CGuiUtility::representedMimeFile(mime); return fi.isReadable(); } bool CGuiUtility::isMimeRepresentingReadableJsonFile(const QMimeData *mime) { const QFileInfo fi = CGuiUtility::representedMimeFile(mime); if (!fi.isReadable()) { return false; } const QString fn = fi.fileName(); return fn.endsWith("json", Qt::CaseInsensitive); } COverlayMessagesFrame *CGuiUtility::nextOverlayMessageFrame(QWidget *widget, int maxLevels) { return nextOverlayMessageWidget(widget, maxLevels); } COverlayMessagesTabWidget *CGuiUtility::nextOverlayMessageTabWidget(QWidget *widget, int maxLevels) { return nextOverlayMessageWidget(widget, maxLevels); } COverlayMessagesWizardPage *CGuiUtility::nextOverlayMessageWizardPage(QWidget *widget, int maxLevels) { return nextOverlayMessageWidget(widget, maxLevels); } void CGuiUtility::checkBoxReadOnly(QCheckBox *checkBox, bool readOnly) { static const QCheckBox defaultBox; BLACK_VERIFY_X(checkBox, Q_FUNC_INFO, "no checkbox"); if (!checkBox) { return; } static const QString background("background: rgba(40,40,40)"); //! \fixme hardcoded stylesheet setting, should come from stylesheet if (readOnly) { checkBox->setAttribute(Qt::WA_TransparentForMouseEvents); checkBox->setFocusPolicy(Qt::NoFocus); // without that, the checkboxes appear not readonly // obviously style sheet only does not work checkBox->setStyleSheet(background); //! fixme hardcoded stylesheet setting } else { checkBox->setAttribute(Qt::WA_TransparentForMouseEvents, defaultBox.testAttribute(Qt::WA_TransparentForMouseEvents)); checkBox->setFocusPolicy(defaultBox.focusPolicy()); checkBox->setStyleSheet(""); } } void CGuiUtility::checkBoxesReadOnly(QWidget *parent, bool readOnly) { if (!parent) { return; } QList allCheckBoxes = parent->findChildren(); for (QCheckBox *cb : allCheckBoxes) { CGuiUtility::checkBoxReadOnly(cb, readOnly); } } void CGuiUtility::tempUnhidePassword(QLineEdit *lineEdit, int unhideMs) { if (!lineEdit) { return; } if (lineEdit->text().isEmpty()) { return; } if (lineEdit->echoMode() != QLineEdit::Password && lineEdit->echoMode() != QLineEdit::PasswordEchoOnEdit) { return; } const QLineEdit::EchoMode mode = lineEdit->echoMode(); lineEdit->setEchoMode(QLineEdit::Normal); QPointer qpLineEdit(lineEdit); QTimer::singleShot(unhideMs, lineEdit, [ = ] { if (qpLineEdit) { qpLineEdit->setEchoMode(mode); } }); } QWidgetList CGuiUtility::topLevelApplicationWidgetsWithName() { QWidgetList tlw = QApplication::topLevelWidgets(); QWidgetList rl; for (QWidget *w : tlw) { if (w->objectName().isEmpty()) { continue; } rl.append(w); } return rl; } QPoint CGuiUtility::mainWidgetGlobalPosition() { QWidget *mw = CGuiUtility::mainApplicationWidget(); if (mw) { return mw->pos(); } // fallback, can be mfw it is not found CEnableForFramelessWindow *mfw = CGuiUtility::mainFramelessEnabledWindow(); if (!mfw || !mfw->getWidget()) { return QPoint(); } return mfw->getWidget()->pos(); // is main window, so not mapToGlobal } QString CGuiUtility::replaceTabCountValue(const QString &oldName, int count) { const QString v = QString(" (").append(QString::number(count)).append(")"); if (oldName.isEmpty()) { return v; } int index = oldName.lastIndexOf('('); if (index == 0) { return v; } if (index < 0) { return QString(oldName).trimmed().append(v); } return QString(oldName.left(index)).trimmed().append(v); } void CGuiUtility::deleteLayout(QLayout *layout, bool deleteWidgets) { // http://stackoverflow.com/a/7569928/356726 if (!layout) { return; } QLayoutItem *item {nullptr}; while ((item = layout->takeAt(0))) { QLayout *sublayout {nullptr}; QWidget *widget {nullptr}; if ((sublayout = item->layout())) { deleteLayout(sublayout, deleteWidgets); } else if ((widget = item->widget())) { widget->hide(); if (deleteWidgets) { delete widget; } } else { delete item; } } // then finally delete layout; } bool CGuiUtility::staysOnTop(QWidget *widget) { if (!widget) { return false; } const Qt::WindowFlags flags = widget->windowFlags(); return Qt::WindowStaysOnTopHint & flags; } QTabWidget *CGuiUtility::parentTabWidget(QWidget *widget, int maxLevels) { int level = 0; do { widget = widget->parentWidget(); if (!widget) { return nullptr; } QTabWidget *tw = qobject_cast(widget); if (tw) { return tw; } level++; } while (level < maxLevels); return nullptr; } bool CGuiUtility::toggleStayOnTop(QWidget *widget) { if (!widget) { return false; } Qt::WindowFlags flags = widget->windowFlags(); if (Qt::WindowStaysOnTopHint & flags) { flags &= ~Qt::WindowStaysOnTopHint; // flags |= Qt::WindowStaysOnBottomHint; } else { flags &= ~Qt::WindowStaysOnBottomHint; flags |= Qt::WindowStaysOnTopHint; } widget->setWindowFlags(flags); widget->show(); return Qt::WindowStaysOnTopHint & flags; } bool CGuiUtility::stayOnTop(bool onTop, QWidget *widget) { if (!widget) { return false; } Qt::WindowFlags flags = widget->windowFlags(); if (onTop) { flags &= ~Qt::WindowStaysOnBottomHint; flags |= Qt::WindowStaysOnTopHint; } else { flags &= ~Qt::WindowStaysOnTopHint; // flags |= Qt::WindowStaysOnBottomHint; } widget->setWindowFlags(flags); return onTop; } QString CGuiUtility::marginsToString(const QMargins &margins) { return QStringLiteral("%1:%2:%3:%4").arg(margins.left()).arg(margins.top()).arg(margins.right()).arg(margins.bottom()); } QMargins CGuiUtility::stringToMargins(const QString &str) { const QStringList parts = str.split(":"); Q_ASSERT_X(parts.size() == 4, Q_FUNC_INFO, "malformed"); bool ok = false; const int l = parts.at(0).toInt(&ok); Q_ASSERT_X(ok, Q_FUNC_INFO, "malformed number"); const int t = parts.at(1).toInt(&ok); Q_ASSERT_X(ok, Q_FUNC_INFO, "malformed number"); const int r = parts.at(2).toInt(&ok); Q_ASSERT_X(ok, Q_FUNC_INFO, "malformed number"); const int b = parts.at(3).toInt(&ok); Q_ASSERT_X(ok, Q_FUNC_INFO, "malformed number"); Q_UNUSED(ok); return QMargins(l, t, r, b); } QList CGuiUtility::indexToUniqueRows(const QModelIndexList &indexes) { QList rows; for (const QModelIndex &i : indexes) { const int r = i.row(); if (rows.contains(r)) { continue; } rows.append(r); } return rows; } int CGuiUtility::clearModel(QAbstractItemModel *model) { if (!model) { return 0; } const int count = model->rowCount(); if (count < 1) { return 0; } model->removeRows(0, count); return count; } bool CGuiUtility::isTopLevelWidget(QWidget *widget) { if (!widget) { return false; } return QApplication::topLevelWidgets().contains(widget); } bool CGuiUtility::isTopLevelWindow(QWidget *widget) { if (!widget) { return false; } if (!widget->isWindow()) { return false; } return QApplication::topLevelWidgets().contains(widget); } bool CGuiUtility::isQMainWindow(QWidget *widget) { if (!widget) { return false; } QMainWindow *mw = qobject_cast(widget); return mw; } bool CGuiUtility::isDialog(QWidget *widget) { if (!widget) { return false; } QDialog *mw = qobject_cast(widget); return mw; } QGraphicsOpacityEffect *CGuiUtility::fadeInWidget(int durationMs, QWidget *widget, double startValue, double endValue) { // http://stackoverflow.com/questions/19087822/how-to-make-qt-widgets-fade-in-or-fade-out# Q_ASSERT(widget); QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(widget); widget->setGraphicsEffect(effect); QPropertyAnimation *a = new QPropertyAnimation(effect, "opacity"); a->setDuration(durationMs); a->setStartValue(startValue); a->setEndValue(endValue); a->setEasingCurve(QEasingCurve::InBack); a->start(QPropertyAnimation::DeleteWhenStopped); return effect; } QGraphicsOpacityEffect *CGuiUtility::fadeOutWidget(int durationMs, QWidget *widget, double startValue, double endValue) { Q_ASSERT(widget); QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(widget); widget->setGraphicsEffect(effect); QPropertyAnimation *a = new QPropertyAnimation(effect, "opacity"); a->setDuration(durationMs); a->setStartValue(startValue); a->setEndValue(endValue); a->setEasingCurve(QEasingCurve::OutBack); a->start(QPropertyAnimation::DeleteWhenStopped); return effect; } QFontMetrics CGuiUtility::currentFontMetrics() { const QWidget *w = CGuiUtility::mainApplicationWidget(); if (w) { return w->fontMetrics(); } return QApplication::fontMetrics(); } QFontMetricsF CGuiUtility::currentFontMetricsF() { return QFontMetricsF(CGuiUtility::currentFontMetrics()); } QFont CGuiUtility::currentFont() { const QWidget *w = CGuiUtility::mainApplicationWidget(); if (w) { return w->font(); } return QApplication::font(); } QSizeF CGuiUtility::fontMetrics80Chars(bool withRatio) { // scale is 3.0 on my hires display static const QString s("01234567890123456789012345678901234567890123456789012345678901234567890123456789"); const QFontMetricsF fm = CGuiUtility::currentFontMetricsF(); const qreal scale = withRatio ? CGuiUtility::mainApplicationWidgetPixelRatio() : 1.0; const qreal w = fm.width(s) * scale; const qreal h = fm.height() * scale; return QSizeF(w, h); } QSizeF CGuiUtility::fontMetricsLazyDog43Chars(bool withRatio) { // 43 characters 0123456789012345678901234567890123456789012 static const QString s("The quick brown fox jumps over the lazy dog"); const QFontMetricsF fm = CGuiUtility::currentFontMetrics(); const qreal scale = withRatio ? CGuiUtility::mainApplicationWidgetPixelRatio() : 1.0; const qreal w = fm.width(s) * scale; const qreal h = fm.height() * scale; return QSizeF(w, h); } QSizeF CGuiUtility::fontMetricsEstimateSize(int xCharacters, int yCharacters, bool withRatio) { // 1920/1080: 560/16 256/16 => 530/960 // 3840/2160: 400/10 178/10 => 375/600 // with ratio we get the physical solution, otherwise logical solution const QSizeF s1 = CGuiUtility::fontMetrics80Chars(withRatio); const QSizeF s2 = CGuiUtility::fontMetricsLazyDog43Chars(withRatio); const QSizeF s = s1 + s2; const qreal w = s.width() * xCharacters / 123; // 123 chars const qreal h = s.height() * yCharacters / 2; // 2 lines return QSizeF(w, h); } void CGuiUtility::centerWidget(QWidget *widget) { const QRect screenGeometry = QApplication::desktop()->screenGeometry(); const int x = (screenGeometry.width() - widget->width()) / 2; const int y = (screenGeometry.height() - widget->height()) / 2; widget->move(x, y); } void CGuiUtility::centerWidget(QWidget *widget, QWidget *host) { if (!host) { host = widget->parentWidget(); } if (host) { const QRect hostRect = host->geometry(); widget->move(hostRect.center() - widget->rect().center()); } else { CGuiUtility::centerWidget(widget); } } QString CGuiUtility::metricsInfo() { static const QString s("%1 %2 %3 | 80 chars: w%4 h%5 | 43 chars: w%6 h%7"); const QSizeF s80 = CGuiUtility::fontMetrics80Chars(); const QSizeF s43 = CGuiUtility::fontMetricsLazyDog43Chars(); QString ratio("-"); QString desktop("-"); const QWidget *mainWidget = CGuiUtility::mainApplicationWidget(); if (mainWidget) { // const QSize sd = QApplication::desktop()->screenGeometry().size(); const QSize sd = QApplication::desktop()->screenGeometry(mainWidget).size(); desktop = QStringLiteral("Desktop w%1 w%2").arg(sd.width()).arg(sd.height()); ratio = QStringLiteral("ratio: %1").arg(mainWidget->devicePixelRatioF()); } return s. arg(desktop). arg(CGuiUtility::isUsingHighDpiScreenSupport() ? "hi DPI" : "-"). arg(ratio). arg(s80.width()).arg(s80.height()).arg(s43.width()).arg(s43.height()); } bool CGuiUtility::isUsingHighDpiScreenSupport() { const QByteArray v = qgetenv("QT_AUTO_SCREEN_SCALE_FACTOR"); const QString vs(v); const bool highDpi = stringToBool(vs); return highDpi; } void CGuiUtility::forceStyleSheetUpdate(QWidget *widget) { if (!widget) { return; } widget->setStyleSheet(widget->styleSheet()); } void CGuiUtility::superviseMainWindowMinSizes(qreal wRatio, qreal hRatio) { QWidget *w = CGuiUtility::mainApplicationWidget(); if (!w) { return; } const QSize s = CGuiUtility::desktopSize(); const int minW = qRound(wRatio * s.width()); const int minH = qRound(hRatio * s.height()); w->setMinimumWidth(qMin(minW, w->minimumWidth())); w->setMinimumHeight(qMin(minH, w->minimumHeight())); } QString CGuiUtility::asSimpleHtmlImageWidth(const CIcon &icon, int width) { if (!icon.hasFileResourcePath()) return {}; const QString p = icon.getFileResourcePath(); if (width < 0) { return QStringLiteral("").arg(p); } return QStringLiteral("").arg(p, QString::number(width)); } QString CGuiUtility::asSimpleHtmlImageHeight(const CIcon &icon, int height) { if (height < 0) { return CGuiUtility::asSimpleHtmlImageWidth(icon); } if (!icon.hasFileResourcePath()) return {}; const QString p = icon.getFileResourcePath(); return QStringLiteral("").arg(p, QString::number(height)); } QDialog *CGuiUtility::findParentDialog(QWidget *widget) { if (CGuiUtility::isDialog(widget)) { return qobject_cast(widget); } while (widget->parent()) { widget = widget->parentWidget(); if (CGuiUtility::isDialog(widget)) { return qobject_cast(widget); } } return nullptr; } void CGuiUtility::setElidedText(QLabel *label, const QString &text, Qt::TextElideMode mode) { if (!label) { return; } label->setToolTip(text); if (mode == Qt::ElideNone) { label->setText(text); return; } const QFontMetrics metrics(label->font()); const int width = qMax(label->width() - 2, 0); const QString clippedText = metrics.elidedText(text, mode, width); label->setText(clippedText); } void CGuiUtility::setElidedText(QLabel *label, const QString &shortText, const QString &longText, Qt::TextElideMode mode) { if (!label) { return; } if (shortText.isEmpty()) { CGuiUtility::setElidedText(label, longText, mode); return; } if (longText.isEmpty()) { CGuiUtility::setElidedText(label, shortText, mode); return; } label->setToolTip(longText); const QFontMetrics metrics(label->font()); const int width = qMax(label->width() - 2, 0); const int wl = metrics.width(longText); if (wl >= width) { label->setText(longText); return; } if (qRound(wl * 0.85) > wl) { const QString clippedText = metrics.elidedText(longText, mode, width); label->setText(clippedText); return; } const QString clippedText = metrics.elidedText(shortText, mode, width); label->setText(clippedText); } void CGuiUtility::setWizardButtonWidths(QWizard *wizard) { if (!wizard) { return; } const int minW = qMax(qRound(CGuiUtility::fontMetricsLazyDog43Chars(true).width() * 6.0 / 43.0), 80); if (wizard->button(QWizard::BackButton)) { wizard->button(QWizard::BackButton)->setMinimumWidth(minW); } if (wizard->button(QWizard::NextButton)) { wizard->button(QWizard::NextButton)->setMinimumWidth(minW); } if (wizard->button(QWizard::CancelButton)) { wizard->button(QWizard::CancelButton)->setMinimumWidth(minW); } if (wizard->button(QWizard::FinishButton)) { wizard->button(QWizard::FinishButton)->setMinimumWidth(minW); } if (wizard->button(QWizard::CustomButton1)) { wizard->button(QWizard::CustomButton1)->setMinimumWidth(minW); } if (wizard->button(QWizard::CustomButton2)) { wizard->button(QWizard::CustomButton2)->setMinimumWidth(minW); } if (wizard->button(QWizard::CustomButton3)) { wizard->button(QWizard::CustomButton3)->setMinimumWidth(minW); } } } // ns