Diagram: Tab/Shift+Tab item-selection cycling + select-all-conductors/text-fields (#574)

Implements the second pillar of #574: keyboard-driven selection on the
diagram canvas.

Tab / Shift+Tab select the next / previous item on the current
diagram, cycling through items() (z-order) and wrapping at either
end. If nothing is selected, Tab selects the first item and
Shift+Tab the last. Skipped while a text item has focus, for the
same reason arrow-key movement already guards on !focusItem().
Candidates use the same "what counts as a real selectable diagram
item" filter (QetGraphicsItem / DiagramTextItem / Conductor) already
established by Diagram::invertSelection(), so the cycling order
always matches what a user could reach by clicking.

Getting Tab to actually reach the scene needed two separate fixes,
each independently discovered by empirical testing rather than
assumption:

- QWidget (DiagramView) intercepts Tab/Backtab for widget focus-chain
  traversal before generating a key event at all. Overriding
  DiagramView::focusNextPrevChild() to return false disables that.
- QGraphicsScene (Diagram) has its own, separate item-focus-chain
  traversal, checked before keyPressEvent() is ever reached. The
  obvious fix -- overriding Diagram::focusNextPrevChild() the same
  way -- silently does nothing on Qt 5, because
  QGraphicsScene::focusNextPrevChild() only becomes virtual in Qt 6
  (guarded by the QT6_VIRTUAL macro); a compile error surfaced this
  immediately when attempted directly, rather than shipping a fix
  that worked on Qt 6 and silently no-opped on Qt 5. Intercepting
  QEvent::KeyPress in Diagram::event() instead is virtual on every Qt
  version and sidesteps the scene's internal traversal entirely.

Also adds Diagram::selectAllConductors() / selectAllTextFields(),
wired up as two new actions in the existing select_all /
select_nothing / select_invert action group in
qetdiagrameditor.cpp, so they appear in the Edit menu and go through
the same QAction -> data() -> selectGroupTriggered() dispatch as the
existing selection commands.

Verified end-to-end in a real running session (Xvfb + xdotool) with
a multi-transistor schematic: Tab/Shift+Tab correctly move a single
selection forward/backward through elements and text fields
(confirmed via the properties panel updating to each new item and
the visual selection box moving on canvas); Tab/Shift+Tab from no
selection correctly select the first/last item; "Select all
conductors" and "Select all text fields" each correctly select every
matching item and deselect everything else.

See discussion #574.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-08-01 00:10:37 +12:00
parent 199444b6db
commit 88823ea35f
5 changed files with 141 additions and 1 deletions
+17
View File
@@ -702,6 +702,23 @@ void DiagramView::focusInEvent(QFocusEvent *e) {
}
}
/**
@brief DiagramView::focusNextPrevChild
By default, QWidget intercepts Tab/Shift+Tab to move keyboard focus to
the next/previous widget before a key press event is ever generated,
which would silently swallow the diagram's Tab-based item-selection
cycling (see Diagram::event()). Returning false here disables that
automatic focus-chain traversal for this view, so Tab/Shift+Tab reach
keyPressEvent() (and from there, the scene) as ordinary key presses
instead.
@return always false
*/
bool DiagramView::focusNextPrevChild(bool next)
{
Q_UNUSED(next)
return false;
}
/**
@brief DiagramView::keyPressEvent
Handles "key press" events. Reimplemented here to switch to visualisation