Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
dba0f1d
Initial work on imgui 1.92 and scalable UI
bgribble Jul 11, 2025
2ee2c65
More work on dummy and spacing elements
bgribble Jul 11, 2025
2a6f2ca
Make reset-zoom zoom to the current DPI scaling
bgribble Jul 12, 2025
b706fd2
Use Inconsolata as app font; tweak formatting
bgribble Jul 15, 2025
3667c21
Show layer for selected object on select
bgribble Jul 16, 2025
44cfc49
Change magnification menu item name
bgribble Jul 16, 2025
cd58cb5
Always process motion events to change the selected app window region
bgribble Jul 16, 2025
0c689f4
Add placeholder for height if there's no text
bgribble Jul 17, 2025
90c8e3f
Include padding in text element size computation
bgribble Jul 17, 2025
8c35440
Increase widget height for newline
bgribble Jul 17, 2025
7462625
Initialize TextElement style defaults correctly
bgribble Jul 17, 2025
652e6f0
Delete selection before checking editpos
bgribble Jul 17, 2025
487b4f3
Add inlet/outlet description params to tooltip
bgribble Jul 17, 2025
eebb50a
Initial implementation of [messagerec]
bgribble Jul 22, 2025
90724b7
Work on [messagerec]
bgribble Jul 24, 2025
b06fa6e
Work on [messagerec]
bgribble Aug 1, 2025
efbc677
Merge branch 'master' into feature/313-scaling-controls
bgribble Aug 1, 2025
b6b8ddc
Work on quantization behavior and beat wraparound
bgribble Aug 2, 2025
4949c90
Update comment
bgribble Aug 2, 2025
801ad65
Merge branch 'master' into feature/313-scaling-controls
bgribble Aug 2, 2025
5ffe72e
Tweak spacing for scalable font
bgribble Aug 8, 2025
91b25c4
Merge branch 'master' into feature/313-scaling-controls
bgribble Aug 14, 2025
3df9fdf
Don't save deleted objects
bgribble Aug 16, 2025
6fcfccb
Merge branch 'master' into feature/313-scaling-controls
bgribble Aug 25, 2025
b1b8617
Merge branch 'master' into feature/313-scaling-controls
bgribble Aug 27, 2025
bd0eef1
Add -m/--magnification option for initial HiDPI comp
bgribble Sep 8, 2025
bb2a338
Merge branch 'master' into feature/313-scaling-controls
bgribble Sep 23, 2025
a033eb2
Merge branch 'master' into feature/313-scaling-controls
bgribble Sep 23, 2025
ace424a
Update imgui-bundle to 1.92.3
bgribble Sep 23, 2025
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
9 changes: 8 additions & 1 deletion mfp/gui/app_window_select.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ async def select(self, obj):

if obj not in self.selected:
self.selected = [obj] + self.selected
obj.layer.patch.selected_layer = obj.layer

obj.select()

await self.signal_emit("select", obj)
return True

Expand Down Expand Up @@ -221,7 +224,11 @@ async def delete_selected(self):
@extends(AppWindow)
def reset_zoom(self):
di = self.selected_patch.display_info
di.view_zoom = 1.0
if self.backend_name == "imgui":
di.view_zoom = self.imgui_global_scale
else:
di.view_zoom = 1.0

di.view_x = 0
di.view_y = 0
self.viewport_pos_set = True
Expand Down
6 changes: 3 additions & 3 deletions mfp/gui/base_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,14 @@ def move_to_top(self):
# their own editors. It's awkward to have type-specific info here
# and in the Processor definition but I can't see a way around it
PROPERTY_ATTRS = {
'lv2_description': ParamInfo(
label="Description", param_type=str, show=True
),
'lv2_type': ParamInfo(
label="(lv2) Port type",
choices=lambda o: [('MIDI', 'midi'), ('Control', 'control')],
param_type=str, show=True
),
'lv2_description': ParamInfo(
label="(lv2) Description", param_type=str, show=True
),
'lv2_default_val': ParamInfo(
label="(lv2) Default value [control ports]", param_type=float, show=True
),
Expand Down
68 changes: 58 additions & 10 deletions mfp/gui/imgui/app_window/app_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,17 @@

MAX_RENDER_US = 200000
PEAK_FPS = 60

BASE_MARKDOWN_FONT_SCALES = [
1.42, 1.33, 1.24, 1.15, 1.1, 1.05
]

def monospace_font():
atlas = imgui.get_io().fonts
fonts = atlas.fonts
for f in fonts:
family = f.get_debug_name().split(' ')[0]
if family == 'Inconsolata-Medium':
return f

class ImguiAppWindowImpl(AppWindow, AppWindowImpl):
backend_name = "imgui"
Expand All @@ -45,6 +55,7 @@ def __init__(self, *args, **kwargs):
self.imgui_prevent_idle = 0
self.imgui_tile_selected = False
self.imgui_popup_open = None
self.imgui_global_scale = 1.0

self.nedit_config = None

Expand Down Expand Up @@ -94,7 +105,7 @@ def __init__(self, *args, **kwargs):

super().__init__(*args, **kwargs)

self.signal_listen("motion-event", self.handle_motion)
self.signal_listen("motion-event", self.handle_motion, prepend=True)
self.signal_listen("toggle-console", self.handle_toggle_console)
self.signal_listen("toggle-info-panel", self.handle_toggle_info_panel)

Expand Down Expand Up @@ -129,6 +140,15 @@ async def handle_toggle_console(self, *rest):
async def handle_toggle_info_panel(self, *rest):
self.info_panel_visible = not self.info_panel_visible

def scaled(self, *args):
if len(args) == 1:
return args[0] * self.imgui_global_scale

return tuple(
v * self.imgui_global_scale
for v in args
)

async def _render_task(self):
from mfp.gui.imgui.text_widget import ImguiTextWidgetImpl

Expand All @@ -150,8 +170,8 @@ async def _render_task(self):
md_options.callbacks.on_image = ImguiTextWidgetImpl.image_callback
md_options.callbacks.on_open_link = ImguiTextWidgetImpl.url_callback
md_options.font_options.regular_size = 16
md_options.font_options.size_diff_between_levels = 4
md_options.font_options.max_header_level = 5
# md_options.font_options.size_diff_between_levels = 4
# md_options.font_options.max_header_level = 5
markdown.initialize_markdown(md_options)
font_loader = markdown.get_font_loader_function()
font_loader()
Expand All @@ -169,6 +189,8 @@ async def _render_task(self):

gl.glClearColor(1.0, 1.0, 1.0, 1)

default_font = None

sync_time = None
while (
keep_going
Expand Down Expand Up @@ -204,9 +226,18 @@ async def _render_task(self):
# start processing for this frame
imgui.new_frame()

if not default_font:
default_font = monospace_font()

if default_font:
imgui.push_font(default_font, 16)

# hard work
keep_going = self.render()

if default_font:
imgui.pop_font()

######################
# bottom of loop stuff - hand over the frame to imgui

Expand Down Expand Up @@ -257,6 +288,7 @@ def shutdown(self):
#####################
# renderer
def render(self):

self.imgui_prevent_idle = max(0, self.imgui_prevent_idle - 1)
keep_going = True

Expand All @@ -267,6 +299,10 @@ def render(self):
nedit.push_style_color(nedit.StyleColor.flow_marker, (1, 1, 1, 0.2))
nedit.push_style_color(nedit.StyleColor.flow, (1, 1, 1, 0.5))

vp = imgui.get_main_viewport()
vp.framebuffer_scale = (2*self.imgui_global_scale, 2*self.imgui_global_scale)
imgui.get_style().font_scale_main = self.imgui_global_scale

########################################
# menu bar
self.imgui_popup_open = False
Expand Down Expand Up @@ -295,9 +331,9 @@ def render(self):
)
if imgui.begin_popup("About MFP##popup"):
from mfp.mfp_main import mfp_banner, mfp_footer, version
imgui.push_style_var(imgui.StyleVar_.item_spacing, (0, 8))
imgui.dummy([1, 4])
imgui.dummy([8, 1])
imgui.push_style_var(imgui.StyleVar_.item_spacing, self.scaled(0, 8))
imgui.dummy(self.scaled(1, 4))
imgui.dummy(self.scaled(8, 1))
imgui.same_line()
imgui.begin_group()
imgui.text(mfp_banner % version())
Expand All @@ -308,8 +344,8 @@ def render(self):
imgui.text(mfp_footer)
imgui.end_group()
imgui.same_line()
imgui.dummy([8, 1])
imgui.dummy([1, 4])
imgui.dummy(self.scaled(8, 1))
imgui.dummy(self.scaled(1, 4))
imgui.pop_style_var()
imgui.end_popup()
popup_open = True
Expand Down Expand Up @@ -431,7 +467,6 @@ def render(self):
# bottom panel
########################################


imgui.pop_style_var() # padding
imgui.pop_style_var() # border
imgui.end()
Expand Down Expand Up @@ -531,6 +566,19 @@ def rezoom(self, **kwargs):
def get_size(self):
return (self.window_width, self.window_height)

def set_app_scale(self, new_scale):
scale_ratio = new_scale / self.imgui_global_scale
self.imgui_global_scale = new_scale
self.canvas_tile_manager.default_zoom = new_scale

for p in self.patches:
if p.display_info:
p.display_info.view_zoom *= scale_ratio

self.viewport_zoom_set = True
self.viewport_pos_set = True
return True

#####################
# element operations
def register(self, element):
Expand Down
4 changes: 3 additions & 1 deletion mfp/gui/imgui/app_window/canvas_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def render_tile(app_window, patch):
"""
render a patch tile
"""

# for some reason this still leaves a gap under the menu bar
canvas_pane_origin = (1, app_window.menu_height + 1)

Expand Down Expand Up @@ -191,8 +192,8 @@ def render_tile(app_window, patch):
app_window.get_color('grid-color:operate').to_rgbaf()
)

imgui.get_style().font_scale_main = 1.0
nedit.begin("canvas_editor", (0.0, 0.0))

conf = nedit.get_config()

# disable NodeEditor dragging and selecting unless we are hovering on
Expand Down Expand Up @@ -417,6 +418,7 @@ def render_tile(app_window, patch):

nedit.end() # node_editor
nedit.pop_style_color(5)
imgui.get_style().font_scale_main = app_window.imgui_global_scale

imgui.end()

Expand Down
6 changes: 3 additions & 3 deletions mfp/gui/imgui/app_window/console_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ def render(app_window):

imgui.push_style_var(imgui.StyleVar_.item_spacing, [2, 2])

imgui.dummy((1, 1))
imgui.dummy(app_window.scaled(1, 1))
imgui.begin_group()
imgui.dummy((1, 1))
imgui.dummy(app_window.scaled(1, 1))
imgui.text(" Filter regex:")
imgui.end_group()
imgui.same_line()
Expand All @@ -56,7 +56,7 @@ def render(app_window):
imgui.same_line()
cur = imgui.get_cursor_pos()
imgui.set_cursor_pos((
app_window.window_width - 110,
app_window.window_width - 120*app_window.imgui_global_scale,
cur[1]
))
_, app_window.log_scroll_follow = imgui.checkbox(
Expand Down
44 changes: 22 additions & 22 deletions mfp/gui/imgui/app_window/info_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def render_param(
if item_selected and choice_label != current_choice[0]:
changed = True
newval = choice_value
imgui.dummy([1, 4])
imgui.dummy(app_window.scaled(1, 4))
imgui.end_popup()
imgui.pop_style_var(2)

Expand Down Expand Up @@ -590,8 +590,8 @@ def render_patch_tab(app_window):

######################
# a little padding
imgui.dummy([1, TAB_PADDING_Y])
imgui.dummy([TAB_PADDING_X, 1])
imgui.dummy(app_window.scaled(1, TAB_PADDING_Y))
imgui.dummy(app_window.scaled(TAB_PADDING_X, 1))
imgui.same_line()

imgui.begin_group()
Expand Down Expand Up @@ -678,8 +678,8 @@ def render_patch_tab(app_window):
def render_object_tab(app_window):
######################
# a little padding
imgui.dummy([1, TAB_PADDING_Y])
imgui.dummy([TAB_PADDING_X, 1])
imgui.dummy(app_window.scaled(1, TAB_PADDING_Y))
imgui.dummy(app_window.scaled(TAB_PADDING_X, 1))
imgui.same_line()

imgui.begin_group()
Expand Down Expand Up @@ -721,8 +721,8 @@ def render_params_tab(app_window, param_list):

######################
# a little padding
imgui.dummy([1, TAB_PADDING_Y])
imgui.dummy([TAB_PADDING_X, 1])
imgui.dummy(app_window.scaled(1, TAB_PADDING_Y))
imgui.dummy(app_window.scaled(TAB_PADDING_X, 1))
imgui.same_line()

imgui.begin_group()
Expand Down Expand Up @@ -755,8 +755,8 @@ def render_style_tab(app_window):

# the Element tab is the only on where params can be edited
if imgui.begin_tab_item("Element")[0]:
imgui.dummy([1, TAB_PADDING_Y])
imgui.dummy([TAB_PADDING_X, 1])
imgui.dummy(app_window.scaled(1, TAB_PADDING_Y))
imgui.dummy(app_window.scaled(TAB_PADDING_X, 1))
imgui.same_line()

imgui.begin_group()
Expand All @@ -771,8 +771,8 @@ def render_style_tab(app_window):

# defaults for this type of element
if imgui.begin_tab_item("Type")[0]:
imgui.dummy([1, TAB_PADDING_Y])
imgui.dummy([TAB_PADDING_X, 1])
imgui.dummy(app_window.scaled(1, TAB_PADDING_Y))
imgui.dummy(app_window.scaled(TAB_PADDING_X, 1))
imgui.same_line()

imgui.begin_group()
Expand All @@ -794,8 +794,8 @@ def render_style_tab(app_window):

# style shared by all element types
if imgui.begin_tab_item("Base")[0]:
imgui.dummy([1, TAB_PADDING_Y])
imgui.dummy([TAB_PADDING_X, 1])
imgui.dummy(app_window.scaled(1, TAB_PADDING_Y))
imgui.dummy(app_window.scaled(TAB_PADDING_X, 1))
imgui.same_line()

imgui.begin_group()
Expand All @@ -817,8 +817,8 @@ def render_style_tab(app_window):
imgui.end_tab_item()

if imgui.begin_tab_item("Global")[0]:
imgui.dummy([1, TAB_PADDING_Y])
imgui.dummy([TAB_PADDING_X, 1])
imgui.dummy(app_window.scaled(1, TAB_PADDING_Y))
imgui.dummy(app_window.scaled(TAB_PADDING_X, 1))
imgui.same_line()

imgui.begin_group()
Expand All @@ -840,8 +840,8 @@ def render_style_tab(app_window):

if len(app_window.selected) == 1:
if imgui.begin_tab_item("Computed")[0]:
imgui.dummy([1, TAB_PADDING_Y])
imgui.dummy([TAB_PADDING_X, 1])
imgui.dummy(app_window.scaled(1, TAB_PADDING_Y))
imgui.dummy(app_window.scaled(TAB_PADDING_X, 1))
imgui.same_line()

imgui.begin_group()
Expand All @@ -866,12 +866,12 @@ def render_bindings_tab(app_window):

######################
# a little padding
imgui.dummy([1, TAB_PADDING_Y])
imgui.dummy([TAB_PADDING_X, 1])
imgui.dummy(app_window.scaled(1, TAB_PADDING_Y))
imgui.dummy(app_window.scaled(TAB_PADDING_X, 1))
imgui.same_line()

imgui.begin_group()
imgui.push_style_var(imgui.StyleVar_.item_spacing, (4.0, 8.0))
imgui.push_style_var(imgui.StyleVar_.item_spacing, app_window.scaled(4.0, 8.0))

imgui.text("OSC bindings")
if imgui.begin_table(
Expand Down Expand Up @@ -938,8 +938,8 @@ def render_activity_tab(app_window):

######################
# a little padding
imgui.dummy([1, TAB_PADDING_Y])
imgui.dummy([TAB_PADDING_X, 1])
imgui.dummy(app_window.scaled(1, TAB_PADDING_Y))
imgui.dummy(app_window.scaled(TAB_PADDING_X, 1))
imgui.same_line()

imgui.begin_group()
Expand Down
Loading