Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion fastplotlib/layouts/_imgui_figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from ._figure import Figure
from ..ui import EdgeWindow, SubplotToolbar, StandardRightClickMenu, Popup, GUI_EDGES
from ..ui import ColormapPicker
from ..ui._base import COLLAPSE_BUTTON_WIDTH


class ImguiFigure(Figure):
Expand Down Expand Up @@ -213,7 +214,10 @@ def get_pygfx_render_area(self, *args) -> tuple[int, int, int, int]:

for edge in ["right"]:
if self.guis[edge]:
width -= self._guis[edge].size
# when collapsed, the expand button floats over plot area
if not self._guis[edge].collapsed:
# subtract gui size plus collapse button width
width -= self._guis[edge].size + COLLAPSE_BUTTON_WIDTH

for edge in ["bottom"]:
if self.guis[edge]:
Expand Down
130 changes: 127 additions & 3 deletions fastplotlib/ui/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@
from typing import Literal
import numpy as np

from imgui_bundle import imgui
from imgui_bundle import imgui, icons_fontawesome_6 as fa

from ..layouts._figure import Figure


# width of the collapse/expand button
COLLAPSE_BUTTON_WIDTH = 12


GUI_EDGES = ["right", "bottom"]


Expand Down Expand Up @@ -111,6 +115,10 @@ def __init__(
self._title = title
self._window_flags = window_flags

# collapse state for right-side GUI panels
# TODO: other sides when they're supported
self._collapsed = False

self._x, self._y, self._width, self._height = self.get_rect()

self._figure.canvas.add_event_handler(self._set_rect, "resize")
Expand Down Expand Up @@ -151,6 +159,20 @@ def height(self) -> int:
"""height of the window"""
return self._height

@property
def collapsed(self) -> bool:
"""whether the window is collapsed, only applicable to right-side GUI"""
return self._collapsed

@collapsed.setter
def collapsed(self, value: bool):
# TODO: support other edges when needed
if self._location != "right":
return

self._collapsed = bool(value)
self._set_rect()

def _set_rect(self, *args):
self._x, self._y, self._width, self._height = self.get_rect()

Expand All @@ -174,6 +196,7 @@ def get_rect(self) -> tuple[int, int, int, int]:
width, height = (width_canvas, self.size)

case "right":
# GUI panel starts after the collapse button area
x_pos, y_pos = (width_canvas - self.size, 0)
width, height = (self.size, height_canvas)

Expand All @@ -184,12 +207,17 @@ def get_rect(self) -> tuple[int, int, int, int]:

def draw_window(self):
"""helps simplify using imgui by managing window creation & position, and pushing/popping the ID"""
if self._location == "right" and self._collapsed:
self._draw_expand_button()
return

if self._location == "right":
self._draw_collapse_button()

# window position & size
x, y, w, h = self.get_rect()
imgui.set_next_window_size((self.width, self.height))
imgui.set_next_window_pos((self.x, self.y))
# imgui.set_next_window_pos((x, y))
# imgui.set_next_window_size((w, h))
flags = self._window_flags

# begin window
Expand All @@ -207,6 +235,102 @@ def draw_window(self):
# end the window
imgui.end()

def _draw_collapse_button(self):
"""draw collapse button in the reserved area between plot and GUI panel"""
width_canvas, height_canvas = self._figure.canvas.get_logical_size()

# account for bottom GUI if present
if self._figure.guis["bottom"] is not None:
height_canvas -= self._figure.guis["bottom"].size

x_pos = width_canvas - self._size - COLLAPSE_BUTTON_WIDTH
y_pos = 0

# remove all window padding so position is exact
imgui.push_style_var(imgui.StyleVar_.window_padding, (0, 0))

imgui.set_next_window_pos((x_pos, y_pos))
imgui.set_next_window_size((COLLAPSE_BUTTON_WIDTH, height_canvas))

flags = (
imgui.WindowFlags_.no_title_bar
| imgui.WindowFlags_.no_resize
| imgui.WindowFlags_.no_move
| imgui.WindowFlags_.no_scrollbar
| imgui.WindowFlags_.no_collapse
| imgui.WindowFlags_.no_background
)

imgui.begin(f"collapse-{self._title}", p_open=None, flags=flags)
imgui.push_id(self._id_counter + 1000)

# transparent button, visible on hover
imgui.push_style_color(imgui.Col_.button, (0, 0, 0, 0))
imgui.push_style_color(imgui.Col_.button_hovered, (0.5, 0.5, 0.5, 0.5))
imgui.push_style_color(imgui.Col_.button_active, (0.6, 0.6, 0.6, 0.6))

if imgui.button(fa.ICON_FA_CARET_RIGHT, (COLLAPSE_BUTTON_WIDTH, height_canvas)):
self._collapsed = True
self._set_rect()
self._figure._fpl_reset_layout()

imgui.pop_style_color(3)

if imgui.is_item_hovered(0):
imgui.set_tooltip("collapse")

imgui.pop_id()
imgui.end()
imgui.pop_style_var(1) # window_padding

def _draw_expand_button(self):
"""draw expand button at right edge when collapsed"""
width_canvas, height_canvas = self._figure.canvas.get_logical_size()

# account for bottom GUI if present
if self._figure.guis["bottom"] is not None:
height_canvas -= self._figure.guis["bottom"].size

x_pos = width_canvas - COLLAPSE_BUTTON_WIDTH
y_pos = 0

# remove all window padding so position is exact
imgui.push_style_var(imgui.StyleVar_.window_padding, (0, 0))

imgui.set_next_window_pos((x_pos, y_pos))
imgui.set_next_window_size((COLLAPSE_BUTTON_WIDTH, height_canvas))

flags = (
imgui.WindowFlags_.no_title_bar
| imgui.WindowFlags_.no_resize
| imgui.WindowFlags_.no_move
| imgui.WindowFlags_.no_scrollbar
| imgui.WindowFlags_.no_collapse
| imgui.WindowFlags_.no_background
)

imgui.begin(f"expand-{self._title}", p_open=None, flags=flags)
imgui.push_id(self._id_counter)

# visible button - needs to stand out when panel is collapsed
imgui.push_style_color(imgui.Col_.button, (0.4, 0.4, 0.4, 0.9))
imgui.push_style_color(imgui.Col_.button_hovered, (0.5, 0.5, 0.5, 1.0))
imgui.push_style_color(imgui.Col_.button_active, (0.6, 0.6, 0.6, 1.0))

if imgui.button(fa.ICON_FA_CARET_LEFT, (COLLAPSE_BUTTON_WIDTH, height_canvas)):
self._collapsed = False
self._set_rect()
self._figure._fpl_reset_layout()

imgui.pop_style_color(3)

if imgui.is_item_hovered(0):
imgui.set_tooltip("expand")

imgui.pop_id()
imgui.end()
imgui.pop_style_var(1) # window_padding

def update(self):
"""Implement your GUI here and it will be drawn within the window. See the GUI examples"""
raise NotImplementedError
Expand Down
Loading