From 20c4d8ca1a7112463da33d47719d5baa0931e7b1 Mon Sep 17 00:00:00 2001 From: KikooDX Date: Tue, 2 Feb 2021 14:21:12 +0100 Subject: [PATCH] Modes. Normal and insert modes implemented. --- README.md | 12 ++++++--- src/actions.zig | 67 ++++++++++++++++++------------------------------- src/draw.zig | 25 ++++++++++++++++++ src/main.zig | 44 ++++++++++++++++++++++---------- src/modes.zig | 12 +++++++++ src/verbs.zig | 8 ++++++ 6 files changed, 110 insertions(+), 58 deletions(-) create mode 100644 src/draw.zig create mode 100644 src/modes.zig diff --git a/README.md b/README.md index 743aa56..aecd88f 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ $ zig build run Press escape to close the program. # Default keybindings -Movement, hold Shift to expand selection: +Movement: * `h`: left * `j`: down * `k`: up @@ -32,15 +32,21 @@ Movement, hold Shift to expand selection: * `u`: up-right * `b`: down-left * `n`: down-right -* ``: reset selection -Actions: +Verbs: +* ``: clear selection * `d`: delete selection * `r`: replace selection * `+`: increase scale (zoom) * `-`: decrease scale (dezoom) * `=`: reset scale +Modes: +* ``: normal mode, default +* `i`: free selection mode +* `v`: rectangle selection mode [not implemented] +* `c`: camera mode [not implemented] + # Mouse control Right click and left click are the same, except right click reset selection before taking effect. diff --git a/src/actions.zig b/src/actions.zig index 836d978..4b78f71 100644 --- a/src/actions.zig +++ b/src/actions.zig @@ -12,21 +12,23 @@ const scaling = @import("scaling.zig"); const verbs = @import("verbs.zig"); const Vec2 = @import("vec2.zig"); const Level = @import("level.zig"); +const Mode = @import("modes.zig").Mode; pub const ActionCat = enum { none, // do nothing movement, // move and change selection verb, // do stuff with selection scale, // change draw scaling + mode, // change mode }; pub const Action = struct { category: ActionCat, - toggle: bool = false, // bool that can be passed to actions, i.e. exclusive for movement // Only one of these should be set, and only one should be used. function_move: fn (*Vec2, conf.arg_type, bool) movement.SelectionUpdate = movement.move_left, function_verb: fn (*Level, conf.arg_type) void = verbs.delete, function_scale: fn (scaling.scale_type) scaling.scale_type = scaling.scale_reset, + next_mode: Mode = Mode.normal, }; pub const ActionsDef = .{ @@ -36,92 +38,55 @@ pub const ActionsDef = .{ // Movement. // Reset selection. .move_but_dont = Action{ - .toggle = true, .category = ActionCat.movement, .function_move = movement.move_but_dont, }, // Left. .move_left = Action{ - .toggle = true, - .category = ActionCat.movement, - .function_move = movement.move_left, - }, - .move_LEFT = Action{ .category = ActionCat.movement, .function_move = movement.move_left, }, // Right. .move_right = Action{ - .toggle = true, - .category = ActionCat.movement, - .function_move = movement.move_right, - }, - .move_RIGHT = Action{ .category = ActionCat.movement, .function_move = movement.move_right, }, // Up. .move_up = Action{ - .toggle = true, - .category = ActionCat.movement, - .function_move = movement.move_up, - }, - .move_UP = Action{ .category = ActionCat.movement, .function_move = movement.move_up, }, // Down. .move_down = Action{ - .toggle = true, - .category = ActionCat.movement, - .function_move = movement.move_down, - }, - .move_DOWN = Action{ .category = ActionCat.movement, .function_move = movement.move_down, }, // Up-left. .move_up_left = Action{ - .toggle = true, - .category = ActionCat.movement, - .function_move = movement.move_up_left, - }, - .move_UP_LEFT = Action{ .category = ActionCat.movement, .function_move = movement.move_up_left, }, // Up-right. .move_up_right = Action{ - .toggle = true, - .category = ActionCat.movement, - .function_move = movement.move_up_right, - }, - .move_UP_RIGHT = Action{ .category = ActionCat.movement, .function_move = movement.move_up_right, }, // Down-left. .move_down_left = Action{ - .toggle = true, - .category = ActionCat.movement, - .function_move = movement.move_down_left, - }, - .move_DOWN_LEFT = Action{ .category = ActionCat.movement, .function_move = movement.move_down_left, }, // Down-right. .move_down_right = Action{ - .toggle = true, - .category = ActionCat.movement, - .function_move = movement.move_down_right, - }, - .move_DOWN_RIGHT = Action{ .category = ActionCat.movement, .function_move = movement.move_down_right, }, // Verbs. + .verb_clear_selection = Action{ + .category = ActionCat.verb, + .function_verb = verbs.clear_selection, + }, .verb_delete = Action{ .category = ActionCat.verb, .function_verb = verbs.delete, @@ -144,4 +109,22 @@ pub const ActionsDef = .{ .category = ActionCat.scale, .function_scale = scaling.scale_down, }, + + // Mode change. + .mode_normal = Action{ + .category = ActionCat.mode, + .next_mode = Mode.normal, + }, + .mode_select = Action{ + .category = ActionCat.mode, + .next_mode = Mode.select, + }, + .mode_rectangle = Action{ + .category = ActionCat.mode, + .next_mode = Mode.rectangle, + }, + .mode_camera = Action{ + .category = ActionCat.mode, + .next_mode = Mode.camera, + }, }; diff --git a/src/draw.zig b/src/draw.zig new file mode 100644 index 0000000..c3b7b69 --- /dev/null +++ b/src/draw.zig @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 KikooDX +// This file is part of [KBLE](https://sr.ht/~kikoodx/kble), which is +// MIT licensed. The MIT license requires this copyright notice to be +// included in all copies and substantial portions of the software. +const ray = @cImport({ + @cInclude("raylib.h"); +}); + +const Vec2 = @import("vec2.zig"); +const scaling = @import("scaling.zig"); +const Mode = @import("modes.zig").Mode; + +/// Draw cursor. +pub fn cursor(scale: scaling.scale_type, offset: Vec2, pos: Vec2, mode: Mode) void { + const x = (pos.x - offset.y) * scale; + const y = (pos.y - offset.y) * scale; + const color: ray.Color = switch (mode) { + .normal => ray.GRAY, + .select => ray.BLUE, + .rectangle => ray.SKYBLUE, + .camera => ray.PURPLE, + }; + ray.DrawRectangleLines(x, y, scale, scale, color); +} diff --git a/src/main.zig b/src/main.zig index ced4376..c8382a1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -15,15 +15,17 @@ const Level = @import("level.zig"); const Vec2 = @import("vec2.zig"); const Rect = @import("rect.zig"); const Mouse = @import("mouse.zig"); +const draw = @import("draw.zig"); const movement = @import("movement.zig"); const scaling = @import("scaling.zig"); const actions = @import("actions.zig"); const ActionsDef = actions.ActionsDef; const ActionCat = actions.ActionCat; +const Mode = @import("modes.zig").Mode; const char_range = 255; -pub fn main() !void { +pub fn main() void { // Create allocator var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); @@ -38,10 +40,11 @@ pub fn main() !void { ray.SetTargetFPS(60); // Create level. - var level: Level = try Level.init(allocator, 16, 16); + var level: Level = Level.init(allocator, 16, 16) catch unreachable; defer level.deinit(allocator); // Create camera. + // TODO: Can't move camera, implement camera mode. var camera: Vec2 = Vec2.init(0, 0); // Init scale, used by drawing code. @@ -53,34 +56,34 @@ pub fn main() !void { // Create cursor. var cursor: Vec2 = Vec2.init(0, 0); + // Set default mode. + var mode: Mode = Mode.normal; + // Create binding "table". var bindings = [_]*const actions.Action{&actions.ActionsDef.none} ** char_range; // Set default bindings. // Movement. - bindings[' '] = &ActionsDef.move_but_dont; bindings['h'] = &ActionsDef.move_left; - bindings['H'] = &ActionsDef.move_LEFT; bindings['j'] = &ActionsDef.move_down; - bindings['J'] = &ActionsDef.move_DOWN; bindings['k'] = &ActionsDef.move_up; - bindings['K'] = &ActionsDef.move_UP; bindings['l'] = &ActionsDef.move_right; - bindings['L'] = &ActionsDef.move_RIGHT; bindings['y'] = &ActionsDef.move_up_left; - bindings['Y'] = &ActionsDef.move_UP_LEFT; bindings['u'] = &ActionsDef.move_up_right; - bindings['U'] = &ActionsDef.move_UP_RIGHT; bindings['b'] = &ActionsDef.move_down_left; - bindings['B'] = &ActionsDef.move_DOWN_LEFT; bindings['n'] = &ActionsDef.move_down_right; - bindings['N'] = &ActionsDef.move_DOWN_RIGHT; // Verbs. + bindings[' '] = &ActionsDef.verb_clear_selection; bindings['d'] = &ActionsDef.verb_delete; bindings['r'] = &ActionsDef.verb_replace; // Scale. bindings['='] = &ActionsDef.scale_reset; bindings['+'] = &ActionsDef.scale_up; bindings['-'] = &ActionsDef.scale_down; + // Mode. + bindings['\n'] = &ActionsDef.mode_normal; + bindings['i'] = &ActionsDef.mode_select; + bindings['v'] = &ActionsDef.mode_rectangle; + bindings['c'] = &ActionsDef.mode_camera; // Create input buffer. const input_buffer_len = 255; @@ -95,6 +98,7 @@ pub fn main() !void { while (!ray.WindowShouldClose()) { { + // TODO: apply DRY // Get keyboard input. var key = ray.GetCharPressed(); // Check if more characters have been pressed. @@ -108,6 +112,14 @@ pub fn main() !void { key = ray.GetCharPressed(); } + // Check for special keys, not detected by GetCharPressed. + if (ray.IsKeyDown(ray.KEY_ENTER)) { + input_buffer[input_cursor] = '\n'; + input_cursor += 1; + // Avoid writing out of memory. + if (input_cursor >= input_buffer_len) + input_cursor = input_buffer_len - 1; + } } // Process buffer content. @@ -120,13 +132,15 @@ pub fn main() !void { 0; const action: actions.Action = bindings[key].*; + const exclusive_movement: bool = false; + const apply_selection: bool = (mode == Mode.select); switch (action.category) { .none => std.log.info("No action bound to {}.", .{key}), .movement => { const selection_update: movement.SelectionUpdate = - action.function_move(&cursor, 1, action.toggle); - if (selection_update.active) { + action.function_move(&cursor, 1, exclusive_movement); + if (apply_selection and selection_update.active) { level.apply_selection_update(selection_update); } }, @@ -136,6 +150,9 @@ pub fn main() !void { .scale => { scale = action.function_scale(scale); }, + .mode => { + mode = action.next_mode; + }, } } @@ -201,6 +218,7 @@ pub fn main() !void { ray.ClearBackground(ray.BLACK); level.draw(scale, camera); level.draw_selection(scale, camera); + draw.cursor(scale, camera, cursor, mode); mouse.draw(scale, camera); //ray.DrawFPS(0, 0); } diff --git a/src/modes.zig b/src/modes.zig new file mode 100644 index 0000000..56394f0 --- /dev/null +++ b/src/modes.zig @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2021 KikooDX +// This file is part of [KBLE](https://sr.ht/~kikoodx/kble), which is +// MIT licensed. The MIT license requires this copyright notice to be +// included in all copies and substantial portions of the software. +/// Different cursor modes (for keyboard). +pub const Mode = enum { + normal, // move cursor and do stuff + select, // same, but select while doing so + rectangle, // same, but select as a rectangle + camera, // move camera instead +}; diff --git a/src/verbs.zig b/src/verbs.zig index 3672b6d..d631a93 100644 --- a/src/verbs.zig +++ b/src/verbs.zig @@ -7,6 +7,14 @@ const conf = @import("conf.zig"); const Level = @import("level.zig"); +/// Clear selection (deselect everything). +pub fn clear_selection(level: *Level, arg: conf.arg_type) void { + var i: u32 = 0; + while (i < level.width * level.height) : (i += 1) { + level.selection[i] = false; + } +} + /// Delete selected cells (set to 0). pub fn delete(level: *Level, arg: conf.arg_type) void { var i: u32 = 0;