Commit b95bc1c3 authored by Amish Naidu's avatar Amish Naidu
Browse files

Sublime: Fix window growing larger by making tool view buttons shrinkable

Summary:
Items will be shrinked in the IdealButtonBarLayout, instead of
overflowing and forcing the window larger.
Geometries are calculated so that only the bigger will be contracted
while items smaller than a relative threshold won't contract.
Consequently, the window will no longer grow when changing from Debug to Code.

IdealToolButtons: Instead of simply truncating text, they will elide text while painting.

IdealButtonBarWidget: Previously the layout attached to the object was being used to add
buttons, which for the bottom bar wrongly meant a super-layout while the
IdealButtonBarLayout added to this super-layout was being ignored, introduced a new
member to use the proper layout for all orientations.

BUG: 384711

Reviewers: #kdevelop, kossebau

Reviewed By: #kdevelop, kossebau

Subscribers: kossebau, kdevelop-devel

Tags: #kdevelop

Differential Revision: https://phabricator.kde.org/D15450
parent f4f15382
......@@ -105,27 +105,29 @@ IdealButtonBarWidget::IdealButtonBarWidget(Qt::DockWidgetArea area,
, 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 @@ void IdealButtonBarWidget::removeAction(QAction* widgetAction)
action->button()->deleteLater();
delete action;
if (layout()->isEmpty()) {
if (m_buttonsLayout->isEmpty()) {
emit emptyChanged();
}
}
......@@ -249,12 +251,7 @@ void IdealButtonBarWidget::addButtonToOrder(const IdealToolButton* button)
{
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,16 +278,16 @@ void IdealButtonBarWidget::applyOrderToLayout()
// 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<IdealToolButton*>(layout()->itemAt(i)->widget())) {
for (int i = 0; i < m_buttonsLayout->count(); ++i) {
if (auto button = dynamic_cast<IdealToolButton*>(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);
}
}
}
......@@ -298,8 +295,8 @@ void IdealButtonBarWidget::applyOrderToLayout()
void IdealButtonBarWidget::takeOrderFromLayout()
{
m_buttonsOrder.clear();
for (int i = 0; i < layout()->count(); ++i) {
if (auto button = dynamic_cast<IdealToolButton*>(layout()->itemAt(i)->widget())) {
for (int i = 0; i < m_buttonsLayout->count(); ++i) {
if (auto button = dynamic_cast<IdealToolButton*>(m_buttonsLayout->itemAt(i)->widget())) {
m_buttonsOrder += id(button);
}
}
......
......@@ -37,6 +37,7 @@ namespace Sublime
class MainWindow;
class IdealController;
class IdealDockWidget;
class IdealButtonBarLayout;
class View;
class Area;
......@@ -93,6 +94,7 @@ private:
QWidget* m_corner;
bool m_showState;
QStringList m_buttonsOrder;
IdealButtonBarLayout* m_buttonsLayout;
};
}
......
......@@ -25,6 +25,8 @@
#include <QStyle>
#include <QWidget>
#include <numeric>
using namespace Sublime;
IdealButtonBarLayout::IdealButtonBarLayout(Qt::Orientation orientation, QWidget *parent)
......@@ -196,23 +198,47 @@ int IdealButtonBarLayout::doVerticalLayout(const QRect &rect, bool updateGeometr
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 IdealButtonBarLayout::doHorizontalLayout(const QRect &rect, bool updateGeome
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;
......
......@@ -88,14 +88,31 @@ QSize IdealToolButton::sizeHint() const
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 @@ void IdealToolButton::paintEvent(QPaintEvent *event)
}
// 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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment