mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-07 20:34:14 +02:00
Merge branch 'feature/customise-gesture-list' into feature/customise-dialog
# Conflicts: # tests/qttest/CMakeLists.txt
This commit is contained in:
@@ -309,6 +309,8 @@ set(QET_SRC_FILES
|
||||
${QET_DIR}/sources/diagramcontexttoolbar.h
|
||||
${QET_DIR}/sources/diagramgestureoverlay.cpp
|
||||
${QET_DIR}/sources/diagramgestureoverlay.h
|
||||
${QET_DIR}/sources/gesturesettings.cpp
|
||||
${QET_DIR}/sources/gesturesettings.h
|
||||
${QET_DIR}/sources/commandsearchpopup.cpp
|
||||
${QET_DIR}/sources/commandsearchpopup.h
|
||||
${QET_DIR}/sources/titleblockcell.cpp
|
||||
@@ -864,6 +866,8 @@ set(QET_SRC_FILES
|
||||
${QET_DIR}/sources/ui/configpage/toolbarcommandsconfigpage.h
|
||||
${QET_DIR}/sources/ui/configpage/toolbarsconfigpage.cpp
|
||||
${QET_DIR}/sources/ui/configpage/toolbarsconfigpage.h
|
||||
${QET_DIR}/sources/ui/configpage/gesturesconfigpage.cpp
|
||||
${QET_DIR}/sources/ui/configpage/gesturesconfigpage.h
|
||||
|
||||
${QET_DIR}/sources/undocommand/addelementtextcommand.cpp
|
||||
${QET_DIR}/sources/undocommand/addelementtextcommand.h
|
||||
|
||||
@@ -58,14 +58,16 @@ bool DiagramGestureOverlay::isEnabled()
|
||||
|
||||
/**
|
||||
@brief DiagramGestureOverlay::showAt
|
||||
Show the ring centred on @a center with @a actions, at most eight,
|
||||
clockwise from the top.
|
||||
Show the ring centred on @a center with @a sectors directions (4 or 8)
|
||||
and @a actions, one per direction clockwise from the top.
|
||||
*/
|
||||
void DiagramGestureOverlay::showAt(const QPoint ¢er,
|
||||
const QList<QAction *> &actions)
|
||||
const QList<QAction *> &actions,
|
||||
int sectors)
|
||||
{
|
||||
m_center = center;
|
||||
m_actions = actions.mid(0, sectors);
|
||||
m_sectors = sectors == 4 ? 4 : 8;
|
||||
m_actions = actions.mid(0, m_sectors);
|
||||
m_active = -1;
|
||||
move(center - QPoint(overlay_width / 2, outer_radius + 1));
|
||||
show();
|
||||
@@ -88,7 +90,7 @@ int DiagramGestureOverlay::sectorAt(const QPoint &viewport_pos) const
|
||||
if (angle < 0) {
|
||||
angle += 360;
|
||||
}
|
||||
return int(qRound(angle / (360.0 / sectors))) % sectors;
|
||||
return int(qRound(angle / (360.0 / m_sectors))) % m_sectors;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,7 +104,7 @@ QAction *DiagramGestureOverlay::actionAt(const QPoint &viewport_pos) const
|
||||
return nullptr;
|
||||
}
|
||||
QAction *action = m_actions.at(sector);
|
||||
return action->isEnabled() ? action : nullptr;
|
||||
return action && action->isEnabled() ? action : nullptr;
|
||||
}
|
||||
|
||||
void DiagramGestureOverlay::setPointer(const QPoint &viewport_pos)
|
||||
@@ -120,7 +122,7 @@ void DiagramGestureOverlay::paintEvent(QPaintEvent *event)
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
const QPointF c(overlay_width / 2, outer_radius + 1);
|
||||
const qreal step = 360.0 / sectors;
|
||||
const qreal step = 360.0 / m_sectors;
|
||||
|
||||
QColor base = palette().color(QPalette::Window);
|
||||
base.setAlpha(225);
|
||||
@@ -130,7 +132,7 @@ void DiagramGestureOverlay::paintEvent(QPaintEvent *event)
|
||||
|
||||
//Highlight the sector the mouse points at, if it holds a command
|
||||
if (m_active >= 0 && m_active < m_actions.count()
|
||||
&& m_actions.at(m_active)->isEnabled())
|
||||
&& m_actions.at(m_active) && m_actions.at(m_active)->isEnabled())
|
||||
{
|
||||
QPainterPath wedge;
|
||||
wedge.moveTo(c);
|
||||
@@ -151,6 +153,9 @@ void DiagramGestureOverlay::paintEvent(QPaintEvent *event)
|
||||
for (int i = 0 ; i < m_actions.count() ; ++i)
|
||||
{
|
||||
QAction *action = m_actions.at(i);
|
||||
if (!action) {
|
||||
continue;
|
||||
}
|
||||
const qreal a = qDegreesToRadians(i * step);
|
||||
const QPointF p(c.x() + icon_radius * qSin(a), c.y() - icon_radius * qCos(a));
|
||||
const QRect r(int(p.x()) - icon_size / 2, int(p.y()) - icon_size / 2,
|
||||
@@ -167,7 +172,7 @@ void DiagramGestureOverlay::paintEvent(QPaintEvent *event)
|
||||
}
|
||||
|
||||
//Name of the highlighted command, under the ring
|
||||
if (m_active >= 0 && m_active < m_actions.count())
|
||||
if (m_active >= 0 && m_active < m_actions.count() && m_actions.at(m_active))
|
||||
{
|
||||
const QString name = m_actions.at(m_active)->text().remove(QLatin1Char('&'));
|
||||
const QRect label(0, 2 * outer_radius + 4, width(), 20);
|
||||
|
||||
@@ -29,8 +29,9 @@ class QAction;
|
||||
mouse's direction highlighted. Releasing runs it, releasing near the
|
||||
centre cancels -- SolidWorks' mouse gestures.
|
||||
|
||||
Commands are placed clockwise from the top. The ring only draws; the
|
||||
view tracks the mouse and asks sectorAt() on release.
|
||||
Commands are placed clockwise from the top, one per direction (4 or 8).
|
||||
A null entry is an empty direction. The ring only draws; the view
|
||||
tracks the mouse and asks sectorAt() on release.
|
||||
*/
|
||||
class DiagramGestureOverlay : public QWidget
|
||||
{
|
||||
@@ -39,14 +40,15 @@ class DiagramGestureOverlay : public QWidget
|
||||
public:
|
||||
explicit DiagramGestureOverlay(QWidget *viewport);
|
||||
|
||||
void showAt(const QPoint ¢er, const QList<QAction *> &actions);
|
||||
void showAt(const QPoint ¢er, const QList<QAction *> &actions,
|
||||
int sectors = 8);
|
||||
void setPointer(const QPoint &viewport_pos);
|
||||
int sectorAt(const QPoint &viewport_pos) const;
|
||||
QAction *actionAt(const QPoint &viewport_pos) const;
|
||||
|
||||
static bool isEnabled();
|
||||
int sectors() const { return m_sectors; }
|
||||
|
||||
static const int sectors = 8;
|
||||
static bool isEnabled();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
@@ -55,6 +57,7 @@ class DiagramGestureOverlay : public QWidget
|
||||
QPoint m_center;
|
||||
QList<QAction *> m_actions;
|
||||
int m_active = -1;
|
||||
int m_sectors = 8;
|
||||
};
|
||||
|
||||
#endif // DIAGRAMGESTUREOVERLAY_H
|
||||
|
||||
+25
-1
@@ -42,6 +42,7 @@
|
||||
#include "diagram.h"
|
||||
#include "diagramcontexttoolbar.h"
|
||||
#include "diagramgestureoverlay.h"
|
||||
#include "gesturesettings.h"
|
||||
#include "shortcutbarsettings.h"
|
||||
#include "shortcutmanager.h"
|
||||
#include "ElementsCollection/xmlelementcollection.h"
|
||||
@@ -794,7 +795,8 @@ void DiagramView::mouseMoveEvent(QMouseEvent *e)
|
||||
m_diagram->clearEventInterface();
|
||||
m_swallow_native_menu = true;
|
||||
}
|
||||
m_gesture_overlay->showAt(m_gesture_origin, selectionCommands());
|
||||
m_gesture_overlay->showAt(m_gesture_origin, gestureCommands(),
|
||||
GestureSettings::directions());
|
||||
}
|
||||
if (m_gesture_overlay->isVisible()) {
|
||||
m_gesture_overlay->setPointer(pos);
|
||||
@@ -981,6 +983,28 @@ QList<QAction *> DiagramView::selectionCommands() const
|
||||
return actions;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief DiagramView::gestureCommands
|
||||
@return the gesture ring's commands for the current selection, as this
|
||||
window's actions. A list the user picked keeps its directions: a
|
||||
command this window lacks leaves its direction empty (nullptr).
|
||||
Otherwise the ring shows the shortcut bar's commands, in order.
|
||||
*/
|
||||
QList<QAction *> DiagramView::gestureCommands() const
|
||||
{
|
||||
QETDiagramEditor *qde = diagramEditor();
|
||||
const auto context = ShortcutBarSettings::contextFor(m_diagram->selectedItems());
|
||||
if (!qde || !GestureSettings::isCustom(context)) {
|
||||
return selectionCommands();
|
||||
}
|
||||
QList<QAction *> actions;
|
||||
for (const QString &id : GestureSettings::ids(context)) {
|
||||
actions << (id.isEmpty() ? nullptr
|
||||
: ShortcutManager::instance().action(id, qde));
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief DiagramView::showContextToolbar
|
||||
After a click that leaves something selected, show the shortcut bar's
|
||||
|
||||
@@ -154,6 +154,7 @@ class DiagramView : public PaletteGraphicsView
|
||||
void placeCellRulers();
|
||||
void showContextToolbar(const QPoint &viewport_pos);
|
||||
QList<QAction *> selectionCommands() const;
|
||||
QList<QAction *> gestureCommands() const;
|
||||
|
||||
/// Lowest and highest allowed value of the view transform scale (m11).
|
||||
/// Prevents wheel-zoom from driving the transform to overflow, which
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Copyright 2006-2026 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "gesturesettings.h"
|
||||
|
||||
#include <QSettings>
|
||||
|
||||
namespace {
|
||||
const QString directions_key = QStringLiteral("diagrameditor/gestures/directions");
|
||||
|
||||
QString settingsKey(ShortcutBarSettings::Context context)
|
||||
{
|
||||
switch (context)
|
||||
{
|
||||
case ShortcutBarSettings::Canvas:
|
||||
return QStringLiteral("diagrameditor/gestures/canvas");
|
||||
case ShortcutBarSettings::Selection:
|
||||
return QStringLiteral("diagrameditor/gestures/selection");
|
||||
case ShortcutBarSettings::Conductor:
|
||||
return QStringLiteral("diagrameditor/gestures/conductor");
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@return how many directions the ring has: 8 (the default) or 4
|
||||
*/
|
||||
int GestureSettings::directions()
|
||||
{
|
||||
return QSettings().value(directions_key, 8).toInt() == 4 ? 4 : 8;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief GestureSettings::setDirections
|
||||
Save 4 or 8 directions. 8 is the default and removes the key.
|
||||
*/
|
||||
void GestureSettings::setDirections(int directions)
|
||||
{
|
||||
QSettings settings;
|
||||
if (directions == 4) {
|
||||
settings.setValue(directions_key, 4);
|
||||
} else {
|
||||
settings.remove(directions_key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@return true if the user picked the commands for @a context, false
|
||||
when the ring follows the shortcut bar
|
||||
*/
|
||||
bool GestureSettings::isCustom(ShortcutBarSettings::Context context)
|
||||
{
|
||||
return QSettings().contains(settingsKey(context));
|
||||
}
|
||||
|
||||
/**
|
||||
@return the ids on the ring for @a context: the user's list if they
|
||||
picked one, the defaults otherwise
|
||||
*/
|
||||
QStringList GestureSettings::ids(ShortcutBarSettings::Context context)
|
||||
{
|
||||
QSettings settings;
|
||||
const QString key = settingsKey(context);
|
||||
if (!settings.contains(key)) {
|
||||
return defaultIds(context);
|
||||
}
|
||||
return settings.value(key).toStringList();
|
||||
}
|
||||
|
||||
/**
|
||||
@return the shortcut bar's commands for @a context, without its pinned
|
||||
elements: what the ring has shown since it was added
|
||||
*/
|
||||
QStringList GestureSettings::defaultIds(ShortcutBarSettings::Context context)
|
||||
{
|
||||
QStringList ids;
|
||||
for (const QString &id : ShortcutBarSettings::ids(context)) {
|
||||
if (!ShortcutBarSettings::isElement(id)) {
|
||||
ids << id;
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief GestureSettings::setIds
|
||||
Save @a ids for @a context; trailing empty directions are dropped.
|
||||
Saving the defaults removes the key, so the ring follows the shortcut
|
||||
bar again.
|
||||
*/
|
||||
void GestureSettings::setIds(ShortcutBarSettings::Context context, QStringList ids)
|
||||
{
|
||||
while (!ids.isEmpty() && ids.constLast().isEmpty()) {
|
||||
ids.removeLast();
|
||||
}
|
||||
if (ids == defaultIds(context)) {
|
||||
reset(context);
|
||||
} else {
|
||||
QSettings().setValue(settingsKey(context), ids);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief GestureSettings::reset
|
||||
Make the ring for @a context follow the shortcut bar again.
|
||||
*/
|
||||
void GestureSettings::reset(ShortcutBarSettings::Context context)
|
||||
{
|
||||
QSettings().remove(settingsKey(context));
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright 2006-2026 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef GESTURESETTINGS_H
|
||||
#define GESTURESETTINGS_H
|
||||
|
||||
#include "shortcutbarsettings.h"
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
/**
|
||||
@brief The commands on the mouse gesture ring (right-drag on a folio).
|
||||
|
||||
Until the user picks them, the ring shows the shortcut bar's commands
|
||||
for the selection, as it always has. A picked list is stored in
|
||||
QSettings, one key per context, and is positional: entry i is the
|
||||
command in direction i, clockwise from the top, and an empty entry is
|
||||
an empty direction. Pinned elements are never on the ring.
|
||||
*/
|
||||
class GestureSettings
|
||||
{
|
||||
public:
|
||||
static int directions();
|
||||
static void setDirections(int directions);
|
||||
|
||||
static bool isCustom(ShortcutBarSettings::Context context);
|
||||
static QStringList ids(ShortcutBarSettings::Context context);
|
||||
static QStringList defaultIds(ShortcutBarSettings::Context context);
|
||||
static void setIds(ShortcutBarSettings::Context context, QStringList ids);
|
||||
static void reset(ShortcutBarSettings::Context context);
|
||||
};
|
||||
|
||||
#endif // GESTURESETTINGS_H
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "ui/aboutqetdialog.h"
|
||||
#include "ui/configpage/generalconfigurationpage.h"
|
||||
#include "ui/configpage/shortcutsconfigpage.h"
|
||||
#include "ui/configpage/gesturesconfigpage.h"
|
||||
#include "ui/configpage/shortcutbarconfigpage.h"
|
||||
#include "ui/configpage/toolbarsconfigpage.h"
|
||||
#include "ui/configpage/toolbarcommandsconfigpage.h"
|
||||
@@ -2227,6 +2228,7 @@ void QETApp::configureQET()
|
||||
cd.addPage(new PrintConfigPage());
|
||||
cd.addPage(new ShortcutsConfigPage());
|
||||
cd.addPage(new ShortcutBarConfigPage());
|
||||
cd.addPage(new GesturesConfigPage());
|
||||
cd.addPage(new ToolbarsConfigPage());
|
||||
cd.addPage(new ToolbarCommandsConfigPage());
|
||||
#ifdef QET_SPACEMOUSE_SUPPORT
|
||||
|
||||
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
Copyright 2006-2026 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "gesturesconfigpage.h"
|
||||
|
||||
#include "../../gesturesettings.h"
|
||||
#include "../../qeticons.h"
|
||||
#include "../../shortcutmanager.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QComboBox>
|
||||
#include <QDataStream>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QListWidget>
|
||||
#include <QMimeData>
|
||||
#include <QKeyEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QtMath>
|
||||
|
||||
namespace {
|
||||
const int ring_radius = 100;
|
||||
const int ring_inner = 26;
|
||||
const int slot_radius = 68;
|
||||
const int slot_icon = 24;
|
||||
/// What QListWidget puts on a drag
|
||||
const QString list_mime = QStringLiteral("application/x-qabstractitemmodeldatalist");
|
||||
|
||||
/**
|
||||
@return the command id carried by a drag from the command list, or an
|
||||
empty string
|
||||
*/
|
||||
QString droppedId(const QMimeData *mime)
|
||||
{
|
||||
if (!mime || !mime->hasFormat(list_mime)) {
|
||||
return QString();
|
||||
}
|
||||
QByteArray data = mime->data(list_mime);
|
||||
QDataStream stream(&data, QIODevice::ReadOnly);
|
||||
int row, column;
|
||||
QMap<int, QVariant> roles;
|
||||
stream >> row >> column >> roles;
|
||||
return roles.value(Qt::UserRole).toString();
|
||||
}
|
||||
}
|
||||
|
||||
GestureRingEditor::GestureRingEditor(QWidget *parent) :
|
||||
QWidget(parent)
|
||||
{
|
||||
setAcceptDrops(true);
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
setMinimumSize(sizeHint());
|
||||
}
|
||||
|
||||
QSize GestureRingEditor::sizeHint() const
|
||||
{
|
||||
return QSize(2 * ring_radius + 8, 2 * ring_radius + 8);
|
||||
}
|
||||
|
||||
void GestureRingEditor::setIds(const QStringList &ids)
|
||||
{
|
||||
m_ids = ids;
|
||||
update();
|
||||
}
|
||||
|
||||
void GestureRingEditor::setDirections(int directions)
|
||||
{
|
||||
m_directions = directions == 4 ? 4 : 8;
|
||||
setCurrentSlot(qMin(m_current, m_directions - 1));
|
||||
update();
|
||||
}
|
||||
|
||||
void GestureRingEditor::setDescriptions(const QHash<QString, QString> &descriptions)
|
||||
{
|
||||
m_descriptions = descriptions;
|
||||
update();
|
||||
}
|
||||
|
||||
void GestureRingEditor::setCurrentSlot(int slot)
|
||||
{
|
||||
if (slot < 0 || slot >= m_directions) {
|
||||
return;
|
||||
}
|
||||
const bool changed = slot != m_current;
|
||||
m_current = slot;
|
||||
update();
|
||||
if (changed) {
|
||||
emit currentSlotChanged(slot);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@return the slot in the direction of @a pos from the centre, 0 at the
|
||||
top then clockwise, or -1 at the centre or outside the ring
|
||||
*/
|
||||
int GestureRingEditor::slotAt(const QPoint &pos) const
|
||||
{
|
||||
const QPointF d = QPointF(pos) - QPointF(rect().center());
|
||||
const qreal distance = qHypot(d.x(), d.y());
|
||||
if (distance < ring_inner || distance > ring_radius) {
|
||||
return -1;
|
||||
}
|
||||
qreal angle = qRadiansToDegrees(qAtan2(d.x(), -d.y()));
|
||||
if (angle < 0) {
|
||||
angle += 360;
|
||||
}
|
||||
return int(qRound(angle / (360.0 / m_directions))) % m_directions;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief GestureRingEditor::place
|
||||
Put @a id in the current slot. A command already elsewhere on the ring
|
||||
moves here, so a command has one direction.
|
||||
*/
|
||||
void GestureRingEditor::place(const QString &id)
|
||||
{
|
||||
if (id.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
const int old = m_ids.indexOf(id);
|
||||
if (old >= 0) {
|
||||
m_ids[old].clear();
|
||||
}
|
||||
while (m_ids.count() <= m_current) {
|
||||
m_ids << QString();
|
||||
}
|
||||
m_ids[m_current] = id;
|
||||
update();
|
||||
emit edited();
|
||||
}
|
||||
|
||||
void GestureRingEditor::clearCurrent()
|
||||
{
|
||||
if (m_current < m_ids.count() && !m_ids.at(m_current).isEmpty()) {
|
||||
m_ids[m_current].clear();
|
||||
update();
|
||||
emit edited();
|
||||
}
|
||||
}
|
||||
|
||||
QString GestureRingEditor::idAt(int slot) const
|
||||
{
|
||||
return slot < m_ids.count() ? m_ids.at(slot) : QString();
|
||||
}
|
||||
|
||||
QPointF GestureRingEditor::slotCenter(int slot) const
|
||||
{
|
||||
const qreal a = qDegreesToRadians(slot * 360.0 / m_directions);
|
||||
const QPointF c = QRectF(rect()).center();
|
||||
return QPointF(c.x() + slot_radius * qSin(a), c.y() - slot_radius * qCos(a));
|
||||
}
|
||||
|
||||
void GestureRingEditor::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
const QPointF c = QRectF(rect()).center();
|
||||
const qreal step = 360.0 / m_directions;
|
||||
const QRectF outer(c.x() - ring_radius, c.y() - ring_radius,
|
||||
2 * ring_radius, 2 * ring_radius);
|
||||
|
||||
QColor line = palette().color(QPalette::Text);
|
||||
line.setAlpha(110);
|
||||
painter.setPen(line);
|
||||
painter.setBrush(palette().color(QPalette::Base));
|
||||
painter.drawEllipse(outer);
|
||||
|
||||
//The chosen slot
|
||||
QPainterPath wedge;
|
||||
wedge.moveTo(c);
|
||||
wedge.arcTo(outer, 90 - m_current * step - step / 2, step);
|
||||
wedge.closeSubpath();
|
||||
painter.setPen(Qt::NoPen);
|
||||
QColor highlight = palette().color(QPalette::Highlight);
|
||||
if (!hasFocus()) {
|
||||
highlight.setAlpha(140);
|
||||
}
|
||||
painter.setBrush(highlight);
|
||||
painter.drawPath(wedge);
|
||||
|
||||
//Lines between the slots
|
||||
painter.setPen(line);
|
||||
for (int i = 0 ; i < m_directions ; ++i) {
|
||||
const qreal a = qDegreesToRadians(i * step + step / 2);
|
||||
painter.drawLine(QPointF(c.x() + ring_inner * qSin(a), c.y() - ring_inner * qCos(a)),
|
||||
QPointF(c.x() + ring_radius * qSin(a), c.y() - ring_radius * qCos(a)));
|
||||
}
|
||||
painter.setBrush(palette().color(QPalette::Window));
|
||||
painter.drawEllipse(c, ring_inner, ring_inner);
|
||||
|
||||
for (int i = 0 ; i < m_directions ; ++i)
|
||||
{
|
||||
const QString id = idAt(i);
|
||||
if (id.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
const QPointF p = slotCenter(i);
|
||||
const QRect r(int(p.x()) - slot_icon / 2, int(p.y()) - slot_icon / 2,
|
||||
slot_icon, slot_icon);
|
||||
QAction *action = ShortcutManager::instance().action(id, nullptr);
|
||||
if (action && !action->icon().isNull()) {
|
||||
action->icon().paint(&painter, r);
|
||||
} else {
|
||||
painter.setPen(palette().color(i == m_current ? QPalette::HighlightedText
|
||||
: QPalette::Text));
|
||||
painter.drawText(r.adjusted(-12, 0, 12, 0), Qt::AlignCenter,
|
||||
m_descriptions.value(id, id).left(3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GestureRingEditor::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
setCurrentSlot(slotAt(event->position().toPoint()));
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void GestureRingEditor::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace) {
|
||||
clearCurrent();
|
||||
} else if (event->key() == Qt::Key_Right || event->key() == Qt::Key_Down) {
|
||||
setCurrentSlot((m_current + 1) % m_directions);
|
||||
} else if (event->key() == Qt::Key_Left || event->key() == Qt::Key_Up) {
|
||||
setCurrentSlot((m_current + m_directions - 1) % m_directions);
|
||||
} else {
|
||||
QWidget::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void GestureRingEditor::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
if (!droppedId(event->mimeData()).isEmpty()) {
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
}
|
||||
|
||||
void GestureRingEditor::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
const int slot = slotAt(event->position().toPoint());
|
||||
if (slot < 0) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
setCurrentSlot(slot);
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
|
||||
void GestureRingEditor::dropEvent(QDropEvent *event)
|
||||
{
|
||||
const int slot = slotAt(event->position().toPoint());
|
||||
const QString id = droppedId(event->mimeData());
|
||||
if (slot < 0 || id.isEmpty()) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
setCurrentSlot(slot);
|
||||
place(id);
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief GesturesConfigPage::GesturesConfigPage
|
||||
@param parent
|
||||
*/
|
||||
GesturesConfigPage::GesturesConfigPage(QWidget *parent) :
|
||||
ConfigPage(parent)
|
||||
{
|
||||
const QStringList available = ShortcutBarSettings::availableIds();
|
||||
for (const ShortcutManager::ShortcutInfo &info :
|
||||
ShortcutManager::instance().allShortcuts()) {
|
||||
if (available.contains(info.id)) {
|
||||
m_descriptions.insert(info.id, info.description);
|
||||
}
|
||||
}
|
||||
for (const ShortcutBarSettings::Context c : ShortcutBarSettings::contexts()) {
|
||||
m_pending.insert(c, GestureSettings::ids(c));
|
||||
m_custom.insert(c, GestureSettings::isCustom(c));
|
||||
}
|
||||
|
||||
auto *explanation = new QLabel(
|
||||
tr("Faites glisser avec le bouton droit sur un folio : un anneau "
|
||||
"de commandes s'ouvre, relâchez vers celle à lancer. Tant que "
|
||||
"vous ne changez pas l'anneau d'un contexte, il montre les "
|
||||
"commandes de la barre de raccourcis. Les gestes s'activent "
|
||||
"ou se désactivent dans la page Général."), this);
|
||||
explanation->setWordWrap(true);
|
||||
|
||||
m_directions = new QComboBox(this);
|
||||
m_directions->setObjectName(QStringLiteral("directionsCombo"));
|
||||
m_directions->addItem(tr("8 directions"), 8);
|
||||
m_directions->addItem(tr("4 directions"), 4);
|
||||
m_directions->setCurrentIndex(m_directions->findData(GestureSettings::directions()));
|
||||
|
||||
m_context = new QComboBox(this);
|
||||
m_context->setObjectName(QStringLiteral("contextCombo"));
|
||||
for (const ShortcutBarSettings::Context c : ShortcutBarSettings::contexts()) {
|
||||
m_context->addItem(ShortcutBarSettings::title(c), c);
|
||||
}
|
||||
|
||||
m_available = new QListWidget(this);
|
||||
m_available->setObjectName(QStringLiteral("availableList"));
|
||||
m_available->setSortingEnabled(true);
|
||||
m_available->setDragEnabled(true);
|
||||
m_available->setDragDropMode(QAbstractItemView::DragOnly);
|
||||
for (auto it = m_descriptions.cbegin(); it != m_descriptions.cend(); ++it) {
|
||||
QIcon icon;
|
||||
if (QAction *action = ShortcutManager::instance().action(it.key(), nullptr)) {
|
||||
icon = action->icon();
|
||||
}
|
||||
auto *item = new QListWidgetItem(icon, it.value(), m_available);
|
||||
item->setData(Qt::UserRole, it.key());
|
||||
}
|
||||
|
||||
m_ring = new GestureRingEditor(this);
|
||||
m_ring->setObjectName(QStringLiteral("ringEditor"));
|
||||
m_ring->setDescriptions(m_descriptions);
|
||||
m_ring->setDirections(GestureSettings::directions());
|
||||
|
||||
m_slot_name = new QLabel(this);
|
||||
m_slot_name->setAlignment(Qt::AlignCenter);
|
||||
m_slot_name->setWordWrap(true);
|
||||
m_state = new QLabel(this);
|
||||
m_state->setWordWrap(true);
|
||||
|
||||
auto *place = new QPushButton(tr("Placer →"), this);
|
||||
place->setObjectName(QStringLiteral("placeButton"));
|
||||
auto *clear = new QPushButton(tr("Vider la direction"), this);
|
||||
auto *follow = new QPushButton(tr("Comme la barre de raccourcis"), this);
|
||||
follow->setObjectName(QStringLiteral("followBarButton"));
|
||||
|
||||
auto *ring_column = new QVBoxLayout();
|
||||
ring_column->addWidget(m_ring, 0, Qt::AlignHCenter);
|
||||
ring_column->addWidget(m_slot_name);
|
||||
ring_column->addWidget(clear);
|
||||
ring_column->addStretch();
|
||||
|
||||
auto *grid = new QGridLayout();
|
||||
grid->addWidget(new QLabel(tr("Commandes disponibles"), this), 0, 0);
|
||||
grid->addWidget(new QLabel(tr("Anneau, la direction choisie en surbrillance"), this), 0, 2);
|
||||
grid->addWidget(m_available, 1, 0);
|
||||
grid->addWidget(place, 1, 1, Qt::AlignVCenter);
|
||||
grid->addLayout(ring_column, 1, 2);
|
||||
grid->setColumnStretch(0, 1);
|
||||
grid->setColumnStretch(2, 1);
|
||||
|
||||
auto *top_row = new QHBoxLayout();
|
||||
top_row->addWidget(new QLabel(tr("Directions :"), this));
|
||||
top_row->addWidget(m_directions);
|
||||
top_row->addSpacing(12);
|
||||
top_row->addWidget(new QLabel(tr("Contexte :"), this));
|
||||
top_row->addWidget(m_context, 1);
|
||||
|
||||
auto *state_row = new QHBoxLayout();
|
||||
state_row->addWidget(m_state, 1);
|
||||
state_row->addWidget(follow);
|
||||
|
||||
auto *layout = new QVBoxLayout(this);
|
||||
layout->addWidget(explanation);
|
||||
layout->addLayout(top_row);
|
||||
layout->addLayout(state_row);
|
||||
layout->addLayout(grid);
|
||||
|
||||
connect(m_directions, qOverload<int>(&QComboBox::currentIndexChanged), this, [this]() {
|
||||
m_ring->setDirections(m_directions->currentData().toInt());
|
||||
updateState();
|
||||
});
|
||||
connect(m_context, qOverload<int>(&QComboBox::currentIndexChanged),
|
||||
this, &GesturesConfigPage::showContext);
|
||||
connect(m_ring, &GestureRingEditor::edited, this, [this]() {
|
||||
m_pending.insert(m_shown, m_ring->ids());
|
||||
m_custom.insert(m_shown, true);
|
||||
updateState();
|
||||
});
|
||||
connect(m_ring, &GestureRingEditor::currentSlotChanged,
|
||||
this, &GesturesConfigPage::updateState);
|
||||
connect(place, &QPushButton::clicked, this, &GesturesConfigPage::placeSelected);
|
||||
connect(m_available, &QListWidget::itemDoubleClicked,
|
||||
this, &GesturesConfigPage::placeSelected);
|
||||
connect(clear, &QPushButton::clicked, m_ring, &GestureRingEditor::clearCurrent);
|
||||
connect(follow, &QPushButton::clicked, this, &GesturesConfigPage::followBar);
|
||||
|
||||
showContext();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief GesturesConfigPage::applyConf
|
||||
Save the directions and every context's ring.
|
||||
*/
|
||||
void GesturesConfigPage::applyConf()
|
||||
{
|
||||
GestureSettings::setDirections(m_directions->currentData().toInt());
|
||||
for (const ShortcutBarSettings::Context c : ShortcutBarSettings::contexts()) {
|
||||
if (m_custom.value(c)) {
|
||||
GestureSettings::setIds(c, m_pending.value(c));
|
||||
} else {
|
||||
GestureSettings::reset(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString GesturesConfigPage::title() const
|
||||
{
|
||||
return tr("Gestes de la souris", "configuration page title");
|
||||
}
|
||||
|
||||
QIcon GesturesConfigPage::icon() const
|
||||
{
|
||||
return QET::Icons::ConfigureShortcuts;
|
||||
}
|
||||
|
||||
void GesturesConfigPage::showContext()
|
||||
{
|
||||
m_shown = static_cast<ShortcutBarSettings::Context>(
|
||||
m_context->currentData().toInt());
|
||||
m_ring->setIds(m_pending.value(m_shown));
|
||||
updateState();
|
||||
}
|
||||
|
||||
void GesturesConfigPage::placeSelected()
|
||||
{
|
||||
if (QListWidgetItem *item = m_available->currentItem()) {
|
||||
m_ring->place(item->data(Qt::UserRole).toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief GesturesConfigPage::followBar
|
||||
Make the shown context's ring follow the shortcut bar again.
|
||||
*/
|
||||
void GesturesConfigPage::followBar()
|
||||
{
|
||||
m_custom.insert(m_shown, false);
|
||||
m_pending.insert(m_shown, GestureSettings::defaultIds(m_shown));
|
||||
m_ring->setIds(m_pending.value(m_shown));
|
||||
updateState();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief GesturesConfigPage::updateState
|
||||
Name the chosen direction's command, and say whether the shown ring is
|
||||
the user's or the shortcut bar's.
|
||||
*/
|
||||
void GesturesConfigPage::updateState()
|
||||
{
|
||||
const int slot = m_ring->currentSlot();
|
||||
const QStringList ids = m_ring->ids();
|
||||
const QString id = slot < ids.count() ? ids.at(slot) : QString();
|
||||
m_slot_name->setText(id.isEmpty() ? tr("(direction vide)")
|
||||
: m_descriptions.value(id, id));
|
||||
m_state->setText(m_custom.value(m_shown)
|
||||
? tr("Anneau personnalisé pour ce contexte.")
|
||||
: tr("Cet anneau suit la barre de raccourcis."));
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
Copyright 2006-2026 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef GESTURESCONFIGPAGE_H
|
||||
#define GESTURESCONFIGPAGE_H
|
||||
|
||||
#include "configpage.h"
|
||||
#include "../../shortcutbarsettings.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QStringList>
|
||||
|
||||
class QComboBox;
|
||||
class QLabel;
|
||||
class QListWidget;
|
||||
|
||||
/**
|
||||
@brief The gesture ring as an editor: one slot per direction, clockwise
|
||||
from the top. Click a slot to choose it; drop a command from the
|
||||
command list on a slot to put it there; Delete empties the chosen slot.
|
||||
*/
|
||||
class GestureRingEditor : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GestureRingEditor(QWidget *parent = nullptr);
|
||||
|
||||
void setIds(const QStringList &ids);
|
||||
QStringList ids() const { return m_ids; }
|
||||
void setDirections(int directions);
|
||||
void setDescriptions(const QHash<QString, QString> &descriptions);
|
||||
int currentSlot() const { return m_current; }
|
||||
void setCurrentSlot(int slot);
|
||||
int slotAt(const QPoint &pos) const;
|
||||
void place(const QString &id);
|
||||
void clearCurrent();
|
||||
|
||||
QSize sizeHint() const override;
|
||||
|
||||
signals:
|
||||
void edited();
|
||||
void currentSlotChanged(int slot);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
|
||||
private:
|
||||
QString idAt(int slot) const;
|
||||
QPointF slotCenter(int slot) const;
|
||||
|
||||
QStringList m_ids;
|
||||
QHash<QString, QString> m_descriptions;
|
||||
int m_directions = 8;
|
||||
int m_current = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@brief The GesturesConfigPage class
|
||||
Choose 4 or 8 directions for the mouse gesture ring, and which command
|
||||
sits in each direction for each selection context. A context the user
|
||||
does not edit keeps following the shortcut bar. Saved by applyConf().
|
||||
*/
|
||||
class GesturesConfigPage : public ConfigPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GesturesConfigPage(QWidget *parent = nullptr);
|
||||
|
||||
void applyConf() override;
|
||||
QString title() const override;
|
||||
QIcon icon() const override;
|
||||
|
||||
private:
|
||||
void showContext();
|
||||
void placeSelected();
|
||||
void followBar();
|
||||
void updateState();
|
||||
|
||||
QComboBox *m_directions;
|
||||
QComboBox *m_context;
|
||||
QListWidget *m_available;
|
||||
GestureRingEditor *m_ring;
|
||||
QLabel *m_slot_name;
|
||||
QLabel *m_state;
|
||||
ShortcutBarSettings::Context m_shown = ShortcutBarSettings::Canvas;
|
||||
QHash<int, QStringList> m_pending;
|
||||
QHash<int, bool> m_custom;
|
||||
QHash<QString, QString> m_descriptions;
|
||||
};
|
||||
|
||||
#endif // GESTURESCONFIGPAGE_H
|
||||
@@ -318,6 +318,29 @@ set_tests_properties(tst_diagramtoolbarsettings PROPERTIES ENVIRONMENT "QT_QPA_P
|
||||
target_include_directories(tst_diagramtoolbarsettings PRIVATE ${QET_DIR}/sources)
|
||||
target_link_libraries(tst_diagramtoolbarsettings PRIVATE Qt::Test Qt::Widgets Qt::Svg)
|
||||
|
||||
# GestureSettings, the gesture ring's 4 / 8 directions and empty slots, and
|
||||
# its configuration page: the ring follows the shortcut bar until the user
|
||||
# picks commands, then keeps each one in its direction.
|
||||
add_executable(
|
||||
tst_gesturesettings
|
||||
tst_gesturesettings.cpp
|
||||
${QET_DIR}/sources/gesturesettings.cpp
|
||||
${QET_DIR}/sources/gesturesettings.h
|
||||
${QET_DIR}/sources/shortcutbarsettings.cpp
|
||||
${QET_DIR}/sources/diagramgestureoverlay.cpp
|
||||
${QET_DIR}/sources/diagramgestureoverlay.h
|
||||
${QET_DIR}/sources/ui/configpage/gesturesconfigpage.cpp
|
||||
${QET_DIR}/sources/ui/configpage/gesturesconfigpage.h
|
||||
${QET_DIR}/sources/ui/configpage/configpage.h
|
||||
${QET_DIR}/sources/shortcutmanager.cpp
|
||||
${QET_DIR}/sources/qeticons.cpp
|
||||
${QET_DIR}/sources/qetpalette.cpp
|
||||
${QET_DIR}/sources/qetstyle.cpp)
|
||||
add_test(NAME tst_gesturesettings COMMAND tst_gesturesettings)
|
||||
set_tests_properties(tst_gesturesettings PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
|
||||
target_include_directories(tst_gesturesettings PRIVATE ${QET_DIR}/sources)
|
||||
target_link_libraries(tst_gesturesettings PRIVATE Qt::Test Qt::Widgets Qt::Svg Qt::Xml pugixml::pugixml)
|
||||
|
||||
# scriptheader.h is header-only: the // ==QETScript== block that turns a
|
||||
# stored script into a button; and ShortcutManager::unregisterAction(), which
|
||||
# takes a deleted script's command out of the lists again.
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
Copyright 2006-2026 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "diagramgestureoverlay.h"
|
||||
#include "gesturesettings.h"
|
||||
#include "shortcutmanager.h"
|
||||
#include "ui/configpage/gesturesconfigpage.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QComboBox>
|
||||
#include <QDropEvent>
|
||||
#include <QListWidget>
|
||||
#include <QMainWindow>
|
||||
#include <QMimeData>
|
||||
#include <QPushButton>
|
||||
#include <QSettings>
|
||||
#include <QStandardPaths>
|
||||
#include <QTest>
|
||||
|
||||
/**
|
||||
The mouse gesture ring's own command list: until the user picks one it
|
||||
follows the shortcut bar as before; a picked list keeps its directions;
|
||||
4 or 8 directions; and the configuration page that edits it.
|
||||
*/
|
||||
class tst_gesturesettings : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QMainWindow m_window;
|
||||
|
||||
QAction *addCommand(const QString &id, const QString &text)
|
||||
{
|
||||
auto *action = new QAction(text, &m_window);
|
||||
ShortcutManager::instance().registerAction(
|
||||
action, id, QStringLiteral("Éditeur de schémas"), QKeySequence());
|
||||
return action;
|
||||
}
|
||||
|
||||
QListWidgetItem *listItem(QListWidget *list, const QString &id)
|
||||
{
|
||||
for (int i = 0 ; i < list->count() ; ++i) {
|
||||
if (list->item(i)->data(Qt::UserRole).toString() == id) {
|
||||
return list->item(i);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private slots:
|
||||
void initTestCase()
|
||||
{
|
||||
QStandardPaths::setTestModeEnabled(true);
|
||||
QSettings().remove(QStringLiteral("diagrameditor"));
|
||||
addCommand(QStringLiteral("diagrameditor.copy"), QStringLiteral("Copier"));
|
||||
addCommand(QStringLiteral("diagrameditor.cut"), QStringLiteral("Couper"));
|
||||
addCommand(QStringLiteral("diagrameditor.paste"), QStringLiteral("Coller"));
|
||||
}
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
QSettings().remove(QStringLiteral("diagrameditor"));
|
||||
}
|
||||
|
||||
void defaultsFollowTheBar()
|
||||
{
|
||||
QCOMPARE(GestureSettings::directions(), 8);
|
||||
for (const auto c : ShortcutBarSettings::contexts()) {
|
||||
QVERIFY(!GestureSettings::isCustom(c));
|
||||
QCOMPARE(GestureSettings::ids(c), ShortcutBarSettings::ids(c));
|
||||
}
|
||||
//A changed bar still reaches the ring, without its elements
|
||||
ShortcutBarSettings::setIds(ShortcutBarSettings::Selection,
|
||||
{QStringLiteral("diagrameditor.copy"),
|
||||
QStringLiteral("common://10_electric/relay.elmt"),
|
||||
QStringLiteral("diagrameditor.cut")});
|
||||
QCOMPARE(GestureSettings::ids(ShortcutBarSettings::Selection),
|
||||
QStringList({QStringLiteral("diagrameditor.copy"),
|
||||
QStringLiteral("diagrameditor.cut")}));
|
||||
}
|
||||
|
||||
void pickedListKeepsDirections()
|
||||
{
|
||||
GestureSettings::setIds(ShortcutBarSettings::Canvas,
|
||||
{QStringLiteral("diagrameditor.copy"), QString(),
|
||||
QStringLiteral("diagrameditor.paste"), QString(), QString()});
|
||||
QVERIFY(GestureSettings::isCustom(ShortcutBarSettings::Canvas));
|
||||
QCOMPARE(GestureSettings::ids(ShortcutBarSettings::Canvas),
|
||||
QStringList({QStringLiteral("diagrameditor.copy"), QString(),
|
||||
QStringLiteral("diagrameditor.paste")}));
|
||||
//The bar no longer drives it
|
||||
ShortcutBarSettings::setIds(ShortcutBarSettings::Canvas,
|
||||
{QStringLiteral("diagrameditor.cut")});
|
||||
QCOMPARE(GestureSettings::ids(ShortcutBarSettings::Canvas).first(),
|
||||
QStringLiteral("diagrameditor.copy"));
|
||||
//Other contexts still follow the bar
|
||||
QVERIFY(!GestureSettings::isCustom(ShortcutBarSettings::Selection));
|
||||
}
|
||||
|
||||
void savingTheDefaultsFollowsTheBarAgain()
|
||||
{
|
||||
GestureSettings::setIds(ShortcutBarSettings::Conductor, {QStringLiteral("diagrameditor.cut")});
|
||||
QVERIFY(GestureSettings::isCustom(ShortcutBarSettings::Conductor));
|
||||
GestureSettings::setIds(ShortcutBarSettings::Conductor,
|
||||
GestureSettings::defaultIds(ShortcutBarSettings::Conductor));
|
||||
QVERIFY(!GestureSettings::isCustom(ShortcutBarSettings::Conductor));
|
||||
}
|
||||
|
||||
void directions()
|
||||
{
|
||||
GestureSettings::setDirections(4);
|
||||
QCOMPARE(GestureSettings::directions(), 4);
|
||||
GestureSettings::setDirections(8);
|
||||
QVERIFY(!QSettings().contains(QStringLiteral("diagrameditor/gestures/directions")));
|
||||
QSettings().setValue(QStringLiteral("diagrameditor/gestures/directions"), 5);
|
||||
QCOMPARE(GestureSettings::directions(), 8);
|
||||
}
|
||||
|
||||
void overlayDirectionsAndEmptySlots()
|
||||
{
|
||||
QWidget viewport;
|
||||
viewport.resize(400, 400);
|
||||
DiagramGestureOverlay overlay(&viewport);
|
||||
QAction *copy = ShortcutManager::instance().action(QStringLiteral("diagrameditor.copy"), &m_window);
|
||||
QAction *paste = ShortcutManager::instance().action(QStringLiteral("diagrameditor.paste"), &m_window);
|
||||
const QPoint c(200, 200);
|
||||
const QPoint right(260, 200), down(200, 260);
|
||||
|
||||
overlay.showAt(c, {copy, nullptr, paste}, 4);
|
||||
QCOMPARE(overlay.sectors(), 4);
|
||||
QCOMPARE(overlay.sectorAt(right), 1);
|
||||
QCOMPARE(overlay.actionAt(right), nullptr);
|
||||
QCOMPARE(overlay.actionAt(down), paste);
|
||||
overlay.setPointer(right);
|
||||
QVERIFY(!overlay.grab().isNull());
|
||||
|
||||
//Today's ring: eight directions
|
||||
overlay.showAt(c, {copy, nullptr, paste});
|
||||
QCOMPARE(overlay.sectors(), 8);
|
||||
QCOMPARE(overlay.sectorAt(right), 2);
|
||||
QCOMPARE(overlay.actionAt(right), paste);
|
||||
}
|
||||
|
||||
void pagePlacesAndSaves()
|
||||
{
|
||||
{
|
||||
GesturesConfigPage page;
|
||||
auto *directions = page.findChild<QComboBox *>(QStringLiteral("directionsCombo"));
|
||||
auto *list = page.findChild<QListWidget *>(QStringLiteral("availableList"));
|
||||
auto *ring = page.findChild<GestureRingEditor *>(QStringLiteral("ringEditor"));
|
||||
QCOMPARE(directions->currentData().toInt(), 8);
|
||||
QCOMPARE(ring->ids(), GestureSettings::defaultIds(ShortcutBarSettings::Canvas));
|
||||
|
||||
directions->setCurrentIndex(directions->findData(4));
|
||||
ring->setCurrentSlot(1);
|
||||
list->setCurrentItem(listItem(list, QStringLiteral("diagrameditor.cut")));
|
||||
page.findChild<QPushButton *>(QStringLiteral("placeButton"))->click();
|
||||
page.applyConf();
|
||||
}
|
||||
QCOMPARE(GestureSettings::directions(), 4);
|
||||
QVERIFY(GestureSettings::isCustom(ShortcutBarSettings::Canvas));
|
||||
QCOMPARE(GestureSettings::ids(ShortcutBarSettings::Canvas).at(1),
|
||||
QStringLiteral("diagrameditor.cut"));
|
||||
//Contexts left alone still follow the bar
|
||||
QVERIFY(!GestureSettings::isCustom(ShortcutBarSettings::Selection));
|
||||
|
||||
{
|
||||
GesturesConfigPage page;
|
||||
page.findChild<QPushButton *>(QStringLiteral("followBarButton"))->click();
|
||||
page.applyConf();
|
||||
}
|
||||
QVERIFY(!GestureSettings::isCustom(ShortcutBarSettings::Canvas));
|
||||
}
|
||||
|
||||
void dropOnASlot()
|
||||
{
|
||||
GesturesConfigPage page;
|
||||
auto *list = page.findChild<QListWidget *>(QStringLiteral("availableList"));
|
||||
auto *ring = page.findChild<GestureRingEditor *>(QStringLiteral("ringEditor"));
|
||||
ring->resize(ring->sizeHint());
|
||||
const QModelIndex index = list->model()->index(
|
||||
list->row(listItem(list, QStringLiteral("diagrameditor.paste"))), 0);
|
||||
QMimeData *mime = list->model()->mimeData({index});
|
||||
//The right-hand slot of eight
|
||||
const QPointF target = QRectF(ring->rect()).center() + QPointF(68, 0);
|
||||
QCOMPARE(ring->slotAt(target.toPoint()), 2);
|
||||
QDropEvent drop(target, Qt::CopyAction, mime, Qt::LeftButton, Qt::NoModifier);
|
||||
//Straight to the widget: QApplication drops drag events when
|
||||
//no real drag is running
|
||||
QVERIFY(static_cast<QObject *>(ring)->event(&drop));
|
||||
QVERIFY(drop.isAccepted());
|
||||
QCOMPARE(ring->currentSlot(), 2);
|
||||
QCOMPARE(ring->ids().value(2), QStringLiteral("diagrameditor.paste"));
|
||||
//Moved, not copied: paste was already on the default canvas ring
|
||||
QCOMPARE(ring->ids().count(QStringLiteral("diagrameditor.paste")), 1);
|
||||
delete mime;
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_gesturesettings)
|
||||
#include "tst_gesturesettings.moc"
|
||||
Reference in New Issue
Block a user