Source code for simvx.editor.panels.anchor_preset_widget
"""Inspector anchor-preset widget — toggle button that reveals a 3x3 preset grid."""
from collections.abc import Callable
from simvx.core.descriptors import Signal
from simvx.core.math.types import Vec2
from simvx.core.ui.containers import GridContainer, HBoxContainer, VBoxContainer
from simvx.core.ui.core import Control
from simvx.core.ui.enums import AnchorPreset
from simvx.core.ui.widgets import Button
__all__ = ["AnchorPresetButton", "PRESET_LABELS"]
PRESET_LABELS: list[tuple[AnchorPreset, str]] = [
(AnchorPreset.TOP_LEFT, "\u2196"), # ↖
(AnchorPreset.CENTER_TOP, "\u2191"), # ↑
(AnchorPreset.TOP_RIGHT, "\u2197"), # ↗
(AnchorPreset.CENTER_LEFT, "\u2190"), # ←
(AnchorPreset.CENTER, "\u25cf"), # ●
(AnchorPreset.CENTER_RIGHT, "\u2192"), # →
(AnchorPreset.BOTTOM_LEFT, "\u2199"), # ↙
(AnchorPreset.CENTER_BOTTOM, "\u2193"), # ↓
(AnchorPreset.BOTTOM_RIGHT, "\u2198"), # ↘
]
_WIDE_PRESETS: list[tuple[AnchorPreset, str]] = [
(AnchorPreset.LEFT_WIDE, "Left"),
(AnchorPreset.RIGHT_WIDE, "Right"),
(AnchorPreset.TOP_WIDE, "Top"),
(AnchorPreset.BOTTOM_WIDE, "Bot"),
]
[docs]
class AnchorPresetButton(VBoxContainer):
"""Compact grid of anchor-preset selectors shown inline in the Inspector.
Renders as a small header label plus a 3×3 directional grid and a row of
wide/full variants. Clicking any preset calls
``target_control.set_anchor_preset(preset)`` and emits ``preset_changed``.
Inline grid (not a modal popup) so the surrounding PropertyRow sizes
correctly and so the affordance stays discoverable.
"""
preset_changed = Signal() # emits AnchorPreset
def __init__(self, target_control: Control | None = None,
on_applied: Callable[[AnchorPreset], None] | None = None,
**kwargs):
super().__init__(**kwargs)
self.target_control = target_control
self._on_applied = on_applied
self._preset_buttons: dict[AnchorPreset, Button] = {}
self.separation = 3
grid = GridContainer(columns=3)
grid.separation = 2
for preset, label in PRESET_LABELS:
btn = Button(label, on_press=lambda p=preset: self._apply_preset(p))
btn.size = Vec2(30, 26)
self._preset_buttons[preset] = btn
grid.add_child(btn)
self.add_child(grid)
wide_row = HBoxContainer()
wide_row.separation = 2
for preset, label in _WIDE_PRESETS:
btn = Button(label, on_press=lambda p=preset: self._apply_preset(p))
btn.size = Vec2(44, 20)
self._preset_buttons[preset] = btn
wide_row.add_child(btn)
self.add_child(wide_row)
full = Button("Full Rect", on_press=lambda: self._apply_preset(AnchorPreset.FULL_RECT))
full.size = Vec2(100, 20)
self._preset_buttons[AnchorPreset.FULL_RECT] = full
self.add_child(full)
# Height = 3 rows of 3x3 (~26) + separation + wide row (~20) + sep + full (~20)
self.size = Vec2(120, 26 * 3 + 2 * 2 + self.separation + 20 + self.separation + 20)
def _apply_preset(self, preset: AnchorPreset) -> None:
if self.target_control is not None:
self.target_control.set_anchor_preset(preset)
self.preset_changed.emit(preset)
if self._on_applied is not None:
self._on_applied(preset)
[docs]
def get_minimum_size(self) -> Vec2:
return Vec2(120, 26 * 3 + 2 * 2 + self.separation + 20 + self.separation + 20)