ImageViewer: Improve tool bar size and behavior

Merge the various export functionality into one tool button instead of
three, for this not-so-often used functionality.

Put the actions into a QToolBar, so if the editor area is made so small
that not all actions fit anymore, the tool bar gets the standard
extension button for accessing the "overflowing" ones.

Fixes: QTCREATORBUG-28309
Change-Id: I2e1fcee9414038aca49648f18f61e1f15ecf3e5a
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
Eike Ziller
2022-10-17 13:18:03 +02:00
parent 570a2f75ea
commit ce6ab1a14d
3 changed files with 230 additions and 140 deletions

View File

@@ -5,34 +5,42 @@
#include "actionmanager.h"
#include "command.h"
#include <utils/proxyaction.h>
#include <utils/qtcassert.h>
using namespace Core;
using namespace Utils;
/*!
\class Core::CommandAction
\inheaderfile coreplugin/actionmanager/commandbutton.h
\inmodule QtCreator
\brief The CommandAction class is an action associated with one of
the registered Command objects.
It shares the icon and text of the command.
The tooltip of the action consists of toolTipBase property value and Command's
key sequence which is automatically updated when user changes it.
*/
/*!
\class Core::CommandButton
\inheaderfile coreplugin/actionmanager/commandbutton.h
\inmodule QtCreator
\brief The CommandButton class is a tool button associated with one of
\brief The CommandButton class is an action associated with one of
the registered Command objects.
Tooltip of this button consists of toolTipBase property value and Command's
The tooltip of the button consists of toolTipBase property value and Command's
key sequence which is automatically updated when user changes it.
*/
/*!
\property CommandButton::toolTipBase
\brief The tool tip base for the command button.
*/
/*!
\internal
*/
CommandButton::CommandButton(QWidget *parent)
: QToolButton(parent)
CommandAction::CommandAction(QWidget *parent)
: QAction(parent)
, m_command(nullptr)
{
}
@@ -40,8 +48,8 @@ CommandButton::CommandButton(QWidget *parent)
/*!
\internal
*/
CommandButton::CommandButton(Id id, QWidget *parent)
: QToolButton(parent)
CommandAction::CommandAction(Id id, QWidget *parent)
: QAction(parent)
, m_command(nullptr)
{
setCommandId(id);
@@ -50,12 +58,83 @@ CommandButton::CommandButton(Id id, QWidget *parent)
/*!
Sets the ID of the command associated with this tool button to \a id.
*/
void CommandButton::setCommandId(Id id)
void CommandAction::setCommandId(Id id)
{
if (m_command)
disconnect(m_command.data(), &Command::keySequenceChanged, this, &CommandButton::updateToolTip);
disconnect(m_command.data(),
&Command::keySequenceChanged,
this,
&CommandAction::updateToolTip);
m_command = ActionManager::command(id);
QTC_ASSERT(m_command, return);
if (m_toolTipBase.isEmpty())
m_toolTipBase = m_command->description();
setIcon(m_command->action()->icon());
setIconText(m_command->action()->iconText());
setText(m_command->action()->text());
updateToolTip();
connect(m_command.data(), &Command::keySequenceChanged, this, &CommandAction::updateToolTip);
}
/*!
The base tool tip that is extended with the command's shortcut.
Defaults to the command's description.
\sa Command::description()
*/
QString CommandAction::toolTipBase() const
{
return m_toolTipBase;
}
/*!
Sets the base tool tip that is extended with the command's shortcut.
\sa toolTipBase()
*/
void CommandAction::setToolTipBase(const QString &toolTipBase)
{
m_toolTipBase = toolTipBase;
updateToolTip();
}
void CommandAction::updateToolTip()
{
if (m_command)
setToolTip(Utils::ProxyAction::stringWithAppendedShortcut(m_toolTipBase,
m_command->keySequence()));
}
/*!
\internal
*/
CommandButton::CommandButton(QWidget *parent)
: QToolButton(parent)
{}
/*!
\internal
*/
CommandButton::CommandButton(Utils::Id id, QWidget *parent)
: QToolButton(parent)
{
setCommandId(id);
}
void CommandButton::setCommandId(Utils::Id id)
{
if (m_command)
disconnect(m_command.data(),
&Command::keySequenceChanged,
this,
&CommandButton::updateToolTip);
m_command = ActionManager::command(id);
QTC_ASSERT(m_command, return);
if (m_toolTipBase.isEmpty())
m_toolTipBase = m_command->description();
@@ -64,11 +143,22 @@ void CommandButton::setCommandId(Id id)
connect(m_command.data(), &Command::keySequenceChanged, this, &CommandButton::updateToolTip);
}
/*!
The base tool tip that is extended with the command's shortcut.
Defaults to the command's description.
\sa Command::description()
*/
QString CommandButton::toolTipBase() const
{
return m_toolTipBase;
}
/*!
Sets the base tool tip that is extended with the command's shortcut.
\sa toolTipBase()
*/
void CommandButton::setToolTipBase(const QString &toolTipBase)
{
m_toolTipBase = toolTipBase;

View File

@@ -15,10 +15,28 @@ namespace Core {
class Command;
class CORE_EXPORT CommandAction : public QAction
{
Q_OBJECT
public:
explicit CommandAction(QWidget *parent = nullptr);
explicit CommandAction(Utils::Id id, QWidget *parent = nullptr);
void setCommandId(Utils::Id id);
QString toolTipBase() const;
void setToolTipBase(const QString &toolTipBase);
private:
void updateToolTip();
QPointer<Command> m_command;
QString m_toolTipBase;
};
class CORE_EXPORT CommandButton : public QToolButton
{
Q_OBJECT
Q_PROPERTY(QString toolTipBase READ toolTipBase WRITE setToolTipBase)
public:
explicit CommandButton(QWidget *parent = nullptr);
explicit CommandButton(Utils::Id id, QWidget *parent = nullptr);
@@ -32,5 +50,4 @@ private:
QPointer<Command> m_command;
QString m_toolTipBase;
};
}

View File

@@ -28,8 +28,9 @@
#include <QImageReader>
#include <QLabel>
#include <QMap>
#include <QMenu>
#include <QSpacerItem>
#include <QWidget>
#include <QToolBar>
#include <QWidget>
using namespace Core;
@@ -44,16 +45,17 @@ struct ImageViewerPrivate
ImageView *imageView;
QWidget *toolbar;
CommandButton *toolButtonExportImage;
CommandButton *toolButtonMultiExportImages;
CommandButton *toolButtonCopyDataUrl;
CommandButton *toolButtonBackground;
CommandButton *toolButtonOutline;
CommandButton *toolButtonFitToScreen;
CommandButton *toolButtonOriginalSize;
CommandButton *toolButtonZoomIn;
CommandButton *toolButtonZoomOut;
CommandButton *toolButtonPlayPause;
QToolButton *shareButton;
CommandAction *actionExportImage;
CommandAction *actionMultiExportImages;
CommandAction *actionButtonCopyDataUrl;
CommandAction *actionBackground;
CommandAction *actionOutline;
CommandAction *actionFitToScreen;
CommandAction *actionOriginalSize;
CommandAction *actionZoomIn;
CommandAction *actionZoomOut;
CommandAction *actionPlayPause;
QLabel *labelImageSize;
QLabel *labelInfo;
};
@@ -63,12 +65,12 @@ struct ImageViewerPrivate
from the current theme. Returns \c true if icon is updated, \c false
otherwise.
*/
static bool updateButtonIconByTheme(QAbstractButton *button, const QString &name)
static bool updateIconByTheme(QAction *action, const QString &name)
{
QTC_ASSERT(!name.isEmpty(), return false);
if (QIcon::hasThemeIcon(name)) {
button->setIcon(QIcon::fromTheme(name));
action->setIcon(QIcon::fromTheme(name));
return true;
}
@@ -100,135 +102,116 @@ void ImageViewer::ctor()
setDuplicateSupported(true);
// toolbar
d->toolbar = new QWidget;
d->toolbar = new StyledBar;
d->toolButtonExportImage = new CommandButton;
d->toolButtonMultiExportImages = new CommandButton;
d->toolButtonCopyDataUrl = new CommandButton;
d->toolButtonBackground = new CommandButton;
d->toolButtonOutline = new CommandButton;
d->toolButtonFitToScreen = new CommandButton;
d->toolButtonOriginalSize = new CommandButton;
d->toolButtonZoomIn = new CommandButton;
d->toolButtonZoomOut = new CommandButton;
d->toolButtonPlayPause = new CommandButton;
d->actionExportImage = new CommandAction(Constants::ACTION_EXPORT_IMAGE, d->toolbar);
d->actionMultiExportImages = new CommandAction(Constants::ACTION_EXPORT_MULTI_IMAGES,
d->toolbar);
d->actionButtonCopyDataUrl = new CommandAction(Constants::ACTION_COPY_DATA_URL, d->toolbar);
d->shareButton = new QToolButton;
d->shareButton->setToolTip(Tr::tr("Export"));
d->shareButton->setPopupMode(QToolButton::InstantPopup);
d->shareButton->setIcon(Icons::EXPORTFILE_TOOLBAR.icon());
d->shareButton->setProperty("noArrow", true);
auto shareMenu = new QMenu(d->shareButton);
shareMenu->addAction(d->actionExportImage);
shareMenu->addAction(d->actionMultiExportImages);
shareMenu->addAction(d->actionButtonCopyDataUrl);
d->shareButton->setMenu(shareMenu);
d->toolButtonBackground->setCheckable(true);
d->toolButtonBackground->setChecked(settings.showBackground);
d->actionBackground = new CommandAction(Constants::ACTION_BACKGROUND, d->toolbar);
d->actionOutline = new CommandAction(Constants::ACTION_OUTLINE, d->toolbar);
d->actionFitToScreen = new CommandAction(Constants::ACTION_FIT_TO_SCREEN, d->toolbar);
d->actionOriginalSize = new CommandAction(Core::Constants::ZOOM_RESET, d->toolbar);
d->actionZoomIn = new CommandAction(Core::Constants::ZOOM_IN, d->toolbar);
d->actionZoomOut = new CommandAction(Core::Constants::ZOOM_OUT, d->toolbar);
d->actionPlayPause = new CommandAction(Constants::ACTION_TOGGLE_ANIMATION, d->toolbar);
d->toolButtonOutline->setCheckable(true);
d->toolButtonOutline->setChecked(settings.showOutline);
d->actionBackground->setCheckable(true);
d->actionBackground->setChecked(settings.showBackground);
d->toolButtonFitToScreen->setCheckable(true);
d->toolButtonFitToScreen->setChecked(settings.fitToScreen);
d->actionOutline->setCheckable(true);
d->actionOutline->setChecked(settings.showOutline);
d->toolButtonZoomIn->setAutoRepeat(true);
d->actionFitToScreen->setCheckable(true);
d->actionFitToScreen->setChecked(settings.fitToScreen);
d->toolButtonZoomOut->setAutoRepeat(true);
d->actionZoomIn->setAutoRepeat(true);
d->toolButtonExportImage->setToolTipBase(Tr::tr("Export as Image"));
d->toolButtonMultiExportImages->setToolTipBase(Tr::tr("Export Images of Multiple Sizes"));
d->toolButtonOutline->setToolTipBase(Tr::tr("Show Outline"));
d->toolButtonFitToScreen->setToolTipBase(Tr::tr("Fit to Screen"));
d->toolButtonOriginalSize->setToolTipBase(Tr::tr("Original Size"));
d->toolButtonZoomIn->setToolTipBase(Tr::tr("Zoom In"));
d->toolButtonZoomOut->setToolTipBase(Tr::tr("Zoom Out"));
d->actionZoomOut->setAutoRepeat(true);
d->toolButtonExportImage->setIcon(Icons::EXPORTFILE_TOOLBAR.icon());
d->toolButtonMultiExportImages->setIcon(Icons::MULTIEXPORTFILE_TOOLBAR.icon());
d->toolButtonCopyDataUrl->setIcon(Icons::COPY_TOOLBAR.icon());
const Icon backgroundIcon({{":/utils/images/desktopdevicesmall.png", Theme::IconsBaseColor}});
d->toolButtonBackground->setIcon(backgroundIcon.icon());
d->toolButtonOutline->setIcon(Icons::BOUNDING_RECT.icon());
d->toolButtonZoomIn->setIcon(
ActionManager::command(Core::Constants::ZOOM_IN)->action()->icon());
d->toolButtonZoomOut->setIcon(
ActionManager::command(Core::Constants::ZOOM_OUT)->action()->icon());
d->toolButtonOriginalSize->setIcon(
d->actionBackground->setIcon(backgroundIcon.icon());
d->actionOutline->setIcon(Icons::BOUNDING_RECT.icon());
d->actionZoomIn->setIcon(ActionManager::command(Core::Constants::ZOOM_IN)->action()->icon());
d->actionZoomOut->setIcon(ActionManager::command(Core::Constants::ZOOM_OUT)->action()->icon());
d->actionOriginalSize->setIcon(
ActionManager::command(Core::Constants::ZOOM_RESET)->action()->icon());
d->toolButtonFitToScreen->setIcon(Icons::FITTOVIEW_TOOLBAR.icon());
d->actionFitToScreen->setIcon(Icons::FITTOVIEW_TOOLBAR.icon());
// icons update - try to use system theme
updateButtonIconByTheme(d->toolButtonFitToScreen, QLatin1String("zoom-fit-best"));
updateIconByTheme(d->actionFitToScreen, QLatin1String("zoom-fit-best"));
// a display - something is on the background
updateButtonIconByTheme(d->toolButtonBackground, QLatin1String("video-display"));
updateIconByTheme(d->actionBackground, QLatin1String("video-display"));
// "emblem to specify the directory where the user stores photographs"
// (photograph has outline - piece of paper)
updateButtonIconByTheme(d->toolButtonOutline, QLatin1String("emblem-photos"));
updateIconByTheme(d->actionOutline, QLatin1String("emblem-photos"));
auto setAsDefaultButton = new QToolButton;
auto setAsDefault = new QAction(Tr::tr("Set as Default"), setAsDefaultButton);
auto setAsDefault = new QAction(Tr::tr("Set as Default"), d->toolbar);
setAsDefault->setToolTip(Tr::tr("Use the current settings for background, outline, and fitting "
"to screen as the default for new image viewers."));
setAsDefaultButton->setDefaultAction(setAsDefault);
d->toolButtonExportImage->setCommandId(Constants::ACTION_EXPORT_IMAGE);
d->toolButtonMultiExportImages->setCommandId(Constants::ACTION_EXPORT_MULTI_IMAGES);
d->toolButtonCopyDataUrl->setCommandId(Constants::ACTION_COPY_DATA_URL);
d->toolButtonZoomIn->setCommandId(Core::Constants::ZOOM_IN);
d->toolButtonZoomOut->setCommandId(Core::Constants::ZOOM_OUT);
d->toolButtonOriginalSize->setCommandId(Core::Constants::ZOOM_RESET);
d->toolButtonFitToScreen->setCommandId(Constants::ACTION_FIT_TO_SCREEN);
d->toolButtonBackground->setCommandId(Constants::ACTION_BACKGROUND);
d->toolButtonOutline->setCommandId(Constants::ACTION_OUTLINE);
d->toolButtonPlayPause->setCommandId(Constants::ACTION_TOGGLE_ANIMATION);
d->labelImageSize = new QLabel;
d->labelInfo = new QLabel;
auto bar = new QToolBar;
bar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
bar->addWidget(d->shareButton);
bar->addSeparator();
bar->addAction(d->actionOriginalSize);
bar->addAction(d->actionZoomIn);
bar->addAction(d->actionZoomOut);
bar->addAction(d->actionPlayPause);
bar->addAction(d->actionPlayPause);
bar->addSeparator();
bar->addAction(d->actionBackground);
bar->addAction(d->actionOutline);
bar->addAction(d->actionFitToScreen);
bar->addAction(setAsDefault);
auto horizontalLayout = new QHBoxLayout(d->toolbar);
horizontalLayout->setSpacing(0);
horizontalLayout->setContentsMargins(0, 0, 0, 0);
horizontalLayout->addWidget(d->toolButtonExportImage);
horizontalLayout->addWidget(d->toolButtonMultiExportImages);
horizontalLayout->addWidget(d->toolButtonCopyDataUrl);
horizontalLayout->addWidget(new StyledSeparator);
horizontalLayout->addWidget(d->toolButtonBackground);
horizontalLayout->addWidget(d->toolButtonOutline);
horizontalLayout->addWidget(d->toolButtonFitToScreen);
horizontalLayout->addWidget(setAsDefaultButton);
horizontalLayout->addWidget(new StyledSeparator);
horizontalLayout->addWidget(d->toolButtonOriginalSize);
horizontalLayout->addWidget(d->toolButtonZoomIn);
horizontalLayout->addWidget(d->toolButtonZoomOut);
horizontalLayout->addWidget(d->toolButtonPlayPause);
horizontalLayout->addWidget(d->toolButtonPlayPause);
horizontalLayout->addWidget(new StyledSeparator);
horizontalLayout->addItem(new QSpacerItem(315, 20, QSizePolicy::Expanding, QSizePolicy::Minimum));
horizontalLayout->addWidget(bar);
horizontalLayout->addItem(
new QSpacerItem(315, 20, QSizePolicy::Expanding, QSizePolicy::Minimum));
horizontalLayout->addWidget(new StyledSeparator);
horizontalLayout->addWidget(d->labelImageSize);
horizontalLayout->addWidget(new StyledSeparator);
horizontalLayout->addWidget(d->labelInfo);
// connections
connect(d->toolButtonExportImage, &QAbstractButton::clicked,
d->imageView, &ImageView::exportImage);
connect(d->toolButtonMultiExportImages, &QAbstractButton::clicked,
d->imageView, &ImageView::exportMultiImages);
connect(d->toolButtonCopyDataUrl, &QAbstractButton::clicked,
d->imageView, &ImageView::copyDataUrl);
connect(d->toolButtonZoomIn, &QAbstractButton::clicked,
d->imageView, &ImageView::zoomIn);
connect(d->toolButtonZoomOut, &QAbstractButton::clicked,
d->imageView, &ImageView::zoomOut);
connect(d->toolButtonFitToScreen,
&QAbstractButton::toggled,
connect(d->actionExportImage, &QAction::triggered, d->imageView, &ImageView::exportImage);
connect(d->actionMultiExportImages,
&QAction::triggered,
d->imageView,
&ImageView::setFitToScreen);
&ImageView::exportMultiImages);
connect(d->actionButtonCopyDataUrl, &QAction::triggered, d->imageView, &ImageView::copyDataUrl);
connect(d->actionZoomIn, &QAction::triggered, d->imageView, &ImageView::zoomIn);
connect(d->actionZoomOut, &QAction::triggered, d->imageView, &ImageView::zoomOut);
connect(d->actionFitToScreen, &QAction::triggered, d->imageView, &ImageView::setFitToScreen);
connect(d->imageView,
&ImageView::fitToScreenChanged,
d->toolButtonFitToScreen,
&QAbstractButton::setChecked);
connect(d->toolButtonOriginalSize,
&QAbstractButton::clicked,
d->actionFitToScreen,
&QAction::setChecked);
connect(d->actionOriginalSize,
&QAction::triggered,
d->imageView,
&ImageView::resetToOriginalSize);
connect(d->toolButtonBackground, &QAbstractButton::toggled,
d->imageView, &ImageView::setViewBackground);
connect(d->toolButtonOutline, &QAbstractButton::toggled,
d->imageView, &ImageView::setViewOutline);
connect(d->toolButtonPlayPause, &CommandButton::clicked,
this, &ImageViewer::playToggled);
connect(d->actionBackground, &QAction::toggled, d->imageView, &ImageView::setViewBackground);
connect(d->actionOutline, &QAction::toggled, d->imageView, &ImageView::setViewOutline);
connect(d->actionPlayPause, &QAction::triggered, this, &ImageViewer::playToggled);
connect(d->file.data(), &ImageViewerFile::imageSizeChanged,
this, &ImageViewer::imageSizeUpdated);
connect(d->file.data(), &ImageViewerFile::openFinished,
@@ -280,18 +263,18 @@ IEditor *ImageViewer::duplicate()
void ImageViewer::exportImage()
{
if (d->file->type() == ImageViewerFile::TypeSvg)
d->toolButtonExportImage->click();
d->actionExportImage->trigger();
}
void ImageViewer::exportMultiImages()
{
if (d->file->type() == ImageViewerFile::TypeSvg)
d->toolButtonMultiExportImages->click();
d->actionMultiExportImages->trigger();
}
void ImageViewer::copyDataUrl()
{
d->toolButtonCopyDataUrl->click();
d->actionButtonCopyDataUrl->trigger();
}
void ImageViewer::imageSizeUpdated(const QSize &size)
@@ -310,45 +293,45 @@ void ImageViewer::scaleFactorUpdate(qreal factor)
void ImageViewer::switchViewBackground()
{
d->toolButtonBackground->click();
d->actionBackground->trigger();
}
void ImageViewer::switchViewOutline()
{
d->toolButtonOutline->click();
d->actionOutline->trigger();
}
void ImageViewer::zoomIn()
{
d->toolButtonZoomIn->click();
d->actionZoomIn->trigger();
}
void ImageViewer::zoomOut()
{
d->toolButtonZoomOut->click();
d->actionZoomOut->trigger();
}
void ImageViewer::resetToOriginalSize()
{
d->toolButtonOriginalSize->click();
d->actionOriginalSize->trigger();
}
void ImageViewer::fitToScreen()
{
d->toolButtonFitToScreen->click();
d->actionFitToScreen->trigger();
}
void ImageViewer::updateToolButtons()
{
const bool isSvg = d->file->type() == ImageViewerFile::TypeSvg;
d->toolButtonExportImage->setEnabled(isSvg);
d->toolButtonMultiExportImages->setEnabled(isSvg);
d->actionExportImage->setEnabled(isSvg);
d->actionMultiExportImages->setEnabled(isSvg);
updatePauseAction();
}
void ImageViewer::togglePlay()
{
d->toolButtonPlayPause->click();
d->actionPlayPause->trigger();
}
void ImageViewer::playToggled()
@@ -360,12 +343,12 @@ void ImageViewer::updatePauseAction()
{
bool isMovie = d->file->type() == ImageViewerFile::TypeMovie;
if (isMovie && !d->file->isPaused()) {
d->toolButtonPlayPause->setToolTipBase(Tr::tr("Pause Animation"));
d->toolButtonPlayPause->setIcon(Icons::INTERRUPT_SMALL_TOOLBAR.icon());
d->actionPlayPause->setToolTipBase(Tr::tr("Pause Animation"));
d->actionPlayPause->setIcon(Icons::INTERRUPT_SMALL_TOOLBAR.icon());
} else {
d->toolButtonPlayPause->setToolTipBase(Tr::tr("Play Animation"));
d->toolButtonPlayPause->setIcon(Icons::RUN_SMALL_TOOLBAR.icon());
d->toolButtonPlayPause->setEnabled(isMovie);
d->actionPlayPause->setToolTipBase(Tr::tr("Play Animation"));
d->actionPlayPause->setIcon(Icons::RUN_SMALL_TOOLBAR.icon());
d->actionPlayPause->setEnabled(isMovie);
}
}