Skip to content

Commit

Permalink
Replace hold shift to arrange with arrange mode
Browse files Browse the repository at this point in the history
It replaces all dock title widgets with a bar that tells you to drag it
to arrange and a button to finish arranging.
  • Loading branch information
askmeaboutlo0m committed Nov 27, 2024
1 parent b89d198 commit 4140017
Show file tree
Hide file tree
Showing 12 changed files with 100 additions and 78 deletions.
1 change: 1 addition & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Unreleased Version 2.2.2-pre
* Feature: Warn when an action will close a relevant window on Android and in the browser. Thanks 3rd_EFNO for suggesting.
* Fix: When enabling a dock and it gets put into a tab, that tab now gets activated.
* Feature: Show icons on dock tabs by default, rather than text that gets squashed. In desktop mode, this can be toggled via View > Docks > Show Icons on Tabs.
* Feature: Replace "hold shift to arrange" with View > Docks > Arrange Docks, which doesn't require a keyboard. Thanks 3rd_EFNO for suggesting.

2024-11-06 Version 2.2.2-beta.4
* Fix: Solve rendering glitches with selection outlines that happen on some systems. Thanks xxxx for reporting.
Expand Down
43 changes: 43 additions & 0 deletions src/desktop/docks/dockbase.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "desktop/docks/dockbase.h"
#include "desktop/widgets/groupedtoolbutton.h"
#include <QAction>
#include <QHBoxLayout>
#include <QLabel>
#include <QMainWindow>
#include <QTabBar>
#include <QVariant>
Expand Down Expand Up @@ -52,6 +55,46 @@ void DockBase::makeTabCurrent(bool toggled)
}
}

QWidget *DockBase::actualTitleBarWidget() const
{
return m_originalTitleBarWidget ? m_originalTitleBarWidget
: titleBarWidget();
}

void DockBase::setArrangeMode(bool arrangeMode)
{
if(arrangeMode && !m_originalTitleBarWidget) {
m_originalTitleBarWidget = titleBarWidget();
QWidget *arrangeWidget = new QWidget;
QHBoxLayout *arrangeLayout = new QHBoxLayout(arrangeWidget);
arrangeLayout->setSpacing(0);
arrangeLayout->setContentsMargins(2, 2, 1, 2);

QLabel *arrangeLabel = new QLabel(tr("Drag here to arrange"));
arrangeLabel->setAlignment(Qt::AlignCenter);
arrangeLayout->addWidget(arrangeLabel, 1);

widgets::GroupedToolButton *arrangeButton =
new widgets::GroupedToolButton(
widgets::GroupedToolButton::NotGrouped);
arrangeButton->setIcon(QIcon::fromTheme("checkbox"));
arrangeButton->setToolTip(tr("Finish arranging"));
arrangeLayout->addWidget(arrangeButton);
connect(
arrangeButton, &widgets::GroupedToolButton::clicked, this,
&DockBase::arrangingFinished);

setTitleBarWidget(arrangeWidget);
} else if(!arrangeMode && m_originalTitleBarWidget) {
QWidget *arrangeWidget = titleBarWidget();
setTitleBarWidget(m_originalTitleBarWidget);
m_originalTitleBarWidget = nullptr;
if(arrangeWidget) {
arrangeWidget->deleteLater();
}
}
}

void DockBase::showEvent(QShowEvent *event)
{
QDockWidget::showEvent(event);
Expand Down
5 changes: 5 additions & 0 deletions src/desktop/docks/dockbase.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ class DockBase : public QDockWidget {

void makeTabCurrent(bool toggled);

QWidget *actualTitleBarWidget() const;
void setArrangeMode(bool arrangeMode);

signals:
void arrangingFinished();
void tabUpdateRequested();

protected:
Expand All @@ -42,6 +46,7 @@ class DockBase : public QDockWidget {
QString m_fullTitle;
QString m_shortTitle;
QIcon m_tabIcon;
QWidget *m_originalTitleBarWidget = nullptr;
bool m_showIcons = false;
};

Expand Down
7 changes: 4 additions & 3 deletions src/desktop/docks/layerlistdock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ LayerList::LayerList(QWidget *parent)
this, &LayerList::opacityChanged);
QHBoxLayout *opacitySliderLayout = new QHBoxLayout;
opacitySliderLayout->setContentsMargins(
titleBarWidget()->layout()->contentsMargins());
titlebar->layout()->contentsMargins());
opacitySliderLayout->addWidget(m_opacitySlider);
rootLayout->addLayout(opacitySliderLayout);

Expand Down Expand Up @@ -214,11 +214,12 @@ void LayerList::setLayerEditActions(const Actions &actions)
// Add the actions below the layer list
QWidget *root = widget();
Q_ASSERT(root);
Q_ASSERT(titleBarWidget());
Q_ASSERT(actualTitleBarWidget());

QHBoxLayout *layout = new QHBoxLayout;
layout->setSpacing(0);
layout->setContentsMargins(titleBarWidget()->layout()->contentsMargins());
layout->setContentsMargins(
actualTitleBarWidget()->layout()->contentsMargins());
addLayerButton(
root, layout, m_actions.addLayer, widgets::GroupedToolButton::GroupLeft,
3);
Expand Down
2 changes: 1 addition & 1 deletion src/desktop/docks/timeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ void Timeline::setUpTitleWidget(
{
using widgets::GroupedToolButton;
docks::TitleWidget *titlebar =
qobject_cast<docks::TitleWidget *>(titleBarWidget());
qobject_cast<docks::TitleWidget *>(actualTitleBarWidget());

m_frameSpinner = new QSpinBox{titlebar};
m_frameSpinner->setWrapping(true);
Expand Down
5 changes: 0 additions & 5 deletions src/desktop/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,8 @@ DrawpileApp::DrawpileApp(int &argc, char **argv)
drawdance::initCpuSupport();
drawdance::DrawContextPool::init();

// Dockers are hard to drag around since their title bars are full of stuff.
// This event filter allows for hiding the title bars by holding shift.
GlobalKeyEventFilter *filter = new GlobalKeyEventFilter{this};
installEventFilter(filter);
connect(
filter, &GlobalKeyEventFilter::setDockTitleBarsHidden, this,
&DrawpileApp::setDockTitleBarsHidden);
connect(
filter, &GlobalKeyEventFilter::focusCanvas, this,
&DrawpileApp::focusCanvas);
Expand Down
1 change: 0 additions & 1 deletion src/desktop/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ class DrawpileApp final : public QApplication {
void tabletProximityChanged(bool enter, bool eraser);
void eraserNear(bool near);
#endif
void setDockTitleBarsHidden(bool hidden);
void focusCanvas();
void shortcutsChanged();
void tabletDriverChanged();
Expand Down
69 changes: 43 additions & 26 deletions src/desktop/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ MainWindow::MainWindow(bool restoreWindowPosition, bool singleSession)
m_fullscreenOldMaximized(false),
#endif
m_tempToolSwitchShortcut(nullptr),
m_titleBarsHidden(false),
m_wasSessionLocked(false),
m_notificationsMuted(false),
m_initialCatchup(false),
Expand Down Expand Up @@ -495,7 +494,6 @@ MainWindow::MainWindow(bool restoreWindowPosition, bool singleSession)
connect(m_doc->client(), &net::Client::bytesSent, m_netstatus, &widgets::NetStatus::bytesSent);
connect(m_doc->client(), &net::Client::lagMeasured, m_netstatus, &widgets::NetStatus::lagMeasured);

connect(&dpApp(), &DrawpileApp::setDockTitleBarsHidden, this, &MainWindow::setDockTitleBarsHidden);
// clang-format on
connect(&dpApp(), &DrawpileApp::focusCanvas, this, [this] {
if(dpApp().settings().doubleTapAltToFocusCanvas()) {
Expand Down Expand Up @@ -3389,10 +3387,14 @@ void MainWindow::setFreezeDocks(bool freeze)
for(QToolBar *tb : findChildren<QToolBar*>(QString(), Qt::FindDirectChildrenOnly)) {
tb->setMovable(!freeze);
}

finishArrangingDocks()->setEnabled(!freeze);
}

// clang-format on
void MainWindow::setDocksHidden(bool hidden)
{
finishArrangingDocks()->setEnabled(!hidden);
keepCanvasPosition([this, hidden] {
m_viewStatusBar->setHidden(hidden);
if(hidden) {
Expand Down Expand Up @@ -3420,19 +3422,30 @@ void MainWindow::setDocksHidden(bool hidden)
m_dockToggles->setDisabled(hidden);
}

void MainWindow::setDockTitleBarsHidden(bool hidden)
void MainWindow::setDockArrangeMode(bool arrange)
{
QAction *freezeDocks = getAction("freezedocks");
QAction *hideDockTitleBars = getAction("hidedocktitlebars");
bool actuallyHidden = hidden && !freezeDocks->isChecked()
&& hideDockTitleBars->isChecked() && !m_smallScreenMode;
if(actuallyHidden != m_titleBarsHidden) {
m_titleBarsHidden = hidden;
for(auto *dw : findChildren<QDockWidget*>(QString(), Qt::FindDirectChildrenOnly)) {
dw->titleBarWidget()->setHidden(hidden);
for(docks::DockBase *dw : findChildren<docks::DockBase *>(
QString(), Qt::FindDirectChildrenOnly)) {
dw->setArrangeMode(arrange);
}
}

QAction *MainWindow::finishArrangingDocks()
{
QAction *arrangeDocks = getAction("arrangedocks");
if(arrangeDocks->isChecked()) {
bool enabled = arrangeDocks->isEnabled();
if(!enabled) {
arrangeDocks->setEnabled(true);
}
arrangeDocks->trigger();
if(!enabled) {
arrangeDocks->setEnabled(false);
}
}
return arrangeDocks;
}
// clang-format off

void MainWindow::updateSideTabDocks()
{
Expand Down Expand Up @@ -4006,6 +4019,7 @@ void MainWindow::showLayoutsDialog()
if(!m_smallScreenMode) {
dialogs::LayoutsDialog *dlg = findChild<dialogs::LayoutsDialog *>(
"layoutsdialog", Qt::FindDirectChildrenOnly);
finishArrangingDocks();
if(dlg) {
dlg->setParent(getStartDialogOrThis());
} else {
Expand Down Expand Up @@ -4434,6 +4448,9 @@ void MainWindow::setupActions()
connect(
dw, &docks::DockBase::tabUpdateRequested, this,
&MainWindow::prepareDockTabUpdate);
connect(
dw, &docks::DockBase::arrangingFinished, this,
&MainWindow::finishArrangingDocks);
}
//clang-format off

Expand Down Expand Up @@ -4473,16 +4490,13 @@ void MainWindow::setupActions()
m_desktopModeActions->addAction(hideDocks);
connect(hideDocks, &QAction::toggled, this, &MainWindow::setDocksHidden);

QAction *hideDockTitleBars =
makeAction("hidedocktitlebars", tr("Hold Shift to Arrange"))
.noDefaultShortcut()
.checkable()
.remembered();
toggledockmenu->addAction(hideDockTitleBars);
m_desktopModeActions->addAction(hideDockTitleBars);
connect(hideDocks, &QAction::toggled, [this]() {
setDockTitleBarsHidden(m_titleBarsHidden);
});
QAction *arrangeDocks = makeAction("arrangedocks", tr("Arrange Docks"))
.noDefaultShortcut()
.checkable();
toggledockmenu->addAction(arrangeDocks);
m_desktopModeActions->addAction(arrangeDocks);
connect(
arrangeDocks, &QAction::toggled, this, &MainWindow::setDockArrangeMode);

//
// File menu and toolbar
Expand Down Expand Up @@ -6009,14 +6023,17 @@ void MainWindow::setupActions()
m_doc->toolCtrl(), &tools::ToolController::cancelMultipartDrawing);

QAction *focusCanvas = makeAction("focuscanvas", tr("Focus canvas")).shortcut(CTRL_KEY | Qt::Key_Tab);
connect(focusCanvas, &QAction::triggered, this, [this]{
// clang-format on
connect(focusCanvas, &QAction::triggered, this, [this] {
m_canvasView->viewWidget()->setFocus();
});

const QList<QAction *> globalDockActions = {
sideTabDocks, hideDocks, hideDockTitleBars, nullptr, layoutsAction};
for(auto *dw : findChildren<QDockWidget *>(QString(), Qt::FindDirectChildrenOnly)) {
if(auto *titlebar = qobject_cast<docks::TitleWidget *>(dw->titleBarWidget())) {
sideTabDocks, hideDocks, arrangeDocks, nullptr, layoutsAction};
for(docks::DockBase *dw : findChildren<docks::DockBase *>(
QString(), Qt::FindDirectChildrenOnly)) {
if(docks::TitleWidget *titlebar =
qobject_cast<docks::TitleWidget *>(dw->actualTitleBarWidget())) {
titlebar->addGlobalDockActions(globalDockActions);
}
}
Expand Down Expand Up @@ -6046,7 +6063,6 @@ void MainWindow::setupActions()
updateInterfaceModeActions();
}

// clang-format on
void MainWindow::setupBrushShortcuts()
{
brushes::BrushPresetModel *brushPresetModel =
Expand Down Expand Up @@ -6300,6 +6316,7 @@ bool MainWindow::isSmallScreenModeSize(const QSize &s)
void MainWindow::switchInterfaceMode(bool smallScreenMode)
{
setUpdatesEnabled(false);
finishArrangingDocks();
saveSplitterState();
saveWindowState();
m_smallScreenMode = smallScreenMode;
Expand Down
4 changes: 2 additions & 2 deletions src/desktop/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,8 @@ private slots:

void setFreezeDocks(bool freeze);
void setDocksHidden(bool hidden);
void setDockTitleBarsHidden(bool hidden);
void setDockArrangeMode(bool arrange);
QAction *finishArrangingDocks();
void updateSideTabDocks();
void setNotificationsMuted(bool muted);
void setToolState(int toolState);
Expand Down Expand Up @@ -477,7 +478,6 @@ private slots:
QElapsedTimer m_toolChangeTime; // how long the user has held down the tool
// change button
ShortcutDetector *m_tempToolSwitchShortcut;
bool m_titleBarsHidden;
bool m_wasSessionLocked;
bool m_notificationsMuted;
bool m_initialCatchup;
Expand Down
2 changes: 1 addition & 1 deletion src/desktop/ui/layoutsdialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
<item>
<widget class="QLabel" name="explanationLabel">
<property name="text">
<string>Drawpile's dockers can be freely arranged and combined by holding Shift and dragging them at the top. You can save and restore your favorite arrangements here. Make sure your arrangement fits your resolution, otherwise some controls may be pushed off-screen.</string>
<string>Drawpile's docks can be freely arranged. You can use View &gt; Docks &gt; Arrange Docks to let you drag them more easily. Make sure your arrangement fits your resolution, otherwise some controls may be pushed off-screen.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
Expand Down
35 changes: 0 additions & 35 deletions src/desktop/utils/globalkeyeventfilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

GlobalKeyEventFilter::GlobalKeyEventFilter(QObject *parent)
: QObject{parent}
, m_wasHidden{false}
, m_lastAltPress{0}
, m_lastAltInternalTimestamp{0}
{
Expand All @@ -16,26 +15,9 @@ GlobalKeyEventFilter::GlobalKeyEventFilter(QObject *parent)
bool GlobalKeyEventFilter::eventFilter(QObject *watched, QEvent *event)
{
switch(event->type()) {
case QEvent::Enter:
case QEvent::Leave: {
updateDockTitleBarsHidden(
QApplication::queryKeyboardModifiers().testFlag(Qt::ShiftModifier));
break;
}
case QEvent::KeyRelease: {
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
checkCanvasFocus(ke);
updateDockTitleBarsHidden(
ke->key() != Qt::Key_Shift &&
ke->modifiers().testFlag(Qt::ShiftModifier));
break;
}
case QEvent::KeyPress:
case QEvent::ShortcutOverride: {
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
updateDockTitleBarsHidden(
ke->key() == Qt::Key_Shift ||
ke->modifiers().testFlag(Qt::ShiftModifier));
break;
}
default:
Expand All @@ -44,23 +26,6 @@ bool GlobalKeyEventFilter::eventFilter(QObject *watched, QEvent *event)
return QObject::eventFilter(watched, event);
}

void GlobalKeyEventFilter::updateDockTitleBarsHidden(bool hidden)
{
bool actuallyHidden = hidden && !hasTextFocus();
if(actuallyHidden != m_wasHidden) {
m_wasHidden = actuallyHidden;
emit setDockTitleBarsHidden(actuallyHidden);
}
}

bool GlobalKeyEventFilter::hasTextFocus()
{
QWidget *widget = QApplication::focusWidget();
return widget &&
(widget->inherits("QLineEdit") || widget->inherits("QTextEdit") ||
widget->inherits("QPlainTextEdit"));
}

void GlobalKeyEventFilter::checkCanvasFocus(QKeyEvent *event)
{
bool altReleased = compat::keyPressed(*event) ==
Expand Down
4 changes: 0 additions & 4 deletions src/desktop/utils/globalkeyeventfilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,14 @@ class GlobalKeyEventFilter : public QObject {
explicit GlobalKeyEventFilter(QObject *parent = nullptr);

signals:
void setDockTitleBarsHidden(bool hidden);
void focusCanvas();

protected:
bool eventFilter(QObject *watched, QEvent *event) override;

private:
void updateDockTitleBarsHidden(bool hidden);
static bool hasTextFocus();
void checkCanvasFocus(QKeyEvent *event);

bool m_wasHidden;
long long m_lastAltPress;
unsigned long long m_lastAltInternalTimestamp;
};
Expand Down

0 comments on commit 4140017

Please sign in to comment.