Skip to content
Merged
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
1 change: 1 addition & 0 deletions misrc_tools/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ if raylib_dep.found()
'misrc_gui/visualization/gui_vu_meter.c',
'misrc_gui/visualization/panel_registry.c',
# UI
'misrc_gui/ui/gui_ui_scale.c',
'misrc_gui/ui/gui_ui.c',
'misrc_gui/ui/gui_dropdown.c',
'misrc_gui/ui/gui_popup.c',
Expand Down
1 change: 1 addition & 0 deletions misrc_tools/misrc_gui/core/gui_app.h
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ typedef struct {
bool show_grid;
float time_scale; // Time per division (ms)
float amplitude_scale; // Amplitude scale factor
int ui_scale_percent; // Ctrl/Cmd+wheel or +/- UI zoom, persisted as 75-200

// Device discovery: V4L2/simple_capture device enumeration is opt-in.
// Disabled by default since most users use hsdaoh/CXADC/DdD/FX3 backends;
Expand Down
6 changes: 6 additions & 0 deletions misrc_tools/misrc_gui/core/gui_settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

#include "../core/gui_app.h"
#include "../ui/gui_ui_scale.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -465,6 +466,7 @@ void gui_settings_init_defaults(gui_settings_t *settings) {
settings->show_grid = true;
settings->time_scale = 1.0f;
settings->amplitude_scale = 1.0f;
settings->ui_scale_percent = GUI_UI_SCALE_DEFAULT_PERCENT;

// V4L2/simple_capture device discovery is opt-in (disabled by default).
settings->discover_simple_capture = false;
Expand Down Expand Up @@ -603,6 +605,7 @@ void gui_settings_save(const gui_settings_t *settings) {
fprintf(f, " \"show_grid\": %s,\n", settings->show_grid ? "true" : "false");
fprintf(f, " \"time_scale\": %.2f,\n", settings->time_scale);
fprintf(f, " \"amplitude_scale\": %.2f,\n", settings->amplitude_scale);
fprintf(f, " \"ui_scale_percent\": %d,\n", settings->ui_scale_percent);
fprintf(f, " \"discover_simple_capture\": %s,\n", settings->discover_simple_capture ? "true" : "false");
fprintf(f, " \"show_core_pinning_in_settings\": %s,\n", settings->show_core_pinning_in_settings ? "true" : "false");
fprintf(f, " \"memory_budget_gb\": %u,\n", (unsigned)settings->memory_budget_gb);
Expand Down Expand Up @@ -1032,6 +1035,9 @@ void gui_settings_load(gui_settings_t *settings) {
if ((value = find_value(content, "amplitude_scale")) != NULL) {
settings->amplitude_scale = (float)atof(value);
}
if ((value = find_value(content, "ui_scale_percent")) != NULL) {
settings->ui_scale_percent = gui_ui_scale_parse_percent(value);
}
if ((value = find_value(content, "discover_simple_capture")) != NULL) {
settings->discover_simple_capture = (strcmp(value, "true") == 0);
}
Expand Down
114 changes: 83 additions & 31 deletions misrc_tools/misrc_gui/core/misrc_gui.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#if defined(__APPLE__)
#include <unistd.h>
#include <limits.h>
Expand Down Expand Up @@ -68,6 +69,7 @@ volatile atomic_int do_exit = 0;
// Font array for Clay
// Index 0: Inter (general UI), Index 1: Space Mono (monospace sections)
#define FONT_COUNT 2
#define UI_FONT_ATLAS_SIZE 64
static Font fonts[FONT_COUNT];

// Clay error handler
Expand Down Expand Up @@ -97,35 +99,22 @@ static void print_usage(const char *program_name) {
fprintf(stdout, "(Headless CLI capture mode is not available in the Android build.)\n");
#endif
}
static int gui_layout_width(void) {
#if defined(__APPLE__)
int width = GetScreenWidth();
#else
int width = GetRenderWidth();
if (width <= 0) {
width = GetScreenWidth();
}
#endif
return (width > 0) ? width : 1;
}
static int gui_layout_height(void) {
#if defined(__APPLE__)
int height = GetScreenHeight();
#else
int height = GetRenderHeight();
if (height <= 0) {
height = GetScreenHeight();
}
#endif
return (height > 0) ? height : 1;
}
static bool gui_status_is_permission_denied(const gui_app_t *app) {
if (!app) return false;
return strstr(app->status_message, "Permission denied") != NULL ||
strstr(app->status_message, "permission denied") != NULL ||
strstr(app->status_message, "device not granted") != NULL ||
strstr(app->status_message, "USB open failed") != NULL;
}

static bool gui_primary_modifier_down(void)
{
bool down = IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL);
#if defined(__APPLE__)
down = down || IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_RIGHT_SUPER);
#endif
return down;
}
static const char *gui_dropout_reason_status(gui_dropout_reason_t reason) {
switch (reason) {
case GUI_DROPOUT_MISSED_FRAME:
Expand Down Expand Up @@ -453,6 +442,7 @@ int main(int argc, char **argv) {

// Load persistent settings (includes desktop path defaults)
gui_settings_load(&app.settings);
gui_ui_set_scale_percent(app.settings.ui_scale_percent);

// Capture limit should not persist across relaunches.
app.settings.capture_limit_seconds = 0;
Expand Down Expand Up @@ -481,7 +471,8 @@ int main(int argc, char **argv) {

// Load embedded Inter font directly from memory (Apache 2.0 licensed)
// Font data is ~342KB and embedded as a C array for complete portability
fonts[0] = LoadFontFromMemory(".ttf", inter_font_data, inter_font_data_size, 32, NULL, 256);
fonts[0] = LoadFontFromMemory(".ttf", inter_font_data, inter_font_data_size,
UI_FONT_ATLAS_SIZE, NULL, 256);
if (fonts[0].texture.id == 0) {
fprintf(stderr, "Error: Failed to load embedded Inter font data\n");
CloseWindow();
Expand All @@ -491,7 +482,8 @@ int main(int argc, char **argv) {

// Load embedded Space Mono font directly from memory (SIL Open Font License)
// Font data is embedded as a C array for complete portability
fonts[1] = LoadFontFromMemory(".ttf", space_mono_font_data, space_mono_font_data_size, 32, NULL, 256);
fonts[1] = LoadFontFromMemory(".ttf", space_mono_font_data, space_mono_font_data_size,
UI_FONT_ATLAS_SIZE, NULL, 256);
if (fonts[1].texture.id == 0) {
fprintf(stderr, "Error: Failed to load embedded Space Mono font data\n");
CloseWindow();
Expand All @@ -509,7 +501,9 @@ int main(int argc, char **argv) {
}

Clay_Arena clay_arena = Clay_CreateArenaWithCapacityAndMemory(clay_memory_size, clay_memory);
Clay_Initialize(clay_arena, (Clay_Dimensions){ (float)gui_layout_width(), (float)gui_layout_height() },
Clay_Initialize(clay_arena,
(Clay_Dimensions){ (float)gui_ui_get_layout_width(),
(float)gui_ui_get_layout_height() },
(Clay_ErrorHandler){
.errorHandlerFunction = clay_error_handler,
.userData = NULL,
Expand Down Expand Up @@ -590,6 +584,9 @@ int main(int argc, char **argv) {
int last_layout_width = -1;
int last_layout_height = -1;
bool recording_fps_throttle = false;
gui_ui_zoom_state_t ui_zoom_state = {0};
bool ui_scale_save_pending = false;
double ui_scale_save_deadline = 0.0;
#if defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__))
double last_thread_promotion_time = 0.0;
const double thread_promotion_interval_s = 0.25;
Expand All @@ -608,6 +605,58 @@ int main(int argc, char **argv) {
recording_fps_throttle = false;
}
float dt = GetFrameTime();
Vector2 wheel_delta = GetMouseWheelMoveV();
bool primary_modifier_down = gui_primary_modifier_down();
gui_ui_zoom_result_t ui_zoom_result =
gui_ui_zoom_process(&ui_zoom_state,
app.settings.ui_scale_percent,
primary_modifier_down,
wheel_delta.x,
wheel_delta.y);

bool zoom_reset_pressed = primary_modifier_down &&
(IsKeyPressed(KEY_ZERO) || IsKeyPressed(KEY_KP_0));
bool zoom_in_pressed = primary_modifier_down &&
(IsKeyPressed(KEY_EQUAL) || IsKeyPressed(KEY_KP_ADD));
bool zoom_out_pressed = primary_modifier_down &&
(IsKeyPressed(KEY_MINUS) || IsKeyPressed(KEY_KP_SUBTRACT));
bool keyboard_step_pressed = zoom_in_pressed != zoom_out_pressed;
bool keyboard_zoom_pressed = zoom_reset_pressed || keyboard_step_pressed;
bool show_ui_scale_hud =
ui_zoom_result.step_attempted || keyboard_zoom_pressed;

if (keyboard_zoom_pressed) {
ui_zoom_state.wheel_remainder = 0.0f;
if (zoom_reset_pressed) {
ui_zoom_result.percent = GUI_UI_SCALE_DEFAULT_PERCENT;
} else {
int direction = zoom_in_pressed ? 1 : -1;
ui_zoom_result.percent =
gui_ui_scale_step_percent(app.settings.ui_scale_percent,
direction);
}
}

ui_zoom_result.changed =
ui_zoom_result.percent != app.settings.ui_scale_percent;

if (ui_zoom_result.changed) {
app.settings.ui_scale_percent = ui_zoom_result.percent;
gui_ui_set_scale_percent(ui_zoom_result.percent);
last_layout_width = -1;
last_layout_height = -1;
ui_scale_save_pending = true;
ui_scale_save_deadline = GetTime() + 0.4;
}

if (show_ui_scale_hud) {
gui_ui_show_scale_hud(ui_zoom_result.percent);
}

if (ui_scale_save_pending && GetTime() >= ui_scale_save_deadline) {
gui_settings_save(&app.settings);
ui_scale_save_pending = false;
}
#if defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__))
if (app.is_capturing) {
double now = GetTime();
Expand All @@ -621,8 +670,8 @@ int main(int argc, char **argv) {
last_thread_promotion_time = 0.0;
}
#endif
int current_layout_width = gui_layout_width();
int current_layout_height = gui_layout_height();
int current_layout_width = gui_ui_get_layout_width();
int current_layout_height = gui_ui_get_layout_height();
if (current_layout_width != last_layout_width || current_layout_height != last_layout_height) {
Clay_SetLayoutDimensions((Clay_Dimensions){
(float)current_layout_width, (float)current_layout_height
Expand Down Expand Up @@ -671,12 +720,12 @@ int main(int argc, char **argv) {
}

// Update Clay mouse state
Vector2 mouse_pos = GetMousePosition();
Vector2 mouse_pos = gui_ui_get_mouse_position();
Clay_SetPointerState((Clay_Vector2){ mouse_pos.x, mouse_pos.y },
IsMouseButtonDown(MOUSE_LEFT_BUTTON));
Clay_UpdateScrollContainers(true, (Clay_Vector2){
GetMouseWheelMoveV().x * 20.0f,
GetMouseWheelMoveV().y * 20.0f
ui_zoom_result.passthrough_x * 20.0f,
ui_zoom_result.passthrough_y * 20.0f
}, dt);

// stop-on-dropout requests are posted from capture callbacks and consumed here.
Expand Down Expand Up @@ -885,7 +934,10 @@ int main(int argc, char **argv) {
}

// Handle panel scroll events (e.g., waveform/FFT zoom)
float wheel = GetMouseWheelMove();
float wheel = fabsf(ui_zoom_result.passthrough_x) >
fabsf(ui_zoom_result.passthrough_y)
? ui_zoom_result.passthrough_x
: ui_zoom_result.passthrough_y;
if (wheel != 0.0f) {
panel_handle_all_scrolls(&app, wheel);
}
Expand Down
7 changes: 4 additions & 3 deletions misrc_tools/misrc_gui/signal/gui_cvbs.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "gui_trigger.h"
#include "gui_vhs_fm.h"
#include "../visualization/gui_text.h"
#include "../ui/gui_ui.h"
#include "../../common/threading.h"
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -2118,7 +2119,7 @@ static void render_cvbs_system_overlay(cvbs_decoder_t *decoder,
decoder->overlay.system_options_rect[i] = opt_rect;

bool is_selected = (sys == sys_values[i]);
Vector2 mouse = GetMousePosition();
Vector2 mouse = gui_ui_get_mouse_position();
bool hover = CheckCollisionPointRec(mouse, opt_rect);

Color opt_bg = gui_dropdown_option_color(is_selected, hover);
Expand Down Expand Up @@ -2153,7 +2154,7 @@ static void render_cvbs_system_overlay(cvbs_decoder_t *decoder,
decoder->overlay.tape_options_rect[i] = opt_rect;

bool is_selected = (decoder->tape_format == values[i]);
Vector2 mouse = GetMousePosition();
Vector2 mouse = gui_ui_get_mouse_position();
bool hover = CheckCollisionPointRec(mouse, opt_rect);

Color opt_bg = gui_dropdown_option_color(is_selected, hover);
Expand Down Expand Up @@ -2181,7 +2182,7 @@ static void render_cvbs_system_overlay(cvbs_decoder_t *decoder,
decoder->overlay.tape_format_options_rect[i] = opt_rect;

bool is_selected = (tape_fmt == i);
Vector2 mouse = GetMousePosition();
Vector2 mouse = gui_ui_get_mouse_position();
bool hover = CheckCollisionPointRec(mouse, opt_rect);

Color opt_bg = gui_dropdown_option_color(is_selected, hover);
Expand Down
6 changes: 3 additions & 3 deletions misrc_tools/misrc_gui/signal/gui_demod.c
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ static void demod_render_overlay(demod_state_t *s, gui_app_t *app, Rectangle bou
Rectangle opt_rect = {mode_btn_x, opt_y + i * opt_h, mode_btn_w, opt_h};
s->overlay.mode_options_rect[i] = opt_rect;
bool is_sel = (i == (int)s->mode);
Vector2 mouse = GetMousePosition();
Vector2 mouse = gui_ui_get_mouse_position();
bool hover = CheckCollisionPointRec(mouse, opt_rect);
Color opt_bg = gui_dropdown_option_color(is_sel, hover);
DrawRectangleRec(opt_rect, opt_bg);
Expand All @@ -727,7 +727,7 @@ static void demod_render_overlay(demod_state_t *s, gui_app_t *app, Rectangle bou
Rectangle opt_rect = {bw_btn_x, opt_y + i * opt_h, bw_btn_w, opt_h};
s->overlay.bw_options_rect[i] = opt_rect;
bool is_sel = (i == bw_cur);
Vector2 mouse = GetMousePosition();
Vector2 mouse = gui_ui_get_mouse_position();
bool hover = CheckCollisionPointRec(mouse, opt_rect);
Color opt_bg = gui_dropdown_option_color(is_sel, hover);
DrawRectangleRec(opt_rect, opt_bg);
Expand All @@ -747,7 +747,7 @@ static void demod_render_overlay(demod_state_t *s, gui_app_t *app, Rectangle bou
Rectangle opt_rect = {out_btn_x, opt_y + i * opt_h, out_btn_w, opt_h};
s->overlay.out_options_rect[i] = opt_rect;
bool is_sel = (i == out_val);
Vector2 mouse = GetMousePosition();
Vector2 mouse = gui_ui_get_mouse_position();
bool hover = CheckCollisionPointRec(mouse, opt_rect);
Color opt_bg = gui_dropdown_option_color(is_sel, hover);
DrawRectangleRec(opt_rect, opt_bg);
Expand Down
16 changes: 15 additions & 1 deletion misrc_tools/misrc_gui/ui/clay_renderer_raylib.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <clay.h>
#include "raylib.h"
#include "rlgl.h"
#include "../visualization/gui_custom_elements.h"
#include "../visualization/gui_panel.h"
#include "../visualization/gui_vu_meter.h"
Expand Down Expand Up @@ -83,6 +84,11 @@ void Clay_Raylib_Close()

void Clay_Raylib_Render(Clay_RenderCommandArray renderCommands, Font* fonts)
{
float ui_scale = gui_ui_get_scale_factor();
Matrix outer_modelview = rlGetMatrixModelview();
rlDrawRenderBatchActive();
rlScalef(ui_scale, ui_scale, 1.0f);

for (int j = 0; j < renderCommands.length; j++)
{
Clay_RenderCommand *renderCommand = Clay_RenderCommandArray_Get(&renderCommands, j);
Expand Down Expand Up @@ -125,7 +131,12 @@ void Clay_Raylib_Render(Clay_RenderCommandArray renderCommands, Font* fonts)
break;
}
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_START: {
BeginScissorMode((int)roundf(boundingBox.x), (int)roundf(boundingBox.y), (int)roundf(boundingBox.width), (int)roundf(boundingBox.height));
Clay_BoundingBox box = renderCommand->boundingBox;
int left = (int)floorf(box.x * ui_scale);
int top = (int)floorf(box.y * ui_scale);
int right = (int)ceilf((box.x + box.width) * ui_scale);
int bottom = (int)ceilf((box.y + box.height) * ui_scale);
BeginScissorMode(left, top, right - left, bottom - top);
break;
}
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_END: {
Expand Down Expand Up @@ -367,4 +378,7 @@ void Clay_Raylib_Render(Clay_RenderCommandArray renderCommands, Font* fonts)
}
}
}

rlDrawRenderBatchActive();
rlSetMatrixModelview(outer_modelview);
}
2 changes: 1 addition & 1 deletion misrc_tools/misrc_gui/ui/gui_dropdown.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ static bool handle_right_view_dropdown(gui_app_t *app, int ch) {

bool gui_dropdown_handle_click(gui_app_t *app) {
bool dropdown_clicked = false;
Vector2 mouse = GetMousePosition();
Vector2 mouse = gui_ui_get_mouse_position();

// Device dropdown (global)
if (handle_device_dropdown(app)) {
Expand Down
Loading
Loading