diff --git a/kdevplatform/sublime/idealbuttonbarwidget.h b/kdevplatform/sublime/idealbuttonbarwidget.h --- a/kdevplatform/sublime/idealbuttonbarwidget.h +++ b/kdevplatform/sublime/idealbuttonbarwidget.h @@ -37,6 +37,7 @@ class MainWindow; class IdealController; class IdealDockWidget; +class IdealButtonBarLayout; class View; class Area; @@ -93,6 +94,7 @@ QWidget* m_corner; bool m_showState; QStringList m_buttonsOrder; + IdealButtonBarLayout* m_buttonsLayout; }; } diff --git a/kdevplatform/sublime/idealbuttonbarwidget.cpp b/kdevplatform/sublime/idealbuttonbarwidget.cpp --- a/kdevplatform/sublime/idealbuttonbarwidget.cpp +++ b/kdevplatform/sublime/idealbuttonbarwidget.cpp @@ -105,27 +105,29 @@ , m_controller(controller) , m_corner(nullptr) , m_showState(false) + , m_buttonsLayout(nullptr) { setContextMenuPolicy(Qt::CustomContextMenu); setToolTip(i18nc("@info:tooltip", "Right click to add new tool views.")); if (area == Qt::BottomDockWidgetArea) { - QBoxLayout *statusLayout = new QBoxLayout(QBoxLayout::RightToLeft, this); + QBoxLayout *statusLayout = new QBoxLayout(QBoxLayout::LeftToRight, this); statusLayout->setMargin(0); - IdealButtonBarLayout *l = new IdealButtonBarLayout(orientation()); - statusLayout->addLayout(l); + m_buttonsLayout = new IdealButtonBarLayout(orientation()); + statusLayout->addLayout(m_buttonsLayout); + + statusLayout->addStretch(1); m_corner = new QWidget(this); QBoxLayout *cornerLayout = new QBoxLayout(QBoxLayout::LeftToRight, m_corner); cornerLayout->setMargin(0); cornerLayout->setSpacing(0); statusLayout->addWidget(m_corner); - statusLayout->addStretch(1); } else - (void) new IdealButtonBarLayout(orientation(), this); + m_buttonsLayout = new IdealButtonBarLayout(orientation(), this); } QAction* IdealButtonBarWidget::addWidget(IdealDockWidget *dock, @@ -194,7 +196,7 @@ action->button()->deleteLater(); delete action; - if (layout()->isEmpty()) { + if (m_buttonsLayout->isEmpty()) { emit emptyChanged(); } } @@ -249,12 +251,7 @@ { QString buttonId = id(button); if (!m_buttonsOrder.contains(buttonId)) { - if (m_area == Qt::BottomDockWidgetArea) { - m_buttonsOrder.push_front(buttonId); - } - else { - m_buttonsOrder.push_back(buttonId); - } + m_buttonsOrder.push_back(buttonId); } } @@ -281,25 +278,25 @@ // If widget already have some buttons in the layout then calling loadOrderSettings() may leads // to situations when loaded order does not contains all existing buttons. Therefore we should // fix this with using addToOrder() method. - for (int i = 0; i < layout()->count(); ++i) { - if (auto button = dynamic_cast(layout()->itemAt(i)->widget())) { + for (int i = 0; i < m_buttonsLayout->count(); ++i) { + if (auto button = dynamic_cast(m_buttonsLayout->itemAt(i)->widget())) { addButtonToOrder(button); - layout()->removeWidget(button); + m_buttonsLayout->removeWidget(button); } } foreach(const QString& id, m_buttonsOrder) { if (auto b = button(id)) { - layout()->addWidget(b); + m_buttonsLayout->addWidget(b); } } } void IdealButtonBarWidget::takeOrderFromLayout() { m_buttonsOrder.clear(); - for (int i = 0; i < layout()->count(); ++i) { - if (auto button = dynamic_cast(layout()->itemAt(i)->widget())) { + for (int i = 0; i < m_buttonsLayout->count(); ++i) { + if (auto button = dynamic_cast(m_buttonsLayout->itemAt(i)->widget())) { m_buttonsOrder += id(button); } } diff --git a/kdevplatform/sublime/ideallayout.cpp b/kdevplatform/sublime/ideallayout.cpp --- a/kdevplatform/sublime/ideallayout.cpp +++ b/kdevplatform/sublime/ideallayout.cpp @@ -25,6 +25,8 @@ #include #include +#include + using namespace Sublime; IdealButtonBarLayout::IdealButtonBarLayout(Qt::Orientation orientation, QWidget *parent) @@ -196,23 +198,47 @@ int y = rect.y() + t; int currentLineWidth = 0; - for (QLayoutItem *item : _items) { - const QSize itemSizeHint = item->sizeHint(); - if (y + itemSizeHint.height() + b > rect.height()) { - int newX = x + currentLineWidth + buttonSpacing; - if (newX + itemSizeHint.width() + r <= rect.width()) - { - x += currentLineWidth + buttonSpacing; - y = rect.y() + t; + 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); + } + + 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, itemSizeHint.width(), itemSizeHint.height())); + if (updateGeometry) { + item->setGeometry(QRect(x, y, itemWidth, itemHeight)); + } - currentLineWidth = qMax(currentLineWidth, itemSizeHint.width()); + currentLineWidth = qMax(currentLineWidth, itemWidth); - y += itemSizeHint.height() + buttonSpacing; + y += itemHeight + buttonSpacing; } m_layoutDirty = updateGeometry; @@ -230,26 +256,47 @@ int y = rect.y() + t; int currentLineHeight = 0; - for (QLayoutItem *item : _items) { - QSize itemSizeHint = item->sizeHint(); - if (x + itemSizeHint.width() + r > rect.width()) { - // Run out of horizontal space. Try to move button to another - // row. - int newY = y + currentLineHeight + buttonSpacing; - if (newY + itemSizeHint.height() + b <= rect.height()) - { - y = newY; - x = rect.x() + l; - currentLineHeight = 0; + if (_items.empty()) { + return y + currentLineHeight + b; + } + + 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, itemSizeHint.width(), itemSizeHint.height())); + if (updateGeometry) { + item->setGeometry(QRect(x, y, itemWidth, itemHeight)); + } - currentLineHeight = qMax(currentLineHeight, itemSizeHint.height()); + currentLineHeight = qMax(currentLineHeight, itemHeight); - x += itemSizeHint.width() + buttonSpacing; + x += itemWidth + buttonSpacing; } m_layoutDirty = updateGeometry; diff --git a/kdevplatform/sublime/idealtoolbutton.cpp b/kdevplatform/sublime/idealtoolbutton.cpp --- a/kdevplatform/sublime/idealtoolbutton.cpp +++ b/kdevplatform/sublime/idealtoolbutton.cpp @@ -88,14 +88,31 @@ void IdealToolButton::paintEvent(QPaintEvent *event) { + Q_UNUSED(event); + + QStylePainter painter(this); + QStyleOptionToolButton option; + initStyleOption(&option); + if (_area == Qt::TopDockWidgetArea || _area == Qt::BottomDockWidgetArea) { - QToolButton::paintEvent(event); + // elide text + int iconWidth = 0; + if (toolButtonStyle() != Qt::ToolButtonTextOnly && !option.icon.isNull()) { + iconWidth = option.iconSize.width(); + } + + // subtract 4 to be consistent with the size calculated by sizeHint, which adds 4, + // again to be consistent with QToolButton + option.text = fontMetrics().elidedText(text(), Qt::ElideRight, contentsRect().width() - iconWidth - 4); + painter.drawComplexControl(QStyle::CC_ToolButton, option); } else { // rotated paint - QStylePainter painter(this); - QStyleOptionToolButton option; - initStyleOption(&option); - + // elide text + int iconHeight = 0; + if (toolButtonStyle() != Qt::ToolButtonTextOnly && !option.icon.isNull()) { + iconHeight = option.iconSize.height(); + } + QString textToDraw = fontMetrics().elidedText(text(), Qt::ElideRight, contentsRect().height() - iconHeight - 4); // first draw normal frame and not text/icon option.text = QString(); option.icon = QIcon(); @@ -116,7 +133,8 @@ } // paint text and icon - option.text = text(); + option.text = textToDraw; + QIcon::Mode iconMode = (option.state & QStyle::State_MouseOver) ? QIcon::Active : QIcon::Normal; QPixmap ic = icon().pixmap(option.iconSize, iconMode, QIcon::On); QTransform tf;