mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-27 12:34:14 +02:00
Merge pull request #1057 from ispyisail/feature/mouse-gestures
Add right-drag mouse gestures to run commands
This commit is contained in:
@@ -289,6 +289,8 @@ set(QET_SRC_FILES
|
||||
${QET_DIR}/sources/shortcutbarsettings.h
|
||||
${QET_DIR}/sources/diagramcontexttoolbar.cpp
|
||||
${QET_DIR}/sources/diagramcontexttoolbar.h
|
||||
${QET_DIR}/sources/diagramgestureoverlay.cpp
|
||||
${QET_DIR}/sources/diagramgestureoverlay.h
|
||||
${QET_DIR}/sources/commandsearchpopup.cpp
|
||||
${QET_DIR}/sources/commandsearchpopup.h
|
||||
${QET_DIR}/sources/titleblockcell.cpp
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
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 <QAction>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QSettings>
|
||||
#include <QtMath>
|
||||
|
||||
namespace {
|
||||
const int outer_radius = 84;
|
||||
/// Releasing closer than this to the centre cancels
|
||||
const int inner_radius = 22;
|
||||
const int icon_radius = 56;
|
||||
const int icon_size = 22;
|
||||
/// Wider than the ring, so a long command name under it is not cut
|
||||
const int overlay_width = 280;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief DiagramGestureOverlay::DiagramGestureOverlay
|
||||
@param viewport : the view's viewport, which it is drawn on. It lets the
|
||||
mouse through, so the view keeps receiving the drag.
|
||||
*/
|
||||
DiagramGestureOverlay::DiagramGestureOverlay(QWidget *viewport) :
|
||||
QWidget(viewport)
|
||||
{
|
||||
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
setFixedSize(overlay_width, 2 * outer_radius + 2 + 24);
|
||||
hide();
|
||||
}
|
||||
|
||||
/**
|
||||
@return whether right-drag gestures are on (a preference)
|
||||
*/
|
||||
bool DiagramGestureOverlay::isEnabled()
|
||||
{
|
||||
return QSettings().value(QStringLiteral("diagrameditor/mouse_gestures"),
|
||||
true).toBool();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief DiagramGestureOverlay::showAt
|
||||
Show the ring centred on @a center with @a actions, at most eight,
|
||||
clockwise from the top.
|
||||
*/
|
||||
void DiagramGestureOverlay::showAt(const QPoint ¢er,
|
||||
const QList<QAction *> &actions)
|
||||
{
|
||||
m_center = center;
|
||||
m_actions = actions.mid(0, sectors);
|
||||
m_active = -1;
|
||||
move(center - QPoint(overlay_width / 2, outer_radius + 1));
|
||||
show();
|
||||
raise();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief DiagramGestureOverlay::sectorAt
|
||||
@return the sector in the direction of @a viewport_pos from the centre,
|
||||
0 at the top then clockwise, or -1 within the cancel radius
|
||||
*/
|
||||
int DiagramGestureOverlay::sectorAt(const QPoint &viewport_pos) const
|
||||
{
|
||||
const QPoint d = viewport_pos - m_center;
|
||||
if (qHypot(d.x(), d.y()) < inner_radius) {
|
||||
return -1;
|
||||
}
|
||||
//Angle clockwise from the top, in degrees
|
||||
qreal angle = qRadiansToDegrees(qAtan2(d.x(), -d.y()));
|
||||
if (angle < 0) {
|
||||
angle += 360;
|
||||
}
|
||||
return int(qRound(angle / (360.0 / sectors))) % sectors;
|
||||
}
|
||||
|
||||
/**
|
||||
@return the command in the direction of @a viewport_pos, or nullptr when
|
||||
there is none there or it is disabled
|
||||
*/
|
||||
QAction *DiagramGestureOverlay::actionAt(const QPoint &viewport_pos) const
|
||||
{
|
||||
const int sector = sectorAt(viewport_pos);
|
||||
if (sector < 0 || sector >= m_actions.count()) {
|
||||
return nullptr;
|
||||
}
|
||||
QAction *action = m_actions.at(sector);
|
||||
return action->isEnabled() ? action : nullptr;
|
||||
}
|
||||
|
||||
void DiagramGestureOverlay::setPointer(const QPoint &viewport_pos)
|
||||
{
|
||||
const int sector = sectorAt(viewport_pos);
|
||||
if (sector != m_active) {
|
||||
m_active = sector;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void DiagramGestureOverlay::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
const QPointF c(overlay_width / 2, outer_radius + 1);
|
||||
const qreal step = 360.0 / sectors;
|
||||
|
||||
QColor base = palette().color(QPalette::Window);
|
||||
base.setAlpha(225);
|
||||
painter.setPen(palette().color(QPalette::Mid));
|
||||
painter.setBrush(base);
|
||||
painter.drawEllipse(c, outer_radius, outer_radius);
|
||||
|
||||
//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())
|
||||
{
|
||||
QPainterPath wedge;
|
||||
wedge.moveTo(c);
|
||||
//Qt angles run counter-clockwise from 3 o'clock
|
||||
const qreal start = 90 - m_active * step - step / 2;
|
||||
wedge.arcTo(QRectF(c.x() - outer_radius, c.y() - outer_radius,
|
||||
2 * outer_radius, 2 * outer_radius), start, step);
|
||||
wedge.closeSubpath();
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.setBrush(palette().color(QPalette::Highlight));
|
||||
painter.drawPath(wedge);
|
||||
}
|
||||
|
||||
painter.setPen(palette().color(QPalette::Mid));
|
||||
painter.setBrush(palette().color(QPalette::Window));
|
||||
painter.drawEllipse(c, inner_radius, inner_radius);
|
||||
|
||||
for (int i = 0 ; i < m_actions.count() ; ++i)
|
||||
{
|
||||
QAction *action = m_actions.at(i);
|
||||
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,
|
||||
icon_size, icon_size);
|
||||
const QIcon::Mode mode = action->isEnabled() ? QIcon::Normal : QIcon::Disabled;
|
||||
if (!action->icon().isNull()) {
|
||||
action->icon().paint(&painter, r, Qt::AlignCenter, mode);
|
||||
} else {
|
||||
painter.setPen(palette().color(action->isEnabled() ? QPalette::Active : QPalette::Disabled,
|
||||
QPalette::WindowText));
|
||||
painter.drawText(r.adjusted(-12, 0, 12, 0), Qt::AlignCenter,
|
||||
action->text().remove(QLatin1Char('&')).left(3));
|
||||
}
|
||||
}
|
||||
|
||||
//Name of the highlighted command, under the ring
|
||||
if (m_active >= 0 && m_active < m_actions.count())
|
||||
{
|
||||
const QString name = m_actions.at(m_active)->text().remove(QLatin1Char('&'));
|
||||
const QRect label(0, 2 * outer_radius + 4, width(), 20);
|
||||
QFont f = font();
|
||||
f.setBold(true);
|
||||
painter.setFont(f);
|
||||
const QRect text = painter.fontMetrics().boundingRect(label, Qt::AlignCenter, name)
|
||||
.adjusted(-6, -2, 6, 2);
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.setBrush(base);
|
||||
painter.drawRoundedRect(text, 4, 4);
|
||||
painter.setPen(palette().color(QPalette::WindowText));
|
||||
painter.drawText(label, Qt::AlignCenter, name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
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 DIAGRAMGESTUREOVERLAY_H
|
||||
#define DIAGRAMGESTUREOVERLAY_H
|
||||
|
||||
#include <QList>
|
||||
#include <QWidget>
|
||||
|
||||
class QAction;
|
||||
|
||||
/**
|
||||
@brief The ring shown while right-dragging on a folio: up to eight
|
||||
commands around the point where the button went down, the one in the
|
||||
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.
|
||||
*/
|
||||
class DiagramGestureOverlay : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DiagramGestureOverlay(QWidget *viewport);
|
||||
|
||||
void showAt(const QPoint ¢er, const QList<QAction *> &actions);
|
||||
void setPointer(const QPoint &viewport_pos);
|
||||
int sectorAt(const QPoint &viewport_pos) const;
|
||||
QAction *actionAt(const QPoint &viewport_pos) const;
|
||||
|
||||
static bool isEnabled();
|
||||
|
||||
static const int sectors = 8;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
QPoint m_center;
|
||||
QList<QAction *> m_actions;
|
||||
int m_active = -1;
|
||||
};
|
||||
|
||||
#endif // DIAGRAMGESTUREOVERLAY_H
|
||||
+131
-8
@@ -39,6 +39,7 @@
|
||||
#include "undocommand/addgraphicsobjectcommand.h"
|
||||
#include "diagram.h"
|
||||
#include "diagramcontexttoolbar.h"
|
||||
#include "diagramgestureoverlay.h"
|
||||
#include "shortcutbarsettings.h"
|
||||
#include "shortcutmanager.h"
|
||||
#include "ElementsCollection/xmlelementcollection.h"
|
||||
@@ -113,6 +114,7 @@ DiagramView::DiagramView(Diagram *diagram, QWidget *parent) :
|
||||
}
|
||||
|
||||
m_context_toolbar = new DiagramContextToolbar(viewport());
|
||||
m_gesture_overlay = new DiagramGestureOverlay(viewport());
|
||||
connect(m_diagram, &QGraphicsScene::selectionChanged, this, [this]() {
|
||||
if (m_diagram->selectedItems().isEmpty()) {
|
||||
m_context_toolbar->hide();
|
||||
@@ -641,6 +643,46 @@ void DiagramView::mousePressEvent(QMouseEvent *e)
|
||||
m_press_pos = e->position().toPoint();
|
||||
}
|
||||
|
||||
//Right button: a click opens the context menu on release, a drag is
|
||||
//a gesture (DiagramGestureOverlay). Left alone while a text is edited.
|
||||
m_swallow_native_menu = false;
|
||||
m_gesture_over_tool = false;
|
||||
if (e->button() == Qt::RightButton
|
||||
&& DiagramGestureOverlay::isEnabled()
|
||||
&& !m_diagram->focusItem())
|
||||
{
|
||||
m_gesture_tracking = true;
|
||||
m_gesture_origin = e->position().toPoint();
|
||||
m_context_toolbar->hide();
|
||||
|
||||
//A tool is running, often one a gesture just started. A right
|
||||
//click still goes to it -- it cancels or finishes the tool -- so
|
||||
//the press carries on to the scene. A drag ends the tool and
|
||||
//shows the ring (see mouseMoveEvent).
|
||||
if (m_diagram->eventInterfaceIsRunning()) {
|
||||
m_gesture_over_tool = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_swallow_native_menu = true;
|
||||
|
||||
//Select what is under the mouse, as the context menu does, so
|
||||
//a gesture acts on it
|
||||
if (QGraphicsItem *item = m_diagram->itemAt(mapToScene(m_gesture_origin), transform())) {
|
||||
if (!item->isSelected()) {
|
||||
m_diagram->clearSelection();
|
||||
//Clearing the selection can delete handler items, so
|
||||
//look the item up again (see contextMenuEvent)
|
||||
if (QGraphicsItem *again = m_diagram->itemAt(mapToScene(m_gesture_origin), transform())) {
|
||||
again->setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
e->accept();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Start drag view when hold the middle button
|
||||
if (e->button() == Qt::MiddleButton)
|
||||
{
|
||||
@@ -692,6 +734,31 @@ void DiagramView::mouseMoveEvent(QMouseEvent *e)
|
||||
setToolTip(tr("X: %1 Y: %2").arg(e->pos().x()).arg(e->pos().y()));
|
||||
if (m_event_interface && m_event_interface->mouseMoveEvent(e)) return;
|
||||
|
||||
if (m_gesture_tracking)
|
||||
{
|
||||
const QPoint pos = e->position().toPoint();
|
||||
if (!m_gesture_overlay->isVisible()
|
||||
&& (pos - m_gesture_origin).manhattanLength() > 2 * QApplication::startDragDistance()) {
|
||||
if (m_gesture_over_tool) {
|
||||
//The drag is a gesture: end the tool, and ignore the
|
||||
//platform's right-click menu like any other gesture
|
||||
m_diagram->clearEventInterface();
|
||||
m_swallow_native_menu = true;
|
||||
}
|
||||
m_gesture_overlay->showAt(m_gesture_origin, selectionCommands());
|
||||
}
|
||||
if (m_gesture_overlay->isVisible()) {
|
||||
m_gesture_overlay->setPointer(pos);
|
||||
e->accept();
|
||||
return;
|
||||
}
|
||||
//Not a drag yet: a running tool keeps following the mouse
|
||||
if (!m_gesture_over_tool) {
|
||||
e->accept();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Drag the view
|
||||
if (e->buttons() == Qt::MiddleButton)
|
||||
{
|
||||
@@ -753,6 +820,40 @@ void DiagramView::mouseReleaseEvent(QMouseEvent *e)
|
||||
{
|
||||
if (m_event_interface && m_event_interface->mouseReleaseEvent(e)) return;
|
||||
|
||||
//A plain right click on a running tool falls through: the tool
|
||||
//handles it, as it always has
|
||||
if (m_gesture_tracking && e->button() == Qt::RightButton
|
||||
&& !(m_gesture_over_tool && !m_gesture_overlay->isVisible()))
|
||||
{
|
||||
m_gesture_tracking = false;
|
||||
const QPoint pos = e->position().toPoint();
|
||||
if (m_gesture_overlay->isVisible())
|
||||
{
|
||||
//A gesture: run the command it points at, if any
|
||||
QAction *action = m_gesture_overlay->actionAt(pos);
|
||||
m_gesture_overlay->hide();
|
||||
if (action) {
|
||||
action->trigger();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//A plain right click: the context menu, opened here on
|
||||
//release on every platform
|
||||
QContextMenuEvent menu_event(QContextMenuEvent::Mouse, pos,
|
||||
e->globalPosition().toPoint(),
|
||||
e->modifiers());
|
||||
m_menu_from_gesture = true;
|
||||
contextMenuEvent(&menu_event);
|
||||
m_menu_from_gesture = false;
|
||||
}
|
||||
e->accept();
|
||||
return;
|
||||
}
|
||||
if (e->button() == Qt::RightButton) {
|
||||
m_gesture_tracking = false;
|
||||
}
|
||||
|
||||
// Stop drag view
|
||||
if (e->button() == Qt::MiddleButton)
|
||||
{
|
||||
@@ -810,6 +911,27 @@ void DiagramView::mouseReleaseEvent(QMouseEvent *e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief DiagramView::selectionCommands
|
||||
@return the shortcut bar's commands for the current selection, as this
|
||||
window's actions
|
||||
*/
|
||||
QList<QAction *> DiagramView::selectionCommands() const
|
||||
{
|
||||
QList<QAction *> actions;
|
||||
QETDiagramEditor *qde = diagramEditor();
|
||||
if (!qde) {
|
||||
return actions;
|
||||
}
|
||||
const auto context = ShortcutBarSettings::contextFor(m_diagram->selectedItems());
|
||||
for (const QString &id : ShortcutBarSettings::ids(context)) {
|
||||
if (QAction *action = ShortcutManager::instance().action(id, qde)) {
|
||||
actions << action;
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief DiagramView::showContextToolbar
|
||||
After a click that leaves something selected, show the shortcut bar's
|
||||
@@ -829,14 +951,7 @@ void DiagramView::showContextToolbar(const QPoint &viewport_pos)
|
||||
return;
|
||||
}
|
||||
|
||||
QList<QAction *> actions;
|
||||
const auto context = ShortcutBarSettings::contextFor(selection);
|
||||
for (const QString &id : ShortcutBarSettings::ids(context)) {
|
||||
if (QAction *action = ShortcutManager::instance().action(id, qde)) {
|
||||
actions << action;
|
||||
}
|
||||
}
|
||||
m_context_toolbar->showAt(viewport_pos, actions);
|
||||
m_context_toolbar->showAt(viewport_pos, selectionCommands());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1689,6 +1804,14 @@ void DiagramView::contextMenuEvent(QContextMenuEvent *e)
|
||||
//right-click gets.
|
||||
const bool from_keyboard = e->reason() == QContextMenuEvent::Keyboard;
|
||||
|
||||
//With gestures on, a right press is tracked by mousePressEvent and
|
||||
//the menu opened on release; the platform's own event (sent on press
|
||||
//on X11, on release on Windows) would open it a second time.
|
||||
if (!from_keyboard && m_swallow_native_menu && !m_menu_from_gesture) {
|
||||
e->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
if (from_keyboard)
|
||||
{
|
||||
//Aim at the selection when there is one, so the menu appears
|
||||
|
||||
@@ -28,6 +28,7 @@ class CellRuler;
|
||||
class Conductor;
|
||||
class Diagram;
|
||||
class DiagramContextToolbar;
|
||||
class DiagramGestureOverlay;
|
||||
class QETDiagramEditor;
|
||||
class DVEventInterface;
|
||||
class QInputEvent;
|
||||
@@ -61,6 +62,16 @@ class DiagramView : public PaletteGraphicsView
|
||||
QPoint m_paste_here_pos;
|
||||
QPoint m_press_pos;
|
||||
DiagramContextToolbar *m_context_toolbar = nullptr;
|
||||
/// Right-drag gestures: tracking since the right button went down
|
||||
bool m_gesture_tracking = false;
|
||||
/// The platform's own right-click menu event is to be ignored:
|
||||
/// the view opens the menu itself on release
|
||||
bool m_swallow_native_menu = false;
|
||||
bool m_menu_from_gesture = false;
|
||||
/// The right press went to a running tool; a drag ends the tool
|
||||
bool m_gesture_over_tool = false;
|
||||
QPoint m_gesture_origin;
|
||||
DiagramGestureOverlay *m_gesture_overlay = nullptr;
|
||||
QPoint m_last_mouse_pos = QPoint(-1, -1);
|
||||
QPointF m_drag_last_pos;
|
||||
bool m_fresh_focus_in,
|
||||
@@ -137,6 +148,7 @@ class DiagramView : public PaletteGraphicsView
|
||||
void updateCellRulers();
|
||||
void placeCellRulers();
|
||||
void showContextToolbar(const QPoint &viewport_pos);
|
||||
QList<QAction *> selectionCommands() const;
|
||||
|
||||
/// Lowest and highest allowed value of the view transform scale (m11).
|
||||
/// Prevents wheel-zoom from driving the transform to overflow, which
|
||||
|
||||
@@ -71,6 +71,7 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) :
|
||||
//is the unchecked state -- a preference reads better as an opt-out.
|
||||
ui->m_collection_dblclick_edits->setChecked(!settings.value("elementscollection/double-click-inserts", true).toBool());
|
||||
ui->m_context_toolbar_cb->setChecked(settings.value("diagrameditor/context_toolbar", true).toBool());
|
||||
ui->m_mouse_gestures_cb->setChecked(settings.value("diagrameditor/mouse_gestures", true).toBool());
|
||||
ui->DiagramEditor_xGrid_sb->setValue(settings.value("diagrameditor/Xgrid", 10).toInt());
|
||||
ui->DiagramEditor_yGrid_sb->setValue(settings.value("diagrameditor/Ygrid", 10).toInt());
|
||||
for (const qreal divisor : TextGrid::divisors)
|
||||
@@ -300,6 +301,7 @@ void GeneralConfigurationPage::applyConf()
|
||||
settings.setValue("diagrameditor/guides_display_startup", ui->guides_startup_cb->isChecked());
|
||||
settings.setValue("elementscollection/double-click-inserts", !ui->m_collection_dblclick_edits->isChecked());
|
||||
settings.setValue("diagrameditor/context_toolbar", ui->m_context_toolbar_cb->isChecked());
|
||||
settings.setValue("diagrameditor/mouse_gestures", ui->m_mouse_gestures_cb->isChecked());
|
||||
//Grid step and key navigation
|
||||
settings.setValue("diagrameditor/Xgrid", ui->DiagramEditor_xGrid_sb->value());
|
||||
settings.setValue("diagrameditor/Ygrid", ui->DiagramEditor_yGrid_sb->value());
|
||||
|
||||
@@ -97,6 +97,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="m_mouse_gestures_cb">
|
||||
<property name="toolTip">
|
||||
<string>Maintenir le bouton droit et glisser dans une direction lance une commande de la barre de raccourcis. Un simple clic droit ouvre toujours le menu contextuel, au relâchement du bouton.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Gestes de la souris avec le bouton droit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="guides_startup_cb">
|
||||
<property name="text">
|
||||
|
||||
Reference in New Issue
Block a user