1
0

show QWERTY controls in settings

This commit is contained in:
Rokas Puzonas 2024-01-21 19:09:03 +02:00
parent 3e5c51d838
commit 6a9be7f811
5 changed files with 193 additions and 48 deletions

38
src/horizontal-layout.zig Normal file
View File

@ -0,0 +1,38 @@
const Self = @This();
const rl = @import("raylib");
bounds: rl.Rectangle,
gap: f32,
used_width: f32,
pub fn init(gap: f32, bounds: rl.Rectangle) Self {
return Self{
.bounds = bounds,
.gap = gap,
.used_width = 0
};
}
pub fn column_sized(self: *Self, width: f32, height: f32) rl.Rectangle {
const rect = rl.Rectangle{
.x = self.bounds.x + self.used_width,
.y = self.bounds.y,
.width = width,
.height = height,
};
self.used_width += width + self.gap;
return rect;
}
pub fn column(self: *Self, width: f32) rl.Rectangle {
return self.column_sized(width, self.bounds.height);
}
pub fn column_full(self: *Self) rl.Rectangle {
const left_width = self.bounds.width - self.used_width;
return self.column_sized(left_width, self.bounds.height);
}
pub fn add_gap(self: *Self, gap: f32) void {
self.used_width += gap;
}

View File

@ -5,6 +5,7 @@ const std = @import("std");
const roms = @import("./roms.zig");
const GUILayout = @import("./gui-layout.zig");
const VerticalLayout = @import("./vertical-layout.zig");
const HorizontalLayout = @import("./horizontal-layout.zig");
const ROM = roms.ROM;
const ChipContext = @import("chip.zig");
@ -71,7 +72,8 @@ pub fn init(allocator: Allocator) !Self {
.chip_sound = chip_sound,
};
self.set_rom(3);
const breakout = comptime roms.findIndexbyName(&rom_list, "br8kout") orelse unreachable;
self.set_rom(@intCast(breakout));
return self;
}
@ -100,6 +102,7 @@ pub fn update(self: *Self, dt: f32) void {
rl.ResumeSound(self.chip_sound);
self.raylib_chip.update(dt);
} else {
self.raylib_chip.update_input();
rl.PauseSound(self.chip_sound);
}
}
@ -184,7 +187,7 @@ fn GuiListViewMinWidth(allocator: Allocator, height: i32, items: []const []const
}
pub fn getWindowBodyBounds(bounds: rl.Rectangle) rl.Rectangle {
const status_bar_height = 24; // defined as RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT in raygui.h
const status_bar_height = gui.RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT;
const margin = 8;
return rl.Rectangle {
@ -203,6 +206,55 @@ pub fn pushGuiWindowBox(layout: *GUILayout, bounds: rl.Rectangle, title: [*:0]co
return gui.GuiWindowBox(bounds, title) != 0;
}
fn GetColor(hex_value: i32) rl.Color {
const hex_value_unsigned: u32 = @bitCast(hex_value);
return rl.Color{
.r = @truncate(hex_value_unsigned >> 24),
.g = @truncate(hex_value_unsigned >> 16),
.b = @truncate(hex_value_unsigned >> 8),
.a = @truncate(hex_value_unsigned)
};
}
fn drawKeyboard(bounds: rl.Rectangle, keyboard_labels: [16]u8, keyboard_state: [16]bool) void {
const font_size = gui.GuiGetStyle(.DEFAULT , @intFromEnum(gui.GuiDefaultProperty.TEXT_SIZE))*2;
const text_color_normal = GetColor(gui.GuiGetStyle(.LABEL, @intFromEnum(gui.GuiControlProperty.TEXT_COLOR_NORMAL)));
const text_color_pressed = GetColor(gui.GuiGetStyle(.LABEL, @intFromEnum(gui.GuiControlProperty.TEXT_COLOR_PRESSED)));
const border_color_normal = GetColor(gui.GuiGetStyle(.LABEL, @intFromEnum(gui.GuiControlProperty.BORDER_COLOR_NORMAL)));
const border_color_pressed = GetColor(gui.GuiGetStyle(.LABEL, @intFromEnum(gui.GuiControlProperty.BORDER_COLOR_PRESSED)));
const cell_margin = 2;
const cell_size = font_size+2*cell_margin;
rl.rlPushMatrix();
rl.rlTranslatef(bounds.x, bounds.y, 0);
const key_indexes = [16]usize {
0x1, 0x2, 0x3, 0xC,
0x4, 0x5, 0x6, 0xD,
0x7, 0x8, 0x9, 0xE,
0xA, 0x0, 0xB, 0xF,
};
for (0.., key_indexes) |i, key_index| {
const cell_y: i32 = @intCast(@divTrunc(i, 4));
const cell_x: i32 = @intCast(i % 4);
const label = [_:0]u8{ keyboard_labels[key_index], 0 };
const label_width = rl.MeasureText(&label, font_size);
var color = text_color_normal;
var border_color = border_color_normal;
if (keyboard_state[key_index]) {
color = text_color_pressed;
color = border_color_pressed;
}
const x = cell_x*(cell_size-1);
const y = cell_y*(cell_size-1);
rl.DrawRectangleLines(x, y, cell_size, cell_size, border_color);
rl.DrawText(&label, x + @divTrunc(cell_size - label_width, 2), y+cell_margin, font_size, color);
}
rl.rlPopMatrix();
}
pub fn drawGui(self: *Self, allocator: Allocator) !void {
if (rl.IsKeyPressed(.KEY_TAB)) {
self.is_gui_open = !self.is_gui_open;
@ -231,38 +283,75 @@ pub fn drawGui(self: *Self, allocator: Allocator) !void {
.width = window_width,
.height = window_height
};
if (pushGuiWindowBox(&window_layout, window, "CHIP-8 Settings")) {
if (pushGuiWindowBox(&window_layout, window, "Settings")) {
self.is_gui_open = false;
}
var vertical_layout = VerticalLayout.init(4, getWindowBodyBounds(window));
const rom_list_names = try allocator.alloc([]const u8, rom_list.len);
defer allocator.free(rom_list_names);
if (gui.GuiButton(vertical_layout.row_sized(100, 24), "Reset") == 1) {
self.reset_rom();
for (0.., rom_list) |i, rom| {
rom_list_names[i] = rom.name;
}
_ = gui.GuiLabel(vertical_layout.row(16), "Current ROM:");
{ // ROM list view
const rom_list_names = try allocator.alloc([]const u8, rom_list.len);
defer allocator.free(rom_list_names);
const rom_list_height = 100;
const rom_list_width = try GuiListViewMinWidth(allocator, rom_list_height, rom_list_names) + 20;
for (0.., rom_list) |i, rom| {
rom_list_names[i] = rom.name;
var columns = HorizontalLayout.init(32, getWindowBodyBounds(window));
{ // First column
var column1 = VerticalLayout.init(4, columns.column(@floatFromInt(rom_list_width)));
if (gui.GuiButton(column1.row_sized(100, 24), "Reset") == 1) {
self.reset_rom();
}
const list_height = 100;
const list_width = try GuiListViewMinWidth(allocator, list_height, rom_list_names) + 20;
var selected_rom = self.selected_rom_index;
_ = try GuiListView(
allocator,
vertical_layout.row_sized(@floatFromInt(list_width), list_height),
rom_list_names,
&self.rom_list_scroll_index,
&selected_rom
);
_ = gui.GuiLabel(column1.row(16), "Current ROM:");
{ // ROM list view
var selected_rom = self.selected_rom_index;
_ = try GuiListView(
allocator,
column1.row_sized(@floatFromInt(rom_list_width), rom_list_height),
rom_list_names,
&self.rom_list_scroll_index,
&selected_rom
);
if (selected_rom != self.selected_rom_index) {
self.set_rom(selected_rom);
if (selected_rom != self.selected_rom_index) {
self.set_rom(selected_rom);
}
}
}
{ // Controls column
var column2 = VerticalLayout.init(0, columns.column(200));
_ = gui.GuiLabel(column2.row(16), "Controls:");
_ = gui.GuiLabel(column2.row(16), "TAB - Toggle settings (this window)");
column2.add_gap(8);
var keyboard_columns = HorizontalLayout.init(0, column2.row_full());
const keyboard_width = 128;
{
var keyboard_column1 = VerticalLayout.init(0, keyboard_columns.column(keyboard_width));
_ = gui.GuiLabel(keyboard_column1.row(16), "Input state (QWERTY):");
var keyboard_labels: [16]u8 = undefined;
for (0.., RaylibChip.default_controls) |i, key| {
keyboard_labels[i] = @intCast(@intFromEnum(key));
}
drawKeyboard(keyboard_column1.row_full(), keyboard_labels, self.chip.input);
}
{
var keyboard_column2 = VerticalLayout.init(0, keyboard_columns.column(keyboard_width));
_ = gui.GuiLabel(keyboard_column2.row(16), "Input state:");
var reference_labels = [16]u8{
'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'A', 'B',
'C', 'D', 'E', 'F',
};
drawKeyboard(keyboard_column2.row_full(), reference_labels, self.chip.input);
}
}

View File

@ -3,6 +3,25 @@ const rl = @import("raylib");
const ChipContext = @import("chip.zig");
const print = @import("std").debug.print;
pub const default_controls = [16]rl.KeyboardKey{
.KEY_X,
.KEY_ONE,
.KEY_TWO,
.KEY_THREE,
.KEY_Q,
.KEY_W,
.KEY_E,
.KEY_A,
.KEY_S,
.KEY_D,
.KEY_Z,
.KEY_C,
.KEY_FOUR,
.KEY_R,
.KEY_F,
.KEY_V,
};
chip: *ChipContext,
on_color: rl.Color,
off_color: rl.Color,
@ -27,26 +46,7 @@ pub fn init(chip: *ChipContext, beep_sound: ?rl.Sound) Self {
}
pub fn update_input(self: *Self) void {
const keys = [16]rl.KeyboardKey{
.KEY_X,
.KEY_ONE,
.KEY_TWO,
.KEY_THREE,
.KEY_Q,
.KEY_W,
.KEY_E,
.KEY_A,
.KEY_S,
.KEY_D,
.KEY_Z,
.KEY_C,
.KEY_FOUR,
.KEY_R,
.KEY_F,
.KEY_V,
};
for (0.., keys) |i, key| {
for (0.., default_controls) |i, key| {
self.chip.input[i] = rl.IsKeyDown(key);
}
}

View File

@ -23,3 +23,12 @@ pub fn listROMs() [options.roms.len]ROM {
return roms;
}
pub fn findIndexbyName(roms: []const ROM, name: []const u8) ?usize {
for (0.., roms) |i, rom| {
if (std.mem.eql(u8, rom.name, name)) {
return i;
}
}
return null;
}

View File

@ -3,27 +3,36 @@ const rl = @import("raylib");
bounds: rl.Rectangle,
gap: f32,
used: f32,
used_height: f32,
pub fn init(gap: f32, bounds: rl.Rectangle) Self {
return Self{
.bounds = bounds,
.gap = gap,
.used = 0
.used_height = 0
};
}
pub fn row_sized(self: *Self, width: f32, height: f32) rl.Rectangle {
const rect = rl.Rectangle{
.x = self.bounds.x,
.y = self.bounds.y + self.used,
.y = self.bounds.y + self.used_height,
.width = width,
.height = height,
};
self.used += height + self.gap;
self.used_height += height + self.gap;
return rect;
}
pub fn row(self: *Self, height: f32) rl.Rectangle {
return self.row_sized(self.bounds.width, height);
}
pub fn row_full(self: *Self) rl.Rectangle {
const left_height = self.bounds.height - self.used_height;
return self.row_sized(self.bounds.width, left_height);
}
pub fn add_gap(self: *Self, gap: f32) void {
self.used_height += gap;
}