Source code for ironflow.gui.canvas_widgets.base

# coding: utf-8
# Copyright (c) Max-Planck-Institut für Eisenforschung GmbH - Computational Materials Design (CM) Department
# Distributed under the terms of "New BSD License", see the LICENSE file.
"""
Shared code among various canvas widgets.
"""

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Optional, Union

from ipycanvas import Canvas

from ironflow.gui.canvas_widgets.layouts import Layout

Number = Union[int, float]
if TYPE_CHECKING:
    from ironflow.gui.gui import GUI
    from ironflow.gui.canvas_widgets.flow import FlowCanvas
    from ironflow.model import Flow


[docs]class CanvasWidget(ABC): """ Parent class for all "widgets" that exist inside the scope of the flow canvas. """ def __init__( self, x: Number, y: Number, parent: FlowCanvas | CanvasWidget, layout: Layout, selected: bool = False, title: Optional[str] = None, ): self._x = x # relative to parent self._y = y self.layout = layout self.parent = parent self._selected = selected self.title = title self.objects_to_draw = [] self._height = self.layout.height
[docs] @abstractmethod def on_click( self, last_selected_object: Optional[CanvasWidget] ) -> CanvasWidget | None: pass
[docs] def on_double_click(self) -> CanvasWidget | None: return self
@property def width(self) -> int: return self.layout.width @property def height(self) -> int: return self._height @property def x(self) -> Number: return self.parent.x + self._x @property def y(self) -> Number: return self.parent.y + self._y @property def canvas(self) -> Canvas: return self.parent.canvas @property def gui(self) -> GUI: return self.parent.gui @property def flow(self) -> Flow: return self.parent.flow @property def flow_canvas(self) -> FlowCanvas: return self.parent.flow_canvas
[docs] def deselect_all(self) -> None: return self.parent.deselect_all()
[docs] def add_widget(self, widget: CanvasWidget) -> None: self.objects_to_draw.append(widget)
[docs] def set_x_y(self, x_in: Number, y_in: Number) -> None: self._x = x_in - self.width // 2 self._y = y_in - self.height // 2
[docs] def add_x_y(self, dx_in: Number, dy_in: Number) -> None: self._x += dx_in self._y += dy_in
@property def color(self) -> str: return ( self.layout.selected_color if self.selected else self.layout.background_color )
[docs] def draw_shape(self) -> None: self.canvas.fill_style = self.color self.canvas.fill_rect( self.x, self.y, self.width, self.height, )
[docs] @abstractmethod def draw_title(self) -> None: pass
[docs] def draw(self) -> None: self.draw_shape() if self.title is not None: self.draw_title() for o in self.objects_to_draw: o.draw()
def _is_at_xy(self, x_in: Number, y_in: Number) -> bool: x_coord = self.x y_coord = self.y return x_coord < x_in < (x_coord + self.width) and y_coord < y_in < ( y_coord + self.height )
[docs] def get_element_at_xy(self, x_in: Number, y_in: Number) -> CanvasWidget | None: if self.is_here(x_in, y_in): for o in self.objects_to_draw: if o.is_here(x_in, y_in): return o.get_element_at_xy(x_in, y_in) return self else: return None
[docs] def is_here(self, x_in: Number, y_in: Number) -> bool: return self._is_at_xy(x_in, y_in)
[docs] def select(self) -> None: self._selected = True
[docs] def deselect(self) -> None: self._selected = False [o.deselect() for o in self.objects_to_draw]
@property def selected(self): return self._selected
[docs]class HideableWidget(CanvasWidget, ABC): def __init__( self, x: Number, y: Number, parent: FlowCanvas | CanvasWidget, layout: Layout, selected: bool = False, title: Optional[str] = None, visible: bool = True, hidden_x: Optional[Number] = None, hidden_y: Optional[Number] = None, ): super().__init__( x=x, y=y, parent=parent, layout=layout, selected=selected, title=title ) self._hidden_x = hidden_x if hidden_x is not None else x self._hidden_y = hidden_y if hidden_y is not None else y self.visible = visible @property def hidden_x(self) -> Number: return self.parent.x + self._hidden_x @property def hidden_y(self) -> Number: return self.parent.y + self._hidden_y @property def x(self) -> Number: if self.visible: return self.parent.x + self._x else: return self.hidden_x @property def y(self) -> Number: if self.visible: return self.parent.y + self._y else: return self.hidden_y
[docs] def show(self): self.visible = True
[docs] def hide(self): self.visible = False
[docs] def is_here(self, x_in: Number, y_in: Number) -> bool: if self.visible: return self._is_at_xy(x_in=x_in, y_in=y_in) else: return False
[docs] def draw(self) -> None: if self.visible: super().draw()