package simulator import "core:log" import "core:strings" import rl "vendor:raylib" import emu "../machine" import tfd "../../external/tinyfiledialogs" gui_left_panel :: proc(rect: rl.Rectangle, sim: ^Simulator) { // ── Top panel and components ── top_panel := rl.Rectangle { rect.x, rect.y, rect.width, rect.height / 2, } rl.DrawRectangleLinesEx(top_panel, 1, rl.DARKGRAY) // Dropzone/file loader file_loader_rect := rl.Rectangle { top_panel.x, top_panel.y, top_panel.width, (top_panel.height / 3) - PANEL_HEADER - PANEL_PADDING * 2, } gui_file_loader(file_loader_rect, sim) // ── Bottom panel and components ── bottom_panel := rl.Rectangle { rect.x, rect.y + top_panel.height, rect.width, rect.height / 2, } rl.DrawRectangleLinesEx(bottom_panel, 1, rl.GREEN) gui_key_pad(bottom_panel, sim.machine.keypad, sim.font) } gui_file_loader :: proc(rect: rl.Rectangle, sim: ^Simulator) { rl.GuiPanel(rect, "Rom / File") // drop-zone occupies the panel's content area, minus space for the button drop_zone := rl.Rectangle { rect.x + PANEL_PADDING, rect.y + PANEL_HEADER + PANEL_PADDING, rect.width - PANEL_PADDING * 2, rect.height - PANEL_HEADER - PANEL_PADDING * 2 - BUTTON_HEIGHT - PANEL_PADDING, } rl.DrawRectangleLinesEx(drop_zone, 1, rl.GREEN) // centered drop-zone text text: cstring = "Drop a CHIP-8 ROM here" text_width := rl.MeasureText(text, BIG_FONT_SIZE) text_x := drop_zone.x + (drop_zone.width - f32(text_width)) / 2 text_y := drop_zone.y + (drop_zone.height - f32(BIG_FONT_SIZE)) / 2 rl.DrawTextEx(sim.font, text, {text_x, text_y}, BIG_FONT_SIZE, 1, rl.WHITE) // open rom button below drop-zone btn_rect := rl.Rectangle { drop_zone.x, drop_zone.y + drop_zone.height + PANEL_PADDING, BUTTON_WIDTH, BUTTON_HEIGHT, } if rl.GuiButton(btn_rect, "Open ROM") { ret := tfd.openFileDialog("Open File Dialog", nil, 0, nil, nil, 0,) rom_path := string(ret) if rom_path == "" do return // reset machine state emu.reset_machine(sim.machine) // load new rom err := emu.load_rom(sim.machine, rom_path) if err != nil { // @TODO: update status bar here panic("failed to load rom!") } sim.rom_loaded = true sim.running = true sim.paused = false } // Handle file drop if rl.IsFileDropped() { dropped_file := rl.LoadDroppedFiles() if dropped_file.count > 0 { mouse := rl.GetMousePosition() if rl.CheckCollisionPointRec(mouse, drop_zone) { path_str := string(dropped_file.paths[0]) log.info("file dropped: ", path_str) // @TODO: Stop sim, reset mem etc, load new rom } else { log.info("File dropped outside drop zone, ignoring") } } rl.UnloadDroppedFiles(dropped_file) } } gui_key_pad :: proc(rect: rl.Rectangle, display: [16]bool, font: rl.Font) { rl.GuiPanel(rect, "Input / Keypad") content := rl.Rectangle { rect.x + PANEL_PADDING, rect.y + PANEL_HEADER + PANEL_PADDING, rect.width - PANEL_PADDING * 2, rect.height - PANEL_HEADER - PANEL_PADDING * 2, } Key :: struct { label: string, index: int, } keys := [16]Key { {"1", 1}, {"2", 2}, {"3", 3}, {"C", 12}, {"4", 4}, {"5", 5}, {"6", 6}, {"D", 13}, {"7", 7}, {"8", 8}, {"9", 9}, {"E", 14}, {"A", 10}, {"0", 0}, {"B", 11}, {"F", 15}, } btn_width := content.width / 4 btn_height := content.height / 4 for val, idx in keys { str := strings.clone_to_cstring(val.label) defer delete(str) ri := idx / 4 ci := idx % 4 irect := rl.Rectangle { x = content.x + btn_width * f32(ci), y = content.y + btn_height * f32(ri), width = btn_width, height = btn_height, } if display[val.index] { rl.DrawRectangleRec(irect, rl.BLACK) } rl.DrawRectangleLinesEx(irect, 1, rl.GRAY) rl.DrawTextEx( font, str, rl.Vector2{irect.x + btn_width / 2, irect.y + btn_height / 2}, KEYPAD_FONT_SIZE, 1, rl.WHITE, ) } }