-
Notifications
You must be signed in to change notification settings - Fork 53
imgui prototype #552
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
imgui prototype #552
Conversation
Discussion with @clewis7
Idea for managing/sequestering: subclass class ImguiFigure
def __init__(self, *args, **kwargs):
super()
self.imgui_renderer ....
# more imgui init stuff
self._guis = list()
def render(self):
super()
# imgui render stuff
for gui in self.guis:
gui.update()
imgui.end_frame()
...
canvas.request_draw()
def add_ui(self, edge: str, callable_or_instance_TBD): # edge is the top, bottom, left, or right edge of the canvas
# parse edge and set Figure bbox, i.e. [x, y, width, height] that the pygfx renderer uses
self._guis["edge"] = callable_or_instance_TBD
def set_ui_size(self, edge: str, size: int):
# set imgui reserved size
self._edges["edge"].size = size
@property
def width(self) -> int
return self.renderer.logical_size[0] - self._edges["left"] -self._edges["right"]
# likewise properties for height, x, and y
# use these [x, y, width, height] properties elsewhere in the `Figure`
# such as the subplots and other `PlotAreas` instead of `renderer.logical_size` Determine whether to import |
Something we will have to solve with right click menus, if an item in the right click menu is clicked we have to stop that click event from propagating to the pygfx stuff below the menu. See if imgui can do pointer capture. |
Idea: use imgui for the legends since it already has layouting etc for this type of use case. But then we're forcing people to use imgui. Will think more about this. |
Maybe instead of letting imgui detect and handle the right click event for creating the right click menu popup: add an event handler to the renderer and any graphics for which we want specific right click events. Have them add to a "request queue", for example right click on hlut tool colorbar will request a specific popup menu to be shown on the next render cycle. In each render cycle we go through the queue. Will need to see if we can execute all items in the queue, or if we just do the first one and discard the rest? This might get messy... |
Right click menu for hlut tool to reset vmin vmax |
We can use the imgui windows to set the viewport rect of subplots, just an idea for the future, needs more protyping & thought to implement. Not committed to this. Might be better to handle moving and resizing subplots directly via pygfx, perhaps after the viewports & renderers refactor. playing_imgui-2024-07-19_00.51.20.mp4Messy implemention:
subplot toolbar: from imgui_bundle import imgui, icons_fontawesome_6 as fa, imgui_ctx
from .._plot_area import PlotArea
ID_COUNTER = 0
class SubplotToolbar:
def __init__(self, subplot: PlotArea, icons: imgui.ImFont):
self._subplot = subplot
self.icons = icons
# required to prevent conflict with multiple Figures
global ID_COUNTER
ID_COUNTER += 1
self.id = ID_COUNTER
self.bbox = subplot.get_rect()
self._subplot.get_rect = self.get_rect
def get_rect(self):
x, y, width, height = self.bbox
return x + 10, y + 50, width - 10, height - 60
def update(self):
x, y, width, height = self._subplot.get_rect()
# pos = (x, y + height)
size = self.bbox[2:]
pos = self.bbox[:2]
imgui.set_next_window_size(size, imgui.Cond_.appearing)
imgui.set_next_window_pos(pos, imgui.Cond_.appearing)
flags = imgui.WindowFlags_.no_collapse | imgui.WindowFlags_.no_background #| imgui.WindowFlags_.no_title_bar
imgui.begin(f"Toolbar-{self._subplot.position}", p_open=None, flags=flags)
width, height = imgui.get_window_size()
x, y = imgui.get_window_pos()
imgui.push_font(self.icons)
imgui.push_id(self.id) # push ID to prevent conflict between multiple figs with same UI
with imgui_ctx.begin_horizontal(f"toolbar-{self._subplot.position}"):
# autoscale button
if imgui.button(fa.ICON_FA_MAXIMIZE):
self._subplot.auto_scale()
imgui.pop_font()
if imgui.is_item_hovered(0):
imgui.set_tooltip("autoscale scene")
# center scene
imgui.push_font(self.icons)
if imgui.button(fa.ICON_FA_ALIGN_CENTER):
self._subplot.center_scene()
# checkbox controller
_, self._subplot.controller.enabled = imgui.checkbox(fa.ICON_FA_COMPUTER_MOUSE, self._subplot.controller.enabled)
# checkbox maintain_apsect
_, self._subplot.camera.maintain_aspect = imgui.checkbox(fa.ICON_FA_EXPAND, self._subplot.camera.maintain_aspect)
imgui.pop_font()
_, flip_y = imgui.checkbox("flip-y", self._subplot.camera.local.scale_y < 0)
if flip_y and self._subplot.camera.local.scale_y > 0:
self._subplot.camera.local.scale_y *= -1
elif not flip_y and self._subplot.camera.local.scale_y < 0:
self._subplot.camera.local.scale_y *= -1
imgui.pop_id()
self.bbox = (x, y, width, height)
self._subplot.set_viewport_rect()
imgui.end() |
@clewis7 let's forget about using imgui to control subplot viewports etc. for this year, we can just focus on the ideas outlined above in #552 (comment) , i.e. toolbar, imagewidget stuff, sequester imgui, and have a way for users to add their own UI on one of the canvas edges. I think that's enough for now and plenty. Controlling subplot viewports like this and other things open up a can of worms, scope explosion, and change how the whole fpl API works. We can think about it next year? |
I have an idea to build upon this, user could right click -> drag to draw a rectangle, and then this rectangle becomes a new subplot on an empty figure canvas 😆 |
superseeded by #571 |
Very early dirty prototype, works in qt windows and gridplots, glfw is crashing for some reason.
We also need to figure out the big-picture of how we implement it, and sequester it. There will always be people who just want to use Qt or some other framework for making their UI. If someone doesn't want to make their UI they can use the built-in imgui, otherwise they don't need to install imgui and can use their preferred framework :D
Can probably have a
UIBaseClass
for all imgui UIs that fastplotlib uses, andFigure
will take an instance ofUIClass
as an instance and call theUIClass.update()
method.Figure
will give it the font and any other config, such as thecanvas
, maybe makes a uniqueID_COUNTER
for eachUIClass
instance? See if having multipleID_COUNTER
that all have diff start addresses works so that user-implemented UIs don't have to worry about pushing ids.Relies on pygfx/wgpu-py#539
ImageWidget:
imgui-2024-07-11_21.50.32.mp4