Commit a420ba69 authored by Peter Mühlenpfordt's avatar Peter Mühlenpfordt Committed by Nate Graham

Use FlowLayout for Crop toolbar

Summary:
The Crop toolbar with enabled {nav Advanced settings} is very wide
and it's not possible to make the Gwenview window smaller with this
toolbar visible.
Using a FlowLayout for the Crop toolbar avoids this issue and breaks
the bar into multiple lines if there is not enough horizontal space.

Before:
{F6251679}

After:
{F6251681}

Test Plan:
* Check Crop toolbar behaviour while resizing Gwenview window
* Check Crop toolbar with {nav Advanced settings} en-/disabled
* Check RedEye toolbar (uses the same `SlideContainer`)
* Check SaveBar after modifying images (uses `SlideContainer`)
* Check Browse Mode {nav Add Filter} (uses `FlowLayout`)

Reviewers: #gwenview, ngraham

Reviewed By: #gwenview, ngraham

Subscribers: shubham, loh.tar, ngraham

Tags: #gwenview

Differential Revision: https://phabricator.kde.org/D15398
parent 2681cee1
......@@ -285,6 +285,8 @@ struct ViewMainPagePrivate
void setupToolContainer()
{
mToolContainer = new SlideContainer;
mToolContainer->setAutoFillBackground(true);
mToolContainer->setBackgroundRole(QPalette::Mid);
}
void setupStatusBar()
......
......@@ -227,7 +227,6 @@ kde_source_files_enable_exceptions(
)
ki18n_wrap_ui(gwenviewlib_SRCS
crop/cropwidget.ui
documentview/messageview.ui
print/printoptionspage.ui
redeyereduction/redeyereductionwidget.ui
......
......@@ -22,8 +22,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
// Qt
#include <QApplication>
#include <QCheckBox>
#include <QComboBox>
#include <QDesktopWidget>
#include <QDialogButtonBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QSpinBox>
#include <QtMath>
#include <QDebug>
#include <QLineEdit>
......@@ -35,8 +41,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <lib/documentview/rasterimageview.h>
#include <QFontDatabase>
#include "croptool.h"
#include "ui_cropwidget.h"
#include "cropwidget.h"
#include "flowlayout.h"
namespace Gwenview
{
......@@ -55,9 +61,19 @@ static QSize ratio(const QSize &size)
return size / divisor;
}
struct CropWidgetPrivate : public Ui_CropWidget
struct CropWidgetPrivate : public QWidget
{
CropWidget* q;
QList<QWidget*> mAdvancedWidgets;
QWidget* mPreserveAspectRatioWidget;
QCheckBox* advancedCheckBox;
QComboBox* ratioComboBox;
QSpinBox* widthSpinBox;
QSpinBox* heightSpinBox;
QSpinBox* leftSpinBox;
QSpinBox* topSpinBox;
QCheckBox* preserveAspectRatioCheckBox;
QDialogButtonBox* dialogButtonBox;
Document::Ptr mDocument;
CropTool* mCropTool;
......@@ -257,6 +273,102 @@ struct CropWidgetPrivate : public Ui_CropWidget
QObject::connect(dialogButtonBox, &QDialogButtonBox::accepted, q, &CropWidget::cropRequested);
QObject::connect(dialogButtonBox, &QDialogButtonBox::rejected, q, &CropWidget::done);
}
QWidget* boxWidget(QWidget* parent = nullptr)
{
QWidget* widget = new QWidget(parent);
QHBoxLayout* layout = new QHBoxLayout(widget);
layout->setMargin(0);
layout->setSpacing(2);
return widget;
}
void setupUi(QWidget* cropWidget) {
cropWidget->setObjectName("CropWidget");
FlowLayout* flowLayout = new FlowLayout(cropWidget, 6, 0);
flowLayout->setObjectName("CropWidgetFlowLayout");
flowLayout->setAlignment(Qt::AlignCenter);
flowLayout->setVerticalSpacing(6);
// (1) Checkbox
QWidget* box = boxWidget(cropWidget);
advancedCheckBox = new QCheckBox(i18nc("@option:check", "Advanced settings"), box);
advancedCheckBox->setFocusPolicy(Qt::NoFocus);
box->layout()->addWidget(advancedCheckBox);
flowLayout->addWidget(box);
flowLayout->addSpacing(14);
// (2) Ratio combobox (Advanced settings)
box = boxWidget(cropWidget);
mAdvancedWidgets << box;
QLabel* label = new QLabel(i18nc("@label:listbox", "Aspect ratio:"), box);
label->setMargin(4);
box->layout()->addWidget(label);
ratioComboBox = new QComboBox(box);
ratioComboBox->setEditable(true);
ratioComboBox->setInsertPolicy(QComboBox::NoInsert);
box->layout()->addWidget(ratioComboBox);
flowLayout->addWidget(box);
flowLayout->addSpacing(8);
// (3) Size spinboxes (Advanced settings)
box = boxWidget(cropWidget);
mAdvancedWidgets << box;
label = new QLabel(i18nc("@label:spinbox", "Size:"), box);
label->setMargin(4);
box->layout()->addWidget(label);
QHBoxLayout* innerLayout = new QHBoxLayout();
innerLayout->setSpacing(3);
widthSpinBox = new QSpinBox(box);
widthSpinBox->setAlignment(Qt::AlignCenter);
innerLayout->addWidget(widthSpinBox);
heightSpinBox = new QSpinBox(box);
heightSpinBox->setAlignment(Qt::AlignCenter);
innerLayout->addWidget(heightSpinBox);
box->layout()->addItem(innerLayout);
flowLayout->addWidget(box);
flowLayout->addSpacing(8);
// (4) Position spinboxes (Advanced settings)
box = boxWidget(cropWidget);
mAdvancedWidgets << box;
label = new QLabel(i18nc("@label:spinbox", "Position:"), box);
label->setMargin(4);
box->layout()->addWidget(label);
innerLayout = new QHBoxLayout();
innerLayout->setSpacing(3);
leftSpinBox = new QSpinBox(box);
leftSpinBox->setAlignment(Qt::AlignCenter);
innerLayout->addWidget(leftSpinBox);
topSpinBox = new QSpinBox(box);
topSpinBox->setAlignment(Qt::AlignCenter);
innerLayout->addWidget(topSpinBox);
box->layout()->addItem(innerLayout);
flowLayout->addWidget(box);
flowLayout->addSpacing(18);
// (5) Preserve ratio checkbox
mPreserveAspectRatioWidget = boxWidget(cropWidget);
preserveAspectRatioCheckBox = new QCheckBox(i18nc("@option:check", "Preserve aspect ratio"), mPreserveAspectRatioWidget);
mPreserveAspectRatioWidget->layout()->addWidget(preserveAspectRatioCheckBox);
flowLayout->addWidget(mPreserveAspectRatioWidget);
flowLayout->addSpacing(18);
// (6) Dialog buttons
box = boxWidget(cropWidget);
dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok, box);
box->layout()->addWidget(dialogButtonBox);
flowLayout->addWidget(box);
}
};
CropWidget::CropWidget(QWidget* parent, RasterImageView* imageView, CropTool* cropTool)
......@@ -270,11 +382,11 @@ CropWidget::CropWidget(QWidget* parent, RasterImageView* imageView, CropTool* cr
d->mCropTool = cropTool;
d->setupUi(this);
setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
layout()->setSizeConstraint(QLayout::SetFixedSize);
connect(d->advancedCheckBox, &QCheckBox::toggled, this, &CropWidget::slotAdvancedCheckBoxToggled);
d->advancedWidget->setVisible(false);
d->advancedWidget->layout()->setMargin(0);
for (auto w : d->mAdvancedWidgets) {
w->setVisible(false);
}
connect(d->preserveAspectRatioCheckBox, &QCheckBox::toggled, this, &CropWidget::applyRatioConstraint);
......@@ -413,8 +525,10 @@ void CropWidget::applyRatioConstraint()
void CropWidget::slotAdvancedCheckBoxToggled(bool checked)
{
d->advancedWidget->setVisible(checked);
d->preserveAspectRatioCheckBox->setVisible(!checked);
for (auto w : d->mAdvancedWidgets) {
w->setVisible(checked);
}
d->mPreserveAspectRatioWidget->setVisible(!checked);
applyRatioConstraint();
}
......
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CropWidget</class>
<widget class="QWidget" name="CropWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1060</width>
<height>58</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Crop</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QCheckBox" name="advancedCheckBox">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Advanced settings</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>12</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QWidget" name="advancedWidget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Aspect ratio:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>ratioComboBox</cstring>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="ratioComboBox">
<property name="editable">
<bool>true</bool>
</property>
<property name="insertPolicy">
<enum>QComboBox::NoInsert</enum>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>6</width>
<height>19</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Size:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>widthSpinBox</cstring>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>3</number>
</property>
<item>
<widget class="QSpinBox" name="widthSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="heightSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>6</width>
<height>19</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Position:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>leftSpinBox</cstring>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>3</number>
</property>
<item>
<widget class="QSpinBox" name="leftSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="topSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="preserveAspectRatioCheckBox">
<property name="text">
<string>Preserve aspect ratio</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>12</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="dialogButtonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>ratioComboBox</tabstop>
<tabstop>widthSpinBox</tabstop>
<tabstop>heightSpinBox</tabstop>
<tabstop>leftSpinBox</tabstop>
<tabstop>topSpinBox</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
......@@ -40,33 +40,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA
namespace Gwenview
{
/**
* A simple container which:
* - Horizontally center the tool widget
* - Provide a darker background
*/
class ToolContainerContent : public QWidget
{
public:
explicit ToolContainerContent(QWidget* parent = nullptr)
: QWidget(parent)
, mLayout(new QHBoxLayout(this))
{
mLayout->setMargin(0);
setAutoFillBackground(true);
setBackgroundRole(QPalette::Mid);
}
void setToolWidget(QWidget* widget)
{
mLayout->addWidget(widget, 0, Qt::AlignCenter);
setFixedHeight(widget->sizeHint().height());
}
private:
QHBoxLayout* mLayout;
};
struct DocumentViewControllerPrivate
{
DocumentViewController* q;
......@@ -74,7 +47,6 @@ struct DocumentViewControllerPrivate
DocumentView* mView;
ZoomWidget* mZoomWidget;
SlideContainer* mToolContainer;
ToolContainerContent* mToolContainerContent;
QAction * mZoomToFitAction;
QAction * mZoomToFillAction;
......@@ -154,7 +126,6 @@ DocumentViewController::DocumentViewController(KActionCollection* actionCollecti
d->mView = nullptr;
d->mZoomWidget = nullptr;
d->mToolContainer = nullptr;
d->mToolContainerContent = new ToolContainerContent;
d->setupActions();
}
......@@ -258,7 +229,7 @@ void DocumentViewController::updateTool()
// Use a QueuedConnection to ensure the size of the view has been
// updated by the time the slot is called.
connect(d->mToolContainer, &SlideContainer::slidedIn, tool, &AbstractRasterImageViewTool::onWidgetSlidedIn, Qt::QueuedConnection);
d->mToolContainerContent->setToolWidget(tool->widget());
d->mToolContainer->setContent(tool->widget());
d->mToolContainer->slideIn();
} else {
d->mToolContainer->slideOut();
......@@ -274,7 +245,6 @@ void DocumentViewController::reset()
void DocumentViewController::setToolContainer(SlideContainer* container)
{
d->mToolContainer = container;
container->setContent(d->mToolContainerContent);
}
} // namespace
......@@ -35,18 +35,24 @@
**
****************************************************************************/
// Self
#include "flowlayout.h"
// Qt
#include <QHash>
FlowLayout::FlowLayout(QWidget *parent, int margin, int spacing)
: QLayout(parent)
{
setMargin(margin);
setSpacing(spacing);
setHorizontalSpacing(spacing);
setVerticalSpacing(spacing);
}
FlowLayout::FlowLayout(int spacing)
{
setSpacing(spacing);
setHorizontalSpacing(spacing);
setVerticalSpacing(spacing);
}
FlowLayout::~FlowLayout()
......@@ -56,6 +62,26 @@ FlowLayout::~FlowLayout()
delete item;
}
int FlowLayout::horizontalSpacing() const
{
return mHorizontalSpacing;
}
void FlowLayout::setHorizontalSpacing(const int spacing)
{
mHorizontalSpacing = spacing;
}
int FlowLayout::verticalSpacing() const
{
return mVerticalSpacing;
}
void FlowLayout::setVerticalSpacing(const int spacing)
{
mVerticalSpacing = spacing;
}
void FlowLayout::addItem(QLayoutItem *item)
{
itemList.append(item);
......@@ -117,27 +143,72 @@ QSize FlowLayout::minimumSize() const
return size;
}
void FlowLayout::addSpacing(const int size)
{
addItem(new QSpacerItem(size, 0, QSizePolicy::Fixed, QSizePolicy::Minimum));
}
int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
{
int x = rect.x();
int y = rect.y();
const int left = rect.x() + margin();
int x = left;
int y = rect.y() + margin();
int lineHeight = 0;
bool lastItemIsSpacer = false;
QHash<int, int> widthForY;
QLayoutItem *item;
foreach(item, itemList) {
int nextX = x + item->sizeHint().width() + spacing();
if (nextX - spacing() > rect.right() && lineHeight > 0) {
x = rect.x();
y = y + lineHeight + spacing();
nextX = x + item->sizeHint().width() + spacing();
const bool itemIsSpacer = item->spacerItem() != nullptr;
// Don't add invisible items or succeeding spacer items
if (item->sizeHint().width() == 0 || (itemIsSpacer && lastItemIsSpacer)) {
continue;
}
int nextX = x + item->sizeHint().width() + horizontalSpacing();
if (nextX - horizontalSpacing() > rect.right() - margin() && lineHeight > 0) {
x = left;
y = y + lineHeight + verticalSpacing();
nextX = x + item->sizeHint().width() + horizontalSpacing();
lineHeight = 0;
}
// Don't place spacer items at start of line
if (itemIsSpacer && x == left) {
continue;
}
if (!testOnly)
item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
x = nextX;
// Don't add spacer items at end of line
if (!itemIsSpacer) {
widthForY[y] = x - margin();
}
lineHeight = qMax(lineHeight, item->sizeHint().height());
lastItemIsSpacer = itemIsSpacer;
}
if (!testOnly) {
const int contentWidth = rect.width() - 2 * margin();
for (auto item : itemList) {
QRect itemRect = item->geometry();
// Center lines horizontally if flag AlignHCenter is set
if (alignment() & Qt::AlignHCenter) {
if (widthForY.contains(itemRect.y())) {
const int offset = (contentWidth - widthForY[itemRect.y()]) / 2;
itemRect.translate(offset, 0);
}
}
// Center items vertically if flag AlignVCenter is set
if (alignment() & Qt::AlignVCenter) {
const int offset = (lineHeight - itemRect.height()) / 2;
itemRect.translate(0, offset);
}
item->setGeometry(itemRect);
}
}
return y + lineHeight - rect.y();
return y + lineHeight - rect.y() + margin();
}
......@@ -50,6 +50,11 @@ public:
FlowLayout(int spacing = -1);
~FlowLayout() override;
int horizontalSpacing() const;
void setHorizontalSpacing(const int spacing);
int verticalSpacing() const;
void setVerticalSpacing(const int spacing);
void addItem(QLayoutItem *item) override;
Qt::Orientations expandingDirections() const override;
bool hasHeightForWidth() const override;
......@@ -60,11 +65,14 @@ public:
void setGeometry(const QRect &rect) override;
QSize sizeHint() const override;
QLayoutItem *takeAt(int index) override;
void addSpacing(const int size);
private:
int doLayout(const QRect &rect, bool testOnly) const;
QList<QLayoutItem *> itemList;
int mHorizontalSpacing;
int mVerticalSpacing;
};
#endif
......@@ -17,7 +17,7 @@
<number>1</number>
</property>
<widget class="QWidget" name="mainPage">
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,0,0,0,0,1">
<property name="topMargin">
<number>0</number>
</property>
......@@ -124,7 +124,7 @@
</layout>
</widget>
<widget class="QWidget" name="notSetPage">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0,0,0,1">
<property name="topMargin">
<number>0</number>
</property>
......
......@@ -122,7 +122,10 @@ void SlideContainer::resizeEvent(QResizeEvent* event)
void SlideContainer::adjustContentGeometry()
{
if (mContent) {
mContent->setGeometry(0, height() - mContent->height(), width(), mContent->height());
const int contentHeight = mContent->hasHeightForWidth()
? mContent->heightForWidth(width())
: mContent->height();
mContent->setGeometry(0, height() - contentHeight, width(), contentHeight);
}
}
......@@ -135,7 +138,7 @@ bool SlideContainer::eventFilter(QObject*, QEvent* event)