Add a shortcut bar that opens at the cursor with S

Pressing S on a folio opens the element picker at the cursor with a row
of commands above it, chosen by what is selected, like the SolidWorks
shortcut bar:

  nothing selected     insert last element, element picker, text, line,
                       rectangle, terminal strip plan, paste, folio
                       properties
  elements selected    rotate, rotate texts, edit, copy, cut, delete
  only conductors      reset path, edit, delete

Each row is a list of ShortcutManager ids, so any registered command can
go on it and the bar carries no command list of its own. The lists are
in QSettings (diagrameditor/shortcut_bar/<context>); a context the user
has not changed follows the defaults. A disabled command keeps its
place, greyed, so a row looks the same each time. Clicking a button
closes the bar and triggers the action.

A new configuration page, "Barre de raccourcis", edits the three lists:
add, remove and reorder any diagram editor command.

To make that possible:
- ShortcutManager::action(id, owner) returns the action a given window
  registered under an id, since each editor window registers its own.
- The add-item actions (text, image, shapes, terminal strip plan) are
  registered as diagrameditor.add_<kind>, with no default key. They also
  appear in the Shortcuts page and can now be bound.

Discussion #1033.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG
(cherry picked from commit 53c1e213282b9f7226ca1c09e81703113236bb88)
This commit is contained in:
ispyisail
2026-09-26 12:38:40 +12:00
parent 07501d604e
commit 2da101ca90
12 changed files with 659 additions and 13 deletions
+4
View File
@@ -285,6 +285,8 @@ set(QET_SRC_FILES
${QET_DIR}/sources/recentfiles.h
${QET_DIR}/sources/shortcutmanager.cpp
${QET_DIR}/sources/shortcutmanager.h
${QET_DIR}/sources/shortcutbarsettings.cpp
${QET_DIR}/sources/shortcutbarsettings.h
${QET_DIR}/sources/titleblockcell.cpp
${QET_DIR}/sources/titleblockcell.h
${QET_DIR}/sources/titleblockproperties.cpp
@@ -799,6 +801,8 @@ set(QET_SRC_FILES
${QET_DIR}/sources/ui/configpage/guidespropertieswidget.h
${QET_DIR}/sources/ui/configpage/shortcutsconfigpage.cpp
${QET_DIR}/sources/ui/configpage/shortcutsconfigpage.h
${QET_DIR}/sources/ui/configpage/shortcutbarconfigpage.cpp
${QET_DIR}/sources/ui/configpage/shortcutbarconfigpage.h
${QET_DIR}/sources/undocommand/addelementtextcommand.cpp
${QET_DIR}/sources/undocommand/addelementtextcommand.h
@@ -19,7 +19,10 @@
#include "elementscollectionwidget.h"
#include <QAction>
#include <QGuiApplication>
#include <QHBoxLayout>
#include <QToolButton>
#include <QKeyEvent>
#include <QLabel>
#include <QLineEdit>
@@ -58,6 +61,13 @@ ElementPickerPopup::ElementPickerPopup(ElementsCollectionWidget *source,
layout->setContentsMargins(6, 6, 6, 6);
layout->setSpacing(4);
//Command row, shown when the picker is opened as the shortcut bar
m_commands = new QWidget(this);
m_commands_layout = new QHBoxLayout(m_commands);
m_commands_layout->setContentsMargins(0, 0, 0, 0);
m_commands_layout->setSpacing(2);
m_commands->hide();
m_search = new QLineEdit(this);
m_search->setPlaceholderText(tr("Rechercher un élément…"));
m_search->setClearButtonEnabled(true);
@@ -73,6 +83,7 @@ ElementPickerPopup::ElementPickerPopup(ElementsCollectionWidget *source,
m_hint = new QLabel(tr("Entrée pour insérer · Échap pour fermer"), this);
m_hint->setEnabled(false);
layout->addWidget(m_commands);
layout->addWidget(m_search);
layout->addWidget(m_view);
layout->addWidget(m_hint);
@@ -97,8 +108,10 @@ ElementPickerPopup::ElementPickerPopup(ElementsCollectionWidget *source,
focused and any previous query cleared.
@param global_pos
*/
void ElementPickerPopup::popUpAt(const QPoint &global_pos)
void ElementPickerPopup::popUpAt(const QPoint &global_pos,
const QList<QAction *> &commands)
{
setCommands(commands);
m_search->clear();
m_model->clear();
showPalette();
@@ -121,6 +134,53 @@ void ElementPickerPopup::popUpAt(const QPoint &global_pos)
m_search->setFocus();
}
/**
@brief ElementPickerPopup::setCommands
Show @a commands as a row of buttons above the search field, or hide the
row when there are none. A disabled command keeps its place, greyed out,
so the row looks the same every time for a given selection.
Clicking a button closes the picker first, then triggers the action: a
command such as "add a line" starts a mode on the folio, which needs the
focus the popup holds.
@param commands
*/
void ElementPickerPopup::setCommands(const QList<QAction *> &commands)
{
while (QLayoutItem *item = m_commands_layout->takeAt(0)) {
delete item->widget();
delete item;
}
for (QAction *action : commands)
{
auto *button = new QToolButton(m_commands);
button->setAutoRaise(true);
button->setIconSize(QSize(24, 24));
const QString text = action->text().remove(QLatin1Char('&'));
if (action->icon().isNull()) {
button->setText(text);
button->setToolButtonStyle(Qt::ToolButtonTextOnly);
} else {
button->setIcon(action->icon());
}
const QKeySequence key = action->shortcut();
button->setToolTip(key.isEmpty()
? text
: QStringLiteral("%1 (%2)").arg(
text, key.toString(QKeySequence::NativeText)));
button->setEnabled(action->isEnabled());
button->setFocusPolicy(Qt::NoFocus);
connect(button, &QToolButton::clicked, this, [this, action]() {
hide();
action->trigger();
});
m_commands_layout->addWidget(button);
}
m_commands_layout->addStretch();
m_commands->setVisible(!commands.isEmpty());
}
/**
@brief ElementPickerPopup::runSearch
*/
@@ -27,6 +27,8 @@ class QLineEdit;
class QListView;
class QStandardItemModel;
class QLabel;
class QAction;
class QHBoxLayout;
/**
@brief A cursor-anchored element picker.
@@ -49,7 +51,8 @@ class ElementPickerPopup : public QFrame
explicit ElementPickerPopup(ElementsCollectionWidget *source,
QWidget *parent = nullptr);
void popUpAt(const QPoint &global_pos);
void popUpAt(const QPoint &global_pos,
const QList<QAction *> &commands = {});
signals:
/// Emitted when the user picks an element; the popup has closed
@@ -62,6 +65,7 @@ class ElementPickerPopup : public QFrame
void runSearch();
void chooseCurrent();
void showPalette();
void setCommands(const QList<QAction *> &commands);
int loadPaletteDir(const QString &dir_path, const QString &prefix,
int depth);
@@ -70,6 +74,8 @@ class ElementPickerPopup : public QFrame
QListView *m_view = nullptr;
QStandardItemModel *m_model = nullptr;
QLabel *m_hint = nullptr;
QWidget *m_commands = nullptr;
QHBoxLayout *m_commands_layout = nullptr;
bool m_palette_mode = true;
};
+2
View File
@@ -40,6 +40,7 @@
#include "ui/aboutqetdialog.h"
#include "ui/configpage/generalconfigurationpage.h"
#include "ui/configpage/shortcutsconfigpage.h"
#include "ui/configpage/shortcutbarconfigpage.h"
#include "machine_info.h"
#include "TerminalStrip/ui/terminalstripeditorwindow.h"
#include "qetversion.h"
@@ -2213,6 +2214,7 @@ void QETApp::configureQET()
cd.addPage(new ExportConfigPage());
cd.addPage(new PrintConfigPage());
cd.addPage(new ShortcutsConfigPage());
cd.addPage(new ShortcutBarConfigPage());
#ifdef QET_SPACEMOUSE_SUPPORT
cd.addPage(new SpaceMouseConfigPage());
#endif
+80 -11
View File
@@ -23,6 +23,8 @@
#include <QToolButton>
#include "ElementsCollection/elementscollectionwidget.h"
#include "ElementsCollection/elementpickerpopup.h"
#include "shortcutbarsettings.h"
#include "qetgraphicsitem/conductor.h"
#include "QWidgetAnimation/qwidgetanimation.h"
#include "autoNum/ui/autonumberingdockwidget.h"
#include "conductornumexport.h"
@@ -76,6 +78,7 @@
#include <QDebug>
#include <QDir>
#include <QTimer>
#include <algorithm>
#ifdef BUILD_WITHOUT_KF
# include "ui/nokde/kautosavefile.h"
#else
@@ -840,6 +843,20 @@ void QETDiagramEditor::setUpActions()
this, &QETDiagramEditor::showElementPicker);
addAction(m_show_element_picker);
//The picker with a row of commands above it, chosen by what is
//selected -- the SolidWorks "S" shortcut bar. S is unbound in this
//editor.
m_show_shortcut_bar = new QAction(tr("Barre de raccourcis"), this);
m_show_shortcut_bar->setStatusTip(
tr("Ouvre à la position du curseur les commandes utiles pour la sélection, et le sélecteur d'éléments",
"status bar tip"));
ShortcutManager::instance().registerAction(
m_show_shortcut_bar, "diagrameditor.show_shortcut_bar",
tr("Éditeur de schémas"), Qt::Key_S);
connect(m_show_shortcut_bar, &QAction::triggered,
this, &QETDiagramEditor::showShortcutBar);
addAction(m_show_shortcut_bar);
m_delete_selection->setStatusTip( tr("Enlève les éléments sélectionnés du folio", "status bar tip"));
m_rotate_selection->setStatusTip( tr("Pivote les éléments et textes sélectionnés", "status bar tip"));
m_rotate_group_selection->setStatusTip( tr("Pivote la sélection comme un groupe autour de son centre, au lieu de chaque élément sur place", "status bar tip"));
@@ -971,6 +988,13 @@ void QETDiagramEditor::setUpActions()
add_path->setCheckable(true);
connect(&m_add_item_actions_group, &QActionGroup::triggered, this, &QETDiagramEditor::addItemGroupTriggered);
//No default key, but an id: they can then be bound in the Shortcuts
//page and placed on the shortcut bar, like every other command.
for (QAction *action : m_add_item_actions_group.actions()) {
ShortcutManager::instance().registerAction(
action, "diagrameditor.add_" + action->data().toString(),
tr("Éditeur de schémas"), QKeySequence());
}
//Depth action
m_depth_action_group = QET::depthActionGroup(this);
@@ -1126,6 +1150,7 @@ void QETDiagramEditor::setUpMenu()
menu_edition -> addAction(m_configure_duplicate);
menu_edition -> addAction(m_insert_last_element);
menu_edition -> addAction(m_show_element_picker);
menu_edition -> addAction(m_show_shortcut_bar);
menu_edition -> addSeparator();
//The same actions the "Ajouter" toolbar holds. They were toolbar-only,
//which left them unreachable for anyone working without a mouse: a
@@ -2035,6 +2060,7 @@ void QETDiagramEditor::slot_updateActions()
m_add_item_actions_group. setEnabled(editable_project);
m_insert_last_element-> setEnabled(opened_diagram && editable_project && !m_last_inserted_element.isNull());
m_show_element_picker-> setEnabled(opened_diagram && editable_project);
m_show_shortcut_bar-> setEnabled(opened_diagram && editable_project);
m_row_column_actions_group. setEnabled(editable_project);
m_background_color_button-> setEnabled(opened_diagram);
m_draw_grid-> setEnabled(opened_diagram);
@@ -3087,18 +3113,12 @@ void QETDiagramEditor::insertLastElement()
}
/**
@brief QETDiagramEditor::showElementPicker
Open the element picker where the mouse is.
Built lazily: most sessions of the diagram editor never open it, and it
holds a list view and a model of its own.
@brief QETDiagramEditor::elementPicker
@return the element picker, built on first use: most sessions never open
it, and it holds a list view and a model of its own.
*/
void QETDiagramEditor::showElementPicker()
ElementPickerPopup *QETDiagramEditor::elementPicker()
{
if (!currentDiagramView()) {
return;
}
if (!m_element_picker)
{
m_element_picker = new ElementPickerPopup(m_element_collection_widget,
@@ -3106,7 +3126,56 @@ void QETDiagramEditor::showElementPicker()
connect(m_element_picker, &ElementPickerPopup::elementChosen,
this, &QETDiagramEditor::insertElementFromCollection);
}
m_element_picker->popUpAt(QCursor::pos());
return m_element_picker;
}
/**
@brief QETDiagramEditor::showElementPicker
Open the element picker where the mouse is.
*/
void QETDiagramEditor::showElementPicker()
{
if (!currentDiagramView()) {
return;
}
elementPicker()->popUpAt(QCursor::pos());
}
/**
@brief QETDiagramEditor::showShortcutBar
Open the element picker where the mouse is, with a row of commands above
it chosen by what is selected: the folio's commands with nothing
selected, conductor commands when only conductors are, and selection
commands otherwise. The commands are ShortcutManager ids, listed in
ShortcutBarSettings and editable in the configuration dialog.
*/
void QETDiagramEditor::showShortcutBar()
{
DiagramView *dv = currentDiagramView();
if (!dv) {
return;
}
const QList<QGraphicsItem *> selection = dv->diagram()->selectedItems();
ShortcutBarSettings::Context context = ShortcutBarSettings::Canvas;
if (!selection.isEmpty())
{
const bool only_conductors = std::all_of(
selection.cbegin(), selection.cend(),
[](QGraphicsItem *item) { return item->type() == Conductor::Type; });
context = only_conductors ? ShortcutBarSettings::Conductor
: ShortcutBarSettings::Selection;
}
QList<QAction *> commands;
for (const QString &id : ShortcutBarSettings::ids(context)) {
if (QAction *action = ShortcutManager::instance().action(id, this)) {
commands << action;
}
}
elementPicker()->popUpAt(QCursor::pos(), commands);
}
/**
+3
View File
@@ -132,6 +132,7 @@ class QETDiagramEditor : public QETMainWindow
void insertLastElement();
void rememberPlacedElement(const ElementsLocation &location);
void showElementPicker();
void showShortcutBar();
void generateTerminalBlock();
void setWindowedMode();
void setTabbedMode();
@@ -273,7 +274,9 @@ class QETDiagramEditor : public QETMainWindow
*m_qdw_elmt_collection,
*qdw_undo; /// Dock for the undo list
ElementPickerPopup *elementPicker();
QAction *m_show_element_picker = nullptr;
QAction *m_show_shortcut_bar = nullptr;
ElementPickerPopup *m_element_picker = nullptr; ///< Built on first use
ElementsCollectionWidget *m_element_collection_widget;
/// Last element placed from the collection, for "insert last"
+122
View File
@@ -0,0 +1,122 @@
/*
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 "shortcutbarsettings.h"
#include <QCoreApplication>
#include <QSettings>
namespace {
QString settingsKey(ShortcutBarSettings::Context context)
{
switch (context)
{
case ShortcutBarSettings::Canvas:
return QStringLiteral("diagrameditor/shortcut_bar/canvas");
case ShortcutBarSettings::Selection:
return QStringLiteral("diagrameditor/shortcut_bar/selection");
case ShortcutBarSettings::Conductor:
return QStringLiteral("diagrameditor/shortcut_bar/conductor");
}
return QString();
}
}
/**
@return every context, in the order they are shown to the user
*/
QList<ShortcutBarSettings::Context> ShortcutBarSettings::contexts()
{
return {Canvas, Selection, Conductor};
}
/**
@return the name of @a context, for the configuration page
*/
QString ShortcutBarSettings::title(Context context)
{
switch (context)
{
case Canvas:
return QCoreApplication::translate("ShortcutBarSettings", "Folio, rien de sélectionné");
case Selection:
return QCoreApplication::translate("ShortcutBarSettings", "Éléments sélectionnés");
case Conductor:
return QCoreApplication::translate("ShortcutBarSettings", "Conducteurs sélectionnés");
}
return QString();
}
/**
@return the ids to show for @a context: the user's list if they saved
one, the defaults otherwise. A saved empty list stays empty.
*/
QStringList ShortcutBarSettings::ids(Context context)
{
QSettings settings;
const QString key = settingsKey(context);
if (!settings.contains(key)) {
return defaultIds(context);
}
return settings.value(key).toStringList();
}
/**
@return the commands a new user sees for @a context
*/
QStringList ShortcutBarSettings::defaultIds(Context context)
{
switch (context)
{
case Canvas:
return {QStringLiteral("diagrameditor.insert_last_element"),
QStringLiteral("diagrameditor.show_element_picker"),
QStringLiteral("diagrameditor.add_text"),
QStringLiteral("diagrameditor.add_line"),
QStringLiteral("diagrameditor.add_rectangle"),
QStringLiteral("diagrameditor.add_terminal_strip"),
QStringLiteral("diagrameditor.paste"),
QStringLiteral("diagrameditor.edit_diagram_properties")};
case Selection:
return {QStringLiteral("diagrameditor.rotate_selection"),
QStringLiteral("diagrameditor.rotate_texts"),
QStringLiteral("diagrameditor.edit_selection"),
QStringLiteral("diagrameditor.copy"),
QStringLiteral("diagrameditor.cut"),
QStringLiteral("diagrameditor.delete_selection")};
case Conductor:
return {QStringLiteral("diagrameditor.conductor_reset"),
QStringLiteral("diagrameditor.edit_selection"),
QStringLiteral("diagrameditor.delete_selection")};
}
return {};
}
/**
@brief ShortcutBarSettings::setIds
Save @a ids for @a context. Saving the defaults removes the key, so a
later change of defaults still reaches this user.
*/
void ShortcutBarSettings::setIds(Context context, const QStringList &ids)
{
QSettings settings;
if (ids == defaultIds(context)) {
settings.remove(settingsKey(context));
} else {
settings.setValue(settingsKey(context), ids);
}
}
+50
View File
@@ -0,0 +1,50 @@
/*
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 SHORTCUTBARSETTINGS_H
#define SHORTCUTBARSETTINGS_H
#include <QList>
#include <QString>
#include <QStringList>
/**
@brief The commands shown on the diagram editor's shortcut bar.
The bar opens at the cursor and shows a different row of commands
depending on what is selected. Each row is a list of ShortcutManager ids,
so any registered command can go on it and the bar needs no command list
of its own. Stored in QSettings, one key per context; a context the user
never changed uses the defaults below.
*/
class ShortcutBarSettings
{
public:
enum Context {
Canvas, ///< nothing selected
Selection, ///< elements, texts or shapes selected
Conductor ///< only conductors selected
};
static QList<Context> contexts();
static QString title(Context context);
static QStringList ids(Context context);
static QStringList defaultIds(Context context);
static void setIds(Context context, const QStringList &ids);
};
#endif // SHORTCUTBARSETTINGS_H
+33
View File
@@ -197,3 +197,36 @@ bool ShortcutManager::trigger(const QString &id) const
}
return false;
}
/**
@return the QAction registered under @a id that belongs to @a owner --
that is, has @a owner among its ancestors -- or nullptr. Several windows
of the same kind each register their own action under one id, so a
window asking for "its" action has to say which window it is.
@param id
@param owner : the window, or nullptr for the first live action
*/
QAction *ShortcutManager::action(const QString &id, const QObject *owner) const
{
auto it = m_entries.find(id);
if (it == m_entries.end()) {
return nullptr;
}
for (const QPointer<QObject> &target : qAsConst(it->targets))
{
auto *action = qobject_cast<QAction *>(target.data());
if (!action) {
continue;
}
if (!owner) {
return action;
}
for (const QObject *o = action->parent(); o; o = o->parent()) {
if (o == owner) {
return action;
}
}
}
return nullptr;
}
+2
View File
@@ -26,6 +26,7 @@
#include <QStringList>
class QObject;
class QAction;
/**
@brief The ShortcutManager class
@@ -84,6 +85,7 @@ class ShortcutManager
/// multi-window case, not a guaranteed-correct dispatch.
/// @return whether a live target was found and triggered.
bool trigger(const QString &id) const;
QAction *action(const QString &id, const QObject *owner) const;
private:
ShortcutManager() = default;
@@ -0,0 +1,231 @@
/*
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 "shortcutbarconfigpage.h"
#include "../../qeticons.h"
#include "../../shortcutmanager.h"
#include <QAction>
#include <QComboBox>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QListWidget>
#include <QPushButton>
#include <QVBoxLayout>
namespace {
/// The bar can hold any diagram editor command, except the one that
/// opens it.
bool offerable(const QString &id)
{
return id.startsWith(QLatin1String("diagrameditor."))
&& id != QLatin1String("diagrameditor.show_shortcut_bar");
}
}
/**
@brief ShortcutBarConfigPage::ShortcutBarConfigPage
@param parent
*/
ShortcutBarConfigPage::ShortcutBarConfigPage(QWidget *parent) :
ConfigPage(parent)
{
for (const ShortcutManager::ShortcutInfo &info :
ShortcutManager::instance().allShortcuts()) {
if (offerable(info.id)) {
m_descriptions.insert(info.id, info.description);
}
}
for (const ShortcutBarSettings::Context c : ShortcutBarSettings::contexts()) {
m_pending.insert(c, ShortcutBarSettings::ids(c));
}
auto *explanation = new QLabel(
tr("La barre de raccourcis s'ouvre à la position du curseur "
"(touche S par défaut). Elle montre les commandes choisies "
"ici selon ce qui est sélectionné, puis le sélecteur "
"d'éléments."), this);
explanation->setWordWrap(true);
m_context = new QComboBox(this);
for (const ShortcutBarSettings::Context c : ShortcutBarSettings::contexts()) {
m_context->addItem(ShortcutBarSettings::title(c), c);
}
m_available = new QListWidget(this);
m_available->setSelectionMode(QAbstractItemView::ExtendedSelection);
m_available->setSortingEnabled(true);
m_chosen = new QListWidget(this);
m_chosen->setSelectionMode(QAbstractItemView::ExtendedSelection);
m_chosen->setDragDropMode(QAbstractItemView::InternalMove);
auto *add = new QPushButton(tr("Ajouter →"), this);
auto *remove = new QPushButton(tr("← Retirer"), this);
auto *up = new QPushButton(tr("Monter"), this);
auto *down = new QPushButton(tr("Descendre"), this);
auto *reset = new QPushButton(tr("Valeurs par défaut"), this);
auto *buttons = new QVBoxLayout();
buttons->addStretch();
buttons->addWidget(add);
buttons->addWidget(remove);
buttons->addSpacing(12);
buttons->addWidget(up);
buttons->addWidget(down);
buttons->addStretch();
auto *grid = new QGridLayout();
grid->addWidget(new QLabel(tr("Commandes disponibles"), this), 0, 0);
grid->addWidget(new QLabel(tr("Dans la barre, dans l'ordre"), this), 0, 2);
grid->addWidget(m_available, 1, 0);
grid->addLayout(buttons, 1, 1);
grid->addWidget(m_chosen, 1, 2);
auto *context_row = new QHBoxLayout();
context_row->addWidget(new QLabel(tr("Contexte :"), this));
context_row->addWidget(m_context, 1);
context_row->addWidget(reset);
auto *layout = new QVBoxLayout(this);
layout->addWidget(explanation);
layout->addLayout(context_row);
layout->addLayout(grid);
connect(m_context, qOverload<int>(&QComboBox::currentIndexChanged), this, [this]() {
storeContext();
showContext();
});
connect(add, &QPushButton::clicked, this, &ShortcutBarConfigPage::addSelected);
connect(remove, &QPushButton::clicked, this, &ShortcutBarConfigPage::removeSelected);
connect(up, &QPushButton::clicked, this, [this]() { moveSelected(-1); });
connect(down, &QPushButton::clicked, this, [this]() { moveSelected(1); });
connect(reset, &QPushButton::clicked, this, &ShortcutBarConfigPage::resetContext);
connect(m_available, &QListWidget::itemDoubleClicked, this, &ShortcutBarConfigPage::addSelected);
connect(m_chosen, &QListWidget::itemDoubleClicked, this, &ShortcutBarConfigPage::removeSelected);
showContext();
}
/**
@brief ShortcutBarConfigPage::applyConf
Save every context's list.
*/
void ShortcutBarConfigPage::applyConf()
{
storeContext();
for (const ShortcutBarSettings::Context c : ShortcutBarSettings::contexts()) {
ShortcutBarSettings::setIds(c, m_pending.value(c));
}
}
QString ShortcutBarConfigPage::title() const
{
return tr("Barre de raccourcis", "configuration page title");
}
QIcon ShortcutBarConfigPage::icon() const
{
return QET::Icons::ConfigureShortcuts;
}
/**
@brief ShortcutBarConfigPage::showContext
Fill both lists for the context chosen in the combo box.
*/
void ShortcutBarConfigPage::showContext()
{
m_shown = static_cast<ShortcutBarSettings::Context>(
m_context->currentData().toInt());
const QStringList chosen = m_pending.value(m_shown);
m_available->clear();
m_chosen->clear();
for (const QString &id : chosen) {
appendItem(m_chosen, id);
}
for (auto it = m_descriptions.cbegin(); it != m_descriptions.cend(); ++it) {
if (!chosen.contains(it.key())) {
appendItem(m_available, it.key());
}
}
}
/**
@brief ShortcutBarConfigPage::storeContext
Keep the shown context's list, in the order on screen.
*/
void ShortcutBarConfigPage::storeContext()
{
QStringList ids;
for (int i = 0 ; i < m_chosen->count() ; ++i) {
ids << m_chosen->item(i)->data(Qt::UserRole).toString();
}
m_pending.insert(m_shown, ids);
}
void ShortcutBarConfigPage::addSelected()
{
for (QListWidgetItem *item : m_available->selectedItems()) {
m_chosen->addItem(m_available->takeItem(m_available->row(item)));
}
}
void ShortcutBarConfigPage::removeSelected()
{
for (QListWidgetItem *item : m_chosen->selectedItems()) {
m_available->addItem(m_chosen->takeItem(m_chosen->row(item)));
}
}
/**
@brief ShortcutBarConfigPage::moveSelected
Move the selected command @a step rows, keeping it selected.
*/
void ShortcutBarConfigPage::moveSelected(int step)
{
const int row = m_chosen->currentRow();
const int target = row + step;
if (row < 0 || target < 0 || target >= m_chosen->count()) {
return;
}
QListWidgetItem *item = m_chosen->takeItem(row);
m_chosen->insertItem(target, item);
m_chosen->setCurrentRow(target);
}
void ShortcutBarConfigPage::resetContext()
{
m_pending.insert(m_shown, ShortcutBarSettings::defaultIds(m_shown));
showContext();
}
/**
@brief ShortcutBarConfigPage::appendItem
Add @a id to @a list with the command's text and icon. An id no live
action carries (a command from a build without it) is still listed, by
its id, so saving does not silently drop it.
*/
void ShortcutBarConfigPage::appendItem(QListWidget *list, const QString &id)
{
QAction *action = ShortcutManager::instance().action(id, nullptr);
const QString text = m_descriptions.value(id, id);
auto *item = new QListWidgetItem(action ? action->icon() : QIcon(), text);
item->setData(Qt::UserRole, id);
list->addItem(item);
}
@@ -0,0 +1,64 @@
/*
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 SHORTCUTBARCONFIGPAGE_H
#define SHORTCUTBARCONFIGPAGE_H
#include "configpage.h"
#include "../../shortcutbarsettings.h"
#include <QHash>
class QComboBox;
class QListWidget;
/**
@brief The ShortcutBarConfigPage class
Choose which commands the diagram editor's shortcut bar shows, and in
what order, for each selection context. Any command registered with
ShortcutManager by the diagram editor can be added. Changes are kept
per context while the dialog is open and saved by applyConf().
*/
class ShortcutBarConfigPage : public ConfigPage
{
Q_OBJECT
public:
explicit ShortcutBarConfigPage(QWidget *parent = nullptr);
void applyConf() override;
QString title() const override;
QIcon icon() const override;
private:
void showContext();
void storeContext();
void addSelected();
void removeSelected();
void moveSelected(int step);
void resetContext();
void appendItem(QListWidget *list, const QString &id);
QComboBox *m_context;
QListWidget *m_available;
QListWidget *m_chosen;
ShortcutBarSettings::Context m_shown = ShortcutBarSettings::Canvas;
QHash<int, QStringList> m_pending;
QHash<QString, QString> m_descriptions;
};
#endif // SHORTCUTBARCONFIGPAGE_H