diff --git a/cmake/qet_compilation_vars.cmake b/cmake/qet_compilation_vars.cmake index 7ca29439c..1d8d7812b 100644 --- a/cmake/qet_compilation_vars.cmake +++ b/cmake/qet_compilation_vars.cmake @@ -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/commandsearchpopup.cpp ${QET_DIR}/sources/commandsearchpopup.h ${QET_DIR}/sources/titleblockcell.cpp @@ -801,6 +803,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 diff --git a/sources/ElementsCollection/elementpickerpopup.cpp b/sources/ElementsCollection/elementpickerpopup.cpp index 553aa3d5c..d3c9e9a39 100644 --- a/sources/ElementsCollection/elementpickerpopup.cpp +++ b/sources/ElementsCollection/elementpickerpopup.cpp @@ -19,7 +19,10 @@ #include "elementscollectionwidget.h" +#include #include +#include +#include #include #include #include @@ -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 &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 &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 */ diff --git a/sources/ElementsCollection/elementpickerpopup.h b/sources/ElementsCollection/elementpickerpopup.h index ab5213579..ae3200a83 100644 --- a/sources/ElementsCollection/elementpickerpopup.h +++ b/sources/ElementsCollection/elementpickerpopup.h @@ -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 &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 &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; }; diff --git a/sources/qetapp.cpp b/sources/qetapp.cpp index 48d9001b6..f7c086756 100644 --- a/sources/qetapp.cpp +++ b/sources/qetapp.cpp @@ -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 diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index 9af425b49..497cb7972 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -23,6 +23,8 @@ #include #include "ElementsCollection/elementscollectionwidget.h" #include "ElementsCollection/elementpickerpopup.h" +#include "shortcutbarsettings.h" +#include "qetgraphicsitem/conductor.h" #include "commandsearchpopup.h" #include "QWidgetAnimation/qwidgetanimation.h" #include "autoNum/ui/autonumberingdockwidget.h" @@ -77,6 +79,7 @@ #include #include #include +#include #ifdef BUILD_WITHOUT_KF # include "ui/nokde/kautosavefile.h" #else @@ -873,6 +876,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")); @@ -1005,7 +1022,8 @@ void QETDiagramEditor::setUpActions() connect(&m_add_item_actions_group, &QActionGroup::triggered, this, &QETDiagramEditor::addItemGroupTriggered); //No default key, but an id: they can then be found by the command - //search and bound in the Shortcuts page, like every other command. + //search, 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(), @@ -1166,6 +1184,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 -> addAction(m_command_search); menu_edition -> addSeparator(); //The same actions the "Ajouter" toolbar holds. They were toolbar-only, @@ -2077,6 +2096,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); @@ -3130,18 +3150,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, @@ -3149,7 +3163,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 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 commands; + for (const QString &id : ShortcutBarSettings::ids(context)) { + if (QAction *action = ShortcutManager::instance().action(id, this)) { + commands << action; + } + } + + elementPicker()->popUpAt(QCursor::pos(), commands); } /** diff --git a/sources/qetdiagrameditor.h b/sources/qetdiagrameditor.h index 880472821..9e432a3be 100644 --- a/sources/qetdiagrameditor.h +++ b/sources/qetdiagrameditor.h @@ -133,6 +133,7 @@ class QETDiagramEditor : public QETMainWindow void insertLastElement(); void rememberPlacedElement(const ElementsLocation &location); void showElementPicker(); + void showShortcutBar(); void generateTerminalBlock(); void setWindowedMode(); void setTabbedMode(); @@ -276,7 +277,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 QAction *m_command_search = nullptr; CommandSearchPopup *m_command_search_popup = nullptr; ///< Built on first use diff --git a/sources/shortcutbarsettings.cpp b/sources/shortcutbarsettings.cpp new file mode 100644 index 000000000..95072076a --- /dev/null +++ b/sources/shortcutbarsettings.cpp @@ -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 . +*/ +#include "shortcutbarsettings.h" + +#include +#include + +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::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); + } +} diff --git a/sources/shortcutbarsettings.h b/sources/shortcutbarsettings.h new file mode 100644 index 000000000..753698e75 --- /dev/null +++ b/sources/shortcutbarsettings.h @@ -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 . +*/ +#ifndef SHORTCUTBARSETTINGS_H +#define SHORTCUTBARSETTINGS_H + +#include +#include +#include + +/** + @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 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 diff --git a/sources/ui/configpage/shortcutbarconfigpage.cpp b/sources/ui/configpage/shortcutbarconfigpage.cpp new file mode 100644 index 000000000..d805aaa2d --- /dev/null +++ b/sources/ui/configpage/shortcutbarconfigpage.cpp @@ -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 . +*/ +#include "shortcutbarconfigpage.h" + +#include "../../qeticons.h" +#include "../../shortcutmanager.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +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(&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( + 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); +} diff --git a/sources/ui/configpage/shortcutbarconfigpage.h b/sources/ui/configpage/shortcutbarconfigpage.h new file mode 100644 index 000000000..9a15537dd --- /dev/null +++ b/sources/ui/configpage/shortcutbarconfigpage.h @@ -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 . +*/ +#ifndef SHORTCUTBARCONFIGPAGE_H +#define SHORTCUTBARCONFIGPAGE_H + +#include "configpage.h" +#include "../../shortcutbarsettings.h" + +#include + +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 m_pending; + QHash m_descriptions; +}; + +#endif // SHORTCUTBARCONFIGPAGE_H