spacr.qt.widgets.height_grip

A drag handle that makes ONE widget in a column taller or shorter.

Qt has no vertical-resize handle for “this one widget inside a column”, and the two things that look like one do not fit: a QSplitter needs two panes to divide, and QSizeGrip resizes the WINDOW. Home grew its own for the release-notes panel; the nested containers of Regression’s Measurements tab need the same affordance, so the class lives here and Home imports it rather than the tool carrying two of them.

WHAT WAS ADDED WHEN IT MOVED, and why each addition is not decoration:

  • an accessible name per instance – “Resize the release notes” is the wrong thing for a screen reader to say about the merge report;

  • keyboard resizing, because a pointer-only handle is not an accessible height-resize affordance. Up and Down move by one step, Page Up/Down by five, Home/End go to the bounds;

  • bounds expressed in BASE pixels and re-scaled on demand. At a 200 % font scale a ceiling of 400 physical px is half a box, so every bound goes through spacr.qt.preferences.scaled_px() and HeightGrip.rescale() re-reads it when the font preference changes.

Classes

HeightGrip

A thin bar that drags the widget above it taller or shorter.

Module Contents

class spacr.qt.widgets.height_grip.HeightGrip(target: PySide6.QtWidgets.QWidget, minimum: int, maximum: int, parent=None, name: str = 'Resize this panel')[source]

Bases: PySide6.QtWidgets.QWidget

A thin bar that drags the widget above it taller or shorter.

A thin line turns blue under the pointer or keyboard focus. The larger transparent grab area keeps it easy to drag without a thick divider.

Parameters:
  • target – the widget whose fixed height this drags.

  • minimum – floor in px at 100 % font scale.

  • maximum – ceiling in px at 100 % font scale.

  • parent – parent widget; ownership only.

  • name – accessible name, said aloud in place of “resize handle”.

Build the grip, bounded so a drag cannot collapse or run away.

bounds() → tuple[source]

The floor and ceiling in device px, as currently scaled.

changeEvent(event)[source]

Follow a font change rather than keep a height chosen for the old one.

The layout is recomputed after a font, locale, theme or display change; first launch is not the only moment the geometry moves. spaCR applies its font scale through the application stylesheet, so what arrives here is a style or font change rather than an explicit call – which is why this listens for the event instead of waiting to be told.

Parameters:

event – the change event; a font, application-font or style change re-fits the height limits, and every event is passed on to the base class.

enterEvent(event)[source]

Light the grip as the pointer arrives.

Parameters:

event – the Qt enter event.

focusInEvent(event)[source]

Redraw when focused, so the grip is visible to keyboard users.

A DRAG HANDLE NOBODY CAN SEE is a control only a mouse can find. The focus ring is what makes the keyboard route discoverable.

Parameters:

event – the Qt focus event.

focusOutEvent(event)[source]

Redraw when focus leaves.

Parameters:

event – the Qt focus event.

keyPressEvent(event)[source]

Arrow keys resize; everything else is passed on.

Passed on matters as much as handled: swallowing Tab would trap focus on the one control whose whole purpose is to be reachable.

Parameters:

event – the key event; Up/Down, +/-/=, Page Up/Down and Home/End resize and are accepted, and any other key goes to the base class.

leaveEvent(event)[source]

Drop the highlight as the pointer leaves.

Parameters:

event – the Qt leave event.

mouseMoveEvent(event)[source]

Resize by how far the pointer moved SINCE THE PRESS.

Measured from the press rather than the last move, so a drag that outruns the redraw lands where the pointer is instead of accumulating rounding.

Parameters:

event – the Qt mouse event.

mousePressEvent(event)[source]

Remember where the drag started, in GLOBAL coordinates.

Global, because this widget MOVES while the drag is happening – it sits under the widget being resized, so growing the target by 40 px slides the grip 40 px down and a local y would double every step.

Parameters:

event – the mouse press event; a left press records its global y position and the target’s height, and other buttons go to the base class.

mouseReleaseEvent(event)[source]

End the drag.

Parameters:

event – the Qt mouse event.

nudge(delta: int) → int[source]

Move the border by delta device px. Returns the new height.

Parameters:

delta – change in the target’s height, in device pixels; positive grows it. The result is clamped by resize_target() and emitted on height_changed.

paintEvent(event)[source]

One thin line, blue under the pointer, during dragging or focus.

Parameters:

event – the paint event; not read, the whole grip is redrawn.

rescale() → None[source]

Re-read the font scale and re-apply the bounds.

Called from the constructor and again after a font-preference change: the bounds are stored in base px precisely so that the answer can be recomputed rather than baked in at construction time.

reset() → int[source]

Put the box back to the height it opened at. Returns that height.

Reached from the handle’s own context menu, because that is where a user who has dragged one too far is already pointing.

resize_target(height: int) → int[source]

Set the target’s height, clamped. Returns what it became.

Public because it is the whole behaviour, and a test that drives it directly is testing the clamp rather than Qt’s event delivery.

Parameters:

height – wanted height in device pixels, clamped between the grip’s minimum and maximum and applied with setFixedHeight.

target_height() → int[source]

How tall the widget under this handle currently is, in device px.