From 2c664b24a99bf0b9628491d9090479fd0e0089d8 Mon Sep 17 00:00:00 2001 From: Jason Hilder Date: Sat, 13 Jun 2026 09:31:32 +0200 Subject: [PATCH] Cleaning up ui components making uniform. --- src/simulator/control_bar.odin | 24 +++--- src/simulator/gui.odin | 129 +++++++++++++++++++-------------- src/simulator/screen.odin | 58 +++++++++------ src/simulator/status_bar.odin | 20 ++++- 4 files changed, 138 insertions(+), 93 deletions(-) diff --git a/src/simulator/control_bar.odin b/src/simulator/control_bar.odin index 08665d0..9073254 100644 --- a/src/simulator/control_bar.odin +++ b/src/simulator/control_bar.odin @@ -7,27 +7,23 @@ PADDING :: 10 gui_control_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) { rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY) - // Small text area - // Control bar buttons - btn_w : f32 = 80 - btn_h : f32 = rect.height - (PADDING * 2) - gap : f32 = 6 - cursor : f32 = rect.x + PADDING + // Cursor moves for every btn call places them left to right with padding + cursor : f32 = rect.x + PANEL_PADDING - if btn(&cursor, rect, btn_h, btn_w, gap, "RUN") { - log.info("RUN clicked") - sim.paused = false - sim.running = true + if btn(&cursor, rect, BUTTON_HEIGHT, BUTTON_WIDTH, PANEL_PADDING, "RUN") { + if sim.rom_loaded { + sim.paused = false + sim.running = true + } else { + log.info("no rom selected, can't run") + } } - if btn(&cursor, rect, btn_h, btn_w, gap, "PAUSE") { - log.info("PAUSE clicked") + if btn(&cursor, rect, BUTTON_HEIGHT, BUTTON_WIDTH, PANEL_PADDING, "PAUSE") { sim.paused = true sim.running = false } - - if btn(&cursor, rect, btn_h, btn_w, gap, "STEP") { log.info("STEP clicked") } } btn :: proc(cursor: ^f32, rect: rl.Rectangle, h, w, gap: f32, label: cstring) -> bool { diff --git a/src/simulator/gui.odin b/src/simulator/gui.odin index 4bcff9b..bef2158 100644 --- a/src/simulator/gui.odin +++ b/src/simulator/gui.odin @@ -8,26 +8,25 @@ WINDOW_WIDTH :: 1920 WINDOW_HEIGHT :: 1080 // @TODO: If this grows lets move it into its own file +// ─── Layout constants ─────────────────────────────────────────────────── SIDEBAR_PERCENT :: 0.20 DISPLAY_PERCENT :: 0.30 CONTROL_BAR_H :: f32(50) STATUS_BAR_H :: f32(30) - -// ─── Layout constants ─────────────────────────────────────────────────── -PANEL_PADDING :: 10 -PANEL_HEADER :: 24 -BUTTON_HEIGHT :: 30 -BUTTON_WIDTH :: 120 -DROP_FONT_SIZE :: 20 -KEYPAD_FONT_SIZE :: 18 - +PANEL_PADDING :: 10 +PANEL_HEADER :: 24 +BUTTON_HEIGHT :: 30 +BUTTON_WIDTH :: 120 +BIG_FONT_SIZE :: 20 +KEYPAD_FONT_SIZE :: 18 Layout :: struct { - control_bar : rl.Rectangle, - left_panel : rl.Rectangle, - display : rl.Rectangle, - right_panel : rl.Rectangle, - status_bar : rl.Rectangle, + control_bar : rl.Rectangle, + left_panel : rl.Rectangle, + display : rl.Rectangle, + bottom_panel : rl.Rectangle, + right_panel : rl.Rectangle, + status_bar : rl.Rectangle, } // Initialize main the gui 'window' @@ -63,8 +62,8 @@ run_gui :: proc(sim: ^Simulator) { rl.BeginDrawing() rl.ClearBackground(rl.BLACK) - // Cycle the machine to update memory etc if (!sim.paused) { + // Cycle the machine to update memory etc emu.run_machine(sim.machine, 12) // Handle delay timer @@ -78,16 +77,11 @@ run_gui :: proc(sim: ^Simulator) { } else { rl.StopSound(beep) } - } gui_control_bar(layout.control_bar, sim) gui_left_panel(layout.left_panel, sim) - // gui_right_panel(layout.right_panel, s.machine) - - // Screen is just drawing the display buffer just needs that as arg - // Not the whole sim struct - gui_screen(layout.display, sim.machine) + gui_screen(layout.display, sim) gui_status_bar(layout.status_bar, sim) rl.EndDrawing() @@ -101,39 +95,64 @@ run_gui :: proc(sim: ^Simulator) { // @TODO: If this grows lets move it into its own file calc_layout :: proc(screen_width: f32, screen_height: f32) -> Layout { - sidebar_width := screen_width * SIDEBAR_PERCENT - content_height := screen_height - CONTROL_BAR_H - STATUS_BAR_H - display_height := screen_height * DISPLAY_PERCENT - CONTROL_BAR_H - STATUS_BAR_H + top_h := CONTROL_BAR_H + bottom_h := STATUS_BAR_H + content_h := screen_height - top_h - bottom_h + content_y := top_h - return Layout { - control_bar = rl.Rectangle { - x = 0, - y = 0, - width = screen_width, - height = CONTROL_BAR_H, - }, - left_panel = rl.Rectangle { - x = 0, - y = CONTROL_BAR_H, - width = sidebar_width, - height = content_height, - }, - display = rl.Rectangle { - x = sidebar_width, - y = CONTROL_BAR_H, - width = screen_width - (sidebar_width * 2), - height = display_height, - }, - right_panel = rl.Rectangle { - x = screen_width - sidebar_width, - y = CONTROL_BAR_H, - width = sidebar_width, - height = content_height, - }, - status_bar = rl.Rectangle { - x = 0, - y = screen_height - STATUS_BAR_H, - width = screen_width, height = STATUS_BAR_H, - }, - } + sidebar_w := screen_width * SIDEBAR_PERCENT + + screen_h_ratio := 0.40 + bottom_panel_h := content_h * f32(1.0 - screen_h_ratio) + screen_h := content_h * f32(screen_h_ratio) + memory_h := content_h - screen_h + + center_x := sidebar_w + center_w := screen_width - sidebar_w * 2 + + return Layout { + control_bar = rl.Rectangle{ + x = 0, + y = 0, + width = screen_width, + height = top_h, + }, + + left_panel = rl.Rectangle{ + x = 0, + y = top_h, + width = sidebar_w, + height = content_h, + }, + + // CHIP-8 screen (top center) + display = rl.Rectangle{ + x = center_x, + y = top_h, + width = center_w, + height = screen_h, + }, + + // MEMORY / DEBUG panel (bottom center) + bottom_panel = rl.Rectangle{ + x = center_x, + y = top_h + screen_h, + width = center_w, + height = memory_h, + }, + + right_panel = rl.Rectangle{ + x = screen_width - sidebar_w, + y = top_h, + width = sidebar_w, + height = content_h, + }, + + status_bar = rl.Rectangle{ + x = 0, + y = screen_height - bottom_h, + width = screen_width, + height = bottom_h, + }, + } } diff --git a/src/simulator/screen.odin b/src/simulator/screen.odin index 4ad3ce4..5d517e2 100644 --- a/src/simulator/screen.odin +++ b/src/simulator/screen.odin @@ -1,38 +1,52 @@ package simulator -import m "../machine" import rl "vendor:raylib" -gui_screen :: proc(rect: rl.Rectangle, s: ^m.System) { - // Make sure screen is staying in its aspect ratio - chip8_aspect := f32(64.0 / 32.0) - available_aspect := rect.width / rect.height - screen_rect := rect +gui_screen :: proc(rect: rl.Rectangle, sim: ^Simulator) { + s := sim.machine - if available_aspect > chip8_aspect { - // Area is too wide - screen_rect.width = rect.height * chip8_aspect - screen_rect.x = rect.x + (rect.width - screen_rect.width) / 2 + // 2 : 1 + // 2 so, for every 1 unit of height I have 2 units of width + // twice as wide as it is tall, or half as tall as it is wide + aspect_ratio : f32 = 64.0 / 32.0 + + // create viewport for the ratio + view := rect + avail_space := rect.width / rect.height + + if avail_space > aspect_ratio { + view.width = rect.height * aspect_ratio + view.x = rect.x + (rect.width - view.width) * 0.5 } else { - // Area is too tall - screen_rect.height = rect.width / chip8_aspect - screen_rect.y = rect.y + (rect.height - screen_rect.height) / 2 + view.height = rect.width / aspect_ratio + view.y = rect.y + (rect.height - view.height) * 0.5 } - pixel_size := min(int(screen_rect.width / 64), int(screen_rect.height / 32)) - pixel_size = max(pixel_size, 1) + // get scale + pixel := min(int(view.width / 64), int(view.height / 32)) + pixel = max(pixel, 1) - actual_width := pixel_size * 64 - actual_height := pixel_size * 32 + draw_w := pixel * 64 + draw_h := pixel * 32 - display_x := i32(screen_rect.x) + i32(int(screen_rect.width) - actual_width) / 2 - display_y := i32(screen_rect.y) + i32(int(screen_rect.height) - actual_height) / 2 + // center frame + x := i32(view.x + (view.width - f32(draw_w)) * 0.5) + y := i32(view.y + (view.height - f32(draw_h)) * 0.5) - // Debug borders rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY) - rl.DrawRectangleLinesEx(screen_rect, 2, rl.WHITE) + rl.DrawRectangleLinesEx(view, 2, rl.WHITE) - render_display(&s.display, display_x, display_y, i32(pixel_size)) + if !sim.rom_loaded { + // centered drop-zone text + text: cstring = "PLEASE SELECT AND LOAD A CHIP 8 ROM" + text_width := rl.MeasureText(text, BIG_FONT_SIZE) + text_x := view.x + (view.width - f32(text_width)) * 0.6 + text_y := view.y + (view.height - f32(BIG_FONT_SIZE)) * 0.5 + + rl.DrawTextEx(sim.font, text, {text_x,text_y}, BIG_FONT_SIZE, 1, rl.WHITE) + } else { + render_display(&s.display, x, y, i32(pixel)) + } } @(private = "file") diff --git a/src/simulator/status_bar.odin b/src/simulator/status_bar.odin index f441ff5..e7d18c6 100644 --- a/src/simulator/status_bar.odin +++ b/src/simulator/status_bar.odin @@ -3,7 +3,9 @@ package simulator import "core:fmt" import rl "vendor:raylib" +// @TODO: render status bar text gui_status_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) { + // Left to right text draws rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY) cursor: f32 = rect.x + PADDING @@ -16,7 +18,21 @@ gui_status_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) { } status_divider(&cursor, cy) - status_text(&cursor, cy, fmt.ctprintf("FPS: %d", rl.GetFPS()), sim.font) + status_text(&cursor, cy, fmt.ctprintf("Rom Loaded: %v", sim.rom_loaded), sim.font) + + // FPS set far right + fps_text := fmt.ctprintf("FPS: %d", rl.GetFPS()) + fps_width := rl.MeasureTextEx(sim.font, fps_text, f32(sim.font.baseSize), 1).x + fps_x := rect.x + rect.width - PADDING - fps_width + + rl.DrawTextEx( + sim.font, + fps_text, + {fps_x, cy - f32(sim.font.baseSize) * 0.5}, + f32(sim.font.baseSize), + 1, + rl.RAYWHITE, + ) } StatusIconShape :: enum { CIRCLE, SQUARE } @@ -43,4 +59,4 @@ status_divider :: proc(cursor: ^f32, cy: f32) { status_text :: proc(cursor: ^f32, cy: f32, text: cstring, font: rl.Font) { rl.DrawTextEx(font, text, {cursor^, cy - f32(font.baseSize) * 0.5}, f32(font.baseSize), 1, rl.RAYWHITE) cursor^ += rl.MeasureTextEx(font, text, f32(font.baseSize), 1).x + PADDING -} \ No newline at end of file +}