fix & improve platform popups
This commit is contained in:
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@@ -8,7 +8,7 @@
|
|||||||
"program": "${workspaceFolder}/build_debug/autosample.app/Contents/MacOS/autosample",
|
"program": "${workspaceFolder}/build_debug/autosample.app/Contents/MacOS/autosample",
|
||||||
"args": [],
|
"args": [],
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
// "preLaunchTask": "build-debug"
|
"preLaunchTask": "build-debug"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Debug autosample (Windows)",
|
"name": "Debug autosample (Windows)",
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
"args": [],
|
"args": [],
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
// "preLaunchTask": "build-debug"
|
"preLaunchTask": "build-debug"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
94
src/main.cpp
94
src/main.cpp
@@ -102,6 +102,10 @@ struct AppState {
|
|||||||
B32 show_settings_window;
|
B32 show_settings_window;
|
||||||
B32 show_about_window;
|
B32 show_about_window;
|
||||||
B32 show_confirm_dialog;
|
B32 show_confirm_dialog;
|
||||||
|
|
||||||
|
// Pop-out windows
|
||||||
|
B32 show_mix_popout;
|
||||||
|
B32 show_patch_popout;
|
||||||
S32 settings_theme_sel;
|
S32 settings_theme_sel;
|
||||||
S32 settings_theme_prev;
|
S32 settings_theme_prev;
|
||||||
B32 settings_vsync;
|
B32 settings_vsync;
|
||||||
@@ -1165,9 +1169,41 @@ static void build_header_bar(AppState *app) {
|
|||||||
CLAY_TEXT(CLAY_STRING("Mix"), mix_active ? &header_btn_active_text : &g_text_config_normal);
|
CLAY_TEXT(CLAY_STRING("Mix"), mix_active ? &header_btn_active_text : &g_text_config_normal);
|
||||||
}
|
}
|
||||||
if (mix_hovered && g_wstate.mouse_clicked) {
|
if (mix_hovered && g_wstate.mouse_clicked) {
|
||||||
|
PopupWindow *mix_pop = popup_find_by_flag(&app->show_mix_popout);
|
||||||
|
if (mix_pop) {
|
||||||
|
platform_focus_window(mix_pop->platform_window);
|
||||||
|
} else {
|
||||||
app->master_layout = 1;
|
app->master_layout = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mix pop-out / pop-in button
|
||||||
|
{
|
||||||
|
B32 mix_popped = app->show_mix_popout;
|
||||||
|
Clay_ElementId pop_eid = CLAY_ID("BtnMixPopOut");
|
||||||
|
B32 pop_hovered = Clay_PointerOver(pop_eid);
|
||||||
|
CLAY(pop_eid,
|
||||||
|
.layout = {
|
||||||
|
.sizing = { .width = CLAY_SIZING_FIXED(uis(22)), .height = CLAY_SIZING_FIXED(uis(22)) },
|
||||||
|
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
|
||||||
|
},
|
||||||
|
.backgroundColor = pop_hovered ? g_theme.accent_hover : g_theme.bg_lighter,
|
||||||
|
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
|
||||||
|
) {
|
||||||
|
ui_icon(mix_popped ? UI_ICON_POP_IN : UI_ICON_POP_OUT, uis(12), g_theme.text_dim);
|
||||||
|
}
|
||||||
|
if (pop_hovered && g_wstate.mouse_clicked) {
|
||||||
|
if (mix_popped) {
|
||||||
|
PopupWindow *p = popup_find_by_flag(&app->show_mix_popout);
|
||||||
|
if (p) popup_close(p);
|
||||||
|
app->master_layout = 1;
|
||||||
|
} else {
|
||||||
|
app->show_mix_popout = 1;
|
||||||
|
if (app->master_layout == 1) app->master_layout = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Patch button
|
// Patch button
|
||||||
{
|
{
|
||||||
@@ -1188,10 +1224,42 @@ static void build_header_bar(AppState *app) {
|
|||||||
CLAY_TEXT(CLAY_STRING("Patch"), patch_active ? &header_btn_active_text : &g_text_config_normal);
|
CLAY_TEXT(CLAY_STRING("Patch"), patch_active ? &header_btn_active_text : &g_text_config_normal);
|
||||||
}
|
}
|
||||||
if (patch_hovered && g_wstate.mouse_clicked) {
|
if (patch_hovered && g_wstate.mouse_clicked) {
|
||||||
|
PopupWindow *patch_pop = popup_find_by_flag(&app->show_patch_popout);
|
||||||
|
if (patch_pop) {
|
||||||
|
platform_focus_window(patch_pop->platform_window);
|
||||||
|
} else {
|
||||||
app->master_layout = 2;
|
app->master_layout = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Patch pop-out / pop-in button
|
||||||
|
{
|
||||||
|
B32 patch_popped = app->show_patch_popout;
|
||||||
|
Clay_ElementId pop_eid = CLAY_ID("BtnPatchPopOut");
|
||||||
|
B32 pop_hovered = Clay_PointerOver(pop_eid);
|
||||||
|
CLAY(pop_eid,
|
||||||
|
.layout = {
|
||||||
|
.sizing = { .width = CLAY_SIZING_FIXED(uis(22)), .height = CLAY_SIZING_FIXED(uis(22)) },
|
||||||
|
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
|
||||||
|
},
|
||||||
|
.backgroundColor = pop_hovered ? g_theme.accent_hover : g_theme.bg_lighter,
|
||||||
|
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
|
||||||
|
) {
|
||||||
|
ui_icon(patch_popped ? UI_ICON_POP_IN : UI_ICON_POP_OUT, uis(12), g_theme.text_dim);
|
||||||
|
}
|
||||||
|
if (pop_hovered && g_wstate.mouse_clicked) {
|
||||||
|
if (patch_popped) {
|
||||||
|
PopupWindow *p = popup_find_by_flag(&app->show_patch_popout);
|
||||||
|
if (p) popup_close(p);
|
||||||
|
app->master_layout = 2;
|
||||||
|
} else {
|
||||||
|
app->show_patch_popout = 1;
|
||||||
|
if (app->master_layout == 2) app->master_layout = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -1676,6 +1744,17 @@ static void build_patch_view(AppState *app) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Pop-out window content callbacks
|
||||||
|
|
||||||
|
static void mix_popout_content(void *user_data) {
|
||||||
|
build_mix_view((AppState *)user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void patch_popout_content(void *user_data) {
|
||||||
|
build_patch_view((AppState *)user_data);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// Build the full UI layout for one frame
|
// Build the full UI layout for one frame
|
||||||
|
|
||||||
@@ -1736,13 +1815,17 @@ static void build_ui(AppState *app) {
|
|||||||
|
|
||||||
build_log_panel(app);
|
build_log_panel(app);
|
||||||
} else if (app->master_layout == 1) {
|
} else if (app->master_layout == 1) {
|
||||||
// === MIX MODE ===
|
// === MIX MODE (skip if popped out) ===
|
||||||
|
if (!app->show_mix_popout) {
|
||||||
build_mix_view(app);
|
build_mix_view(app);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// === PATCH MODE ===
|
// === PATCH MODE (skip if popped out) ===
|
||||||
|
if (!app->show_patch_popout) {
|
||||||
build_patch_view(app);
|
build_patch_view(app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1783,6 +1866,9 @@ static void do_frame(AppState *app) {
|
|||||||
// Gather input
|
// Gather input
|
||||||
PlatformInput input = platform_get_input(app->window);
|
PlatformInput input = platform_get_input(app->window);
|
||||||
|
|
||||||
|
// Sync scale from popups (they may have changed g_ui_scale)
|
||||||
|
app->ui_scale = g_ui_scale;
|
||||||
|
|
||||||
// Cmd+= / Cmd+- (or Ctrl on Windows) to zoom UI, Cmd+0 to reset
|
// Cmd+= / Cmd+- (or Ctrl on Windows) to zoom UI, Cmd+0 to reset
|
||||||
for (S32 k = 0; k < input.key_count; k++) {
|
for (S32 k = 0; k < input.key_count; k++) {
|
||||||
if (input.ctrl_held) {
|
if (input.ctrl_held) {
|
||||||
@@ -1973,6 +2059,10 @@ int main(int argc, char **argv) {
|
|||||||
popup_open(window, renderer, "Preferences", &app.show_settings_window, 480, 400, settings_window_content, &app);
|
popup_open(window, renderer, "Preferences", &app.show_settings_window, 480, 400, settings_window_content, &app);
|
||||||
if (app.show_about_window && !popup_find_by_flag(&app.show_about_window))
|
if (app.show_about_window && !popup_find_by_flag(&app.show_about_window))
|
||||||
popup_open(window, renderer, "About", &app.show_about_window, 260, 200, about_window_content, nullptr);
|
popup_open(window, renderer, "About", &app.show_about_window, 260, 200, about_window_content, nullptr);
|
||||||
|
if (app.show_mix_popout && !popup_find_by_flag(&app.show_mix_popout))
|
||||||
|
popup_open(window, renderer, "Mix", &app.show_mix_popout, 900, 600, mix_popout_content, &app, PLATFORM_WINDOW_STYLE_POPUP_RESIZABLE, 1);
|
||||||
|
if (app.show_patch_popout && !popup_find_by_flag(&app.show_patch_popout))
|
||||||
|
popup_open(window, renderer, "Patch", &app.show_patch_popout, 900, 600, patch_popout_content, &app, PLATFORM_WINDOW_STYLE_POPUP_RESIZABLE, 1);
|
||||||
|
|
||||||
// Check for OS close on popups
|
// Check for OS close on popups
|
||||||
popup_close_check();
|
popup_close_check();
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ struct PlatformWindow;
|
|||||||
|
|
||||||
enum PlatformWindowStyle {
|
enum PlatformWindowStyle {
|
||||||
PLATFORM_WINDOW_STYLE_NORMAL = 0,
|
PLATFORM_WINDOW_STYLE_NORMAL = 0,
|
||||||
PLATFORM_WINDOW_STYLE_POPUP = 1, // utility panel, owned by parent
|
PLATFORM_WINDOW_STYLE_POPUP = 1, // utility panel, owned by parent, fixed size
|
||||||
|
PLATFORM_WINDOW_STYLE_POPUP_RESIZABLE = 2, // utility panel, owned by parent, resizable
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PlatformWindowDesc {
|
struct PlatformWindowDesc {
|
||||||
@@ -64,6 +65,7 @@ struct PlatformWindowDesc {
|
|||||||
S32 height = 720;
|
S32 height = 720;
|
||||||
PlatformWindowStyle style = PLATFORM_WINDOW_STYLE_NORMAL;
|
PlatformWindowStyle style = PLATFORM_WINDOW_STYLE_NORMAL;
|
||||||
PlatformWindow *parent = nullptr;
|
PlatformWindow *parent = nullptr;
|
||||||
|
B32 independent = 0; // if true, don't attach as child (independent top-level window)
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PlatformMsgBoxType {
|
enum PlatformMsgBoxType {
|
||||||
@@ -104,6 +106,9 @@ PlatformInput platform_get_input(PlatformWindow *window);
|
|||||||
// Returns true if the window's close button was clicked (for popup windows).
|
// Returns true if the window's close button was clicked (for popup windows).
|
||||||
B32 platform_window_should_close(PlatformWindow *window);
|
B32 platform_window_should_close(PlatformWindow *window);
|
||||||
|
|
||||||
|
// Bring a window to front and give it keyboard focus.
|
||||||
|
void platform_focus_window(PlatformWindow *window);
|
||||||
|
|
||||||
// Blocks until user responds. Returns 0=first button, 1=second button, -1=dismissed.
|
// Blocks until user responds. Returns 0=first button, 1=second button, -1=dismissed.
|
||||||
S32 platform_message_box(PlatformWindow *parent, const char *title,
|
S32 platform_message_box(PlatformWindow *parent, const char *title,
|
||||||
const char *message, PlatformMsgBoxType type);
|
const char *message, PlatformMsgBoxType type);
|
||||||
|
|||||||
@@ -262,6 +262,8 @@ PlatformWindow *platform_create_window(PlatformWindowDesc *desc) {
|
|||||||
NSWindowStyleMask style_mask;
|
NSWindowStyleMask style_mask;
|
||||||
if (desc->style == PLATFORM_WINDOW_STYLE_POPUP) {
|
if (desc->style == PLATFORM_WINDOW_STYLE_POPUP) {
|
||||||
style_mask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable;
|
style_mask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable;
|
||||||
|
} else if (desc->style == PLATFORM_WINDOW_STYLE_POPUP_RESIZABLE) {
|
||||||
|
style_mask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable;
|
||||||
} else {
|
} else {
|
||||||
style_mask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
|
style_mask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
|
||||||
NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
|
NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
|
||||||
@@ -305,8 +307,8 @@ PlatformWindow *platform_create_window(PlatformWindowDesc *desc) {
|
|||||||
g_main_window = window;
|
g_main_window = window;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If popup, add as child of parent
|
// If popup, add as child of parent (unless independent)
|
||||||
if (desc->style == PLATFORM_WINDOW_STYLE_POPUP && desc->parent) {
|
if (!desc->independent && (desc->style == PLATFORM_WINDOW_STYLE_POPUP || desc->style == PLATFORM_WINDOW_STYLE_POPUP_RESIZABLE) && desc->parent) {
|
||||||
[desc->parent->ns_window addChildWindow:ns_window ordered:NSWindowAbove];
|
[desc->parent->ns_window addChildWindow:ns_window ordered:NSWindowAbove];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,6 +450,11 @@ B32 platform_window_should_close(PlatformWindow *window) {
|
|||||||
return window ? window->should_close : 0;
|
return window ? window->should_close : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void platform_focus_window(PlatformWindow *window) {
|
||||||
|
if (!window || !window->ns_window) return;
|
||||||
|
[window->ns_window makeKeyAndOrderFront:nil];
|
||||||
|
}
|
||||||
|
|
||||||
F32 platform_get_dpi_scale(PlatformWindow *window) {
|
F32 platform_get_dpi_scale(PlatformWindow *window) {
|
||||||
(void)window;
|
(void)window;
|
||||||
return 1.0f; // macOS handles Retina via backing scale factor, not DPI
|
return 1.0f; // macOS handles Retina via backing scale factor, not DPI
|
||||||
|
|||||||
@@ -121,7 +121,10 @@ PlatformWindow *platform_create_window(PlatformWindowDesc *desc) {
|
|||||||
HWND parent_hwnd = nullptr;
|
HWND parent_hwnd = nullptr;
|
||||||
if (desc->style == PLATFORM_WINDOW_STYLE_POPUP) {
|
if (desc->style == PLATFORM_WINDOW_STYLE_POPUP) {
|
||||||
style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;
|
style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;
|
||||||
if (desc->parent) parent_hwnd = desc->parent->hwnd;
|
if (desc->parent && !desc->independent) parent_hwnd = desc->parent->hwnd;
|
||||||
|
} else if (desc->style == PLATFORM_WINDOW_STYLE_POPUP_RESIZABLE) {
|
||||||
|
style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MAXIMIZEBOX;
|
||||||
|
if (desc->parent && !desc->independent) parent_hwnd = desc->parent->hwnd;
|
||||||
} else {
|
} else {
|
||||||
style = WS_OVERLAPPEDWINDOW;
|
style = WS_OVERLAPPEDWINDOW;
|
||||||
}
|
}
|
||||||
@@ -264,6 +267,12 @@ B32 platform_window_should_close(PlatformWindow *window) {
|
|||||||
return window ? window->should_close : 0;
|
return window ? window->should_close : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void platform_focus_window(PlatformWindow *window) {
|
||||||
|
if (!window || !window->hwnd) return;
|
||||||
|
SetForegroundWindow(window->hwnd);
|
||||||
|
SetFocus(window->hwnd);
|
||||||
|
}
|
||||||
|
|
||||||
F32 platform_get_dpi_scale(PlatformWindow *window) {
|
F32 platform_get_dpi_scale(PlatformWindow *window) {
|
||||||
if (!window || !window->hwnd) return 1.0f;
|
if (!window || !window->hwnd) return 1.0f;
|
||||||
return (F32)GetDpiForWindow(window->hwnd) / 96.0f;
|
return (F32)GetDpiForWindow(window->hwnd) / 96.0f;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ B32 renderer_begin_frame(Renderer *renderer);
|
|||||||
void renderer_end_frame(Renderer *renderer, Clay_RenderCommandArray render_commands);
|
void renderer_end_frame(Renderer *renderer, Clay_RenderCommandArray render_commands);
|
||||||
void renderer_resize(Renderer *renderer, S32 width, S32 height);
|
void renderer_resize(Renderer *renderer, S32 width, S32 height);
|
||||||
void renderer_set_font_scale(Renderer *renderer, F32 scale);
|
void renderer_set_font_scale(Renderer *renderer, F32 scale);
|
||||||
|
void renderer_sync_from_parent(Renderer *renderer); // sync shared font atlas from parent
|
||||||
void renderer_set_clear_color(Renderer *renderer, F32 r, F32 g, F32 b);
|
void renderer_set_clear_color(Renderer *renderer, F32 r, F32 g, F32 b);
|
||||||
|
|
||||||
// Text measurement callback compatible with UI_MeasureTextFn
|
// Text measurement callback compatible with UI_MeasureTextFn
|
||||||
|
|||||||
@@ -1537,3 +1537,12 @@ void renderer_set_font_scale(Renderer *r, F32 scale) {
|
|||||||
if (r->font_texture) { r->font_texture->Release(); r->font_texture = nullptr; }
|
if (r->font_texture) { r->font_texture->Release(); r->font_texture = nullptr; }
|
||||||
create_font_atlas(r, target_size);
|
create_font_atlas(r, target_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void renderer_sync_from_parent(Renderer *r) {
|
||||||
|
if (!r || !r->parent) return;
|
||||||
|
Renderer *p = r->parent;
|
||||||
|
r->font_texture = p->font_texture;
|
||||||
|
r->font_atlas_size = p->font_atlas_size;
|
||||||
|
r->font_line_height = p->font_line_height;
|
||||||
|
memcpy(r->glyphs, p->glyphs, sizeof(r->glyphs));
|
||||||
|
}
|
||||||
|
|||||||
@@ -1003,6 +1003,16 @@ void renderer_set_font_scale(Renderer *r, F32 scale) {
|
|||||||
create_font_atlas(r, target_size);
|
create_font_atlas(r, target_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void renderer_sync_from_parent(Renderer *r) {
|
||||||
|
if (!r || !r->parent) return;
|
||||||
|
Renderer *p = r->parent;
|
||||||
|
r->font_texture = p->font_texture;
|
||||||
|
r->font_sampler = p->font_sampler;
|
||||||
|
r->font_atlas_size = p->font_atlas_size;
|
||||||
|
r->font_line_height = p->font_line_height;
|
||||||
|
memcpy(r->glyphs, p->glyphs, sizeof(r->glyphs));
|
||||||
|
}
|
||||||
|
|
||||||
void renderer_resize(Renderer *r, S32 width, S32 height) {
|
void renderer_resize(Renderer *r, S32 width, S32 height) {
|
||||||
if (width <= 0 || height <= 0) return;
|
if (width <= 0 || height <= 0) return;
|
||||||
r->width = width;
|
r->width = width;
|
||||||
|
|||||||
@@ -126,6 +126,20 @@ static const char *g_icon_svgs[UI_ICON_COUNT] = {
|
|||||||
R"(<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
R"(<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||||
<circle cx="12" cy="12" r="8" fill="white"/>
|
<circle cx="12" cy="12" r="8" fill="white"/>
|
||||||
</svg>)",
|
</svg>)",
|
||||||
|
|
||||||
|
// UI_ICON_POP_OUT - box with arrow pointing out (top-right)
|
||||||
|
R"(<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||||
|
<rect x="3" y="6" width="14" height="14" rx="2" stroke="white" stroke-width="2" fill="none"/>
|
||||||
|
<path d="M14 3 L21 3 L21 10" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
||||||
|
<path d="M21 3 L12 12" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
</svg>)",
|
||||||
|
|
||||||
|
// UI_ICON_POP_IN - arrow pointing into a box (bottom-left)
|
||||||
|
R"(<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||||
|
<rect x="3" y="6" width="14" height="14" rx="2" stroke="white" stroke-width="2" fill="none"/>
|
||||||
|
<path d="M21 3 L12 12" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M12 5 L12 12 L19 12" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
||||||
|
</svg>)",
|
||||||
};
|
};
|
||||||
|
|
||||||
U8 *ui_icons_rasterize_atlas(S32 *out_w, S32 *out_h, S32 icon_size) {
|
U8 *ui_icons_rasterize_atlas(S32 *out_w, S32 *out_h, S32 icon_size) {
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ enum UI_IconID {
|
|||||||
UI_ICON_TRANSPORT_STOP,
|
UI_ICON_TRANSPORT_STOP,
|
||||||
UI_ICON_TRANSPORT_PLAY,
|
UI_ICON_TRANSPORT_PLAY,
|
||||||
UI_ICON_TRANSPORT_RECORD,
|
UI_ICON_TRANSPORT_RECORD,
|
||||||
|
UI_ICON_POP_OUT,
|
||||||
|
UI_ICON_POP_IN,
|
||||||
UI_ICON_COUNT
|
UI_ICON_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
static PopupWindow g_popups[MAX_POPUP_WINDOWS];
|
static PopupWindow g_popups[MAX_POPUP_WINDOWS];
|
||||||
|
|
||||||
|
static void popup_frame_callback(void *user_data) {
|
||||||
|
PopupWindow *popup = (PopupWindow *)user_data;
|
||||||
|
if (popup && popup->alive)
|
||||||
|
popup_do_frame(popup, 1.0f / 60.0f);
|
||||||
|
}
|
||||||
|
|
||||||
PopupWindow *popup_find_by_flag(B32 *flag) {
|
PopupWindow *popup_find_by_flag(B32 *flag) {
|
||||||
for (S32 i = 0; i < MAX_POPUP_WINDOWS; i++)
|
for (S32 i = 0; i < MAX_POPUP_WINDOWS; i++)
|
||||||
if (g_popups[i].alive && g_popups[i].open_flag == flag)
|
if (g_popups[i].alive && g_popups[i].open_flag == flag)
|
||||||
@@ -12,7 +18,8 @@ PopupWindow *popup_find_by_flag(B32 *flag) {
|
|||||||
PopupWindow *popup_open(PlatformWindow *parent_window, Renderer *parent_renderer,
|
PopupWindow *popup_open(PlatformWindow *parent_window, Renderer *parent_renderer,
|
||||||
const char *title, B32 *open_flag,
|
const char *title, B32 *open_flag,
|
||||||
S32 width, S32 height,
|
S32 width, S32 height,
|
||||||
UI_WindowContentFn content_fn, void *user_data) {
|
UI_WindowContentFn content_fn, void *user_data,
|
||||||
|
PlatformWindowStyle style, B32 independent) {
|
||||||
// Find free slot
|
// Find free slot
|
||||||
PopupWindow *popup = nullptr;
|
PopupWindow *popup = nullptr;
|
||||||
for (S32 i = 0; i < MAX_POPUP_WINDOWS; i++) {
|
for (S32 i = 0; i < MAX_POPUP_WINDOWS; i++) {
|
||||||
@@ -27,8 +34,9 @@ PopupWindow *popup_open(PlatformWindow *parent_window, Renderer *parent_renderer
|
|||||||
desc.title = title;
|
desc.title = title;
|
||||||
desc.width = width;
|
desc.width = width;
|
||||||
desc.height = height;
|
desc.height = height;
|
||||||
desc.style = PLATFORM_WINDOW_STYLE_POPUP;
|
desc.style = style;
|
||||||
desc.parent = parent_window;
|
desc.parent = parent_window;
|
||||||
|
desc.independent = independent;
|
||||||
popup->platform_window = platform_create_window(&desc);
|
popup->platform_window = platform_create_window(&desc);
|
||||||
if (!popup->platform_window) return nullptr;
|
if (!popup->platform_window) return nullptr;
|
||||||
|
|
||||||
@@ -61,6 +69,8 @@ PopupWindow *popup_open(PlatformWindow *parent_window, Renderer *parent_renderer
|
|||||||
popup->title = title;
|
popup->title = title;
|
||||||
popup->wstate = {};
|
popup->wstate = {};
|
||||||
|
|
||||||
|
platform_set_frame_callback(popup->platform_window, popup_frame_callback, popup);
|
||||||
|
|
||||||
return popup;
|
return popup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,6 +105,19 @@ void popup_do_frame(PopupWindow *popup, F32 dt) {
|
|||||||
// Gather input from popup window
|
// Gather input from popup window
|
||||||
PlatformInput input = platform_get_input(popup->platform_window);
|
PlatformInput input = platform_get_input(popup->platform_window);
|
||||||
|
|
||||||
|
// Handle Cmd+/- zoom (propagate to global scale)
|
||||||
|
for (S32 k = 0; k < input.key_count; k++) {
|
||||||
|
if (input.ctrl_held) {
|
||||||
|
if (input.keys[k] == PKEY_EQUAL) g_ui_scale *= 1.1f;
|
||||||
|
if (input.keys[k] == PKEY_MINUS) g_ui_scale /= 1.1f;
|
||||||
|
if (input.keys[k] == PKEY_0) g_ui_scale = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_ui_scale = Clamp(0.5f, g_ui_scale, 3.0f);
|
||||||
|
|
||||||
|
// Sync shared font atlas from parent renderer (picks up zoom changes)
|
||||||
|
renderer_sync_from_parent(popup->renderer);
|
||||||
|
|
||||||
// Swap widget state
|
// Swap widget state
|
||||||
UI_WidgetState saved_wstate = g_wstate;
|
UI_WidgetState saved_wstate = g_wstate;
|
||||||
g_wstate = popup->wstate;
|
g_wstate = popup->wstate;
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ struct PopupWindow {
|
|||||||
PopupWindow *popup_open(PlatformWindow *parent_window, Renderer *parent_renderer,
|
PopupWindow *popup_open(PlatformWindow *parent_window, Renderer *parent_renderer,
|
||||||
const char *title, B32 *open_flag,
|
const char *title, B32 *open_flag,
|
||||||
S32 width, S32 height,
|
S32 width, S32 height,
|
||||||
UI_WindowContentFn content_fn, void *user_data);
|
UI_WindowContentFn content_fn, void *user_data,
|
||||||
|
PlatformWindowStyle style = PLATFORM_WINDOW_STYLE_POPUP,
|
||||||
|
B32 independent = 0);
|
||||||
void popup_close(PopupWindow *popup);
|
void popup_close(PopupWindow *popup);
|
||||||
PopupWindow *popup_find_by_flag(B32 *flag);
|
PopupWindow *popup_find_by_flag(B32 *flag);
|
||||||
void popup_do_frame(PopupWindow *popup, F32 dt);
|
void popup_do_frame(PopupWindow *popup, F32 dt);
|
||||||
|
|||||||
Reference in New Issue
Block a user