mirror of https://git.sr.ht/~kikoodx/kble
Modes. Normal and insert modes implemented.
This commit is contained in:
parent
47a05d56f1
commit
20c4d8ca1a
12
README.md
12
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
|
||||
* `<space>`: reset selection
|
||||
|
||||
Actions:
|
||||
Verbs:
|
||||
* `<space>`: clear selection
|
||||
* `d`: delete selection
|
||||
* `r`: replace selection
|
||||
* `+`: increase scale (zoom)
|
||||
* `-`: decrease scale (dezoom)
|
||||
* `=`: reset scale
|
||||
|
||||
Modes:
|
||||
* `<return>`: 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.
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
44
src/main.zig
44
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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue