diff --git a/kdevplatform/sublime/idealbuttonbarwidget.cpp b/kdevplatform/sublime/idealbuttonbarwidget.cpp --- a/kdevplatform/sublime/idealbuttonbarwidget.cpp +++ b/kdevplatform/sublime/idealbuttonbarwidget.cpp @@ -110,12 +110,12 @@ setContextMenuPolicy(Qt::CustomContextMenu); setToolTip(i18nc("@info:tooltip", "Right click to add new tool views.")); + m_buttonsLayout = new IdealButtonBarLayout(orientation(), this); if (area == Qt::BottomDockWidgetArea) { QBoxLayout *statusLayout = new QBoxLayout(QBoxLayout::LeftToRight, this); statusLayout->setMargin(0); - m_buttonsLayout = new IdealButtonBarLayout(orientation()); statusLayout->addLayout(m_buttonsLayout); statusLayout->addStretch(1); @@ -125,9 +125,13 @@ cornerLayout->setMargin(0); cornerLayout->setSpacing(0); statusLayout->addWidget(m_corner); + } else { + QBoxLayout *superLayout = new QBoxLayout(QBoxLayout::TopToBottom, this); + superLayout->setMargin(0); + + superLayout->addLayout(m_buttonsLayout); + superLayout->addStretch(1); } - else - m_buttonsLayout = new IdealButtonBarLayout(orientation(), this); } QAction* IdealButtonBarWidget::addWidget(IdealDockWidget *dock, diff --git a/kdevplatform/sublime/ideallayout.h b/kdevplatform/sublime/ideallayout.h --- a/kdevplatform/sublime/ideallayout.h +++ b/kdevplatform/sublime/ideallayout.h @@ -22,59 +22,34 @@ #ifndef KDEVPLATFORM_SUBLIME_IDEALLAYOUT_H #define KDEVPLATFORM_SUBLIME_IDEALLAYOUT_H -#include +#include #include "sublimedefs.h" namespace Sublime { -class IdealButtonBarLayout: public QLayout +class IdealButtonBarLayout: public QBoxLayout { Q_OBJECT public: - explicit IdealButtonBarLayout(Qt::Orientation orientation, QWidget *parent = nullptr); + IdealButtonBarLayout(Qt::Orientation orientation, QWidget* styleParent); ~IdealButtonBarLayout() override; - void setHeight(int height); - inline Qt::Orientation orientation() const; Qt::Orientations expandingDirections() const override; - QSize minimumSize() const override; - - QSize sizeHint() const override; - - void setGeometry(const QRect &rect) override; - - void addItem(QLayoutItem *item) override; - - QLayoutItem* itemAt(int index) const override; - - QLayoutItem* takeAt(int index) override; - - int count() const override; - - void invalidate() override; - protected: - int doVerticalLayout(const QRect &rect, bool updateGeometry = true) const; - int doHorizontalLayout(const QRect &rect, bool updateGeometry = true) const; + bool eventFilter(QObject* watched, QEvent* event) override; int buttonSpacing() const; private: - QList _items; + QWidget* const m_styleParentWidget; const Qt::Orientation _orientation; - int _height; - mutable bool m_minSizeDirty : 1; - mutable bool m_sizeHintDirty : 1; - mutable bool m_layoutDirty : 1; - mutable QSize m_min; - mutable QSize m_hint; }; } diff --git a/kdevplatform/sublime/ideallayout.cpp b/kdevplatform/sublime/ideallayout.cpp --- a/kdevplatform/sublime/ideallayout.cpp +++ b/kdevplatform/sublime/ideallayout.cpp @@ -24,42 +24,37 @@ #include #include +#include #include using namespace Sublime; -IdealButtonBarLayout::IdealButtonBarLayout(Qt::Orientation orientation, QWidget *parent) - : QLayout(parent) - , _orientation(orientation) - , _height(0) - +namespace { - setContentsMargins(0, 0, 0, 0); - invalidate(); -} -void IdealButtonBarLayout::invalidate() -{ - m_minSizeDirty = true; - m_sizeHintDirty = true; - m_layoutDirty = true; - QLayout::invalidate(); -} + QBoxLayout::Direction toDirection(Qt::Orientation orientation) + { + return orientation == Qt::Horizontal ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom; + } -IdealButtonBarLayout::~IdealButtonBarLayout() -{ - qDeleteAll(_items); } -void IdealButtonBarLayout::setHeight(int height) +IdealButtonBarLayout::IdealButtonBarLayout(Qt::Orientation orientation, QWidget* styleParent) + : QBoxLayout(toDirection(orientation)) // creating a child layout, styleParent is only saved for style + , m_styleParentWidget(styleParent) + , _orientation(orientation) { - Q_ASSERT(orientation() == Qt::Vertical); - _height = height; + if (m_styleParentWidget) { + m_styleParentWidget->installEventFilter(this); + } - (void) invalidate(); + setContentsMargins(0, 0, 0, 0); + setSpacing(buttonSpacing()); } +IdealButtonBarLayout::~IdealButtonBarLayout() = default; + Qt::Orientation IdealButtonBarLayout::orientation() const { return _orientation; @@ -70,237 +65,19 @@ return orientation(); } -QSize IdealButtonBarLayout::minimumSize() const -{ - // The code below appears to be completely wrong -- - // it will return the maximum size of a single button, not any - // estimate as to how much space is necessary to draw all buttons - // in a minimally acceptable way. - if (m_minSizeDirty) { - if (orientation() == Qt::Vertical) { - const int width = doVerticalLayout(QRect(0, 0, 0, _height), false); - return QSize(width, 0); - } - - m_min = QSize(0, 0); - for (QLayoutItem* item : _items) { - m_min = m_min.expandedTo(item->minimumSize()); - } - - m_minSizeDirty = false; - } - return m_min; -} - -QSize IdealButtonBarLayout::sizeHint() const -{ - if (m_sizeHintDirty) { - const int buttonSpacing = this->buttonSpacing(); - - int orientationSize = 0; - int crossSize = 0; - - bool first = true; - for (QLayoutItem *item : _items) { - QSize hint = item->sizeHint(); - int orientationSizeHere; - int crossSizeHere; - if (orientation() == Qt::Vertical) - { - orientationSizeHere = hint.height(); - crossSizeHere = hint.width(); - } - else - { - orientationSizeHere = hint.width(); - crossSizeHere = hint.height(); - } - - if (first) - { - crossSize = crossSizeHere; - } - else - { - orientationSize += buttonSpacing; - } - orientationSize += orientationSizeHere; - first = false; - } - - if (orientation() == Qt::Vertical) - m_hint = QSize(crossSize, orientationSize); - else - m_hint = QSize(orientationSize, crossSize); - - if (!_items.empty()) - { - /* If we have no items, just use (0, 0) as hint, don't - append any margins. */ - int l, t, r, b; - getContentsMargins(&l, &t, &r, &b); - m_hint += QSize(l+r, t+b); - } - - m_sizeHintDirty = false; - } - return m_hint; -} - -void IdealButtonBarLayout::setGeometry(const QRect &rect) -{ - if (m_layoutDirty || rect != geometry()) { - if (orientation() == Qt::Vertical) - doVerticalLayout(rect); - else - doHorizontalLayout(rect); - } -} - -void IdealButtonBarLayout::addItem(QLayoutItem *item) -{ - _items.append(item); - invalidate(); -} - -QLayoutItem* IdealButtonBarLayout::itemAt(int index) const -{ - return _items.value(index, nullptr); -} - -QLayoutItem* IdealButtonBarLayout::takeAt(int index) -{ - if (index >= 0 && index < _items.count()) - return _items.takeAt(index); - invalidate(); - return nullptr; -} - -int IdealButtonBarLayout::count() const -{ - return _items.count(); -} - int IdealButtonBarLayout::buttonSpacing() const { - auto pw = parentWidget(); - return pw ? pw->style()->pixelMetric(QStyle::PM_ToolBarItemSpacing) : 0; -} - - -int IdealButtonBarLayout::doVerticalLayout(const QRect &rect, bool updateGeometry) const -{ - const int buttonSpacing = this->buttonSpacing(); - - int l, t, r, b; - getContentsMargins(&l, &t, &r, &b); - int x = rect.x() + l; - int y = rect.y() + t; - int currentLineWidth = 0; - - if (_items.empty()) { - return x + currentLineWidth + r; - } - - const bool shrink = rect.height() < sizeHint().height(); - - const int maximumHeight = rect.height() / _items.size(); - int shrinkedHeight = -1; - - if (shrink) { - int smallItemCount = 0; - const int surplus = std::accumulate(_items.begin(), _items.end(), 0, [maximumHeight, &smallItemCount](int acc, QLayoutItem* item) { - const int itemHeight = item->sizeHint().height(); - if (itemHeight <= maximumHeight) { - acc += maximumHeight - itemHeight; - ++smallItemCount; - } - return acc; - }); - - Q_ASSERT(_items.size() != smallItemCount); // should be true since rect.width != sizeHint.width - // evenly distribute surplus height over large items - shrinkedHeight = maximumHeight + surplus / (_items.size() - smallItemCount); + if (!m_styleParentWidget) { + return 0; } - - for (QLayoutItem* item : _items) { - const QSize itemSizeHint = item->sizeHint(); - const int itemWidth = itemSizeHint.width(); - int itemHeight = itemSizeHint.height(); - - if (shrink && itemSizeHint.height() > maximumHeight) { - itemHeight = shrinkedHeight; - } - - if (updateGeometry) { - item->setGeometry(QRect(x, y, itemWidth, itemHeight)); - } - - currentLineWidth = qMax(currentLineWidth, itemWidth); - - y += itemHeight + buttonSpacing; - } - - m_layoutDirty = updateGeometry; - - return x + currentLineWidth + r; + return m_styleParentWidget->style()->pixelMetric(QStyle::PM_ToolBarItemSpacing); } -int IdealButtonBarLayout::doHorizontalLayout(const QRect &rect, bool updateGeometry) const +bool IdealButtonBarLayout::eventFilter(QObject* watched, QEvent* event) { - const int buttonSpacing = this->buttonSpacing(); - - int l, t, r, b; - getContentsMargins(&l, &t, &r, &b); - int x = rect.x() + l; - int y = rect.y() + t; - int currentLineHeight = 0; - - if (_items.empty()) { - return y + currentLineHeight + b; + if (event->type() == QEvent::StyleChange) { + setSpacing(buttonSpacing()); } - const bool shrink = rect.width() < sizeHint().width(); - - const int maximumWidth = rect.width() / _items.size(); - int shrinkedWidth = -1; - - if (shrink) { - int smallItemCount = 0; - const int surplus = std::accumulate(_items.begin(), _items.end(), 0, [maximumWidth, &smallItemCount](int acc, QLayoutItem* item) { - const int itemWidth = item->sizeHint().width(); - if (itemWidth <= maximumWidth) { - acc += maximumWidth - itemWidth; - ++smallItemCount; - } - return acc; - }); - - Q_ASSERT(_items.size() != smallItemCount); // should be true since rect.width != sizeHint.width - // evenly distribute surplus width on the large items - shrinkedWidth = maximumWidth + surplus / (_items.size() - smallItemCount); - } - - for (QLayoutItem* item : _items) { - const QSize itemSizeHint = item->sizeHint(); - int itemWidth = itemSizeHint.width(); - const int itemHeight = itemSizeHint.height(); - - if (shrink && itemSizeHint.width() > maximumWidth) { - itemWidth = shrinkedWidth; - } - - if (updateGeometry) { - item->setGeometry(QRect(x, y, itemWidth, itemHeight)); - } - - currentLineHeight = qMax(currentLineHeight, itemHeight); - - x += itemWidth + buttonSpacing; - } - - m_layoutDirty = updateGeometry; - - return y + currentLineHeight + b; + return QBoxLayout::eventFilter(watched, event); } - diff --git a/kdevplatform/sublime/idealtoolbutton.h b/kdevplatform/sublime/idealtoolbutton.h --- a/kdevplatform/sublime/idealtoolbutton.h +++ b/kdevplatform/sublime/idealtoolbutton.h @@ -36,6 +36,8 @@ QSize sizeHint() const override; + QSize minimumSizeHint() const override; + protected: void paintEvent(QPaintEvent *event) override; diff --git a/kdevplatform/sublime/idealtoolbutton.cpp b/kdevplatform/sublime/idealtoolbutton.cpp --- a/kdevplatform/sublime/idealtoolbutton.cpp +++ b/kdevplatform/sublime/idealtoolbutton.cpp @@ -2,6 +2,7 @@ Copyright 2007 Roberto Raggi Copyright 2007 Hamish Rodda Copyright 2011 Alexander Dymo + Copyright 2018 Amish Naidu Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that @@ -24,6 +25,7 @@ #include #include #include +#include IdealToolButton::IdealToolButton(Qt::DockWidgetArea area, QWidget *parent) : QToolButton(parent), _area(area) @@ -35,6 +37,14 @@ setToolButtonStyle(Qt::ToolButtonTextBesideIcon); setContextMenuPolicy(Qt::CustomContextMenu); + + QSizePolicy sizePolicy = this->sizePolicy(); + if (orientation() == Qt::Horizontal) { + sizePolicy.setHorizontalPolicy(QSizePolicy::Maximum); + } else { + sizePolicy.setVerticalPolicy(QSizePolicy::Maximum); + } + setSizePolicy(sizePolicy); } Qt::Orientation IdealToolButton::orientation() const @@ -86,6 +96,36 @@ } } +QSize IdealToolButton::minimumSizeHint() const +{ + ensurePolished(); + + QStyleOptionToolButton opt; + initStyleOption(&opt); + + QSize minimumSize; + // if style has icons, minimumSize is the size of the icon + if (toolButtonStyle() != Qt::ToolButtonTextOnly && !opt.icon.isNull()) { + minimumSize = opt.iconSize; + if (_area == Qt::LeftDockWidgetArea || _area == Qt::RightDockWidgetArea) { + minimumSize.transpose(); + } + } else { + // if no icon, set an arbitrary minimum size + QFontMetrics fm = fontMetrics(); + minimumSize = fm.size(Qt::TextShowMnemonic, opt.text.left(4)); + } + + minimumSize = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, minimumSize, this). + expandedTo(QApplication::globalStrut()); + + if (_area == Qt::TopDockWidgetArea || _area == Qt::BottomDockWidgetArea) { + return minimumSize; + } + return minimumSize.transposed(); +} + + void IdealToolButton::paintEvent(QPaintEvent *event) { Q_UNUSED(event);