wolfhece._sculpt_manager ======================== .. py:module:: wolfhece._sculpt_manager .. autoapi-nested-parse:: Sculpt brush and profile brush companion object for WolfMapViewer. All sculpt-brush and profile-brush interaction logic lives here. ``WolfMapViewer`` holds a single instance as ``self._sculpt`` and exposes one-line delegators for every method so that external callers remain unaffected. Design notes ------------ * ``SculptManager`` owns all *private* transient state (cursor positions, pressure, show-overlay flags, rect-rotation helpers, brush-refresh coalescing flag). The *public* panel references (``sculpt_panel``, ``profile_panel``) stay as regular attributes on ``WolfMapViewer`` because ``wolf_sculpt.py`` sets them directly (``mapviewer.sculpt_panel = self``). * Six *event-hook* methods let the viewer delegate its mouse / keyboard / action events with a single call. * wx parent for dialogs is always ``self._viewer``. Module Contents --------------- .. py:class:: SculptManager(viewer: wolfhece.PyDraw.WolfMapViewer) Companion object that owns sculpt-brush and profile-brush logic. .. py:attribute:: _viewer .. py:attribute:: cursor_xy :type: Optional[tuple] :value: None .. py:attribute:: pressure :type: float :value: 1.0 .. py:attribute:: show_size :type: bool :value: False .. py:attribute:: show_zone :type: bool :value: False .. py:attribute:: profile_cursor_xy :type: Optional[tuple] :value: None .. py:attribute:: profile_last_seg :type: Optional[tuple] :value: None .. py:attribute:: brush_refresh_pending :type: bool :value: False .. py:attribute:: _rect_rot_center_xy :type: Optional[tuple] :value: None .. py:attribute:: _rect_rot_angle_offset :type: float :value: 0.0 .. py:attribute:: _rect_rot_calibrated :type: bool :value: False .. py:method:: on_wheel(ctx: wolfhece._viewer_plugin_handlers.MouseContext) -> bool Handle mouse-wheel brush controls when action == 'sculpt'. :param ctx: :class:`MouseContext` built from the wheel event. The relevant fields are ``shift``, ``ctrl``, ``alt``, ``wheel_rotation`` and ``wheel_delta``. :param Returns ``True`` if the event was fully consumed (caller should return).: .. py:method:: on_left_down(ctx: wolfhece._viewer_plugin_handlers.MouseContext) -> bool Handle left-button press for sculpt / profile actions. :param ctx: :class:`MouseContext` built from the left-down event. The relevant fields are ``x``, ``y``, ``left_down`` and ``shift``. :param Returns ``True`` if the event was consumed (caller should return).: .. py:method:: on_motion(ctx: wolfhece._viewer_plugin_handlers.MouseContext) -> bool Handle mouse motion for sculpt / profile actions. :param ctx: Pre-built :class:`MouseContext` with world coordinates, pixel coordinates, modifier flags, button states and stylus pressure. The caller (``On_Mouse_Motion``) stores this object in ``viewer._mouse_context`` *before* calling this method, so tooltip helpers can read it directly. :param Returns ``True`` when the event is fully consumed (caller should return).: :param Returns ``False`` when sculpt middle-drag must fall through to the pan: :param code: :param or when the action is neither 'sculpt' nor 'profile'.: .. py:method:: on_end_action(prev_action: str) -> None Clean up sculpt / profile state and notify panels when action ends. .. py:method:: on_key_z(ctx: wolfhece._viewer_plugin_handlers.KeyboardSnapshot) -> bool Handle Ctrl+Z undo for sculpt / profile. Returns ``True`` if the key was consumed (caller should skip the default zoom-on-array action). .. py:method:: on_key_r(ctx: wolfhece._viewer_plugin_handlers.KeyboardSnapshot) -> bool Guard: suppress reset-selection when sculpt RECTANGLE rotate mode is active. Returns ``True`` if R was suppressed; the caller is responsible for calling ``e.Skip()`` so the key event continues to propagate. .. py:method:: hide_size() -> None Callback scheduled via ``viewer.schedule_once`` to hide the radius-size overlay. .. py:method:: hide_zone() -> None Callback scheduled via ``viewer.schedule_once`` to hide the search-zone overlay. .. py:method:: get_event_pressure(e) -> float Return stylus pressure in [0, 1]. Reads from WinTab (Wintab32.dll) when available, which works reliably on wx.GLCanvas. Falls back to wx then to 1.0. .. py:method:: profile_apply_at(x: float, y: float) -> None Apply the profile brush at world position (x, y). .. py:method:: request_brush_refresh() -> None Schedule a single Refresh() for the next event-loop idle. Multiple calls from the same burst of mouse-motion events all land here; only the *first* actually posts a deferred call so that one repaint serves all pending GPU patches. .. py:method:: do_brush_refresh() -> None Callback — executed once per burst, repaints the canvas. .. py:method:: sculpt_apply_at(x: float, y: float, pressure: float = 1.0) -> None Apply the sculpt brush at world position (x, y). *pressure* is a stylus pressure value in [0, 1]. .. py:method:: draw_profile_cursor() -> None Draw the profile brush ghost overlay on the OpenGL canvas. .. py:method:: draw_sculpt_cursor() -> None Draw the sculpt brush footprint (circle / square / rectangle).