Source code for fury.ui.containers

"""UI container module."""

from warnings import warn

import numpy as np

from fury.actor import grid
from fury.decorators import warn_on_args_to_kwargs
from fury.io import load_image
from fury.lib import (
    CellArray,
    FloatArray,
    Points,
    PolyData,
    PolyDataMapper2D,
    Property2D,
    Texture,
    TexturedActor2D,
)
from fury.ui.core import UI, Rectangle2D, TextBlock2D
from fury.utils import rotate, set_input


[docs] class Panel2D(UI): """A 2D UI Panel. Can contain one or more UI elements. Attributes ---------- alignment : [left, right] Alignment of the panel with respect to the overall screen. """ @warn_on_args_to_kwargs() def __init__( self, size, *, position=(0, 0), color=(0.1, 0.1, 0.1), opacity=0.7, align="left", border_color=(1, 1, 1), border_width=0, has_border=False, ): """Init class instance. Parameters ---------- size : (int, int) Size (width, height) in pixels of the panel. position : (float, float) Absolute coordinates (x, y) of the lower-left corner of the panel. color : (float, float, float) Must take values in [0, 1]. opacity : float Must take values in [0, 1]. align : [left, right] Alignment of the panel with respect to the overall screen. border_color: (float, float, float), optional Must take values in [0, 1]. border_width: float, optional width of the border has_border: bool, optional If the panel should have borders. """ self.has_border = has_border self._border_color = border_color self._border_width = border_width super(Panel2D, self).__init__(position=position) self.resize(size) self.alignment = align self.color = color self.opacity = opacity self.position = position self._drag_offset = None def _setup(self): """Setup this UI component. Create the background (Rectangle2D) of the panel. Create the borders (Rectangle2D) of the panel. """ self._elements = [] self.element_offsets = [] self.background = Rectangle2D() if self.has_border: self.borders = { "left": Rectangle2D(), "right": Rectangle2D(), "top": Rectangle2D(), "bottom": Rectangle2D(), } self.border_coords = { "left": (0.0, 0.0), "right": (1.0, 0.0), "top": (0.0, 1.0), "bottom": (0.0, 0.0), } for key in self.borders.keys(): self.borders[key].color = self._border_color self.add_element(self.borders[key], self.border_coords[key]) for key in self.borders.keys(): self.borders[ key ].on_left_mouse_button_pressed = self.left_button_pressed self.borders[ key ].on_left_mouse_button_dragged = self.left_button_dragged self.add_element(self.background, (0, 0)) # Add default events listener for this UI component. self.background.on_left_mouse_button_pressed = self.left_button_pressed self.background.on_left_mouse_button_dragged = self.left_button_dragged def _get_actors(self): """Get the actors composing this UI component.""" actors = [] for element in self._elements: actors += element.actors return actors def _add_to_scene(self, scene): """Add all subcomponents or VTK props that compose this UI component. Parameters ---------- scene : scene """ for element in self._elements: element.add_to_scene(scene) def _get_size(self): return self.background.size
[docs] def resize(self, size): """Set the panel size. Parameters ---------- size : (float, float) Panel size (width, height) in pixels. """ self.background.resize(size) if self.has_border: self.borders["left"].resize( (self._border_width, size[1] + self._border_width) ) self.borders["right"].resize( (self._border_width, size[1] + self._border_width) ) self.borders["top"].resize( (self.size[0] + self._border_width, self._border_width) ) self.borders["bottom"].resize( (self.size[0] + self._border_width, self._border_width) ) self.update_border_coords()
def _set_position(self, coords): """Set the lower-left corner position of this UI component. Parameters ---------- coords: (float, float) Absolute pixel coordinates (x, y). """ coords = np.array(coords) for element, offset in self.element_offsets: element.position = coords + offset
[docs] def set_visibility(self, visibility): for element in self._elements: element.set_visibility(visibility)
@property def color(self): return self.background.color @color.setter def color(self, color): self.background.color = color @property def opacity(self): return self.background.opacity @opacity.setter def opacity(self, opacity): self.background.opacity = opacity
[docs] @warn_on_args_to_kwargs() def add_element(self, element, coords, *, anchor="position"): """Add a UI component to the panel. The coordinates represent an offset from the lower left corner of the panel. Parameters ---------- element : UI The UI item to be added. coords : (float, float) or (int, int) If float, normalized coordinates are assumed and they must be between [0,1]. If int, pixels coordinates are assumed and it must fit within the panel's size. """ coords = np.array(coords) if np.issubdtype(coords.dtype, np.floating): if np.any(coords < 0) or np.any(coords > 1): raise ValueError("Normalized coordinates must be in [0,1].") coords = coords * self.size if anchor == "center": element.center = self.position + coords elif anchor == "position": element.position = self.position + coords else: msg = "Unknown anchor {}. Supported anchors are 'position'" " and 'center'." raise ValueError(msg) self._elements.append(element) offset = element.position - self.position self.element_offsets.append((element, offset))
[docs] def remove_element(self, element): """Remove a UI component from the panel. Parameters ---------- element : UI The UI item to be removed. """ idx = self._elements.index(element) del self._elements[idx] del self.element_offsets[idx]
[docs] @warn_on_args_to_kwargs() def update_element(self, element, coords, *, anchor="position"): """Update the position of a UI component in the panel. Parameters ---------- element : UI The UI item to be updated. coords : (float, float) or (int, int) New coordinates. If float, normalized coordinates are assumed and they must be between [0,1]. If int, pixels coordinates are assumed and it must fit within the panel's size. """ self.remove_element(element) self.add_element(element, coords, anchor=anchor)
[docs] def left_button_pressed(self, i_ren, _obj, panel2d_object): click_pos = np.array(i_ren.event.position) self._drag_offset = click_pos - self.position i_ren.event.abort() # Stop propagating the event.
[docs] def left_button_dragged(self, i_ren, _obj, _panel2d_object): if self._drag_offset is not None: click_position = np.array(i_ren.event.position) new_position = click_position - self._drag_offset self.position = new_position i_ren.force_render()
[docs] def re_align(self, window_size_change): """Re-organise the elements in case the window size is changed. Parameters ---------- window_size_change : (int, int) New window size (width, height) in pixels. """ if self.alignment == "left": pass elif self.alignment == "right": self.position += np.array(window_size_change) else: msg = "You can only left-align or right-align objects in a panel." raise ValueError(msg)
[docs] def update_border_coords(self): """Update the coordinates of the borders""" self.border_coords = { "left": (0.0, 0.0), "right": (1.0, 0.0), "top": (0.0, 1.0), "bottom": (0.0, 0.0), } for key in self.borders.keys(): self.update_element(self.borders[key], self.border_coords[key])
@property def border_color(self): sides = ["left", "right", "top", "bottom"] return [self.borders[side].color for side in sides] @border_color.setter def border_color(self, side_color): """Set the color of a specific border Parameters ---------- side_color: Iterable Iterable to pack side, color values """ side, color = side_color if side.lower() not in ["left", "right", "top", "bottom"]: raise ValueError(f"{side} not a valid border side") self.borders[side].color = color @property def border_width(self): sides = ["left", "right", "top", "bottom"] widths = [] for side in sides: if side in ["left", "right"]: widths.append(self.borders[side].width) elif side in ["top", "bottom"]: widths.append(self.borders[side].height) else: raise ValueError(f"{side} not a valid border side") return widths @border_width.setter def border_width(self, side_width): """Set the border width of a specific border Parameters ---------- side_width: Iterable Iterable to pack side, width values """ side, border_width = side_width if side.lower() in ["left", "right"]: self.borders[side].width = border_width elif side.lower() in ["top", "bottom"]: self.borders[side].height = border_width else: raise ValueError(f"{side} not a valid border side")
[docs] class TabPanel2D(UI): """Render content within a Tab. Attributes ---------- content_panel: :class: 'Panel2D' Hold all the content UI components. text_block: :class: 'TextBlock2D' Renders the title of the tab. """ @warn_on_args_to_kwargs() def __init__( self, *, position=(0, 0), size=(100, 100), title="New Tab", color=(0.5, 0.5, 0.5), content_panel=None, ): """Init class instance. Parameters ---------- position : (float, float) Absolute coordinates (x, y) of the lower-left corner of the UI component size : (int, int) Width and height of the pixels of this UI component. title : str Renders the title for Tab panel. color : list of 3 floats Background color of tab panel. content_panel : Panel2D Panel consisting of the content UI elements. """ self.content_panel = content_panel self.panel_size = size self._text_size = (int(1.0 * size[0]), size[1]) super(TabPanel2D, self).__init__() self.title = title self.panel.position = position self.color = color def _setup(self): """Setup this UI component. Create parent panel. Create Text to hold tab information. Create Button to close tab. """ self.panel = Panel2D(size=self.panel_size) self.text_block = TextBlock2D(size=self._text_size, color=(0, 0, 0)) self.panel.add_element(self.text_block, (0, 0)) def _get_actors(self): """Get the actors composing this UI component.""" return self.panel.actors + self.content_panel.actors def _add_to_scene(self, _scene): """Add all subcomponents or VTK props that compose this UI component. Parameters ---------- scene : scene """ self.panel.add_to_scene(_scene) self.content_panel.add_to_scene(_scene) def _set_position(self, _coords): """Set the lower-left corner position of this UI component. Parameters ---------- coords: (float, float) Absolute pixel coordinates (x, y). """ self.panel.position = _coords def _get_size(self): return self.panel.size
[docs] def resize(self, size): """Resize Tab panel. Parameters ---------- size : (int, int) New width and height in pixels. """ self._text_size = (int(0.7 * size[0]), size[1]) self._button_size = (int(0.3 * size[0]), size[1]) self.panel.resize(size) self.text_block.resize(self._text_size)
@property def color(self): """Return the background color of tab panel.""" return self.panel.color @color.setter def color(self, color): """Set background color of tab panel. Parameters ---------- color : list of 3 floats. """ self.panel.color = color @property def title(self): """Return the title of tab panel.""" return self.text_block.message @title.setter def title(self, text): """Set the title of tab panel. Parameters ---------- text : str New title for tab panel. """ self.text_block.message = text @property def title_bold(self): """Is the title of a tab panel bold.""" return self.text_block.bold @title_bold.setter def title_bold(self, bold): """Determine if the text title of a tab panel must be bold. Parameters ---------- bold : bool Bold property for a text title in a tab panel. """ self.text_block.bold = bold @property def title_color(self): """Return the title color of tab panel.""" return self.text_block.color @title_color.setter def title_color(self, color): """Set the title color of tab panel. Parameters ---------- color : tuple New title color for tab panel. """ self.text_block.color = color @property def title_font_size(self): """Return the title font size of tab panel.""" return self.text_block.font_size @title_font_size.setter def title_font_size(self, font_size): """Set the title font size of tab panel. Parameters ---------- font_size : int New title font size for tab panel. """ self.text_block.font_size = font_size @property def title_italic(self): """Is the title of a tab panel italic.""" return self.text_block.italic @title_italic.setter def title_italic(self, italic): """Determine if the text title of a tab panel must be italic. Parameters ---------- italic : bool Italic property for a text title in a tab panel. """ self.text_block.italic = italic
[docs] @warn_on_args_to_kwargs() def add_element(self, element, coords, *, anchor="position"): """Add a UI component to the content panel. The coordinates represent an offset from the lower left corner of the panel. Parameters ---------- element : UI The UI item to be added. coords : (float, float) or (int, int) If float, normalized coordinates are assumed and they must be between [0,1]. If int, pixels coordinates are assumed and it must fit within the panel's size. """ element.set_visibility(False) self.content_panel.add_element(element, coords, anchor=anchor)
[docs] def remove_element(self, element): """Remove a UI component from the content panel. Parameters ---------- element : UI The UI item to be removed. """ self.content_panel.remove_element(element)
[docs] @warn_on_args_to_kwargs() def update_element(self, element, coords, *, anchor="position"): """Update the position of a UI component in the content panel. Parameters ---------- element : UI The UI item to be updated. coords : (float, float) or (int, int) New coordinates. If float, normalized coordinates are assumed and they must be between [0,1]. If int, pixels coordinates are assumed and it must fit within the panel's size. """ self.content_panel.update_element(element, coords, anchor="position")
[docs] class TabUI(UI): """UI element to add multiple panels within a single window. Attributes ---------- tabs: :class: List of 'TabPanel2D' Stores all the instances of 'TabPanel2D' that renders the contents. """ @warn_on_args_to_kwargs() def __init__( self, *, position=(0, 0), size=(100, 100), nb_tabs=1, active_color=(1, 1, 1), inactive_color=(0.5, 0.5, 0.5), draggable=False, startup_tab_id=None, tab_bar_pos="top", ): """Init class instance. Parameters ---------- position : (float, float) Absolute coordinates (x, y) of the lower-left corner of this UI component. size : (int, int) Width and height in pixels of this UI component. nb_tabs : int Number of tabs to be renders. active_color : tuple of 3 floats. Background color of active tab panel. inactive_color : tuple of 3 floats. Background color of inactive tab panels. draggable : bool Whether the UI element is draggable or not. startup_tab_id : int, optional Tab to be activated and uncollapsed on startup. by default None is activated/ all collapsed. tab_bar_pos : str, optional Position of the Tab Bar in the panel """ self.tabs = [] self.nb_tabs = nb_tabs self.parent_size = size self.content_size = (size[0], int(0.9 * size[1])) self.draggable = draggable self.active_color = active_color self.inactive_color = inactive_color self.active_tab_idx = startup_tab_id self.collapsed = True self.tab_bar_pos = tab_bar_pos super(TabUI, self).__init__() self.position = position def _setup(self): """Setup this UI component. Create parent panel. Create tab panels. """ self.parent_panel = Panel2D(self.parent_size, opacity=0.0) # Offer some standard hooks to the user. self.on_change = lambda ui: None self.on_collapse = lambda ui: None for _ in range(self.nb_tabs): content_panel = Panel2D(size=self.content_size) content_panel.set_visibility(False) tab_panel = TabPanel2D(content_panel=content_panel) self.tabs.append(tab_panel) self.update_tabs() if self.active_tab_idx is not None: self.tabs[self.active_tab_idx].color = self.active_color self.tabs[self.active_tab_idx].content_panel.set_visibility(True) def _get_actors(self): """Get the actors composing this UI component.""" actors = [] actors += self.parent_panel.actors for tab_panel in self.tabs: actors += tab_panel.actors return actors def _add_to_scene(self, _scene): """Add all subcomponents or VTK props that compose this UI component. Parameters ---------- scene : scene """ self.parent_panel.add_to_scene(_scene) for tab_panel in self.tabs: tab_panel.add_to_scene(_scene) def _set_position(self, _coords): """Set the lower-left corner position of this UI component. Parameters ---------- coords: (float, float) Absolute pixel coordinates (x, y). """ self.parent_panel.position = _coords def _get_size(self): return self.parent_panel.size
[docs] def update_tabs(self): """Update position, size and callbacks for tab panels.""" self.tab_panel_size = (self.size[0] // self.nb_tabs, int(0.1 * self.size[1])) if self.tab_bar_pos.lower() not in ["top", "bottom"]: warn("tab_bar_pos can only have value top/bottom", stacklevel=2) self.tab_bar_pos = "top" if self.tab_bar_pos.lower() == "top": tab_panel_pos = [0.0, 0.9] elif self.tab_bar_pos.lower() == "bottom": tab_panel_pos = [0.0, 0.0] for tab_panel in self.tabs: tab_panel.resize(self.tab_panel_size) tab_panel.content_panel.position = self.position content_panel = tab_panel.content_panel if self.draggable: tab_panel.panel.background.on_left_mouse_button_pressed = ( self.left_button_pressed ) content_panel.background.on_left_mouse_button_pressed = ( self.left_button_pressed ) tab_panel.text_block.on_left_mouse_button_pressed = ( self.left_button_pressed ) tab_panel.panel.background.on_left_mouse_button_dragged = ( self.left_button_dragged ) content_panel.background.on_left_mouse_button_dragged = ( self.left_button_dragged ) tab_panel.text_block.on_left_mouse_button_dragged = ( self.left_button_dragged ) else: tab_panel.panel.background.on_left_mouse_button_dragged = ( lambda i_ren, _obj, _comp: i_ren.force_render ) content_panel.background.on_left_mouse_button_dragged = ( lambda i_ren, _obj, _comp: i_ren.force_render ) tab_panel.text_block.on_left_mouse_button_clicked = self.select_tab_callback tab_panel.panel.background.on_left_mouse_button_clicked = ( self.select_tab_callback ) tab_panel.text_block.on_right_mouse_button_clicked = self.collapse_tab_ui tab_panel.panel.background.on_right_mouse_button_clicked = ( self.collapse_tab_ui ) tab_panel.content_panel.resize(self.content_size) self.parent_panel.add_element(tab_panel, tab_panel_pos) if self.tab_bar_pos.lower() == "top": self.parent_panel.add_element(tab_panel.content_panel, (0.0, 0.0)) elif self.tab_bar_pos.lower() == "bottom": self.parent_panel.add_element(tab_panel.content_panel, (0.0, 0.1)) tab_panel_pos[0] += 1 / self.nb_tabs
[docs] def select_tab_callback(self, iren, _obj, _tab_comp): """Handle events when a tab is selected.""" for idx, tab_panel in enumerate(self.tabs): if ( tab_panel.text_block is not _tab_comp and tab_panel.panel.background is not _tab_comp ): tab_panel.color = self.inactive_color tab_panel.content_panel.set_visibility(False) else: current_visibility = tab_panel.content_panel.actors[0].GetVisibility() if not current_visibility: tab_panel.color = self.active_color else: tab_panel.color = self.inactive_color tab_panel.content_panel.set_visibility(not current_visibility) self.active_tab_idx = idx self.collapsed = False self.on_change(self) iren.force_render() iren.event.abort()
[docs] def collapse_tab_ui(self, iren, _obj, _tab_comp): """Handle events when Tab UI is collapsed.""" if self.active_tab_idx is not None: active_tab_panel = self.tabs[self.active_tab_idx] active_tab_panel.color = self.inactive_color active_tab_panel.content_panel.set_visibility(False) self.active_tab_idx = None self.collapsed = True self.on_collapse(self) iren.force_render() iren.event.abort()
[docs] @warn_on_args_to_kwargs() def add_element(self, tab_idx, element, coords, *, anchor="position"): """Add element to content panel after checking its existence.""" if tab_idx < self.nb_tabs and tab_idx >= 0: self.tabs[tab_idx].add_element(element, coords, anchor=anchor) if tab_idx == self.active_tab_idx: element.set_visibility(True) else: raise IndexError("Tab with index " "{} does not exist".format(tab_idx))
[docs] def remove_element(self, tab_idx, element): """Remove element from content panel after checking its existence.""" if tab_idx < self.nb_tabs and tab_idx >= 0: self.tabs[tab_idx].remove_element(element) else: raise IndexError("Tab with index " "{} does not exist".format(tab_idx))
[docs] @warn_on_args_to_kwargs() def update_element(self, tab_idx, element, coords, *, anchor="position"): """Update element on content panel after checking its existence.""" if tab_idx < self.nb_tabs and tab_idx >= 0: self.tabs[tab_idx].update_element(element, coords, anchor=anchor) else: raise IndexError("Tab with index " "{} does not exist".format(tab_idx))
[docs] def left_button_pressed(self, i_ren, _obj, _sub_component): click_pos = np.array(i_ren.event.position) self._click_position = click_pos i_ren.event.abort() # Stop propagating the event.
[docs] def left_button_dragged(self, i_ren, _obj, _sub_component): click_position = np.array(i_ren.event.position) change = click_position - self._click_position self.parent_panel.position += change self._click_position = click_position i_ren.force_render()
[docs] class ImageContainer2D(UI): """A 2D container to hold an image. Currently Supports: - png and jpg/jpeg images Attributes ---------- size: (float, float) Image size (width, height) in pixels. img : ImageData The image loaded from the specified path. """ @warn_on_args_to_kwargs() def __init__(self, img_path, *, position=(0, 0), size=(100, 100)): """Init class instance. Parameters ---------- img_path : string URL or local path of the image position : (float, float), optional Absolute coordinates (x, y) of the lower-left corner of the image. size : (int, int), optional Width and height in pixels of the image. """ super(ImageContainer2D, self).__init__(position=position) self.img = load_image(img_path, as_vtktype=True) self.set_img(self.img) self.resize(size) def _get_size(self): lower_left_corner = self.texture_points.GetPoint(0) upper_right_corner = self.texture_points.GetPoint(2) size = np.array(upper_right_corner) - np.array(lower_left_corner) return abs(size[:2]) def _setup(self): """Setup this UI Component. Return an image as a 2D actor with a specific position. Returns ------- :class:`vtkTexturedActor2D` """ self.texture_polydata = PolyData() self.texture_points = Points() self.texture_points.SetNumberOfPoints(4) polys = CellArray() polys.InsertNextCell(4) polys.InsertCellPoint(0) polys.InsertCellPoint(1) polys.InsertCellPoint(2) polys.InsertCellPoint(3) self.texture_polydata.SetPolys(polys) tc = FloatArray() tc.SetNumberOfComponents(2) tc.SetNumberOfTuples(4) tc.InsertComponent(0, 0, 0.0) tc.InsertComponent(0, 1, 0.0) tc.InsertComponent(1, 0, 1.0) tc.InsertComponent(1, 1, 0.0) tc.InsertComponent(2, 0, 1.0) tc.InsertComponent(2, 1, 1.0) tc.InsertComponent(3, 0, 0.0) tc.InsertComponent(3, 1, 1.0) self.texture_polydata.GetPointData().SetTCoords(tc) texture_mapper = PolyDataMapper2D() texture_mapper = set_input(texture_mapper, self.texture_polydata) image = TexturedActor2D() image.SetMapper(texture_mapper) self.texture = Texture() image.SetTexture(self.texture) image_property = Property2D() image_property.SetOpacity(1.0) image.SetProperty(image_property) self.actor = image # Add default events listener to the VTK actor. self.handle_events(self.actor) def _get_actors(self): """Return the actors that compose this UI component.""" return [self.actor] def _add_to_scene(self, scene): """Add all subcomponents or VTK props that compose this UI component. Parameters ---------- scene : scene """ scene.add(self.actor)
[docs] def resize(self, size): """Resize the image. Parameters ---------- size : (float, float) image size (width, height) in pixels. """ # Update actor. self.texture_points.SetPoint(0, 0, 0, 0.0) self.texture_points.SetPoint(1, size[0], 0, 0.0) self.texture_points.SetPoint(2, size[0], size[1], 0.0) self.texture_points.SetPoint(3, 0, size[1], 0.0) self.texture_polydata.SetPoints(self.texture_points)
def _set_position(self, coords): """Set the lower-left corner position of this UI component. Parameters ---------- coords: (float, float) Absolute pixel coordinates (x, y). """ self.actor.SetPosition(*coords)
[docs] def scale(self, factor): """Scale the image. Parameters ---------- factor : (float, float) Scaling factor (width, height) in pixels. """ self.resize(self.size * factor)
[docs] def set_img(self, img): """Modify the image used by the vtkTexturedActor2D. Parameters ---------- img : imageData """ self.texture = set_input(self.texture, img)
[docs] class GridUI(UI): """Add actors in a grid and interact with them individually.""" @warn_on_args_to_kwargs() def __init__( self, actors, *, captions=None, caption_offset=(0, -100, 0), cell_padding=0, cell_shape="rect", aspect_ratio=16 / 9.0, dim=None, rotation_speed=1, rotation_axis=(0, 1, 0), ): # TODO: add rotation axis None by default self.container = grid( actors, captions=captions, caption_offset=caption_offset, cell_padding=cell_padding, cell_shape=cell_shape, aspect_ratio=aspect_ratio, dim=dim, ) self._actors = [] self._actors_dict = {} self.rotation_speed = rotation_speed self.rotation_axis = rotation_axis for item in self.container._items: actor = item if captions is None else item._items[0] self._actors.append(actor) self._actors_dict[actor] = {"x": -np.inf, "y": -np.inf} super(GridUI, self).__init__(position=(0, 0, 0)) def _get_size(self): return
[docs] @staticmethod def left_click_callback(istyle, _obj, _what): istyle.trackball_actor.OnLeftButtonDown() istyle.force_render() istyle.event.abort()
[docs] @staticmethod def left_release_callback(istyle, _obj, _what): istyle.trackball_actor.OnLeftButtonUp() istyle.force_render() istyle.event.abort()
[docs] @staticmethod def mouse_move_callback(istyle, _obj, _what): istyle.trackball_actor.OnMouseMove() istyle.force_render() istyle.event.abort()
[docs] @staticmethod def left_click_callback2(istyle, obj, self): rx, ry, rz = self.rotation_axis clockwise_rotation = np.array([self.rotation_speed, rx, ry, rz]) rotate(obj, clockwise_rotation) istyle.force_render() istyle.event.abort()
[docs] @staticmethod def left_release_callback2(istyle, _obj, _what): istyle.force_render() istyle.event.abort()
[docs] @staticmethod def mouse_move_callback2(istyle, obj, self): if self._actors_dict[obj]["y"] == -np.inf: iren = istyle.GetInteractor() event_pos = iren.GetEventPosition() self._actors_dict[obj]["y"] = event_pos[1] else: iren = istyle.GetInteractor() event_pos = iren.GetEventPosition() rx, ry, rz = self.rotation_axis if event_pos[1] >= self._actors_dict[obj]["y"]: clockwise_rotation = np.array([-self.rotation_speed, rx, ry, rz]) rotate(obj, clockwise_rotation) else: anti_clockwise_rotation = np.array([self.rotation_speed, rx, ry, rz]) rotate(obj, anti_clockwise_rotation) self._actors_dict[obj]["y"] = event_pos[1] istyle.force_render() istyle.event.abort()
ANTICLOCKWISE_ROTATION_Y = np.array([-10, 0, 1, 0]) CLOCKWISE_ROTATION_Y = np.array([10, 0, 1, 0]) ANTICLOCKWISE_ROTATION_X = np.array([-10, 1, 0, 0]) CLOCKWISE_ROTATION_X = np.array([10, 1, 0, 0])
[docs] def key_press_callback(self, istyle, obj, _what): has_changed = False if istyle.event.key == "Left": has_changed = True for a in self._actors: rotate(a, self.ANTICLOCKWISE_ROTATION_Y) elif istyle.event.key == "Right": has_changed = True for a in self._actors: rotate(a, self.CLOCKWISE_ROTATION_Y) elif istyle.event.key == "Up": has_changed = True for a in self._actors: rotate(a, self.ANTICLOCKWISE_ROTATION_X) elif istyle.event.key == "Down": has_changed = True for a in self._actors: rotate(a, self.CLOCKWISE_ROTATION_X) if has_changed: istyle.force_render()
def _setup(self): """Set up this UI component and the events of its actor.""" # Add default events listener to the VTK actor. for actor in self._actors: # self.handle_events(actor) if self.rotation_axis is None: self.add_callback( actor, "LeftButtonPressEvent", self.left_click_callback ) self.add_callback( actor, "LeftButtonReleaseEvent", self.left_release_callback ) self.add_callback(actor, "MouseMoveEvent", self.mouse_move_callback) else: self.add_callback( actor, "LeftButtonPressEvent", self.left_click_callback2 ) # TODO: possibly add this too self.add_callback( actor, "LeftButtonReleaseEvent", self.left_release_callback2 ) self.add_callback(actor, "MouseMoveEvent", self.mouse_move_callback2) # TODO: this is currently not running self.add_callback(actor, "KeyPressEvent", self.key_press_callback) # self.on_key_press = self.key_press_callback2 def _get_actors(self): """Get the actors composing this UI component.""" return self._actors def _add_to_scene(self, scene): """Add all subcomponents or VTK props that compose this UI component. Parameters ---------- scene : scene """ self.container.add_to_scene(scene)
[docs] def resize(self, size): """Resize the button. Parameters ---------- size : (float, float) Button size (width, height) in pixels. """ # Update actor. pass
def _set_position(self, coords): """Set the lower-left corner position of this UI component. Parameters ---------- coords: (float, float) Absolute pixel coordinates (x, y). """ # coords = (0, 0, 0) pass
# self.actor.SetPosition(*coords) # self.container.SetPosition(*coords)