From 337a8908508d3c7eac459bcffc2aff38db793c7d Mon Sep 17 00:00:00 2001 From: Jakob Gahde Date: Wed, 26 Aug 2020 00:13:25 +0200 Subject: [PATCH 1/8] Add more useful widgets to the status bar --- app/src/mainwindow2.cpp | 175 +++++++++++++++++++++++++++-- app/src/mainwindow2.h | 23 +++- core_lib/src/tool/basetool.h | 5 +- core_lib/src/tool/polylinetool.cpp | 3 + 4 files changed, 194 insertions(+), 12 deletions(-) diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index 8550209899..e59f4d9a09 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -19,6 +19,9 @@ GNU General Public License for more details. #include "mainwindow2.h" #include "ui_mainwindow2.h" +// standard headers +#include + // Qt headers #include #include @@ -29,7 +32,11 @@ GNU General Public License for more details. #include #include #include +#include #include +#include +#include +#include // core_lib headers #include "pencildef.h" @@ -115,19 +122,15 @@ MainWindow2::MainWindow2(QWidget* parent) : createDockWidgets(); createMenus(); + createStatusBar(); setupKeyboardShortcuts(); readSettings(); - mZoomLabel = new QLabel(""); - ui->statusbar->addWidget(mZoomLabel); - - updateZoomLabel(); selectionChanged(); connect(mEditor, &Editor::needSave, this, &MainWindow2::autoSave); connect(mToolBox, &ToolBoxWidget::clearButtonClicked, mEditor, &Editor::clearCurrentFrame); - connect(mEditor->view(), &ViewManager::viewChanged, this, &MainWindow2::updateZoomLabel); mEditor->tools()->setDefaultTool(); ui->background->init(mEditor->preference()); @@ -415,6 +418,55 @@ void MainWindow2::createMenus() connect(ui->menuEdit, &QMenu::aboutToHide, this, &MainWindow2::undoActSetEnabled); } +void MainWindow2::createStatusBar() { + mToolIcon = new QLabel(this); + ui->statusbar->addWidget(mToolIcon); + mToolLabel = new QLabel(this); + ui->statusbar->addWidget(mToolLabel); + connect(mEditor->tools(), &ToolManager::toolChanged, this, &MainWindow2::updateToolStatus); + connect(mEditor->tools()->getTool(POLYLINE), &BaseTool::isActiveChanged, this, &MainWindow2::updateToolStatus); + + mModifiedLabel = new QLabel("*", this); + mModifiedLabel->setToolTip(tr("The file has unsaved changes")); + ui->statusbar->addPermanentWidget(mModifiedLabel); + + mBitmapIcon = QIcon(":/icons/layer-bitmap.png"); + mVectorIcon = QIcon(":/icons/layer-vector.png"); + mSoundIcon = QIcon(":/icons/layer-sound.png"); + mCameraIcon = QIcon(":/icons/layer-camera.png"); + + mLayerBox = new QComboBox(this); + ui->statusbar->addPermanentWidget(mLayerBox); + updateLayerStatus(); + connect(mEditor->layers(), &LayerManager::layerCountChanged, this, QOverload<>::of(&MainWindow2::updateLayerStatus)); + connect(mEditor->layers(), &LayerManager::currentLayerChanged, this, QOverload::of(&MainWindow2::updateLayerStatus)); + connect(mLayerBox, QOverload::of(&QComboBox::currentIndexChanged), mEditor->layers(), QOverload::of(&LayerManager::setCurrentLayer)); + + mZoomBox = new QComboBox(this); + mZoomBox->setEditable(true); + mZoomBox->lineEdit()->setAlignment(Qt::AlignRight); + ui->statusbar->addPermanentWidget(mZoomBox); + connect(mZoomBox, QOverload::of(&QComboBox::activated), [this](const QString ¤tText) { + QString zoomString = currentText; + zoomString = zoomString.remove('%'); + mEditor->view()->scale(zoomString.toDouble() / 100); + }); + + mZoomSlider = new QSlider(Qt::Horizontal, this); + mZoomSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + mZoomSlider->setMinimum(-200); + mZoomSlider->setMaximum(200); + mZoomSlider->setTickPosition(QSlider::TicksBelow); + mZoomSlider->setTickInterval(200); + ui->statusbar->addPermanentWidget(mZoomSlider); + connect(mZoomSlider, &QSlider::valueChanged, [this](int value) { + mEditor->view()->scale(std::pow(10, value / 100.)); + }); + + connect(mEditor->view(), &ViewManager::viewChanged, this, &MainWindow2::updateZoomStatus); + updateZoomStatus(); +} + void MainWindow2::setOpacity(int opacity) { mEditor->preference()->set(SETTING::WINDOW_OPACITY, 100 - opacity); @@ -424,6 +476,7 @@ void MainWindow2::setOpacity(int opacity) void MainWindow2::updateSaveState() { setWindowModified(mEditor->currentBackup() != mBackupAtSave); + mModifiedLabel->setVisible(mEditor->currentBackup() != mBackupAtSave); } void MainWindow2::clearRecentFilesList() @@ -617,6 +670,7 @@ bool MainWindow2::openObject(const QString& strFilePath) setWindowTitle(mEditor->object()->filePath().prepend("[*]")); setWindowModified(false); + mModifiedLabel->hide(); progress.setValue(progress.maximum()); @@ -1437,10 +1491,115 @@ void MainWindow2::makeConnections(Editor* pEditor, ColorPaletteWidget* pColorPal connect(pColorManager, &ColorManager::colorNumberChanged, pColorPalette, &ColorPaletteWidget::selectColorNumber); } -void MainWindow2::updateZoomLabel() +void MainWindow2::updateToolStatus(ToolType tool) +{ + switch (tool) { + case PENCIL: + mToolIcon->setPixmap(QPixmap(":icons/new/svg/pencil_detailed.svg")); + mToolLabel->setText(tr("Click to draw. Hold Ctrl and Shift to erase or Alt to select a color from the canvas.")); + break; + case ERASER: + mToolIcon->setPixmap(QPixmap(":icons/new/svg/eraser_detailed.svg")); + mToolLabel->setText(tr("Click to erase.")); + break; + case SELECT: + mToolIcon->setPixmap(QPixmap(":icons/new/svg/selection.svg")); + mToolLabel->setText(tr("Click and drag to create or modify a selection. Hold Alt to modify its contents.")); + break; + case MOVE: + mToolIcon->setPixmap(QPixmap(":icons/new/svg/arrow.svg")); + if (ui->scribbleArea->isTemporaryTool()) { + mToolLabel->setText(tr("Click and drag to move an object.")); + } else { + mToolLabel->setText(tr("Click and drag to move an object. Hold Ctrl to rotate.")); + } + break; + case HAND: + mToolIcon->setPixmap(QPixmap(":icons/new/svg/hand_detailed.svg")); + mToolLabel->setText(tr("Click and drag to pan. Hold Ctrl to zoom or Alt to rotate.")); + break; + case SMUDGE: + mToolIcon->setPixmap(QPixmap(":icons/new/svg/smudge_detailed.svg")); + mToolLabel->setText(tr("Click to liquefy pixels or modify a vector line. Hold Alt to smooth.")); + break; + case PEN: + mToolIcon->setPixmap(QPixmap(":icons/new/svg/pen_detailed.svg")); + mToolLabel->setText(tr("Click to draw. Hold Ctrl and Shift to erase or Alt to select a color from the canvas.")); + break; + case POLYLINE: + mToolIcon->setPixmap(QPixmap(":icons/new/svg/line.svg")); + if (mEditor->tools()->getTool(tool)->isActive()) { + mToolLabel->setText(tr("Click to continue the polyline. Double-click or press enter to complete the line or press Escape to discard it.")); + } else { + mToolLabel->setText(tr("Click to create a new polyline. Hold Ctrl and Shift to erase or Alt to select a color from the canvas.")); + } + break; + case BUCKET: + mToolIcon->setPixmap(QPixmap(":icons/new/svg/bucket_detailed.svg")); + mToolLabel->setText(tr("Click to fill an area with the current color. Hold Alt to select a color from the canvas.")); + break; + case EYEDROPPER: + mToolIcon->setPixmap(QPixmap(":icons/new/svg/eyedropper_detailed.svg")); + mToolLabel->setText(tr("Click to select a color from the canvas.")); + break; + case BRUSH: + mToolIcon->setPixmap(QPixmap(":icons/new/svg/brush_detailed.svg")); + mToolLabel->setText(tr("Click to paint. Hold Ctrl and Shift to erase or Alt to select a color from the canvas.")); + break; + default: + Q_ASSERT(false); + } + mToolIcon->setToolTip(BaseTool::TypeName(tool)); +} + +void MainWindow2::updateLayerStatus() +{ + QSignalBlocker b(mLayerBox); + mLayerBox->clear(); + for (int i = 0; i < mEditor->layers()->count(); i++) + { + Layer *layer = mEditor->layers()->getLayer(i); + mLayerBox->addItem(layer->name()); + switch (layer->type()) + { + case Layer::BITMAP: + mLayerBox->setItemIcon(i, mBitmapIcon); + break; + case Layer::VECTOR: + mLayerBox->setItemIcon(i, mVectorIcon); + break; + case Layer::SOUND: + mLayerBox->setItemIcon(i, mSoundIcon); + break; + case Layer::CAMERA: + mLayerBox->setItemIcon(i, mCameraIcon); + break; + case Layer::MOVIE: + case Layer::UNDEFINED: + // no icon + break; + } + } + mLayerBox->setCurrentIndex(mEditor->layers()->currentLayerIndex()); +} + +void MainWindow2::updateLayerStatus(int layer) +{ + mLayerBox->setItemText(layer, mEditor->layers()->getLayer(layer)->name()); + mLayerBox->setCurrentIndex(layer); +} + +void MainWindow2::updateZoomStatus() { - qreal zoom = mEditor->view()->scaling() * 100.f; - mZoomLabel->setText(tr("Zoom: %0%").arg(zoom, 0, 'f', 1)); + double zoom = mEditor->view()->scaling() * 100; + QSignalBlocker b1(mZoomBox); + mZoomBox->clear(); + // Keep the dropdown list limited to our predefined entries + // insertPolicy can't handle that without preventing custom values outright + mZoomBox->addItems(QStringList() << "10000.0%" << "6400.0%" << "1600.0%" << "800.0%" << "400.0%" << "200.0%" << "100.0%" << "75.0%" << "50.0%" << "33.0%" << "25.0%" << "12.0%" << "1.0%"); + mZoomBox->setCurrentText(QString("%0%").arg(zoom, 0, 'f', 1)); + QSignalBlocker b2(mZoomSlider); + mZoomSlider->setValue(static_cast(std::round(std::log10(mEditor->view()->scaling()) * 100))); } void MainWindow2::changePlayState(bool isPlaying) diff --git a/app/src/mainwindow2.h b/app/src/mainwindow2.h index 94ecddb9d0..e4e878d11c 100644 --- a/app/src/mainwindow2.h +++ b/app/src/mainwindow2.h @@ -19,9 +19,13 @@ GNU General Public License for more details. #define MAINWINDOW2_H #include +#include "pencildef.h" template class QList; class QActionGroup; +class QComboBox; +class QLabel; +class QSlider; class Object; class Editor; class ScribbleArea; @@ -42,7 +46,6 @@ class ActionCommands; class ImportImageSeqDialog; class BackupElement; class LayerOpacityDialog; -class QLabel; class PegBarAlignmentDialog; enum class SETTING; @@ -119,9 +122,13 @@ public slots: void createDockWidgets(); void createMenus(); + void createStatusBar(); void setupKeyboardShortcuts(); void clearKeyboardShortcuts(); - void updateZoomLabel(); + void updateToolStatus(ToolType tool); + void updateLayerStatus(); + void updateLayerStatus(int layer); + void updateZoomStatus(); bool loadMostRecent(); bool tryLoadPreset(); @@ -174,11 +181,21 @@ public slots: QIcon mStartIcon; QIcon mStopIcon; + QIcon mBitmapIcon; + QIcon mVectorIcon; + QIcon mSoundIcon; + QIcon mCameraIcon; + // a hack for MacOS because closeEvent fires twice bool m2ndCloseEvent = false; // statusbar widgets - QLabel* mZoomLabel = nullptr; + QLabel* mToolIcon = nullptr; + QLabel* mToolLabel = nullptr; + QLabel* mModifiedLabel = nullptr; + QComboBox* mLayerBox = nullptr; + QComboBox* mZoomBox = nullptr; + QSlider* mZoomSlider = nullptr; // Whether to suppress the auto save dialog due to internal work bool mSuppressAutoSaveDialog = false; diff --git a/core_lib/src/tool/basetool.h b/core_lib/src/tool/basetool.h index 0334ac9986..24c8047931 100644 --- a/core_lib/src/tool/basetool.h +++ b/core_lib/src/tool/basetool.h @@ -68,7 +68,7 @@ class BaseTool : public QObject QString typeName() { return TypeName(type()); } void initialize(Editor* editor); - + virtual ToolType type() = 0; virtual void loadSettings() = 0; virtual QCursor cursor(); @@ -134,6 +134,9 @@ class BaseTool : public QObject bool isPropertyEnabled(ToolPropertyType t) { return mPropertyEnabled[t]; } bool isDrawingTool(); +signals: + bool isActiveChanged(ToolType, bool); + protected: StrokeManager* strokeManager() { return mStrokeManager; } Editor* editor() { return mEditor; } diff --git a/core_lib/src/tool/polylinetool.cpp b/core_lib/src/tool/polylinetool.cpp index 6dd6f04ccd..2e3df4a54b 100644 --- a/core_lib/src/tool/polylinetool.cpp +++ b/core_lib/src/tool/polylinetool.cpp @@ -24,6 +24,7 @@ GNU General Public License for more details. #include "strokemanager.h" #include "layermanager.h" #include "colormanager.h" +#include "toolmanager.h" #include "viewmanager.h" #include "pointerevent.h" #include "layervector.h" @@ -104,6 +105,7 @@ QCursor PolylineTool::cursor() void PolylineTool::clearToolData() { mPoints.clear(); + emit isActiveChanged(POLYLINE, false); } void PolylineTool::pointerPressEvent(PointerEvent* event) @@ -127,6 +129,7 @@ void PolylineTool::pointerPressEvent(PointerEvent* event) } } mPoints << getCurrentPoint(); + emit isActiveChanged(POLYLINE, true); } } } From 6524803d270e9dbdcbb68639ad569ba377b1eb00 Mon Sep 17 00:00:00 2001 From: Jakob Gahde Date: Fri, 28 Aug 2020 19:31:50 +0200 Subject: [PATCH 2/8] Separate the status bar code from the main window --- app/app.pro | 6 +- app/src/mainwindow2.cpp | 181 ++---------------------- app/src/mainwindow2.h | 24 +--- app/src/statusbar.cpp | 217 +++++++++++++++++++++++++++++ app/src/statusbar.h | 124 +++++++++++++++++ app/ui/mainwindow2.ui | 9 +- core_lib/src/tool/polylinetool.cpp | 1 - 7 files changed, 369 insertions(+), 193 deletions(-) create mode 100644 app/src/statusbar.cpp create mode 100644 app/src/statusbar.h diff --git a/app/app.pro b/app/app.pro index 3a9acf0c9b..f1b66e3b6e 100644 --- a/app/app.pro +++ b/app/app.pro @@ -79,7 +79,8 @@ HEADERS += \ src/checkupdatesdialog.h \ src/presetdialog.h \ src/commandlineparser.h \ - src/commandlineexporter.h + src/commandlineexporter.h \ + src/statusbar.h SOURCES += \ src/importlayersdialog.cpp \ @@ -122,7 +123,8 @@ SOURCES += \ src/presetdialog.cpp \ src/app_util.cpp \ src/commandlineparser.cpp \ - src/commandlineexporter.cpp + src/commandlineexporter.cpp \ + src/statusbar.cpp FORMS += \ ui/importimageseqpreview.ui \ diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index e59f4d9a09..2449ab845b 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -19,9 +19,6 @@ GNU General Public License for more details. #include "mainwindow2.h" #include "ui_mainwindow2.h" -// standard headers -#include - // Qt headers #include #include @@ -32,11 +29,6 @@ GNU General Public License for more details. #include #include #include -#include -#include -#include -#include -#include // core_lib headers #include "pencildef.h" @@ -117,12 +109,15 @@ MainWindow2::MainWindow2(QWidget* parent) : ui->scribbleArea->setEditor(mEditor); ui->scribbleArea->init(); + ui->statusBar->setEditor(mEditor); + ui->statusBar->updateLayerStatus(); + ui->statusBar->updateZoomStatus(); + mCommands = new ActionCommands(this); mCommands->setCore(mEditor); createDockWidgets(); createMenus(); - createStatusBar(); setupKeyboardShortcuts(); readSettings(); @@ -229,6 +224,7 @@ void MainWindow2::createDockWidgets() makeConnections(mEditor, mColorPalette); makeConnections(mEditor, mToolOptions); makeConnections(mEditor, mDisplayOptionWidget); + makeConnections(mEditor, ui->statusBar); for (BaseDockWidget* w : mDockWidgets) { @@ -418,55 +414,6 @@ void MainWindow2::createMenus() connect(ui->menuEdit, &QMenu::aboutToHide, this, &MainWindow2::undoActSetEnabled); } -void MainWindow2::createStatusBar() { - mToolIcon = new QLabel(this); - ui->statusbar->addWidget(mToolIcon); - mToolLabel = new QLabel(this); - ui->statusbar->addWidget(mToolLabel); - connect(mEditor->tools(), &ToolManager::toolChanged, this, &MainWindow2::updateToolStatus); - connect(mEditor->tools()->getTool(POLYLINE), &BaseTool::isActiveChanged, this, &MainWindow2::updateToolStatus); - - mModifiedLabel = new QLabel("*", this); - mModifiedLabel->setToolTip(tr("The file has unsaved changes")); - ui->statusbar->addPermanentWidget(mModifiedLabel); - - mBitmapIcon = QIcon(":/icons/layer-bitmap.png"); - mVectorIcon = QIcon(":/icons/layer-vector.png"); - mSoundIcon = QIcon(":/icons/layer-sound.png"); - mCameraIcon = QIcon(":/icons/layer-camera.png"); - - mLayerBox = new QComboBox(this); - ui->statusbar->addPermanentWidget(mLayerBox); - updateLayerStatus(); - connect(mEditor->layers(), &LayerManager::layerCountChanged, this, QOverload<>::of(&MainWindow2::updateLayerStatus)); - connect(mEditor->layers(), &LayerManager::currentLayerChanged, this, QOverload::of(&MainWindow2::updateLayerStatus)); - connect(mLayerBox, QOverload::of(&QComboBox::currentIndexChanged), mEditor->layers(), QOverload::of(&LayerManager::setCurrentLayer)); - - mZoomBox = new QComboBox(this); - mZoomBox->setEditable(true); - mZoomBox->lineEdit()->setAlignment(Qt::AlignRight); - ui->statusbar->addPermanentWidget(mZoomBox); - connect(mZoomBox, QOverload::of(&QComboBox::activated), [this](const QString ¤tText) { - QString zoomString = currentText; - zoomString = zoomString.remove('%'); - mEditor->view()->scale(zoomString.toDouble() / 100); - }); - - mZoomSlider = new QSlider(Qt::Horizontal, this); - mZoomSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - mZoomSlider->setMinimum(-200); - mZoomSlider->setMaximum(200); - mZoomSlider->setTickPosition(QSlider::TicksBelow); - mZoomSlider->setTickInterval(200); - ui->statusbar->addPermanentWidget(mZoomSlider); - connect(mZoomSlider, &QSlider::valueChanged, [this](int value) { - mEditor->view()->scale(std::pow(10, value / 100.)); - }); - - connect(mEditor->view(), &ViewManager::viewChanged, this, &MainWindow2::updateZoomStatus); - updateZoomStatus(); -} - void MainWindow2::setOpacity(int opacity) { mEditor->preference()->set(SETTING::WINDOW_OPACITY, 100 - opacity); @@ -476,7 +423,7 @@ void MainWindow2::setOpacity(int opacity) void MainWindow2::updateSaveState() { setWindowModified(mEditor->currentBackup() != mBackupAtSave); - mModifiedLabel->setVisible(mEditor->currentBackup() != mBackupAtSave); + ui->statusBar->updateModifiedStatus(mEditor->currentBackup() != mBackupAtSave); } void MainWindow2::clearRecentFilesList() @@ -670,7 +617,7 @@ bool MainWindow2::openObject(const QString& strFilePath) setWindowTitle(mEditor->object()->filePath().prepend("[*]")); setWindowModified(false); - mModifiedLabel->hide(); + ui->statusBar->updateModifiedStatus(false); progress.setValue(progress.maximum()); @@ -1491,115 +1438,17 @@ void MainWindow2::makeConnections(Editor* pEditor, ColorPaletteWidget* pColorPal connect(pColorManager, &ColorManager::colorNumberChanged, pColorPalette, &ColorPaletteWidget::selectColorNumber); } -void MainWindow2::updateToolStatus(ToolType tool) -{ - switch (tool) { - case PENCIL: - mToolIcon->setPixmap(QPixmap(":icons/new/svg/pencil_detailed.svg")); - mToolLabel->setText(tr("Click to draw. Hold Ctrl and Shift to erase or Alt to select a color from the canvas.")); - break; - case ERASER: - mToolIcon->setPixmap(QPixmap(":icons/new/svg/eraser_detailed.svg")); - mToolLabel->setText(tr("Click to erase.")); - break; - case SELECT: - mToolIcon->setPixmap(QPixmap(":icons/new/svg/selection.svg")); - mToolLabel->setText(tr("Click and drag to create or modify a selection. Hold Alt to modify its contents.")); - break; - case MOVE: - mToolIcon->setPixmap(QPixmap(":icons/new/svg/arrow.svg")); - if (ui->scribbleArea->isTemporaryTool()) { - mToolLabel->setText(tr("Click and drag to move an object.")); - } else { - mToolLabel->setText(tr("Click and drag to move an object. Hold Ctrl to rotate.")); - } - break; - case HAND: - mToolIcon->setPixmap(QPixmap(":icons/new/svg/hand_detailed.svg")); - mToolLabel->setText(tr("Click and drag to pan. Hold Ctrl to zoom or Alt to rotate.")); - break; - case SMUDGE: - mToolIcon->setPixmap(QPixmap(":icons/new/svg/smudge_detailed.svg")); - mToolLabel->setText(tr("Click to liquefy pixels or modify a vector line. Hold Alt to smooth.")); - break; - case PEN: - mToolIcon->setPixmap(QPixmap(":icons/new/svg/pen_detailed.svg")); - mToolLabel->setText(tr("Click to draw. Hold Ctrl and Shift to erase or Alt to select a color from the canvas.")); - break; - case POLYLINE: - mToolIcon->setPixmap(QPixmap(":icons/new/svg/line.svg")); - if (mEditor->tools()->getTool(tool)->isActive()) { - mToolLabel->setText(tr("Click to continue the polyline. Double-click or press enter to complete the line or press Escape to discard it.")); - } else { - mToolLabel->setText(tr("Click to create a new polyline. Hold Ctrl and Shift to erase or Alt to select a color from the canvas.")); - } - break; - case BUCKET: - mToolIcon->setPixmap(QPixmap(":icons/new/svg/bucket_detailed.svg")); - mToolLabel->setText(tr("Click to fill an area with the current color. Hold Alt to select a color from the canvas.")); - break; - case EYEDROPPER: - mToolIcon->setPixmap(QPixmap(":icons/new/svg/eyedropper_detailed.svg")); - mToolLabel->setText(tr("Click to select a color from the canvas.")); - break; - case BRUSH: - mToolIcon->setPixmap(QPixmap(":icons/new/svg/brush_detailed.svg")); - mToolLabel->setText(tr("Click to paint. Hold Ctrl and Shift to erase or Alt to select a color from the canvas.")); - break; - default: - Q_ASSERT(false); - } - mToolIcon->setToolTip(BaseTool::TypeName(tool)); -} - -void MainWindow2::updateLayerStatus() +void MainWindow2::makeConnections(Editor* editor, StatusBar *statusBar) { - QSignalBlocker b(mLayerBox); - mLayerBox->clear(); - for (int i = 0; i < mEditor->layers()->count(); i++) - { - Layer *layer = mEditor->layers()->getLayer(i); - mLayerBox->addItem(layer->name()); - switch (layer->type()) - { - case Layer::BITMAP: - mLayerBox->setItemIcon(i, mBitmapIcon); - break; - case Layer::VECTOR: - mLayerBox->setItemIcon(i, mVectorIcon); - break; - case Layer::SOUND: - mLayerBox->setItemIcon(i, mSoundIcon); - break; - case Layer::CAMERA: - mLayerBox->setItemIcon(i, mCameraIcon); - break; - case Layer::MOVIE: - case Layer::UNDEFINED: - // no icon - break; - } - } - mLayerBox->setCurrentIndex(mEditor->layers()->currentLayerIndex()); -} + connect(editor->tools(), &ToolManager::toolChanged, statusBar, &StatusBar::updateToolStatus); + connect(editor->tools()->getTool(POLYLINE), &BaseTool::isActiveChanged, statusBar, &StatusBar::updateToolStatus); -void MainWindow2::updateLayerStatus(int layer) -{ - mLayerBox->setItemText(layer, mEditor->layers()->getLayer(layer)->name()); - mLayerBox->setCurrentIndex(layer); -} + connect(editor->layers(), &LayerManager::layerCountChanged, statusBar, QOverload<>::of(&StatusBar::updateLayerStatus)); + connect(editor->layers(), &LayerManager::currentLayerChanged, statusBar, QOverload::of(&StatusBar::updateLayerStatus)); + connect(statusBar, &StatusBar::layerIndexChanged, editor->layers(), QOverload::of(&LayerManager::setCurrentLayer)); -void MainWindow2::updateZoomStatus() -{ - double zoom = mEditor->view()->scaling() * 100; - QSignalBlocker b1(mZoomBox); - mZoomBox->clear(); - // Keep the dropdown list limited to our predefined entries - // insertPolicy can't handle that without preventing custom values outright - mZoomBox->addItems(QStringList() << "10000.0%" << "6400.0%" << "1600.0%" << "800.0%" << "400.0%" << "200.0%" << "100.0%" << "75.0%" << "50.0%" << "33.0%" << "25.0%" << "12.0%" << "1.0%"); - mZoomBox->setCurrentText(QString("%0%").arg(zoom, 0, 'f', 1)); - QSignalBlocker b2(mZoomSlider); - mZoomSlider->setValue(static_cast(std::round(std::log10(mEditor->view()->scaling()) * 100))); + connect(editor->view(), &ViewManager::viewChanged, statusBar, &StatusBar::updateZoomStatus); + connect(statusBar, &StatusBar::zoomChanged, editor->view(), &ViewManager::scale); } void MainWindow2::changePlayState(bool isPlaying) diff --git a/app/src/mainwindow2.h b/app/src/mainwindow2.h index e4e878d11c..e78858199c 100644 --- a/app/src/mainwindow2.h +++ b/app/src/mainwindow2.h @@ -19,13 +19,9 @@ GNU General Public License for more details. #define MAINWINDOW2_H #include -#include "pencildef.h" template class QList; class QActionGroup; -class QComboBox; -class QLabel; -class QSlider; class Object; class Editor; class ScribbleArea; @@ -47,6 +43,7 @@ class ImportImageSeqDialog; class BackupElement; class LayerOpacityDialog; class PegBarAlignmentDialog; +class StatusBar; enum class SETTING; @@ -122,13 +119,8 @@ public slots: void createDockWidgets(); void createMenus(); - void createStatusBar(); void setupKeyboardShortcuts(); void clearKeyboardShortcuts(); - void updateToolStatus(ToolType tool); - void updateLayerStatus(); - void updateLayerStatus(int layer); - void updateZoomStatus(); bool loadMostRecent(); bool tryLoadPreset(); @@ -151,6 +143,7 @@ public slots: void makeConnections(Editor*, DisplayOptionWidget*); void makeConnections(Editor*, ToolOptionWidget*); void makeConnections(Editor*, OnionSkinWidget*); + void makeConnections(Editor*, StatusBar*); bool tryRecoverUnsavedProject(); void startProjectRecovery(int result); @@ -181,22 +174,9 @@ public slots: QIcon mStartIcon; QIcon mStopIcon; - QIcon mBitmapIcon; - QIcon mVectorIcon; - QIcon mSoundIcon; - QIcon mCameraIcon; - // a hack for MacOS because closeEvent fires twice bool m2ndCloseEvent = false; - // statusbar widgets - QLabel* mToolIcon = nullptr; - QLabel* mToolLabel = nullptr; - QLabel* mModifiedLabel = nullptr; - QComboBox* mLayerBox = nullptr; - QComboBox* mZoomBox = nullptr; - QSlider* mZoomSlider = nullptr; - // Whether to suppress the auto save dialog due to internal work bool mSuppressAutoSaveDialog = false; diff --git a/app/src/statusbar.cpp b/app/src/statusbar.cpp new file mode 100644 index 0000000000..31d9a9c70a --- /dev/null +++ b/app/src/statusbar.cpp @@ -0,0 +1,217 @@ +/* + +Pencil2D - Traditional Animation Software +Copyright (C) 2020 Jakob Gahde + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +*/ + +#include +#include +#include +#include + +#include "editor.h" +#include "layermanager.h" +#include "scribblearea.h" +#include "toolmanager.h" +#include "viewmanager.h" + +#include "statusbar.h" + +StatusBar::StatusBar(QWidget *parent) : QStatusBar(parent) +{ + setContentsMargins(3, 0, 3, 0); + + mToolIcon = new QLabel(this); + addWidget(mToolIcon); + mToolLabel = new QLabel(this); + addWidget(mToolLabel); + + mModifiedLabel = new QLabel(this); + updateModifiedStatus(false); + addPermanentWidget(mModifiedLabel); + + mLayerBox = new QComboBox(this); + connect(mLayerBox, QOverload::of(&QComboBox::currentIndexChanged), this, &StatusBar::layerIndexChanged); + addPermanentWidget(mLayerBox); + + mZoomBox = new QComboBox(this); + mZoomBox->addItems(QStringList() + << "10000.0%" << "6400.0%" << "1600.0%" << "800.0%" << "400.0%" << "200.0%" + << "100.0%" << "75.0%" << "50.0%" << "33.0%" << "25.0%" << "12.0%" << "1.0%"); + mZoomBox->setMaxCount(mZoomBox->count() + 1); + mZoomBox->setEditable(true); + mZoomBox->lineEdit()->setAlignment(Qt::AlignRight); + connect(mZoomBox, QOverload::of(&QComboBox::activated), [this](const QString ¤tText) + { + if (mZoomBox->count() == mZoomBox->maxCount()) + { + // Keep the size of the list reasonable by preventing user entries + mZoomBox->removeItem(mZoomBox->maxCount() - 1); + } + emit zoomChanged(QString(currentText).remove('%').toDouble() / 100); + }); + addPermanentWidget(mZoomBox); + + mZoomSlider = new QSlider(Qt::Horizontal, this); + mZoomSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + mZoomSlider->setRange(-20, 20); + mZoomSlider->setTickPosition(QSlider::TicksBelow); + mZoomSlider->setTickInterval(20); + connect(mZoomSlider, &QSlider::valueChanged, [this](int value) + { + emit zoomChanged(std::pow(10, value / 10.)); + }); + addPermanentWidget(mZoomSlider); +} + +void StatusBar::updateToolStatus(ToolType tool) +{ + Q_ASSERT(mEditor); + switch (tool) { + case PENCIL: + mToolLabel->setText(tr("Click to draw. Hold Ctrl and Shift to erase or Alt to select a color from the canvas.")); + break; + case ERASER: + mToolLabel->setText(tr("Click to erase.")); + break; + case SELECT: + mToolLabel->setText(tr("Click and drag to create or modify a selection. Hold Alt to modify its contents or press Backspace to clear them.")); + break; + case MOVE: + if (mEditor->getScribbleArea()->isTemporaryTool()) + { + mToolLabel->setText(tr("Click and drag to move an object.")); + } + else + { + mToolLabel->setText(tr("Click and drag to move an object. Hold Ctrl to rotate.")); + } + break; + case HAND: + mToolLabel->setText(tr("Click and drag to pan. Hold Ctrl to zoom or Alt to rotate.")); + break; + case SMUDGE: + mToolLabel->setText(tr("Click to liquefy pixels or modify a vector line. Hold Alt to smooth.")); + break; + case PEN: + mToolLabel->setText(tr("Click to draw. Hold Ctrl and Shift to erase or Alt to select a color from the canvas.")); + break; + case POLYLINE: + if (mEditor->tools()->getTool(tool)->isActive()) + { + mToolLabel->setText(tr("Click to continue the polyline. Double-click or press enter to complete the line or press Escape to discard it.")); + } + else + { + mToolLabel->setText(tr("Click to create a new polyline. Hold Ctrl and Shift to erase.")); + } + break; + case BUCKET: + mToolLabel->setText(tr("Click to fill an area with the current color. Hold Alt to select a color from the canvas.")); + break; + case EYEDROPPER: + mToolLabel->setText(tr("Click to select a color from the canvas.")); + break; + case BRUSH: + mToolLabel->setText(tr("Click to paint. Hold Ctrl and Shift to erase or Alt to select a color from the canvas.")); + break; + default: + Q_ASSERT(false); + } + + static QPixmap toolIcons[TOOL_TYPE_COUNT]{ + {":icons/new/svg/pencil_detailed.svg"}, + {":icons/new/svg/eraser_detailed.svg"}, + {":icons/new/svg/selection.svg"}, + {":icons/new/svg/arrow.svg"}, + {":icons/new/svg/hand_detailed.svg"}, + {":icons/new/svg/smudge_detailed.svg"}, + {":icons/new/svg/pen_detailed.svg"}, + {":icons/new/svg/line.svg"}, + {":icons/new/svg/bucket_detailed.svg"}, + {":icons/new/svg/eyedropper_detailed.svg"}, + {":icons/new/svg/brush_detailed.svg"} + }; + mToolIcon->setPixmap(toolIcons[tool]); + mToolIcon->setToolTip(BaseTool::TypeName(tool)); +} + +void StatusBar::updateModifiedStatus(bool modified) +{ + static QPixmap modifiedIcon(":/icons/saveas.png"), + unmodifiedIcon(":/icons/save.png"); + + if (modified) + { + mModifiedLabel->setPixmap(modifiedIcon); + mModifiedLabel->setToolTip(tr("The file has unsaved changes")); + return; + } + mModifiedLabel->setPixmap(unmodifiedIcon); + mModifiedLabel->setToolTip(tr("The file has no unsaved changes")); +} + +void StatusBar::updateLayerStatus() +{ + Q_ASSERT(mEditor); + static QIcon bitmapIcon(":/icons/layer-bitmap.png"), + vectorIcon(":/icons/layer-vector.png"), + soundIcon(":/icons/layer-sound.png"), + cameraIcon(":/icons/layer-camera.png"); + + QSignalBlocker b(mLayerBox); + mLayerBox->clear(); + for (int i = 0; i < mEditor->layers()->count(); i++) + { + Layer *layer = mEditor->layers()->getLayer(i); + mLayerBox->addItem(layer->name()); + switch (layer->type()) + { + case Layer::BITMAP: + mLayerBox->setItemIcon(i, bitmapIcon); + break; + case Layer::VECTOR: + mLayerBox->setItemIcon(i, vectorIcon); + break; + case Layer::SOUND: + mLayerBox->setItemIcon(i, soundIcon); + break; + case Layer::CAMERA: + mLayerBox->setItemIcon(i, cameraIcon); + break; + case Layer::MOVIE: + case Layer::UNDEFINED: + // no icon + break; + } + } + mLayerBox->setCurrentIndex(mEditor->layers()->currentLayerIndex()); +} + +void StatusBar::updateLayerStatus(int layer) +{ + Q_ASSERT(mEditor); + mLayerBox->setItemText(layer, mEditor->layers()->getLayer(layer)->name()); + mLayerBox->setCurrentIndex(layer); +} + +void StatusBar::updateZoomStatus() +{ + Q_ASSERT(mEditor); + + QSignalBlocker b1(mZoomBox); + mZoomBox->setCurrentText(QString("%0%").arg(mEditor->view()->scaling() * 100, 0, 'f', 1)); + + QSignalBlocker b2(mZoomSlider); + mZoomSlider->setValue(static_cast(std::round(std::log10(mEditor->view()->scaling()) * 10))); +} diff --git a/app/src/statusbar.h b/app/src/statusbar.h new file mode 100644 index 0000000000..49e3aaa417 --- /dev/null +++ b/app/src/statusbar.h @@ -0,0 +1,124 @@ +/* + +Pencil2D - Traditional Animation Software +Copyright (C) 2020 Jakob Gahde + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +*/ + +#ifndef STATUSBAR_H +#define STATUSBAR_H + +#include + +#include "pencildef.h" + +class Editor; +class QComboBox; +class QLabel; +class QSlider; + +/** + * The status bar of Pencil2D's main window. + */ +class StatusBar : public QStatusBar +{ + Q_OBJECT + +public: + /** + * Constructs a new status bar. For the status bar to work properly, you must also use setEditor() to pass an Editor instance to it. + * + * @param parent The parent object of the status bar + */ + explicit StatusBar(QWidget *parent); + + /** + * Associates an Editor instance with the status bar. + * + * This is necessary for most functionality to work. + * + * @param editor + */ + void setEditor(Editor *editor) { mEditor = editor; } + +public slots: + /** + * Updates the status bar with information about the current tool. + * + * @param tool The currently active tool + */ + void updateToolStatus(ToolType tool); + + /** + * Updates the file modification status. + * + * @param modified Whether the current file contains unsaved modifications + */ + void updateModifiedStatus(bool modified); + + /** + * Completely rebuilds the layer status for all layers. + * + * This is necessary when layers are added, removed or reordered. + * + * @see updateLayerStatus(int) + */ + void updateLayerStatus(); + + /** + * Updates the current layer. + * + * @param layer The index of the currently active layer + * + * @see updateLayerStatus() + */ + void updateLayerStatus(int layer); + + /** + * Updates the zoom level displayed in the status bar. + */ + void updateZoomStatus(); + +signals: + /** + * This signal is sent when the user selects a new active layer through the status bar. + * + * @param index The index of the newly selected layer + */ + void layerIndexChanged(int index); + + /** + * This signal is sent when the user chooses a new zoom level through the status bar. + * + * @param scale The new zoom level selected by the user, represented as a scale factor + */ + void zoomChanged(double scale); + +private: + /** The editor associated with this status bar */ + Editor *mEditor = nullptr; + + /** Label used to display the icon of the current tool */ + QLabel *mToolIcon = nullptr; + /** Label used to display a short help text for the current tool */ + QLabel *mToolLabel = nullptr; + /** Label indicating that the current file contains unsaved changes */ + QLabel *mModifiedLabel = nullptr; + /** Combo box for the active layer */ + QComboBox *mLayerBox = nullptr; + /** Combo box for choosing pre-defined or custom zoom levels */ + QComboBox *mZoomBox = nullptr; + /** Slider for adjusting the zoom level */ + QSlider *mZoomSlider = nullptr; +}; + +#endif // STATUSBAR_H diff --git a/app/ui/mainwindow2.ui b/app/ui/mainwindow2.ui index 2a5929f53c..bc7514bd60 100644 --- a/app/ui/mainwindow2.ui +++ b/app/ui/mainwindow2.ui @@ -42,8 +42,8 @@ - - + + 0 @@ -1137,6 +1137,11 @@
scribblearea.h
1 + + StatusBar + QStatusBar +
statusbar.h
+
diff --git a/core_lib/src/tool/polylinetool.cpp b/core_lib/src/tool/polylinetool.cpp index 2e3df4a54b..724f1888b7 100644 --- a/core_lib/src/tool/polylinetool.cpp +++ b/core_lib/src/tool/polylinetool.cpp @@ -24,7 +24,6 @@ GNU General Public License for more details. #include "strokemanager.h" #include "layermanager.h" #include "colormanager.h" -#include "toolmanager.h" #include "viewmanager.h" #include "pointerevent.h" #include "layervector.h" From d10113fb1e4b8838c5367ce23533663b7e86e5b0 Mon Sep 17 00:00:00 2001 From: Jakob Gahde Date: Fri, 4 Sep 2020 15:52:37 +0200 Subject: [PATCH 3/8] Modify status bar as discussed --- app/src/mainwindow2.cpp | 9 ++-- app/src/shortcutspage.cpp | 1 + app/src/statusbar.cpp | 60 ++------------------- app/src/statusbar.h | 26 --------- app/ui/mainwindow2.ui | 17 ++++-- core_lib/data/resources/kb.ini | 1 + core_lib/src/managers/preferencemanager.cpp | 4 ++ core_lib/src/managers/preferencemanager.h | 1 + core_lib/src/util/pencildef.h | 2 + 9 files changed, 31 insertions(+), 90 deletions(-) diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index 2449ab845b..c706aaab0c 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -110,8 +110,8 @@ MainWindow2::MainWindow2(QWidget* parent) : ui->scribbleArea->init(); ui->statusBar->setEditor(mEditor); - ui->statusBar->updateLayerStatus(); ui->statusBar->updateZoomStatus(); + ui->statusBar->setVisible(mEditor->preference()->isOn(SETTING::SHOW_STATUS_BAR)); mCommands = new ActionCommands(this); mCommands->setCore(mEditor); @@ -325,6 +325,8 @@ void MainWindow2::createMenus() connect(mEditor->view(), &ViewManager::viewFlipped, this, &MainWindow2::viewFlipped); PreferenceManager* prefs = mEditor->preference(); + connect(ui->actionStatusBar, &QAction::triggered, ui->statusBar, &QStatusBar::setVisible); + bindPreferenceSetting(ui->actionStatusBar, prefs, SETTING::SHOW_STATUS_BAR); bindPreferenceSetting(ui->actionGrid, prefs, SETTING::GRID); bindPreferenceSetting(ui->actionOnionPrev, prefs, SETTING::PREV_ONION); bindPreferenceSetting(ui->actionOnionNext, prefs, SETTING::NEXT_ONION); @@ -1181,6 +1183,7 @@ void MainWindow2::setupKeyboardShortcuts() ui->actionGrid->setShortcut(cmdKeySeq(CMD_GRID)); ui->actionOnionPrev->setShortcut(cmdKeySeq(CMD_ONIONSKIN_PREV)); ui->actionOnionNext->setShortcut(cmdKeySeq(CMD_ONIONSKIN_NEXT)); + ui->actionStatusBar->setShortcut(cmdKeySeq(CMD_TOGGLE_STATUS_BAR)); ui->actionPlay->setShortcut(cmdKeySeq(CMD_PLAY)); ui->actionLoop->setShortcut(cmdKeySeq(CMD_LOOP)); @@ -1443,10 +1446,6 @@ void MainWindow2::makeConnections(Editor* editor, StatusBar *statusBar) connect(editor->tools(), &ToolManager::toolChanged, statusBar, &StatusBar::updateToolStatus); connect(editor->tools()->getTool(POLYLINE), &BaseTool::isActiveChanged, statusBar, &StatusBar::updateToolStatus); - connect(editor->layers(), &LayerManager::layerCountChanged, statusBar, QOverload<>::of(&StatusBar::updateLayerStatus)); - connect(editor->layers(), &LayerManager::currentLayerChanged, statusBar, QOverload::of(&StatusBar::updateLayerStatus)); - connect(statusBar, &StatusBar::layerIndexChanged, editor->layers(), QOverload::of(&LayerManager::setCurrentLayer)); - connect(editor->view(), &ViewManager::viewChanged, statusBar, &StatusBar::updateZoomStatus); connect(statusBar, &StatusBar::zoomChanged, editor->view(), &ViewManager::scale); } diff --git a/app/src/shortcutspage.cpp b/app/src/shortcutspage.cpp index 1049c76aab..b3c09698cc 100644 --- a/app/src/shortcutspage.cpp +++ b/app/src/shortcutspage.cpp @@ -353,6 +353,7 @@ static QString getHumanReadableShortcutName(const QString& cmdName) {CMD_SAVE_AS, ShortcutsPage::tr("Save File As", "Shortcut")}, {CMD_SAVE_FILE, ShortcutsPage::tr("Save File", "Shortcut")}, {CMD_SELECT_ALL, ShortcutsPage::tr("Select All", "Shortcut")}, + {CMD_TOGGLE_STATUS_BAR, ShortcutsPage::tr("Toggle Status Bar Visibility", "Shortcut")}, {CMD_TOGGLE_COLOR_INSPECTOR, ShortcutsPage::tr("Toggle Color Inspector Window Visibility", "Shortcut")}, {CMD_TOGGLE_COLOR_LIBRARY, ShortcutsPage::tr("Toggle Color Palette Window Visibility", "Shortcut")}, {CMD_TOGGLE_COLOR_WHEEL, ShortcutsPage::tr("Toggle Color Box Window Visibility", "Shortcut")}, diff --git a/app/src/statusbar.cpp b/app/src/statusbar.cpp index 31d9a9c70a..480f497f1b 100644 --- a/app/src/statusbar.cpp +++ b/app/src/statusbar.cpp @@ -37,13 +37,10 @@ StatusBar::StatusBar(QWidget *parent) : QStatusBar(parent) addWidget(mToolLabel); mModifiedLabel = new QLabel(this); + mModifiedLabel->setPixmap(QPixmap(":/icons/save.png")); updateModifiedStatus(false); addPermanentWidget(mModifiedLabel); - mLayerBox = new QComboBox(this); - connect(mLayerBox, QOverload::of(&QComboBox::currentIndexChanged), this, &StatusBar::layerIndexChanged); - addPermanentWidget(mLayerBox); - mZoomBox = new QComboBox(this); mZoomBox->addItems(QStringList() << "10000.0%" << "6400.0%" << "1600.0%" << "800.0%" << "400.0%" << "200.0%" @@ -56,6 +53,7 @@ StatusBar::StatusBar(QWidget *parent) : QStatusBar(parent) if (mZoomBox->count() == mZoomBox->maxCount()) { // Keep the size of the list reasonable by preventing user entries + // insertPolicy is unsuitable as it prevents entering custom values at all mZoomBox->removeItem(mZoomBox->maxCount() - 1); } emit zoomChanged(QString(currentText).remove('%').toDouble() / 100); @@ -148,61 +146,13 @@ void StatusBar::updateToolStatus(ToolType tool) void StatusBar::updateModifiedStatus(bool modified) { - static QPixmap modifiedIcon(":/icons/saveas.png"), - unmodifiedIcon(":/icons/save.png"); - + mModifiedLabel->setDisabled(!modified); if (modified) { - mModifiedLabel->setPixmap(modifiedIcon); - mModifiedLabel->setToolTip(tr("The file has unsaved changes")); + mModifiedLabel->setToolTip(tr("This file has unsaved changes")); return; } - mModifiedLabel->setPixmap(unmodifiedIcon); - mModifiedLabel->setToolTip(tr("The file has no unsaved changes")); -} - -void StatusBar::updateLayerStatus() -{ - Q_ASSERT(mEditor); - static QIcon bitmapIcon(":/icons/layer-bitmap.png"), - vectorIcon(":/icons/layer-vector.png"), - soundIcon(":/icons/layer-sound.png"), - cameraIcon(":/icons/layer-camera.png"); - - QSignalBlocker b(mLayerBox); - mLayerBox->clear(); - for (int i = 0; i < mEditor->layers()->count(); i++) - { - Layer *layer = mEditor->layers()->getLayer(i); - mLayerBox->addItem(layer->name()); - switch (layer->type()) - { - case Layer::BITMAP: - mLayerBox->setItemIcon(i, bitmapIcon); - break; - case Layer::VECTOR: - mLayerBox->setItemIcon(i, vectorIcon); - break; - case Layer::SOUND: - mLayerBox->setItemIcon(i, soundIcon); - break; - case Layer::CAMERA: - mLayerBox->setItemIcon(i, cameraIcon); - break; - case Layer::MOVIE: - case Layer::UNDEFINED: - // no icon - break; - } - } - mLayerBox->setCurrentIndex(mEditor->layers()->currentLayerIndex()); -} - -void StatusBar::updateLayerStatus(int layer) -{ - Q_ASSERT(mEditor); - mLayerBox->setItemText(layer, mEditor->layers()->getLayer(layer)->name()); - mLayerBox->setCurrentIndex(layer); + mModifiedLabel->setToolTip(tr("This file has no unsaved changes")); } void StatusBar::updateZoomStatus() diff --git a/app/src/statusbar.h b/app/src/statusbar.h index 49e3aaa417..3ad82982eb 100644 --- a/app/src/statusbar.h +++ b/app/src/statusbar.h @@ -65,36 +65,12 @@ public slots: */ void updateModifiedStatus(bool modified); - /** - * Completely rebuilds the layer status for all layers. - * - * This is necessary when layers are added, removed or reordered. - * - * @see updateLayerStatus(int) - */ - void updateLayerStatus(); - - /** - * Updates the current layer. - * - * @param layer The index of the currently active layer - * - * @see updateLayerStatus() - */ - void updateLayerStatus(int layer); - /** * Updates the zoom level displayed in the status bar. */ void updateZoomStatus(); signals: - /** - * This signal is sent when the user selects a new active layer through the status bar. - * - * @param index The index of the newly selected layer - */ - void layerIndexChanged(int index); /** * This signal is sent when the user chooses a new zoom level through the status bar. @@ -113,8 +89,6 @@ public slots: QLabel *mToolLabel = nullptr; /** Label indicating that the current file contains unsaved changes */ QLabel *mModifiedLabel = nullptr; - /** Combo box for the active layer */ - QComboBox *mLayerBox = nullptr; /** Combo box for choosing pre-defined or custom zoom levels */ QComboBox *mZoomBox = nullptr; /** Slider for adjusting the zoom level */ diff --git a/app/ui/mainwindow2.ui b/app/ui/mainwindow2.ui index bc7514bd60..86ac656e03 100644 --- a/app/ui/mainwindow2.ui +++ b/app/ui/mainwindow2.ui @@ -94,7 +94,6 @@ -
@@ -173,12 +172,11 @@ - - - + + @@ -1123,6 +1121,17 @@ Reset Rotation + + + true + + + true + + + Status Bar + + diff --git a/core_lib/data/resources/kb.ini b/core_lib/data/resources/kb.ini index d121e1cdb2..32af52ff46 100644 --- a/core_lib/data/resources/kb.ini +++ b/core_lib/data/resources/kb.ini @@ -42,6 +42,7 @@ CmdPreview=Alt+P CmdGrid=G CmdOnionSkinPrevious=O CmdOnionSkinNext=Alt+O +CmdToggleStatusBar= CmdPlay=Ctrl+Return CmdLoop=Ctrl+L CmdFlipInBetween=Alt+Z diff --git a/core_lib/src/managers/preferencemanager.cpp b/core_lib/src/managers/preferencemanager.cpp index ff1e82d3c5..fb3d33512e 100644 --- a/core_lib/src/managers/preferencemanager.cpp +++ b/core_lib/src/managers/preferencemanager.cpp @@ -77,6 +77,7 @@ void PreferenceManager::loadPrefs() set(SETTING::ROTATION_INCREMENT, settings.value(SETTING_ROTATION_INCREMENT, 15).toInt()); set(SETTING::WINDOW_OPACITY, settings.value(SETTING_WINDOW_OPACITY, 0).toInt()); + set(SETTING::SHOW_STATUS_BAR, settings.value(SETTING_SHOW_STATUS_BAR, true).toBool()); set(SETTING::CURVE_SMOOTHING, settings.value(SETTING_CURVE_SMOOTHING, 20).toInt()); set(SETTING::BACKGROUND_STYLE, settings.value(SETTING_BACKGROUND_STYLE, "white").toString()); @@ -343,6 +344,9 @@ void PreferenceManager::set(SETTING option, bool value) QSettings settings(PENCIL2D, PENCIL2D); switch (option) { + case SETTING::SHOW_STATUS_BAR: + settings.setValue(SETTING_SHOW_STATUS_BAR, value); + break; case SETTING::ANTIALIAS: settings.setValue(SETTING_ANTIALIAS, value); break; diff --git a/core_lib/src/managers/preferencemanager.h b/core_lib/src/managers/preferencemanager.h index f43356b9c9..c5caf37b9e 100644 --- a/core_lib/src/managers/preferencemanager.h +++ b/core_lib/src/managers/preferencemanager.h @@ -39,6 +39,7 @@ enum class SETTING DOTTED_CURSOR, HIGH_RESOLUTION, WINDOW_OPACITY, + SHOW_STATUS_BAR, CURVE_SMOOTHING, BACKGROUND_STYLE, AUTO_SAVE, diff --git a/core_lib/src/util/pencildef.h b/core_lib/src/util/pencildef.h index 9f01776709..dda5ecd7c2 100644 --- a/core_lib/src/util/pencildef.h +++ b/core_lib/src/util/pencildef.h @@ -147,6 +147,7 @@ const static int MaxFramesBound = 9999; #define CMD_GRID "CmdGrid" #define CMD_ONIONSKIN_PREV "CmdOnionSkinPrevious" #define CMD_ONIONSKIN_NEXT "CmdOnionSkinNext" +#define CMD_TOGGLE_STATUS_BAR "CmdToggleStatusBar" #define CMD_PLAY "CmdPlay" #define CMD_LOOP "CmdLoop" #define CMD_FLIP_INBETWEEN "CmdFlipInBetween" @@ -210,6 +211,7 @@ const static int MaxFramesBound = 9999; #define SETTING_WINDOW_OPACITY "WindowOpacity" #define SETTING_WINDOW_GEOMETRY "WindowGeometry" #define SETTING_WINDOW_STATE "WindowState" +#define SETTING_SHOW_STATUS_BAR "ShowStatusBar" #define SETTING_CURVE_SMOOTHING "CurveSmoothing" #define SETTING_DISPLAY_EFFECT "RenderEffect" #define SETTING_SHORT_SCRUB "ShortScrub" From ed56e3317afe6ee3fff666efd62ea1f829d07ead Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Thu, 8 Apr 2021 12:57:36 -0600 Subject: [PATCH 4/8] Minor stylistic improvements --- app/src/mainwindow2.cpp | 5 +++-- app/src/statusbar.cpp | 6 ++++-- app/src/statusbar.h | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index c706aaab0c..cfb7f658e5 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -424,8 +424,9 @@ void MainWindow2::setOpacity(int opacity) void MainWindow2::updateSaveState() { - setWindowModified(mEditor->currentBackup() != mBackupAtSave); - ui->statusBar->updateModifiedStatus(mEditor->currentBackup() != mBackupAtSave); + const bool hasUnsavedChanges = mEditor->currentBackup() != mBackupAtSave; + setWindowModified(hasUnsavedChanges); + ui->statusBar->updateModifiedStatus(hasUnsavedChanges); } void MainWindow2::clearRecentFilesList() diff --git a/app/src/statusbar.cpp b/app/src/statusbar.cpp index 480f497f1b..306abb5320 100644 --- a/app/src/statusbar.cpp +++ b/app/src/statusbar.cpp @@ -150,9 +150,11 @@ void StatusBar::updateModifiedStatus(bool modified) if (modified) { mModifiedLabel->setToolTip(tr("This file has unsaved changes")); - return; } - mModifiedLabel->setToolTip(tr("This file has no unsaved changes")); + else + { + mModifiedLabel->setToolTip(tr("This file has no unsaved changes")); + } } void StatusBar::updateZoomStatus() diff --git a/app/src/statusbar.h b/app/src/statusbar.h index 3ad82982eb..6ab09dc085 100644 --- a/app/src/statusbar.h +++ b/app/src/statusbar.h @@ -39,7 +39,7 @@ class StatusBar : public QStatusBar * * @param parent The parent object of the status bar */ - explicit StatusBar(QWidget *parent); + explicit StatusBar(QWidget *parent = nullptr); /** * Associates an Editor instance with the status bar. From 6ec0d0d5eca425c9537ef4f42c2735b8c056b1dd Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Thu, 8 Apr 2021 13:05:19 -0600 Subject: [PATCH 5/8] Use static cast for Qt 5.6 compatibility --- app/src/statusbar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/statusbar.cpp b/app/src/statusbar.cpp index 306abb5320..07577e41a4 100644 --- a/app/src/statusbar.cpp +++ b/app/src/statusbar.cpp @@ -48,7 +48,7 @@ StatusBar::StatusBar(QWidget *parent) : QStatusBar(parent) mZoomBox->setMaxCount(mZoomBox->count() + 1); mZoomBox->setEditable(true); mZoomBox->lineEdit()->setAlignment(Qt::AlignRight); - connect(mZoomBox, QOverload::of(&QComboBox::activated), [this](const QString ¤tText) + connect(mZoomBox, static_cast(&QComboBox::activated), [this](const QString ¤tText) { if (mZoomBox->count() == mZoomBox->maxCount()) { From fd57dce3f359e3037de93c9506a99f0865175aef Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Thu, 8 Apr 2021 13:52:37 -0600 Subject: [PATCH 6/8] Add ellipsis text overflow for status bar tool tips --- app/app.pro | 6 +- app/src/elidedlabel.cpp | 132 ++++++++++++++++++++++++++++++++++++++++ app/src/elidedlabel.h | 86 ++++++++++++++++++++++++++ app/src/statusbar.cpp | 5 +- app/src/statusbar.h | 3 +- 5 files changed, 227 insertions(+), 5 deletions(-) create mode 100644 app/src/elidedlabel.cpp create mode 100644 app/src/elidedlabel.h diff --git a/app/app.pro b/app/app.pro index f1b66e3b6e..a12fa9b39f 100644 --- a/app/app.pro +++ b/app/app.pro @@ -80,7 +80,8 @@ HEADERS += \ src/presetdialog.h \ src/commandlineparser.h \ src/commandlineexporter.h \ - src/statusbar.h + src/statusbar.h \ + src/elidedlabel.h SOURCES += \ src/importlayersdialog.cpp \ @@ -124,7 +125,8 @@ SOURCES += \ src/app_util.cpp \ src/commandlineparser.cpp \ src/commandlineexporter.cpp \ - src/statusbar.cpp + src/statusbar.cpp \ + src/elidedlabel.cpp FORMS += \ ui/importimageseqpreview.ui \ diff --git a/app/src/elidedlabel.cpp b/app/src/elidedlabel.cpp new file mode 100644 index 0000000000..c27209e4d7 --- /dev/null +++ b/app/src/elidedlabel.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "elidedlabel.h" + +#include +#include +#include + + +ElidedLabel::ElidedLabel(QWidget *parent) + : QFrame(parent) + , elided(false) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); +} + +//! [0] +ElidedLabel::ElidedLabel(const QString &text, QWidget *parent) : + ElidedLabel(parent) +{ + content = text; +} +//! [0] + +//! [1] +void ElidedLabel::setText(const QString &newText) +{ + content = newText; + update(); +} +//! [1] + +QSize ElidedLabel::sizeHint() const +{ + return fontMetrics().size(0, content); +} + +//! [2] +void ElidedLabel::paintEvent(QPaintEvent *event) +{ + QFrame::paintEvent(event); + + QPainter painter(this); + QFontMetrics fontMetrics = painter.fontMetrics(); + + bool didElide = false; + int lineSpacing = fontMetrics.lineSpacing(); + int y = 0; + + QTextLayout textLayout(content, painter.font()); + textLayout.beginLayout(); + forever { + QTextLine line = textLayout.createLine(); + + if (!line.isValid()) + break; + + line.setLineWidth(width()); + int nextLineY = y + lineSpacing; + + if (height() >= nextLineY + lineSpacing) { + line.draw(&painter, QPoint(0, y)); + y = nextLineY; + //! [2] + //! [3] + } else { + QString lastLine = content.mid(line.textStart()); + QString elidedLastLine = fontMetrics.elidedText(lastLine, Qt::ElideRight, width()); + painter.drawText(QPoint(0, y + fontMetrics.ascent()), elidedLastLine); + line = textLayout.createLine(); + didElide = line.isValid(); + break; + } + } + textLayout.endLayout(); + //! [3] + + //! [4] + if (didElide != elided) { + elided = didElide; + emit elisionChanged(didElide); + } +} +//! [4] diff --git a/app/src/elidedlabel.h b/app/src/elidedlabel.h new file mode 100644 index 0000000000..36c21ff14b --- /dev/null +++ b/app/src/elidedlabel.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ELIDEDLABEL_H +#define ELIDEDLABEL_H + +#include +#include + +//! [0] +class ElidedLabel : public QFrame +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText) + Q_PROPERTY(bool isElided READ isElided) + +public: + explicit ElidedLabel(QWidget *parent = nullptr); + explicit ElidedLabel(const QString &text, QWidget *parent = nullptr); + + void setText(const QString &text); + const QString & text() const { return content; } + bool isElided() const { return elided; } + + virtual QSize sizeHint() const override; + +protected: + void paintEvent(QPaintEvent *event) override; + +signals: + void elisionChanged(bool elided); + +private: + bool elided; + QString content; +}; +//! [0] + +#endif // TEXTWRAPPINGWIDGET_H diff --git a/app/src/statusbar.cpp b/app/src/statusbar.cpp index 07577e41a4..96982d227b 100644 --- a/app/src/statusbar.cpp +++ b/app/src/statusbar.cpp @@ -20,6 +20,7 @@ GNU General Public License for more details. #include #include "editor.h" +#include "elidedlabel.h" #include "layermanager.h" #include "scribblearea.h" #include "toolmanager.h" @@ -33,8 +34,8 @@ StatusBar::StatusBar(QWidget *parent) : QStatusBar(parent) mToolIcon = new QLabel(this); addWidget(mToolIcon); - mToolLabel = new QLabel(this); - addWidget(mToolLabel); + mToolLabel = new ElidedLabel(this); + addWidget(mToolLabel, 1); mModifiedLabel = new QLabel(this); mModifiedLabel->setPixmap(QPixmap(":/icons/save.png")); diff --git a/app/src/statusbar.h b/app/src/statusbar.h index 6ab09dc085..754c76bbe4 100644 --- a/app/src/statusbar.h +++ b/app/src/statusbar.h @@ -22,6 +22,7 @@ GNU General Public License for more details. #include "pencildef.h" class Editor; +class ElidedLabel; class QComboBox; class QLabel; class QSlider; @@ -86,7 +87,7 @@ public slots: /** Label used to display the icon of the current tool */ QLabel *mToolIcon = nullptr; /** Label used to display a short help text for the current tool */ - QLabel *mToolLabel = nullptr; + ElidedLabel *mToolLabel = nullptr; /** Label indicating that the current file contains unsaved changes */ QLabel *mModifiedLabel = nullptr; /** Combo box for choosing pre-defined or custom zoom levels */ From 70a778245d03b2dc385d0280478230243adbf387 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Thu, 22 Apr 2021 15:03:18 -0600 Subject: [PATCH 7/8] Make tool label fixed-height so it is vertically aligned --- app/src/statusbar.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/statusbar.cpp b/app/src/statusbar.cpp index 96982d227b..193a5e76e2 100644 --- a/app/src/statusbar.cpp +++ b/app/src/statusbar.cpp @@ -35,6 +35,7 @@ StatusBar::StatusBar(QWidget *parent) : QStatusBar(parent) mToolIcon = new QLabel(this); addWidget(mToolIcon); mToolLabel = new ElidedLabel(this); + mToolLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); addWidget(mToolLabel, 1); mModifiedLabel = new QLabel(this); From 9e60eca1d678d5bf98221fef42f96c531b3fb83d Mon Sep 17 00:00:00 2001 From: Jakob Gahde Date: Sun, 25 Apr 2021 02:10:48 +0200 Subject: [PATCH 8/8] Localise zoom percentage --- app/src/statusbar.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/app/src/statusbar.cpp b/app/src/statusbar.cpp index 193a5e76e2..db00a9a699 100644 --- a/app/src/statusbar.cpp +++ b/app/src/statusbar.cpp @@ -43,14 +43,26 @@ StatusBar::StatusBar(QWidget *parent) : QStatusBar(parent) updateModifiedStatus(false); addPermanentWidget(mModifiedLabel); + QLocale locale; mZoomBox = new QComboBox(this); mZoomBox->addItems(QStringList() - << "10000.0%" << "6400.0%" << "1600.0%" << "800.0%" << "400.0%" << "200.0%" - << "100.0%" << "75.0%" << "50.0%" << "33.0%" << "25.0%" << "12.0%" << "1.0%"); + << locale.toString(10000., 'f', 1) + locale.percent() + << locale.toString(6400., 'f', 1) + locale.percent() + << locale.toString(1600., 'f', 1) + locale.percent() + << locale.toString(800., 'f', 1) + locale.percent() + << locale.toString(400., 'f', 1) + locale.percent() + << locale.toString(200., 'f', 1) + locale.percent() + << locale.toString(100., 'f', 1) + locale.percent() + << locale.toString(75., 'f', 1) + locale.percent() + << locale.toString(50., 'f', 1) + locale.percent() + << locale.toString(33., 'f', 1) + locale.percent() + << locale.toString(25., 'f', 1) + locale.percent() + << locale.toString(12., 'f', 1) + locale.percent() + << locale.toString(1., 'f', 1) + locale.percent()); mZoomBox->setMaxCount(mZoomBox->count() + 1); mZoomBox->setEditable(true); mZoomBox->lineEdit()->setAlignment(Qt::AlignRight); - connect(mZoomBox, static_cast(&QComboBox::activated), [this](const QString ¤tText) + connect(mZoomBox, static_cast(&QComboBox::activated), [=](const QString ¤tText) { if (mZoomBox->count() == mZoomBox->maxCount()) { @@ -58,7 +70,7 @@ StatusBar::StatusBar(QWidget *parent) : QStatusBar(parent) // insertPolicy is unsuitable as it prevents entering custom values at all mZoomBox->removeItem(mZoomBox->maxCount() - 1); } - emit zoomChanged(QString(currentText).remove('%').toDouble() / 100); + emit zoomChanged(locale.toDouble(QString(currentText).remove(locale.percent())) / 100); }); addPermanentWidget(mZoomBox); @@ -163,8 +175,9 @@ void StatusBar::updateZoomStatus() { Q_ASSERT(mEditor); + QLocale locale; QSignalBlocker b1(mZoomBox); - mZoomBox->setCurrentText(QString("%0%").arg(mEditor->view()->scaling() * 100, 0, 'f', 1)); + mZoomBox->setCurrentText(locale.toString(mEditor->view()->scaling() * 100, 'f', 1) + locale.percent()); QSignalBlocker b2(mZoomSlider); mZoomSlider->setValue(static_cast(std::round(std::log10(mEditor->view()->scaling()) * 10)));