diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 99ee96e6..1ddbe264 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -354,18 +354,35 @@ void Configuration::loadDarkStylesheet() } } -const QFont Configuration::getFont() const +const QFont Configuration::getBaseFont() const { QFont font = s.value("font", QFont("Inconsolata", 11)).value(); return font; } +const QFont Configuration::getFont() const +{ + QFont font = getBaseFont(); + font.setPointSizeF(font.pointSizeF() * getZoomFactor()); + return font; +} + void Configuration::setFont(const QFont &font) { s.setValue("font", font); emit fontsUpdated(); } +qreal Configuration::getZoomFactor() const { + qreal fontZoom = s.value("zoomFactor", 1.0).value(); + return qMax(fontZoom, 0.1); +} + +void Configuration::setZoomFactor(qreal zoom) { + s.setValue("zoomFactor", qMax(zoom, 0.1)); + emit fontsUpdated(); +} + QString Configuration::getLastThemeOf(const CutterInterfaceTheme &currInterfaceTheme) const { return s.value("lastThemeOf." + currInterfaceTheme.name, diff --git a/src/common/Configuration.h b/src/common/Configuration.h index 47ab2883..f2d59470 100644 --- a/src/common/Configuration.h +++ b/src/common/Configuration.h @@ -75,8 +75,22 @@ public: QStringList getAvailableTranslations(); // Fonts + + /** + * @brief Gets the configured font set by the font selection box + * @return the configured font + */ + const QFont getBaseFont() const; + + /** + * @brief Gets the configured font with the point size adjusted by the configured zoom + * level (minimum of 10%) + * @return the configured font size adjusted by zoom level + */ const QFont getFont() const; void setFont(const QFont &font); + qreal getZoomFactor() const; + void setZoomFactor(qreal zoom); // Colors bool windowColorIsDark(); diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index e4160a9b..d80e509a 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -160,6 +160,10 @@ void MainWindow::initUI() QShortcut *refresh_shortcut = new QShortcut(QKeySequence(QKeySequence::Refresh), this); connect(refresh_shortcut, SIGNAL(activated()), this, SLOT(refreshAll())); + connect(ui->actionZoomIn, SIGNAL(triggered()), this, SLOT(onZoomIn())); + connect(ui->actionZoomOut, SIGNAL(triggered()), this, SLOT(onZoomOut())); + connect(ui->actionZoomReset, SIGNAL(triggered()), this, SLOT(onZoomReset())); + connect(core, SIGNAL(projectSaved(bool, const QString &)), this, SLOT(projectSaved(bool, const QString &))); @@ -1509,3 +1513,18 @@ void MainWindow::chooseThemeIcons() static_cast(obj)->setIcon(icon); }); } + +void MainWindow::onZoomIn() +{ + Config()->setZoomFactor(Config()->getZoomFactor() + 0.1); +} + +void MainWindow::onZoomOut() +{ + Config()->setZoomFactor(Config()->getZoomFactor() - 0.1); +} + +void MainWindow::onZoomReset() +{ + Config()->setZoomFactor(1.0); +} diff --git a/src/core/MainWindow.h b/src/core/MainWindow.h index 92c0ac9f..ea5e5b51 100644 --- a/src/core/MainWindow.h +++ b/src/core/MainWindow.h @@ -201,6 +201,10 @@ private slots: void changeDefinedView(); void chooseThemeIcons(); + void onZoomIn(); + void onZoomOut(); + void onZoomReset(); + private: CutterCore *core; diff --git a/src/core/MainWindow.ui b/src/core/MainWindow.ui index 7c6cbf16..f8cabced 100644 --- a/src/core/MainWindow.ui +++ b/src/core/MainWindow.ui @@ -81,6 +81,15 @@ false + + + Zoom + + + + + + @@ -89,6 +98,8 @@ + + @@ -1072,6 +1083,39 @@ Grouped dock dragging + + + Zoom In + + + Ctrl++ + + + Qt::ApplicationShortcut + + + + + Zoom Out + + + Ctrl+- + + + Qt::ApplicationShortcut + + + + + Reset + + + Ctrl+= + + + Qt::ApplicationShortcut + + diff --git a/src/dialogs/NewFileDialog.cpp b/src/dialogs/NewFileDialog.cpp index 78415eaf..56d60155 100644 --- a/src/dialogs/NewFileDialog.cpp +++ b/src/dialogs/NewFileDialog.cpp @@ -43,7 +43,7 @@ static QIcon getIconFor(const QString &str, int pos) pixPaint.setBrush(getColorFor(pos)); pixPaint.drawEllipse(1, 1, w - 2, h - 2); pixPaint.setPen(Qt::white); - QFont font = Config()->getFont(); + QFont font = Config()->getBaseFont(); font.setBold(true); font.setPointSize(18); pixPaint.setFont(font); diff --git a/src/dialogs/TypesInteractionDialog.cpp b/src/dialogs/TypesInteractionDialog.cpp index 1d36f5e4..5ff70837 100644 --- a/src/dialogs/TypesInteractionDialog.cpp +++ b/src/dialogs/TypesInteractionDialog.cpp @@ -14,7 +14,7 @@ TypesInteractionDialog::TypesInteractionDialog(QWidget *parent, bool readOnly) : ui(new Ui::TypesInteractionDialog) { ui->setupUi(this); - QFont font = Config()->getFont(); + QFont font = Config()->getBaseFont(); ui->plainTextEdit->setFont(font); ui->plainTextEdit->setPlainText(""); #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) diff --git a/src/dialogs/XrefsDialog.cpp b/src/dialogs/XrefsDialog.cpp index 89332e58..ff0e5f02 100644 --- a/src/dialogs/XrefsDialog.cpp +++ b/src/dialogs/XrefsDialog.cpp @@ -68,7 +68,7 @@ QString XrefsDialog::normalizeAddr(const QString &addr) const void XrefsDialog::setupPreviewFont() { - ui->previewTextEdit->setFont(Config()->getFont()); + ui->previewTextEdit->setFont(Config()->getBaseFont()); } void XrefsDialog::setupPreviewColors() diff --git a/src/dialogs/preferences/AppearanceOptionsWidget.cpp b/src/dialogs/preferences/AppearanceOptionsWidget.cpp index ff4d9cd8..0391ca50 100644 --- a/src/dialogs/preferences/AppearanceOptionsWidget.cpp +++ b/src/dialogs/preferences/AppearanceOptionsWidget.cpp @@ -11,6 +11,7 @@ #include #include +#include #include "PreferencesDialog.h" #include "AppearanceOptionsWidget.h" #include "ui_AppearanceOptionsWidget.h" @@ -62,13 +63,18 @@ AppearanceOptionsWidget::AppearanceOptionsWidget(PreferencesDialog *dialog) connect(ui->colorComboBox, &QComboBox::currentTextChanged, this, &AppearanceOptionsWidget::updateModificationButtons); + + connect(ui->fontZoomBox, + static_cast(&QSpinBox::valueChanged), + this, + &AppearanceOptionsWidget::onFontZoomBoxValueChanged); } AppearanceOptionsWidget::~AppearanceOptionsWidget() {} void AppearanceOptionsWidget::updateFontFromConfig() { - QFont currentFont = Config()->getFont(); + QFont currentFont = Config()->getBaseFont(); ui->fontSelectionLabel->setText(currentFont.toString()); } @@ -91,9 +97,16 @@ void AppearanceOptionsWidget::updateThemeFromConfig(bool interfaceThemeChanged) updateModificationButtons(ui->colorComboBox->currentText()); } +void AppearanceOptionsWidget::onFontZoomBoxValueChanged(int zoom) +{ + qreal zoomFactor = zoom / 100.0; + Config()->setZoomFactor(zoomFactor); +} + + void AppearanceOptionsWidget::on_fontSelectionButton_clicked() { - QFont currentFont = Config()->getFont(); + QFont currentFont = Config()->getBaseFont(); bool ok; QFont newFont = QFontDialog::getFont(&ok, currentFont, this, QString(), QFontDialog::DontUseNativeDialog); diff --git a/src/dialogs/preferences/AppearanceOptionsWidget.h b/src/dialogs/preferences/AppearanceOptionsWidget.h index 8c1ed682..f0a6bae9 100644 --- a/src/dialogs/preferences/AppearanceOptionsWidget.h +++ b/src/dialogs/preferences/AppearanceOptionsWidget.h @@ -30,6 +30,7 @@ private slots: void updateThemeFromConfig(bool interfaceThemeChanged = true); void on_fontSelectionButton_clicked(); + void onFontZoomBoxValueChanged(int zoom); void on_themeComboBox_currentIndexChanged(int index); void on_copyButton_clicked(); void on_deleteButton_clicked(); diff --git a/src/dialogs/preferences/AppearanceOptionsWidget.ui b/src/dialogs/preferences/AppearanceOptionsWidget.ui index 060c20a9..ebc86ed0 100644 --- a/src/dialogs/preferences/AppearanceOptionsWidget.ui +++ b/src/dialogs/preferences/AppearanceOptionsWidget.ui @@ -57,6 +57,57 @@ + + + + Qt::Horizontal + + + + 30 + 20 + + + + + + + + Zoom + + + + + + + false + + + true + + + QAbstractSpinBox::PlusMinus + + + false + + + % + + + 10 + + + 3000 + + + 10 + + + 100 + + + diff --git a/src/widgets/CutterDockWidget.cpp b/src/widgets/CutterDockWidget.cpp index 23ca259e..c617a76e 100644 --- a/src/widgets/CutterDockWidget.cpp +++ b/src/widgets/CutterDockWidget.cpp @@ -3,6 +3,7 @@ #include #include +#include CutterDockWidget::CutterDockWidget(MainWindow *parent, QAction *action) : QDockWidget(parent), @@ -97,4 +98,3 @@ QString CutterDockWidget::getDockNumber() } return QString(); } - diff --git a/src/widgets/DecompilerWidget.cpp b/src/widgets/DecompilerWidget.cpp index fb1701ed..418a4cfa 100644 --- a/src/widgets/DecompilerWidget.cpp +++ b/src/widgets/DecompilerWidget.cpp @@ -26,7 +26,7 @@ DecompilerWidget::DecompilerWidget(MainWindow *main, QAction *action) : setupFonts(); colorsUpdatedSlot(); - connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdated())); + connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdatedSlot())); connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(colorsUpdatedSlot())); decompiledFunctionAddr = RVA_INVALID; @@ -249,8 +249,7 @@ void DecompilerWidget::updateCursorPosition() void DecompilerWidget::setupFonts() { - QFont font = Config()->getFont(); - ui->textEdit->setFont(font); + ui->textEdit->setFont(Config()->getFont()); } void DecompilerWidget::updateSelection() @@ -275,7 +274,7 @@ QString DecompilerWidget::getWindowTitle() const return tr("Decompiler"); } -void DecompilerWidget::fontsUpdated() +void DecompilerWidget::fontsUpdatedSlot() { setupFonts(); } diff --git a/src/widgets/DecompilerWidget.h b/src/widgets/DecompilerWidget.h index c952039a..dd0679b6 100644 --- a/src/widgets/DecompilerWidget.h +++ b/src/widgets/DecompilerWidget.h @@ -30,7 +30,7 @@ public slots: void showDisasContextMenu(const QPoint &pt); private slots: - void fontsUpdated(); + void fontsUpdatedSlot(); void colorsUpdatedSlot(); void refreshDecompiler(); void decompilerSelected(); diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index aab6c2aa..42903806 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -2,6 +2,7 @@ #include "DisassemblerGraphView.h" #include "common/CutterSeekable.h" #include "core/Cutter.h" +#include "core/MainWindow.h" #include "common/Colors.h" #include "common/Configuration.h" #include "common/CachedFontMetrics.h" @@ -32,6 +33,10 @@ #include +const int DisassemblerGraphView::KEY_ZOOM_IN = Qt::Key_Plus + Qt::ControlModifier; +const int DisassemblerGraphView::KEY_ZOOM_OUT = Qt::Key_Minus + Qt::ControlModifier; +const int DisassemblerGraphView::KEY_ZOOM_RESET = Qt::Key_Equal + Qt::ControlModifier; + DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable *seekable, MainWindow *mainWindow, QList additionalMenuActions) : GraphView(parent), @@ -66,19 +71,6 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable *se shortcut_escape->setContext(Qt::WidgetShortcut); connect(shortcut_escape, SIGNAL(activated()), seekable, SLOT(seekPrev())); - // Zoom shortcuts - QShortcut *shortcut_zoom_in = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Plus), this); - shortcut_zoom_in->setContext(Qt::WidgetShortcut); - connect(shortcut_zoom_in, &QShortcut::activated, this, std::bind(&DisassemblerGraphView::zoom, this, - QPointF(0.5, 0.5), 1)); - QShortcut *shortcut_zoom_out = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Minus), this); - shortcut_zoom_out->setContext(Qt::WidgetShortcut); - connect(shortcut_zoom_out, &QShortcut::activated, this, std::bind(&DisassemblerGraphView::zoom, - this, QPointF(0.5, 0.5), -1)); - QShortcut *shortcut_zoom_reset = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Equal), this); - shortcut_zoom_reset->setContext(Qt::WidgetShortcut); - connect(shortcut_zoom_reset, SIGNAL(activated()), this, SLOT(zoomReset())); - // Branch shortcuts QShortcut *shortcut_take_true = new QShortcut(QKeySequence(Qt::Key_T), this); shortcut_take_true->setContext(Qt::WidgetShortcut); @@ -95,9 +87,6 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable *se shortcut_prev_instr->setContext(Qt::WidgetShortcut); connect(shortcut_prev_instr, SIGNAL(activated()), this, SLOT(prevInstr())); shortcuts.append(shortcut_escape); - shortcuts.append(shortcut_zoom_in); - shortcuts.append(shortcut_zoom_out); - shortcuts.append(shortcut_zoom_reset); shortcuts.append(shortcut_next_instr); shortcuts.append(shortcut_prev_instr); @@ -412,7 +401,7 @@ void DisassemblerGraphView::cleanupEdges() void DisassemblerGraphView::initFont() { - setFont(Config()->getFont()); + setFont(Config()->getBaseFont()); QFontMetricsF metrics(font()); baseline = int(metrics.ascent()); charWidth = metrics.width('X'); @@ -429,7 +418,7 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block, p.setPen(Qt::black); p.setBrush(Qt::gray); - p.setFont(Config()->getFont()); + p.setFont(Config()->getBaseFont()); p.drawRect(blockRect); breakpoints = Core()->getBreakpointsAddresses(); @@ -805,6 +794,16 @@ void DisassemblerGraphView::zoom(QPointF mouseRelativePos, double velocity) emit viewZoomed(); } +void DisassemblerGraphView::zoomIn() +{ + zoom(QPointF(0.5, 0.5), 1); +} + +void DisassemblerGraphView::zoomOut() +{ + zoom(QPointF(0.5, 0.5), -1); +} + void DisassemblerGraphView::zoomReset() { setViewScale(1.0); @@ -1034,6 +1033,40 @@ void DisassemblerGraphView::blockTransitionedTo(GraphView::GraphBlock *to) seekLocal(to->entry); } +bool DisassemblerGraphView::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::ShortcutOverride: { + QKeyEvent *keyEvent = static_cast(event); + int key = keyEvent->key() + keyEvent->modifiers(); + if (key == KEY_ZOOM_OUT || key == KEY_ZOOM_RESET + || key == KEY_ZOOM_IN || (key == (KEY_ZOOM_IN | Qt::ShiftModifier))) { + event->accept(); + return true; + } + break; + } + case QEvent::KeyPress: { + QKeyEvent *keyEvent = static_cast(event); + int key = keyEvent->key() + keyEvent->modifiers(); + if (key == KEY_ZOOM_IN || (key == (KEY_ZOOM_IN | Qt::ShiftModifier))) { + zoomIn(); + return true; + } else if (key == KEY_ZOOM_OUT) { + zoomOut(); + return true; + } else if (key == KEY_ZOOM_RESET) { + zoomReset(); + return true; + } + break; + } + default: + break; + } + return GraphView::event(event); +} + Q_DECLARE_METATYPE(DisassemblerGraphView::GraphExportType); diff --git a/src/widgets/DisassemblerGraphView.h b/src/widgets/DisassemblerGraphView.h index 2be8fd6f..2951640d 100644 --- a/src/widgets/DisassemblerGraphView.h +++ b/src/widgets/DisassemblerGraphView.h @@ -101,6 +101,7 @@ public: GraphView::GraphBlock *to, bool interactive) override; virtual void blockTransitionedTo(GraphView::GraphBlock *to) override; + virtual bool event(QEvent *event) override; void loadCurrentGraph(); QString windowTitle; @@ -130,6 +131,8 @@ public slots: void fontsUpdatedSlot(); void onSeekChanged(RVA addr); void zoom(QPointF mouseRelativePos, double velocity); + void zoomIn(); + void zoomOut(); void zoomReset(); void takeTrue(); @@ -222,6 +225,10 @@ private: QAction actionUnhighlight; QLabel *emptyText = nullptr; + + static const int KEY_ZOOM_IN; + static const int KEY_ZOOM_OUT; + static const int KEY_ZOOM_RESET; signals: void viewRefreshed(); void viewZoomed(); diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index 80ee98e0..b5e042c5 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -206,11 +206,6 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action) ADD_ACTION(QKeySequence::MoveToPreviousPage, Qt::WidgetWithChildrenShortcut, [this]() { moveCursorRelative(true, true); }) - - // Zoom shortcuts - ADD_ACTION(QKeySequence(Qt::CTRL + Qt::Key_Plus), Qt::WidgetWithChildrenShortcut, &DisassemblyWidget::zoomIn) - ADD_ACTION(QKeySequence(Qt::CTRL + Qt::Key_Minus), Qt::WidgetWithChildrenShortcut, &DisassemblyWidget::zoomOut) - ADD_ACTION(QKeySequence(Qt::CTRL + Qt::Key_Equal), Qt::WidgetWithChildrenShortcut, &DisassemblyWidget::zoomReset) #undef ADD_ACTION } @@ -373,27 +368,6 @@ bool DisassemblyWidget::updateMaxLines() return false; } -void DisassemblyWidget::zoomIn() -{ - mDisasTextEdit->zoomIn(); - updateMaxLines(); - leftPanel->update(); -} - -void DisassemblyWidget::zoomOut() -{ - mDisasTextEdit->zoomOut(); - updateMaxLines(); - leftPanel->update(); -} - -void DisassemblyWidget::zoomReset() -{ - setupFonts(); - updateMaxLines(); - leftPanel->update(); -} - void DisassemblyWidget::highlightCurrentLine() { QList extraSelections; diff --git a/src/widgets/DisassemblyWidget.h b/src/widgets/DisassemblyWidget.h index 504d6efc..455a772c 100644 --- a/src/widgets/DisassemblyWidget.h +++ b/src/widgets/DisassemblyWidget.h @@ -46,10 +46,6 @@ protected slots: void cursorPositionChanged(); - void zoomIn(); - void zoomOut(); - void zoomReset(); - protected: DisassemblyContextMenu *mCtxMenu; DisassemblyScrollArea *mDisasScrollArea; diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index 349fbbc9..41effa61 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -40,7 +40,8 @@ HexWidget::HexWidget(QWidget *parent) : connect(horizontalScrollBar(), &QScrollBar::valueChanged, this, [this]() { viewport()->update(); }); connect(Config(), &Configuration::colorsUpdated, this, &HexWidget::updateColors); - connect(Config(), &Configuration::fontsUpdated, this, [this]() { setMonospaceFont(Config()->getFont()); }); + connect(Config(), &Configuration::fontsUpdated, this, [this]() { setMonospaceFont( + Config()->getFont()); }); auto sizeActionGroup = new QActionGroup(this); for (int i = 1; i <= 8; i *= 2) { diff --git a/src/widgets/SearchWidget.cpp b/src/widgets/SearchWidget.cpp index 028fe5d5..013bc573 100644 --- a/src/widgets/SearchWidget.cpp +++ b/src/widgets/SearchWidget.cpp @@ -78,7 +78,7 @@ QVariant SearchModel::data(const QModelIndex &index, int role) const previewContent = Core()->getHexdumpPreview(exp.offset, kMaxTooltipHexdumpBytes); } - const QFont &fnt = Config()->getFont(); + const QFont &fnt = Config()->getBaseFont(); QFontMetrics fm{ fnt }; QString toolTipContent = QString("
")