From a423ceb669daed93f3e07f1690d761231f5fb9f5 Mon Sep 17 00:00:00 2001 From: Jojojoppe Date: Sun, 3 Aug 2025 20:29:04 +0200 Subject: [PATCH] Added scrolling as well --- negstation/negstation.py | 59 ++++++++++++++--------- negstation/widgets/stage_viewer_widget.py | 28 +++++++++++ 2 files changed, 63 insertions(+), 24 deletions(-) diff --git a/negstation/negstation.py b/negstation/negstation.py index 973307c..0aec7c3 100644 --- a/negstation/negstation.py +++ b/negstation/negstation.py @@ -13,8 +13,7 @@ from .layout_manager import LayoutManager from .widgets.base_widget import BaseWidget -logging.basicConfig(level=logging.INFO, - format="%(asctime)s %(levelname)s %(message)s") +logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s") logger = logging.getLogger(__name__) @@ -62,35 +61,39 @@ class EditorManager: and cls is not ModuleBaseWidget and cls.register ): - logging.info( - f" -> Found and registered widget: {name}") + logging.info(f" -> Found and registered widget: {name}") self._register_widget(name, cls) except Exception as e: logging.error(f"Failed to import widget '{py_file.name}': {e}") def _register_widget(self, name: str, widget_class: object): if name in self.widget_classes: - logging.warning( - f"Widget '{name}' is already registered. Overwriting.") + logging.warning(f"Widget '{name}' is already registered. Overwriting.") self.widget_classes[name] = widget_class - def _add_widget(self, widget_type: str, config:dict = {}): + def _add_widget(self, widget_type: str, config: dict = {}): WidgetClass = self.widget_classes[widget_type] instance = WidgetClass(self, logger) - logger.info(f'Created instance: {str(instance)}') + logger.info(f"Created instance: {str(instance)}") self.widgets.append(instance) instance.create() instance.set_config(config) def _on_drag(self, sender, app_data, user_data): - self.bus.publish_deferred("mouse_dragged", { - "button": ( - "right" - if app_data[0] == 0 - else ("left" if app_data[0] == 1 else ("middle")) - ), - "delta": (app_data[1], app_data[2]) - }) + self.bus.publish_deferred( + "mouse_dragged", + { + "button": ( + "right" + if app_data[0] == 0 + else ("left" if app_data[0] == 1 else ("middle")) + ), + "delta": (app_data[1], app_data[2]), + }, + ) + + def _on_scroll(self, sender, app_data, user_data): + self.bus.publish_deferred("mouse_scrolled", app_data) def setup(self): self._discover_and_register_widgets( @@ -107,11 +110,12 @@ class EditorManager: label="Save Layout", callback=self.layout_manager.save_layout ) dpg.add_menu_item( - label="Run full-res pipeline", callback=lambda: self.bus.publish_deferred("process_full_res", None) - ) - dpg.add_menu_item( - label="Quit", callback=lambda: dpg.stop_dearpygui() + label="Run full-res pipeline", + callback=lambda: self.bus.publish_deferred( + "process_full_res", None + ), ) + dpg.add_menu_item(label="Quit", callback=lambda: dpg.stop_dearpygui()) with dpg.menu(label="View"): for widget_name in sorted(self.widget_classes.keys()): @@ -120,11 +124,18 @@ class EditorManager: callback=lambda s, a, ud: self._add_widget(ud), user_data=widget_name, ) - + with dpg.handler_registry() as self.handler_registry: - dpg.add_mouse_drag_handler(callback=self._on_drag, threshold=1.0, button=0) - dpg.add_mouse_drag_handler(callback=self._on_drag, threshold=1.0, button=1) - dpg.add_mouse_drag_handler(callback=self._on_drag, threshold=1.0, button=2) + dpg.add_mouse_drag_handler( + callback=self._on_drag, threshold=1.0, button=0 + ) + dpg.add_mouse_drag_handler( + callback=self._on_drag, threshold=1.0, button=1 + ) + dpg.add_mouse_drag_handler( + callback=self._on_drag, threshold=1.0, button=2 + ) + dpg.add_mouse_wheel_handler(callback=self._on_scroll) def run(self): self.setup() diff --git a/negstation/widgets/stage_viewer_widget.py b/negstation/widgets/stage_viewer_widget.py index 5041a38..176f84e 100644 --- a/negstation/widgets/stage_viewer_widget.py +++ b/negstation/widgets/stage_viewer_widget.py @@ -21,6 +21,7 @@ class PipelineStageViewer(PipelineStageWidget): self.image_position = (0, 0) self.manager.bus.subscribe("mouse_dragged", self._on_mouse_drag, False) + self.manager.bus.subscribe("mouse_scrolled", self._on_mouse_scroll, False) def create_pipeline_stage_content(self): # Create an empty dynamic texture @@ -96,6 +97,33 @@ class PipelineStageViewer(PipelineStageWidget): }, ) + def _on_mouse_scroll(self, data): + mouse_x, mouse_y = dpg.get_mouse_pos(local=False) + canvas_x, canvas_y = dpg.get_item_rect_min(self.drawlist) + local_x = mouse_x - canvas_x + local_y = mouse_y - canvas_y + + img_x, img_y = self.image_position + img_w, img_h = self.scaled_size + + if ( + local_x >= img_x + and local_x < img_x + img_w + and local_y >= img_y + and local_y < img_y + img_h + ): + # calculate the image coordinate + x = int((local_x - img_x) * self.img.shape[1] / img_w) + y = int((local_y - img_y) * self.img.shape[0] / img_h) + self.manager.bus.publish_deferred( + "img_scrolled", + { + "stage_id": self.pipeline_stage_in_id, + "pos": (x, y), + "delta": data + }, + ) + def on_resize(self, width, height): self.needs_update = True