Stepped keyboard zoom and a steady tab strip (12.9b)
This commit is contained in:
1 parent
fdb62978c5
commit
9ac3b1b81c
17 files changed
+533
-38
No files matched your search
@@ -129,8 +129,13 @@ CompositorMenus::CompositorMenus(ProjectWorkspace &workspace, QMenuBar &bar, QWi
|
||||
QMenu *view = bar.addMenu(QStringLiteral("&View"));
|
||||
add(view, QStringLiteral("fit"), QStringLiteral("Fit Canvas"), QKeySequence(Qt::CTRL | Qt::Key_0), [this] { session().fit(); });
|
||||
add(view, QStringLiteral("actualPixels"), QStringLiteral("Actual Pixels"), QKeySequence(Qt::CTRL | Qt::Key_1), [this] { session().zoom(1); });
|
||||
add(view, QStringLiteral("zoomIn"), QStringLiteral("Zoom In"), QKeySequence(Qt::CTRL | Qt::Key_Equal), [this] { session().zoom(session().viewport.zoom() * 1.25); });
|
||||
add(view, QStringLiteral("zoomOut"), QStringLiteral("Zoom Out"), QKeySequence(Qt::CTRL | Qt::Key_Minus), [this] { session().zoom(session().viewport.zoom() / 1.25); });
|
||||
// Swift's stops; open text keeps the keys, as NSText does.
|
||||
const auto zoomBy = [this](int step) {
|
||||
if (!m_field && !(m_canvas && session().textDraft()))
|
||||
session().zoomKeyboard(step);
|
||||
};
|
||||
add(view, QStringLiteral("zoomIn"), QStringLiteral("Zoom In"), QKeySequence(Qt::CTRL | Qt::Key_Equal), [zoomBy] { zoomBy(1); });
|
||||
add(view, QStringLiteral("zoomOut"), QStringLiteral("Zoom Out"), QKeySequence(Qt::CTRL | Qt::Key_Minus), [zoomBy] { zoomBy(-1); });
|
||||
add(view, QStringLiteral("pixelGrid"), QStringLiteral("Pixel Grid (800% and above)"), QKeySequence(), [this] { session().setShowsPixelGrid(!session().showsPixelGrid()); })
|
||||
->setCheckable(true);
|
||||
add(view, QStringLiteral("snap"), QStringLiteral("Snap"), QKeySequence(), [this] { session().setSnappingEnabled(!session().snappingEnabled()); })
|
||||
|
||||
+49
-13
@@ -4,9 +4,13 @@
|
||||
#include <QDragEnterEvent>
|
||||
#include <QDropEvent>
|
||||
#include <QEvent>
|
||||
#include <QFontMetricsF>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPainter>
|
||||
#include <QScrollBar>
|
||||
#include <QStyleOptionToolButton>
|
||||
#include <QStylePainter>
|
||||
#include <QTimer>
|
||||
|
||||
namespace {
|
||||
QFont tabFont(bool active)
|
||||
@@ -16,17 +20,40 @@ QFont tabFont(bool active)
|
||||
font.setWeight(active ? QFont::DemiBold : QFont::Medium);
|
||||
return font;
|
||||
}
|
||||
|
||||
// Swift's leading label: text from the left, 8 kept after.
|
||||
class TabTitle : public QToolButton {
|
||||
public:
|
||||
using QToolButton::QToolButton;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *) override
|
||||
{
|
||||
QStylePainter painter(this);
|
||||
QStyleOptionToolButton option;
|
||||
initStyleOption(&option);
|
||||
option.text.clear();
|
||||
painter.drawComplexControl(QStyle::CC_ToolButton, option);
|
||||
painter.setPen(palette().color(isEnabled() ? QPalette::Active : QPalette::Disabled, QPalette::ButtonText));
|
||||
painter.drawText(rect().adjusted(0, 0, -8, 0), Qt::AlignLeft | Qt::AlignVCenter, text());
|
||||
}
|
||||
};
|
||||
|
||||
// Swift's projectTabLabelWidth: the title's own width, 35 to 155.
|
||||
int labelWidth(const QString &title, bool active, bool modified)
|
||||
{
|
||||
const double titleWidth = QFontMetricsF(tabFont(active)).horizontalAdvance(title);
|
||||
return int(std::min(155.0, std::max(35.0, std::ceil(titleWidth) + (modified ? 10 : 0))));
|
||||
}
|
||||
}
|
||||
|
||||
ProjectTabButton::ProjectTabButton(ProjectWorkspace &workspace, std::shared_ptr<ProjectTab> tab, QWidget *parent)
|
||||
: QWidget(parent), tab(std::move(tab)), m_workspace(workspace), m_select(new QToolButton(this)), m_close(new QToolButton(this))
|
||||
: QWidget(parent), tab(std::move(tab)), m_workspace(workspace), m_select(new TabTitle(this)), m_close(new QToolButton(this))
|
||||
{
|
||||
// 28 high: the strip's 34 less its margins.
|
||||
m_select->setObjectName(QStringLiteral("selectTab"));
|
||||
m_select->setAutoRaise(true);
|
||||
m_select->setFocusPolicy(Qt::NoFocus);
|
||||
m_select->setMinimumWidth(35);
|
||||
m_select->setMaximumWidth(155);
|
||||
m_close->setObjectName(QStringLiteral("closeTab"));
|
||||
m_close->setAutoRaise(true);
|
||||
m_close->setFocusPolicy(Qt::NoFocus);
|
||||
@@ -48,9 +75,15 @@ ProjectTabButton::ProjectTabButton(ProjectWorkspace &workspace, std::shared_ptr<
|
||||
void ProjectTabButton::synchronize()
|
||||
{
|
||||
const bool active = m_workspace.selectedID() == tab->id;
|
||||
// Swift's dot for unsaved changes stands before the title.
|
||||
m_select->setText((tab->session.isModified() ? QStringLiteral("● ") : QString()) + tab->title());
|
||||
// The unsaved dot leads; fixed widths move later tabs only.
|
||||
const bool modified = tab->session.isModified();
|
||||
const int label = labelWidth(tab->title(), active, modified);
|
||||
const QString dot = modified ? QStringLiteral("● ") : QString();
|
||||
const QFontMetrics metrics(tabFont(active));
|
||||
m_select->setText(dot + metrics.elidedText(tab->title(), Qt::ElideRight, label - (modified ? 10 : 0)));
|
||||
m_select->setFont(tabFont(active));
|
||||
// Swift's trailing 8 inside; a character dot outgrows Swift's 10.
|
||||
m_select->setFixedWidth(label + 8 + (modified ? metrics.horizontalAdvance(dot) - 10 : 0));
|
||||
m_select->setToolTip(tab->title());
|
||||
m_select->setEnabled(m_workspace.canSwitch() || active);
|
||||
m_close->setToolTip(QStringLiteral("Close %1").arg(tab->title()));
|
||||
@@ -265,18 +298,21 @@ void ProjectTabStrip::synchronize()
|
||||
bool ProjectTabStrip::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
// A title changed size: the row takes its new width.
|
||||
if (event->type() == QEvent::LayoutRequest) {
|
||||
if (event->type() == QEvent::LayoutRequest)
|
||||
m_row->resize(m_row->sizeHint());
|
||||
showFront();
|
||||
}
|
||||
return QScrollArea::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
// The front tab scrolls into view.
|
||||
// Only a new front tab scrolls into view.
|
||||
void ProjectTabStrip::showFront()
|
||||
{
|
||||
for (ProjectTabButton *button : buttons()) {
|
||||
if (button->tab->id == m_workspace.selectedID())
|
||||
ensureWidgetVisible(button, 0, 0);
|
||||
}
|
||||
if (std::exchange(m_shownFront, m_workspace.selectedID()) == m_workspace.selectedID())
|
||||
return;
|
||||
// Posted, as Swift's: the row's layout request runs first.
|
||||
QTimer::singleShot(0, this, [this] {
|
||||
for (ProjectTabButton *button : buttons()) {
|
||||
if (button->tab->id == m_workspace.selectedID())
|
||||
ensureWidgetVisible(button, 0, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -70,4 +70,6 @@ private:
|
||||
|
||||
ProjectWorkspace &m_workspace;
|
||||
QWidget *const m_row;
|
||||
// Swift's lastSelectedID: only a new front tab scrolls.
|
||||
std::optional<QUuid> m_shownFront;
|
||||
};
|
||||
@@ -41,14 +41,8 @@ ProjectWorkspaceView::ProjectWorkspaceView(ProjectWorkspace &workspace, QWidget
|
||||
connect(m_newCanvas, &QAction::triggered, this, [this] { m_workspace.current().controller.newCanvas(); });
|
||||
connect(m_fit, &QAction::triggered, this, [this] { m_workspace.current().session.fit(); });
|
||||
connect(m_actualPixels, &QAction::triggered, this, [this] { m_workspace.current().session.zoom(1); });
|
||||
connect(m_zoomIn, &QAction::triggered, this, [this] {
|
||||
EditorSession &session = m_workspace.current().session;
|
||||
session.zoom(session.viewport.zoom() * 1.25);
|
||||
});
|
||||
connect(m_zoomOut, &QAction::triggered, this, [this] {
|
||||
EditorSession &session = m_workspace.current().session;
|
||||
session.zoom(session.viewport.zoom() / 1.25);
|
||||
});
|
||||
connect(m_zoomIn, &QAction::triggered, this, [this] { m_workspace.current().session.zoomKeyboard(1); });
|
||||
connect(m_zoomOut, &QAction::triggered, this, [this] { m_workspace.current().session.zoomKeyboard(-1); });
|
||||
connect(&m_workspace, &ProjectWorkspace::changed, this, &ProjectWorkspaceView::synchronize);
|
||||
synchronize();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user