mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-03 09:14:12 +02:00
Merge pull request #1042 from ispyisail/feature/place-without-drag
Add double-click placement from the collection, and A to repeat it
This commit is contained in:
@@ -35,6 +35,8 @@
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QDesktopServices>
|
||||
#include <QSettings>
|
||||
#include <QShortcut>
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFileDialog>
|
||||
@@ -266,15 +268,7 @@ void ElementsCollectionWidget::setUpConnection()
|
||||
this, &ElementsCollectionWidget::dirProperties);
|
||||
|
||||
connect(m_tree_view, &QTreeView::doubleClicked,
|
||||
[this](const QModelIndex &index)
|
||||
{
|
||||
this->m_index_at_context_menu = index ;
|
||||
ElementCollectionItem *eci = elementCollectionItemForIndex(index);
|
||||
if (eci && eci->collectionPath().endsWith(".qetmak")) {
|
||||
return; // Do nothing on double click for macros
|
||||
}
|
||||
this->editElement();
|
||||
});
|
||||
[this](const QModelIndex &index) { this->activateIndex(index); });
|
||||
|
||||
connect(m_tree_view, &QTreeView::entered,
|
||||
[this] (const QModelIndex &index) {
|
||||
@@ -284,19 +278,23 @@ void ElementsCollectionWidget::setUpConnection()
|
||||
qde->statusBar()->showMessage(eci->localName());
|
||||
});
|
||||
|
||||
//Enter on the highlighted item does the same as a double click, so a
|
||||
//run of elements can be placed without leaving the keyboard. Bound as
|
||||
//a shortcut on the view rather than by reimplementing keyPressEvent,
|
||||
//which would mean subclassing ElementsTreeView for one key.
|
||||
for (const auto key : {Qt::Key_Return, Qt::Key_Enter}) {
|
||||
auto *sc = new QShortcut(QKeySequence(key), m_tree_view);
|
||||
sc->setContext(Qt::WidgetShortcut);
|
||||
connect(sc, &QShortcut::activated, this, [this]() {
|
||||
this->activateIndex(m_tree_view->currentIndex());
|
||||
});
|
||||
}
|
||||
|
||||
connect(m_macros_tree_view, &QTreeView::customContextMenuRequested,
|
||||
this, &ElementsCollectionWidget::customContextMenu);
|
||||
|
||||
connect(m_macros_tree_view, &QTreeView::doubleClicked,
|
||||
[this](const QModelIndex &index)
|
||||
{
|
||||
this->m_index_at_context_menu = index ;
|
||||
ElementCollectionItem *eci = elementCollectionItemForIndex(index);
|
||||
if (eci && eci->collectionPath().endsWith(".qetmak")) {
|
||||
return; // Do nothing on double click for macros
|
||||
}
|
||||
this->editElement();
|
||||
});
|
||||
[this](const QModelIndex &index) { this->activateIndex(index); });
|
||||
|
||||
connect(m_macros_tree_view, &QTreeView::entered,
|
||||
[this] (const QModelIndex &index) {
|
||||
@@ -405,6 +403,60 @@ void ElementsCollectionWidget::openDir()
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementsCollectionWidget::activateIndex
|
||||
What a double click (or Enter) on @a index does.
|
||||
|
||||
Historically this opened the element editor, which is the slowest action
|
||||
available on a symbol you are most likely about to place. Placing is now
|
||||
the default and editing has moved to the context menu, where it already
|
||||
was. The old behaviour is preserved behind a preference for anyone who
|
||||
relies on it.
|
||||
@param index
|
||||
*/
|
||||
void ElementsCollectionWidget::activateIndex(const QModelIndex &index)
|
||||
{
|
||||
m_index_at_context_menu = index;
|
||||
|
||||
ElementCollectionItem *eci = elementCollectionItemForIndex(index);
|
||||
if (!eci) {
|
||||
return;
|
||||
}
|
||||
//Macros are placed, never edited, and were already skipped here.
|
||||
const bool is_macro = eci->collectionPath().endsWith(".qetmak");
|
||||
|
||||
QSettings settings;
|
||||
const bool insert = settings.value(
|
||||
QStringLiteral("elementscollection/double-click-inserts"), true).toBool();
|
||||
|
||||
if (insert) {
|
||||
insertCurrentElement();
|
||||
return;
|
||||
}
|
||||
if (!is_macro) {
|
||||
editElement();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementsCollectionWidget::insertCurrentElement
|
||||
Ask for the current item to be placed on the folio.
|
||||
*/
|
||||
void ElementsCollectionWidget::insertCurrentElement()
|
||||
{
|
||||
ElementCollectionItem *eci =
|
||||
elementCollectionItemForIndex(m_index_at_context_menu);
|
||||
if (!(eci && eci->isElement())) {
|
||||
return;
|
||||
}
|
||||
|
||||
ElementsLocation location(eci->collectionPath());
|
||||
if (!location.exist()) {
|
||||
return;
|
||||
}
|
||||
emit insertElementRequested(location);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementsCollectionWidget::editElement
|
||||
Edit the element represented by the current selected item
|
||||
@@ -415,10 +467,19 @@ void ElementsCollectionWidget::editElement()
|
||||
|
||||
if ( !(eci && eci->isElement()) ) return;
|
||||
|
||||
// Prevent the element editor from opening for macros
|
||||
if (eci->collectionPath().endsWith(".qetmak")) return;
|
||||
editLocation(ElementsLocation(eci->collectionPath()));
|
||||
}
|
||||
|
||||
ElementsLocation location(eci->collectionPath());
|
||||
/**
|
||||
@brief ElementsCollectionWidget::editLocation
|
||||
Open the element editor on @a location. Macros have no editor and are
|
||||
ignored.
|
||||
@param location
|
||||
*/
|
||||
void ElementsCollectionWidget::editLocation(const ElementsLocation &location)
|
||||
{
|
||||
// Prevent the element editor from opening for macros
|
||||
if (!location.exist() || location.path().endsWith(".qetmak")) return;
|
||||
|
||||
QETApp *app = QETApp::instance();
|
||||
app->openElementLocations(QList<ElementsLocation>() << location);
|
||||
|
||||
@@ -86,9 +86,22 @@ class ElementsCollectionWidget : public QWidget
|
||||
public slots:
|
||||
void reload();
|
||||
void loadingFinished();
|
||||
void insertCurrentElement();
|
||||
void editLocation(const ElementsLocation &location);
|
||||
|
||||
signals:
|
||||
/**
|
||||
Emitted when the user asks for an element to be placed on the
|
||||
current folio. Whoever hosts this widget decides which view
|
||||
receives it -- the dock is inside a diagram editor, but the
|
||||
picker popup is not, so the widget must not reach for an
|
||||
ancestor editor itself.
|
||||
*/
|
||||
void insertElementRequested(const ElementsLocation &location);
|
||||
|
||||
private:
|
||||
void locationWasSaved(const ElementsLocation& location);
|
||||
void activateIndex(const QModelIndex &index);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
+60
-2
@@ -234,14 +234,72 @@ void DiagramView::handleElementDrop(QDropEvent *event)
|
||||
QPointF drop_pos;
|
||||
drop_pos = mapToScene(event->position().toPoint());
|
||||
|
||||
startElementPlacement(location, drop_pos);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief DiagramView::startElementPlacement
|
||||
Enter the interactive placement mode for @a location, with the pending
|
||||
element starting at @a scene_pos.
|
||||
|
||||
This is the mode where the element follows the cursor on the grid, a left
|
||||
click drops a copy, Space rotates it and the element stays loaded so a run
|
||||
of identical symbols can be placed with successive clicks.
|
||||
|
||||
Split out of handleElementDrop() so that placement is reachable without a
|
||||
drag: the mode itself was always general, it simply had no caller other
|
||||
than the end of a drop.
|
||||
@param location : the element or macro to place
|
||||
@param scene_pos : where the pending element first appears, in scene
|
||||
coordinates
|
||||
@return true if the placement mode was entered
|
||||
*/
|
||||
bool DiagramView::startElementPlacement(const ElementsLocation &location,
|
||||
const QPointF &scene_pos)
|
||||
{
|
||||
if (!diagram() || !(location.isElement() && location.exist())) {
|
||||
return false;
|
||||
}
|
||||
if (diagram()->isReadOnly()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (location.path().endsWith(".qetmak")) {
|
||||
diagram()->setEventInterface(new DiagramEventAddMacro(location, diagram(), drop_pos));
|
||||
diagram()->setEventInterface(
|
||||
new DiagramEventAddMacro(location, diagram(), scene_pos));
|
||||
} else {
|
||||
diagram()->setEventInterface(new DiagramEventAddElement(location, diagram(), drop_pos));
|
||||
//DiagramEventAddElement takes a non-const reference, so it needs
|
||||
//an lvalue it may modify. Copying keeps the caller's location
|
||||
//untouched -- QETDiagramEditor stores the same one for
|
||||
//"insert last element".
|
||||
ElementsLocation loc(location);
|
||||
diagram()->setEventInterface(
|
||||
new DiagramEventAddElement(loc, diagram(), scene_pos));
|
||||
emit elementPlacementStarted(location);
|
||||
}
|
||||
|
||||
//Set focus to the view to get event
|
||||
this->setFocus();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief DiagramView::defaultPlacementPos
|
||||
@return where a pending element should appear when placement was not
|
||||
started by a drop, so there is no cursor position to use.
|
||||
|
||||
The cursor is used when it is over the view -- picking up a placement where
|
||||
the user is already looking -- and the centre of the visible area
|
||||
otherwise.
|
||||
*/
|
||||
QPointF DiagramView::defaultPlacementPos() const
|
||||
{
|
||||
const QPoint local = mapFromGlobal(QCursor::pos());
|
||||
if (viewport() && viewport()->rect().contains(local)) {
|
||||
return mapToScene(local);
|
||||
}
|
||||
return mapToScene(viewport() ? viewport()->rect().center()
|
||||
: rect().center());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -85,6 +85,10 @@ class DiagramView : public PaletteGraphicsView
|
||||
/// cursor query (QCursor::pos()/setPos() are silently ignored by
|
||||
/// several window managers and compositors, Wayland included).
|
||||
QPoint lastMousePos() const { return m_last_mouse_pos; }
|
||||
|
||||
bool startElementPlacement(const ElementsLocation &location,
|
||||
const QPointF &scene_pos);
|
||||
QPointF defaultPlacementPos() const;
|
||||
void setCellRulersShown(bool shown);
|
||||
void setCellLinesShown(bool shown);
|
||||
|
||||
@@ -145,6 +149,9 @@ class DiagramView : public PaletteGraphicsView
|
||||
/// Signal emitted when free rubberband changed.
|
||||
/// When free rubberband selection ends this signal will be emitted with null value.
|
||||
void freeRubberBandChanged(QPolygonF polygon);
|
||||
/// Signal emitted when the placement mode is entered for an
|
||||
/// element (not a macro), whether from a drop or not.
|
||||
void elementPlacementStarted(const ElementsLocation &);
|
||||
|
||||
public slots:
|
||||
void setVisualisationMode();
|
||||
|
||||
@@ -229,6 +229,13 @@ void QETDiagramEditor::setUpElementsCollectionWidget()
|
||||
m_qdw_elmt_collection->setWidget(m_element_collection_widget);
|
||||
m_element_collection_widget->expandFirstItems();
|
||||
|
||||
//The widget does not know which view should receive the element -- it
|
||||
//is also used by the picker popup, which has no editor ancestor -- so
|
||||
//the host decides.
|
||||
connect(m_element_collection_widget,
|
||||
&ElementsCollectionWidget::insertElementRequested,
|
||||
this, &QETDiagramEditor::insertElementFromCollection);
|
||||
|
||||
addDockWidget(Qt::RightDockWidgetArea, m_qdw_elmt_collection);
|
||||
}
|
||||
|
||||
@@ -809,6 +816,25 @@ void QETDiagramEditor::setUpActions()
|
||||
ShortcutManager::instance().registerAction(m_rotate_texts, "diagrameditor.rotate_texts", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_Space);
|
||||
ShortcutManager::instance().registerAction(m_edit_selection, "diagrameditor.edit_selection", tr("Éditeur de schémas"), Qt::CTRL | Qt::Key_E);
|
||||
|
||||
//Re-enter placement mode with the element placed last. Bare A rather
|
||||
//than Space: Space already rotates the pending element *inside*
|
||||
//placement mode (diagrameventaddelement.cpp), and is taken three times
|
||||
//over in this editor besides. A matches KiCad's add-symbol key and
|
||||
//reads correctly in the source language ("Ajouter"). ShortcutManager
|
||||
//makes it a default, not a commitment -- it appears in the Shortcuts
|
||||
//preference page like every other binding.
|
||||
m_insert_last_element = new QAction(QET::Icons::ElementNew,
|
||||
tr("Insérer le dernier élément"), this);
|
||||
m_insert_last_element->setStatusTip(
|
||||
tr("Place à nouveau le dernier élément inséré", "status bar tip"));
|
||||
m_insert_last_element->setData("insert_last_element");
|
||||
m_insert_last_element->setEnabled(false);
|
||||
ShortcutManager::instance().registerAction(
|
||||
m_insert_last_element, "diagrameditor.insert_last_element",
|
||||
tr("Éditeur de schémas"), Qt::Key_A);
|
||||
connect(m_insert_last_element, &QAction::triggered,
|
||||
this, &QETDiagramEditor::insertLastElement);
|
||||
addAction(m_insert_last_element);
|
||||
//Type to find and run any command, as SolidWorks' "Search Commands"
|
||||
//and the command palette of many editors. Ctrl+Shift+P, the key those
|
||||
//editors use, is taken by the autonumbering dock; M for "menu".
|
||||
@@ -1121,6 +1147,7 @@ void QETDiagramEditor::setUpMenu()
|
||||
menu_edition -> addAction(m_paste);
|
||||
menu_edition -> addAction(m_duplicate);
|
||||
menu_edition -> addAction(m_configure_duplicate);
|
||||
menu_edition -> addAction(m_insert_last_element);
|
||||
menu_edition -> addAction(m_command_search);
|
||||
menu_edition -> addSeparator();
|
||||
//The same actions the "Ajouter" toolbar holds. They were toolbar-only,
|
||||
@@ -2030,6 +2057,7 @@ void QETDiagramEditor::slot_updateActions()
|
||||
m_zoom_actions_group. setEnabled(opened_diagram);
|
||||
m_select_actions_group. setEnabled(opened_diagram);
|
||||
m_add_item_actions_group. setEnabled(editable_project);
|
||||
m_insert_last_element-> setEnabled(opened_diagram && editable_project && !m_last_inserted_element.isNull());
|
||||
m_row_column_actions_group. setEnabled(editable_project);
|
||||
m_background_color_button-> setEnabled(opened_diagram);
|
||||
m_draw_grid-> setEnabled(opened_diagram);
|
||||
@@ -2925,6 +2953,7 @@ void QETDiagramEditor::diagramWasAdded(DiagramView *dv)
|
||||
&QETDiagramEditor::selectionChanged,
|
||||
Qt::DirectConnection);
|
||||
connect(dv, &DiagramView::modeChanged, this, &QETDiagramEditor::slot_updateModeActions);
|
||||
connect(dv, &DiagramView::elementPlacementStarted, this, &QETDiagramEditor::rememberPlacedElement);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3034,6 +3063,53 @@ void QETDiagramEditor::selectionChanged()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief QETDiagramEditor::insertElementFromCollection
|
||||
Place @a location on the current folio using the interactive placement
|
||||
mode -- the same mode a drag and drop ends in, entered without the drag.
|
||||
@param location
|
||||
*/
|
||||
void QETDiagramEditor::insertElementFromCollection(const ElementsLocation &location)
|
||||
{
|
||||
DiagramView *dv = currentDiagramView();
|
||||
if (dv && dv->startElementPlacement(location, dv->defaultPlacementPos())) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Nowhere to place it: no folio open, or a read-only project. Do what
|
||||
//a double click did before it placed, rather than nothing.
|
||||
m_element_collection_widget->editLocation(location);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETDiagramEditor::rememberPlacedElement
|
||||
Remember @a location for "insert last element". Connected to every view,
|
||||
so an element placed by drag and drop counts as well as one placed from
|
||||
the collection without a drag. Macros never reach here: the view does not
|
||||
report them, since re-entering their placement mode from a shortcut has
|
||||
not been thought through.
|
||||
@param location
|
||||
*/
|
||||
void QETDiagramEditor::rememberPlacedElement(const ElementsLocation &location)
|
||||
{
|
||||
m_last_inserted_element = location;
|
||||
m_insert_last_element->setEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETDiagramEditor::insertLastElement
|
||||
Re-enter placement mode with the element placed most recently, so a run of
|
||||
the same symbol can be dropped without returning to the collection.
|
||||
*/
|
||||
void QETDiagramEditor::insertLastElement()
|
||||
{
|
||||
if (!m_last_inserted_element.isElement()
|
||||
|| !m_last_inserted_element.exist()) {
|
||||
return;
|
||||
}
|
||||
insertElementFromCollection(m_last_inserted_element);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETDiagramEditor::generateTerminalBlock
|
||||
*/
|
||||
|
||||
@@ -128,6 +128,9 @@ class QETDiagramEditor : public QETMainWindow
|
||||
void slot_updatePasteAction();
|
||||
void slot_updateWindowsMenu();
|
||||
void slot_updateAutoNumDock();
|
||||
void insertElementFromCollection(const ElementsLocation &location);
|
||||
void insertLastElement();
|
||||
void rememberPlacedElement(const ElementsLocation &location);
|
||||
void generateTerminalBlock();
|
||||
void setWindowedMode();
|
||||
void setTabbedMode();
|
||||
@@ -273,6 +276,9 @@ class QETDiagramEditor : public QETMainWindow
|
||||
QAction *m_command_search = nullptr;
|
||||
CommandSearchPopup *m_command_search_popup = nullptr; ///< Built on first use
|
||||
ElementsCollectionWidget *m_element_collection_widget;
|
||||
/// Last element placed from the collection, for "insert last"
|
||||
ElementsLocation m_last_inserted_element;
|
||||
QAction *m_insert_last_element = nullptr;
|
||||
|
||||
DiagramPropertiesEditorDockWidget *m_selection_properties_editor;
|
||||
/// Elements panel
|
||||
|
||||
@@ -67,6 +67,9 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) :
|
||||
|
||||
ui->grid_startup_cb->setChecked(settings.value("diagrameditor/grid_display_startup", true).toBool());
|
||||
ui->guides_startup_cb->setChecked(settings.value("diagrameditor/guides_display_startup", false).toBool());
|
||||
//Stored as "inserts" but presented as "edits", so the default (insert)
|
||||
//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->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)
|
||||
@@ -294,6 +297,7 @@ void GeneralConfigurationPage::applyConf()
|
||||
|
||||
settings.setValue("diagrameditor/grid_display_startup", ui->grid_startup_cb->isChecked());
|
||||
settings.setValue("diagrameditor/guides_display_startup", ui->guides_startup_cb->isChecked());
|
||||
settings.setValue("elementscollection/double-click-inserts", !ui->m_collection_dblclick_edits->isChecked());
|
||||
//Grid step and key navigation
|
||||
settings.setValue("diagrameditor/Xgrid", ui->DiagramEditor_xGrid_sb->value());
|
||||
settings.setValue("diagrameditor/Ygrid", ui->DiagramEditor_yGrid_sb->value());
|
||||
|
||||
@@ -77,6 +77,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="m_collection_dblclick_edits">
|
||||
<property name="toolTip">
|
||||
<string>Par défaut, un double-clic insère l'élément sur le folio ; l'édition reste accessible par le menu contextuel.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Double-cliquer dans la collection ouvre l'éditeur d'élément au lieu de l'insérer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="guides_startup_cb">
|
||||
<property name="text">
|
||||
|
||||
Reference in New Issue
Block a user