mirror of https://git.sr.ht/~kikoodx/kble
Compare commits
3 Commits
8cc9aeb129
...
25335e94a6
Author | SHA1 | Date |
---|---|---|
KikooDX | 25335e94a6 | |
KikooDX | 75351eb8b5 | |
KikooDX | a0528de619 |
15
README.md
15
README.md
|
@ -9,7 +9,7 @@ Subject to change.
|
|||
* Fully keyboard driven modal editing. Mouse support is secondary.
|
||||
* GUI software made in [Zig](https://ziglang.org/) with
|
||||
[raylib](https://www.raylib.com/).
|
||||
* Configurable (format unknown).
|
||||
* Configurable (editing `src/conf.zig`).
|
||||
|
||||
# Installation
|
||||
Runtime requirements: [raylib](https://www.raylib.com).
|
||||
|
@ -40,7 +40,18 @@ $ kble sample.kble
|
|||
$ kble $HOME/projects/kble/sample.kble
|
||||
```
|
||||
|
||||
# Configuration.
|
||||
In `src/conf.zig`, edit values from `BEGIN USER CONFIG`.
|
||||
The configuration is applied at compile time. You have the possibility to:
|
||||
* Disable mouse support.
|
||||
* Swap mouse buttons.
|
||||
* Change and add colors.
|
||||
* Edit keybindings.
|
||||
|
||||
# Default keybindings
|
||||
Repetition/parameter:
|
||||
* `0` → `9`: behavior similar to Vi.
|
||||
|
||||
Movement:
|
||||
* `h`: left
|
||||
* `j`: down
|
||||
|
@ -54,7 +65,7 @@ Movement:
|
|||
Verbs:
|
||||
* `<space>`: clear selection
|
||||
* `d`: delete selection
|
||||
* `r`: replace selection
|
||||
* `r`: replace selection with parameter
|
||||
* `+`: increase scale (zoom)
|
||||
* `-`: decrease scale (dezoom)
|
||||
* `=`: reset scale
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
#!/usr/bin/lua
|
||||
local out = io.open("sample.kble", "wb")
|
||||
out:write(string.char(
|
||||
2,
|
||||
0, 2,
|
||||
0, 2,
|
||||
0, 1,
|
||||
0, 0,
|
||||
0, 0,
|
||||
1, 1))
|
||||
out:close()
|
|
@ -6,7 +6,7 @@
|
|||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
|
||||
const conf = @import("conf.zig");
|
||||
const Parameter = @import("parameter.zig");
|
||||
const movement = @import("movement.zig");
|
||||
const scaling = @import("scaling.zig");
|
||||
const verbs = @import("verbs.zig");
|
||||
|
@ -16,6 +16,7 @@ const Mode = @import("modes.zig").Mode;
|
|||
|
||||
pub const ActionCat = enum {
|
||||
none, // do nothing
|
||||
parameter, // add key to Parameter buffer
|
||||
movement, // move and change selection
|
||||
verb, // do stuff with selection
|
||||
scale, // change draw scaling
|
||||
|
@ -26,9 +27,10 @@ pub const ActionCat = enum {
|
|||
pub const Action = struct {
|
||||
category: ActionCat,
|
||||
// Only one of these should be set, and only one should be used.
|
||||
function_move: fn (*Vec2, conf.arg_type) 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,
|
||||
function_parameter: fn (*Parameter, u8) void = Parameter.process_key,
|
||||
function_move: fn (*Vec2, Parameter.buffer_type) movement.SelectionUpdate = movement.move_left,
|
||||
function_verb: fn (*Level, Parameter.buffer_type) void = verbs.delete,
|
||||
function_scale: fn (scaling.scale_type, Parameter.buffer_type) scaling.scale_type = scaling.scale_reset,
|
||||
function_file: fn (*Level, *std.mem.Allocator, [*:0]const u8) void = Level.action_write,
|
||||
next_mode: Mode = Mode.normal,
|
||||
};
|
||||
|
@ -37,6 +39,12 @@ pub const ActionsDef = .{
|
|||
.none = Action{
|
||||
.category = ActionCat.none,
|
||||
},
|
||||
// Parameter/repetition.
|
||||
.parameter = Action{
|
||||
.category = ActionCat.parameter,
|
||||
.function_parameter = Parameter.process_key,
|
||||
},
|
||||
|
||||
// Movement.
|
||||
// Reset selection.
|
||||
.move_but_dont = Action{
|
||||
|
|
61
src/conf.zig
61
src/conf.zig
|
@ -3,12 +3,63 @@
|
|||
// 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.
|
||||
//! Values and types used by different files and that don't fit in any.
|
||||
//! Read /etc/kble.conf and execute content.
|
||||
/// Number passed to commands.
|
||||
const std = @import("std");
|
||||
//! User defined settings.
|
||||
const ray = @import("raylib.zig");
|
||||
const cell_type = @import("level.zig").cell_type;
|
||||
|
||||
pub const arg_type: type = u16;
|
||||
/// raylib.Color initialisation wrapper.
|
||||
fn col(r: u8, g: u8, b: u8) ray.Color {
|
||||
return ray.Color{
|
||||
.r = r,
|
||||
.g = g,
|
||||
.b = b,
|
||||
.a = 255,
|
||||
};
|
||||
}
|
||||
|
||||
// BEGIN USER CONFIG
|
||||
pub const mouse_enabled: bool = true;
|
||||
pub const mouse_left_btn: c_int = 0;
|
||||
pub const mouse_right_btn: c_int = 1;
|
||||
|
||||
pub const theme = .{
|
||||
.background = ray.BLACK,
|
||||
.mode = .{
|
||||
.normal = ray.GRAY,
|
||||
.select = ray.BLUE,
|
||||
.select_rect = ray.SKYBLUE,
|
||||
.camera = ray.PURPLE,
|
||||
},
|
||||
};
|
||||
|
||||
/// Return user defined color for corresponding cell ID.
|
||||
pub fn cell_color(cell: cell_type) ray.Color {
|
||||
return switch (cell) {
|
||||
0 => comptime col(026, 026, 026), // air
|
||||
1 => comptime col(144, 144, 144), // solid
|
||||
2 => comptime col(240, 010, 050), // red thing
|
||||
else => ray.PURPLE, // undefined
|
||||
};
|
||||
}
|
||||
|
||||
/// Used to set keybindings.
|
||||
/// Only bind to default keybindings, use 0 to unbind a key.
|
||||
pub fn bind_key(key: u8) u8 {
|
||||
return switch (key) {
|
||||
// // jkl; movement.
|
||||
// 'j' => 'h',
|
||||
// 'k' => 'j',
|
||||
// 'l' => 'k',
|
||||
// ';' => 'l',
|
||||
// // Backward movement with HJKL.
|
||||
// 'H' => 'l',
|
||||
// 'J' => 'k',
|
||||
// 'K' => 'j',
|
||||
// 'L' => 'h',
|
||||
// // Use x instead of return for normal mode.
|
||||
// '\n' => 0,
|
||||
// 'x' => '\n',
|
||||
else => key
|
||||
};
|
||||
}
|
||||
// END USER CONFIG
|
||||
|
|
15
src/draw.zig
15
src/draw.zig
|
@ -3,10 +3,9 @@
|
|||
// 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 ray = @import("raylib.zig");
|
||||
|
||||
const conf = @import("conf.zig");
|
||||
const Vec2 = @import("vec2.zig");
|
||||
const Rect = @import("rect.zig");
|
||||
const scaling = @import("scaling.zig");
|
||||
|
@ -17,10 +16,10 @@ pub fn cursor(scale: scaling.scale_type, offset: Vec2, pos: Vec2, mode: Mode) vo
|
|||
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,
|
||||
.normal => conf.theme.mode.normal,
|
||||
.select => conf.theme.mode.select,
|
||||
.rectangle => conf.theme.mode.select_rect,
|
||||
.camera => conf.theme.mode.camera,
|
||||
};
|
||||
ray.DrawRectangleLines(x, y, scale, scale, color);
|
||||
}
|
||||
|
@ -31,5 +30,5 @@ pub fn rectangle_selection(scale: scaling.scale_type, offset: Vec2, rect: Rect)
|
|||
const w = (rect.right_x - rect.left_x + 1) * scale;
|
||||
const y = (rect.top_y - offset.y) * scale;
|
||||
const h = (rect.bottom_y - rect.top_y + 1) * scale;
|
||||
ray.DrawRectangleLines(x, y, w, h, ray.SKYBLUE);
|
||||
ray.DrawRectangleLines(x, y, w, h, conf.theme.mode.select_rect);
|
||||
}
|
||||
|
|
|
@ -4,12 +4,11 @@
|
|||
// MIT licensed. The MIT license requires this copyright notice to be
|
||||
// included in all copies and substantial portions of the software.
|
||||
//! Level structure, grid containing tile data.
|
||||
const ray = @cImport({
|
||||
@cInclude("raylib.h");
|
||||
});
|
||||
const ray = @import("raylib.zig");
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
|
||||
const conf = @import("conf.zig");
|
||||
const Vec2 = @import("vec2.zig");
|
||||
const Rect = @import("rect.zig");
|
||||
const SelectionUpdate = @import("movement.zig").SelectionUpdate;
|
||||
|
@ -190,11 +189,7 @@ pub fn draw(self: Self, scale: u16, offset: Vec2) void {
|
|||
var cy: Vec2.int_type = offset.y;
|
||||
while (cy < self.height) {
|
||||
const cell_content: cell_type = self.content[cy * self.width + cx];
|
||||
const color = switch (cell_content) {
|
||||
0 => ray.Color{ .r = 26, .g = 26, .b = 26, .a = 255 },
|
||||
1 => ray.Color{ .r = 144, .g = 144, .b = 144, .a = 255 },
|
||||
else => ray.PURPLE, //unknown
|
||||
};
|
||||
const color: ray.Color = conf.cell_color(cell_content);
|
||||
ray.DrawRectangle(x + 1, y + 1, scale - 2, scale - 2, color);
|
||||
y += scale;
|
||||
cy += 1;
|
||||
|
|
95
src/main.zig
95
src/main.zig
|
@ -3,9 +3,7 @@
|
|||
// 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 ray = @import("raylib.zig");
|
||||
const std = @import("std");
|
||||
const maxInt = std.math.maxInt;
|
||||
const log = std.log.info;
|
||||
|
@ -16,6 +14,7 @@ const Vec2 = @import("vec2.zig");
|
|||
const Rect = @import("rect.zig");
|
||||
const Mouse = @import("mouse.zig");
|
||||
const draw = @import("draw.zig");
|
||||
const Parameter = @import("parameter.zig");
|
||||
const movement = @import("movement.zig");
|
||||
const verbs = @import("verbs.zig");
|
||||
const scaling = @import("scaling.zig");
|
||||
|
@ -72,34 +71,53 @@ pub fn main() void {
|
|||
// Set default mode.
|
||||
var mode: Mode = Mode.normal;
|
||||
|
||||
// Parameter buffer.
|
||||
var parameter: Parameter = Parameter{};
|
||||
|
||||
// Create binding "table".
|
||||
var bindings = [_]*const actions.Action{&actions.ActionsDef.none} ** char_range;
|
||||
// Set default bindings.
|
||||
// Movement.
|
||||
bindings['h'] = &ActionsDef.move_left;
|
||||
bindings['j'] = &ActionsDef.move_down;
|
||||
bindings['k'] = &ActionsDef.move_up;
|
||||
bindings['l'] = &ActionsDef.move_right;
|
||||
bindings['y'] = &ActionsDef.move_up_left;
|
||||
bindings['u'] = &ActionsDef.move_up_right;
|
||||
bindings['b'] = &ActionsDef.move_down_left;
|
||||
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;
|
||||
// File.
|
||||
bindings['e'] = &ActionsDef.file_read;
|
||||
bindings['w'] = &ActionsDef.file_write;
|
||||
// Mode.
|
||||
bindings['\n'] = &ActionsDef.mode_normal;
|
||||
bindings['i'] = &ActionsDef.mode_select;
|
||||
bindings['v'] = &ActionsDef.mode_rectangle;
|
||||
bindings['c'] = &ActionsDef.mode_camera;
|
||||
comptime {
|
||||
// Set default bindings.
|
||||
var default_bindings = [_]*const actions.Action{&actions.ActionsDef.none} ** char_range;
|
||||
comptime {
|
||||
var i: u8 = 0;
|
||||
while (i < 10) : (i += 1) {
|
||||
default_bindings['0' + i] = &ActionsDef.parameter;
|
||||
}
|
||||
}
|
||||
// Movement.
|
||||
default_bindings['h'] = &ActionsDef.move_left;
|
||||
default_bindings['j'] = &ActionsDef.move_down;
|
||||
default_bindings['k'] = &ActionsDef.move_up;
|
||||
default_bindings['l'] = &ActionsDef.move_right;
|
||||
default_bindings['y'] = &ActionsDef.move_up_left;
|
||||
default_bindings['u'] = &ActionsDef.move_up_right;
|
||||
default_bindings['b'] = &ActionsDef.move_down_left;
|
||||
default_bindings['n'] = &ActionsDef.move_down_right;
|
||||
// Verbs.
|
||||
default_bindings[' '] = &ActionsDef.verb_clear_selection;
|
||||
default_bindings['d'] = &ActionsDef.verb_delete;
|
||||
default_bindings['r'] = &ActionsDef.verb_replace;
|
||||
// Scale.
|
||||
default_bindings['='] = &ActionsDef.scale_reset;
|
||||
default_bindings['+'] = &ActionsDef.scale_up;
|
||||
default_bindings['-'] = &ActionsDef.scale_down;
|
||||
// File.
|
||||
default_bindings['e'] = &ActionsDef.file_read;
|
||||
default_bindings['w'] = &ActionsDef.file_write;
|
||||
// Mode.
|
||||
default_bindings['\n'] = &ActionsDef.mode_normal;
|
||||
default_bindings['i'] = &ActionsDef.mode_select;
|
||||
default_bindings['v'] = &ActionsDef.mode_rectangle;
|
||||
default_bindings['c'] = &ActionsDef.mode_camera;
|
||||
// Map user bindings.
|
||||
comptime {
|
||||
var i: u8 = 0;
|
||||
while (i < char_range) : (i += 1) {
|
||||
bindings[i] = default_bindings[conf.bind_key(i)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create input buffer.
|
||||
const input_buffer_len = 255;
|
||||
|
@ -142,8 +160,8 @@ pub fn main() void {
|
|||
// Read the buffer backwards. This is placeholder logic.
|
||||
while (input_cursor > 0) {
|
||||
input_cursor -= 1;
|
||||
const key = if (input_buffer[input_cursor] <= char_range)
|
||||
input_buffer[input_cursor]
|
||||
const key: u8 = if (input_buffer[input_cursor] <= char_range)
|
||||
@intCast(u8, input_buffer[input_cursor])
|
||||
else
|
||||
0;
|
||||
|
||||
|
@ -153,18 +171,21 @@ pub fn main() void {
|
|||
|
||||
switch (action.category) {
|
||||
.none => std.log.info("No action bound to {}.", .{key}),
|
||||
.parameter => {
|
||||
action.function_parameter(¶meter, key);
|
||||
},
|
||||
.movement => {
|
||||
const selection_update: movement.SelectionUpdate =
|
||||
action.function_move(&cursor, 1);
|
||||
action.function_move(&cursor, parameter.pop(1));
|
||||
if (apply_selection and selection_update.active) {
|
||||
level.apply_selection_update(selection_update);
|
||||
}
|
||||
},
|
||||
.verb => {
|
||||
action.function_verb(&level, 1);
|
||||
action.function_verb(&level, parameter.pop(1));
|
||||
},
|
||||
.scale => {
|
||||
scale = action.function_scale(scale);
|
||||
scale = action.function_scale(scale, parameter.pop(1));
|
||||
},
|
||||
.file => {
|
||||
action.function_file(&level, allocator, level_path);
|
||||
|
@ -243,13 +264,13 @@ pub fn main() void {
|
|||
ray.BeginDrawing();
|
||||
defer ray.EndDrawing();
|
||||
|
||||
ray.ClearBackground(ray.BLACK);
|
||||
ray.ClearBackground(conf.theme.background);
|
||||
level.draw(scale, camera);
|
||||
level.draw_selection(scale, camera);
|
||||
draw.cursor(scale, camera, cursor, mode);
|
||||
if (mode == Mode.rectangle)
|
||||
draw.rectangle_selection(scale, camera, Rect.init_from_vec2(cursor, cursor_before));
|
||||
mouse.draw(scale, camera);
|
||||
//ray.DrawFPS(0, 0);
|
||||
if (conf.mouse_enabled)
|
||||
mouse.draw(scale, camera);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,11 +4,10 @@
|
|||
// MIT licensed. The MIT license requires this copyright notice to be
|
||||
// included in all copies and substantial portions of the software.
|
||||
//! Mouse (eurk) logic and operations.
|
||||
const ray = @cImport({
|
||||
@cInclude("raylib.h");
|
||||
});
|
||||
const ray = @import("raylib.zig");
|
||||
const std = @import("std");
|
||||
|
||||
const conf = @import("conf.zig");
|
||||
const Vec2 = @import("vec2.zig");
|
||||
const Rect = @import("rect.zig");
|
||||
const scaling = @import("scaling.zig");
|
||||
|
@ -42,7 +41,7 @@ pub fn draw(self: *Self, scale: scaling.scale_type, offset: Vec2) void {
|
|||
MouseMode.sel => {
|
||||
const x = (self.pos.x - offset.y) * scale;
|
||||
const y = (self.pos.y - offset.y) * scale;
|
||||
ray.DrawRectangleLines(x, y, scale, scale, ray.SKYBLUE);
|
||||
ray.DrawRectangleLines(x, y, scale, scale, conf.theme.mode.select);
|
||||
},
|
||||
MouseMode.rect_sel => {
|
||||
const rect = Rect.init_from_vec2(self.pos, self.start_pos);
|
||||
|
@ -51,3 +50,4 @@ pub fn draw(self: *Self, scale: scaling.scale_type, offset: Vec2) void {
|
|||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ const std = @import("std");
|
|||
const expect = std.testing.expect;
|
||||
const maxInt = std.math.maxInt;
|
||||
|
||||
const conf = @import("conf.zig");
|
||||
const Parameter = @import("parameter.zig");
|
||||
const Vec2 = @import("vec2.zig");
|
||||
const Rect = @import("rect.zig");
|
||||
|
||||
|
@ -22,27 +22,27 @@ pub const SelectionUpdate = struct {
|
|||
};
|
||||
|
||||
/// Universal move system, prefer direction wrappers.
|
||||
fn move(cursor: *Vec2, arg: conf.arg_type, dx: i2, dy: i2) SelectionUpdate {
|
||||
fn move(cursor: *Vec2, arg: Parameter.buffer_type, dx: i2, dy: i2) SelectionUpdate {
|
||||
const before: Vec2 = cursor.*;
|
||||
|
||||
if (dx > 0) {
|
||||
var i: conf.arg_type = 0;
|
||||
var i: Parameter.buffer_type= 0;
|
||||
while (i != arg and cursor.x < maxIntVec2) : (i += 1) {
|
||||
cursor.x += 1;
|
||||
}
|
||||
} else if (dx < 0) {
|
||||
var i: conf.arg_type = 0;
|
||||
var i: Parameter.buffer_type= 0;
|
||||
while (i != arg and cursor.x > 0) : (i += 1) {
|
||||
cursor.x -= 1;
|
||||
}
|
||||
}
|
||||
if (dy > 0) {
|
||||
var i: conf.arg_type = 0;
|
||||
var i: Parameter.buffer_type= 0;
|
||||
while (i != arg and cursor.y < maxIntVec2) : (i += 1) {
|
||||
cursor.y += 1;
|
||||
}
|
||||
} else if (dy < 0) {
|
||||
var i: conf.arg_type = 0;
|
||||
var i: Parameter.buffer_type= 0;
|
||||
while (i != arg and cursor.y > 0) : (i += 1) {
|
||||
cursor.y -= 1;
|
||||
}
|
||||
|
@ -56,47 +56,47 @@ fn move(cursor: *Vec2, arg: conf.arg_type, dx: i2, dy: i2) SelectionUpdate {
|
|||
}
|
||||
|
||||
/// Just don't move.
|
||||
pub fn move_but_dont(cursor: *Vec2, arg: conf.arg_type) SelectionUpdate {
|
||||
pub fn move_but_dont(cursor: *Vec2, arg: Parameter.buffer_type) SelectionUpdate {
|
||||
return move(cursor, arg, 0, 0);
|
||||
}
|
||||
|
||||
/// Try to move the cursor `n` times left.
|
||||
pub fn move_left(cursor: *Vec2, arg: conf.arg_type) SelectionUpdate {
|
||||
pub fn move_left(cursor: *Vec2, arg: Parameter.buffer_type) SelectionUpdate {
|
||||
return move(cursor, arg, -1, 0);
|
||||
}
|
||||
|
||||
/// Try to move the cursor `n` times right.
|
||||
pub fn move_right(cursor: *Vec2, arg: conf.arg_type) SelectionUpdate {
|
||||
pub fn move_right(cursor: *Vec2, arg: Parameter.buffer_type) SelectionUpdate {
|
||||
return move(cursor, arg, 1, 0);
|
||||
}
|
||||
|
||||
/// Try to move the cursor `n` times up.
|
||||
pub fn move_up(cursor: *Vec2, arg: conf.arg_type) SelectionUpdate {
|
||||
pub fn move_up(cursor: *Vec2, arg: Parameter.buffer_type) SelectionUpdate {
|
||||
return move(cursor, arg, 0, -1);
|
||||
}
|
||||
|
||||
/// Try to move the cursor `n` times down.
|
||||
pub fn move_down(cursor: *Vec2, arg: conf.arg_type) SelectionUpdate {
|
||||
pub fn move_down(cursor: *Vec2, arg: Parameter.buffer_type) SelectionUpdate {
|
||||
return move(cursor, arg, 0, 1);
|
||||
}
|
||||
|
||||
/// Try to move the cursor `n` times up and left.
|
||||
pub fn move_up_left(cursor: *Vec2, arg: conf.arg_type) SelectionUpdate {
|
||||
pub fn move_up_left(cursor: *Vec2, arg: Parameter.buffer_type) SelectionUpdate {
|
||||
return move(cursor, arg, -1, -1);
|
||||
}
|
||||
|
||||
/// Try to move the cursor `n` times up and right.
|
||||
pub fn move_up_right(cursor: *Vec2, arg: conf.arg_type) SelectionUpdate {
|
||||
pub fn move_up_right(cursor: *Vec2, arg: Parameter.buffer_type) SelectionUpdate {
|
||||
return move(cursor, arg, 1, -1);
|
||||
}
|
||||
|
||||
/// Try to move the cursor `n` times down and left.
|
||||
pub fn move_down_left(cursor: *Vec2, arg: conf.arg_type) SelectionUpdate {
|
||||
pub fn move_down_left(cursor: *Vec2, arg: Parameter.buffer_type) SelectionUpdate {
|
||||
return move(cursor, arg, -1, 1);
|
||||
}
|
||||
|
||||
/// Try to move the cursor `n` times down and right.
|
||||
pub fn move_down_right(cursor: *Vec2, arg: conf.arg_type) SelectionUpdate {
|
||||
pub fn move_down_right(cursor: *Vec2, arg: Parameter.buffer_type) SelectionUpdate {
|
||||
return move(cursor, arg, 1, 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
// 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 std = @import("std");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub const buffer_type = u16;
|
||||
pub const buffer_limit = std.math.maxInt(buffer_type) / 10;
|
||||
|
||||
buffer: buffer_type = 0, // hold current number
|
||||
used: bool = false, // keep track of buffer usage
|
||||
|
||||
/// Only accept key between '0' and '9' inclusive. Add a number to the buffer.
|
||||
pub fn process_key(self: *Self, key: u8) void {
|
||||
if (key < '0' or key > '9') unreachable;
|
||||
self.used = true;
|
||||
|
||||
const number: buffer_type = key - '0';
|
||||
if (self.buffer < buffer_limit) {
|
||||
self.buffer *= 10;
|
||||
self.buffer += number;
|
||||
std.log.info("Parameter buffer: {}", .{self});
|
||||
} else {
|
||||
std.log.warn("Buffer limit reached.", .{});
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the buffer value if used and reset it. Otherwise return `default`.
|
||||
pub fn pop(self: *Self, default: buffer_type) buffer_type {
|
||||
defer self.buffer = 0;
|
||||
defer self.used = false;
|
||||
return if (self.used) self.buffer else default;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/// Simplest imaginable raylib wrapper
|
||||
pub usingnamespace @cImport({
|
||||
@cInclude("raylib.h");
|
||||
});
|
|
@ -8,38 +8,40 @@ const std = @import("std");
|
|||
const expect = std.testing.expect;
|
||||
const maxInt = std.math.maxInt;
|
||||
|
||||
const Parameter = @import("parameter.zig");
|
||||
|
||||
pub const scale_type = u8;
|
||||
pub const scale_default: comptime_int = 16;
|
||||
const scale_min: comptime_int = 3;
|
||||
const scale_max: comptime_int = maxInt(scale_type);
|
||||
const scale_min = 3;
|
||||
const scale_max = maxInt(scale_type);
|
||||
|
||||
pub fn scale_reset(current_scale: scale_type) scale_type {
|
||||
pub fn scale_reset(current_scale: scale_type, arg: Parameter.buffer_type) scale_type {
|
||||
return scale_default;
|
||||
}
|
||||
|
||||
pub fn scale_up(current_scale: scale_type) scale_type {
|
||||
if (current_scale < scale_max) {
|
||||
return current_scale + 1;
|
||||
} else return current_scale;
|
||||
pub fn scale_up(current_scale: scale_type, arg: Parameter.buffer_type) scale_type {
|
||||
if (@intCast(u32, current_scale) + @intCast(u32, arg) < @intCast(u32, scale_max)) {
|
||||
return current_scale + @intCast(u8, arg);
|
||||
} else return scale_max;
|
||||
}
|
||||
|
||||
pub fn scale_down(current_scale: scale_type) scale_type {
|
||||
if (current_scale > scale_min) {
|
||||
return current_scale - 1;
|
||||
} else return current_scale;
|
||||
pub fn scale_down(current_scale: scale_type, arg: Parameter.buffer_type) scale_type {
|
||||
if (@intCast(i32, current_scale) - @intCast(i32, arg) > @intCast(i32, scale_min)) {
|
||||
return current_scale - @intCast(u8, arg);
|
||||
} else return scale_min;
|
||||
}
|
||||
|
||||
test "scale reset" {
|
||||
expect(scale_reset(42) == scale_default);
|
||||
expect(scale_reset(42, 1) == scale_default);
|
||||
}
|
||||
|
||||
test "scale up" {
|
||||
expect(scale_up(42) == 43);
|
||||
expect(scale_up(scale_max) == scale_max);
|
||||
expect(scale_up(42, 1) == 43);
|
||||
expect(scale_up(scale_max - 4, 42) == scale_max);
|
||||
}
|
||||
|
||||
test "scale down" {
|
||||
expect(scale_down(42) == 41);
|
||||
expect(scale_down(scale_min) == scale_min);
|
||||
expect(scale_down(42, 1) == 41);
|
||||
expect(scale_down(scale_min + 2, 42) == scale_min);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
// MIT licensed. The MIT license requires this copyright notice to be
|
||||
// included in all copies and substantial portions of the software.
|
||||
//! Act on level using selection.
|
||||
const conf = @import("conf.zig");
|
||||
const Parameter = @import("parameter.zig");
|
||||
const Level = @import("level.zig");
|
||||
|
||||
/// Clear selection (deselect everything).
|
||||
pub fn clear_selection(level: *Level, arg: conf.arg_type) void {
|
||||
pub fn clear_selection(level: *Level, arg: Parameter.buffer_type) void {
|
||||
var i: u32 = 0;
|
||||
while (i < level.width * level.height) : (i += 1) {
|
||||
level.selection[i] = false;
|
||||
|
@ -16,7 +16,7 @@ pub fn clear_selection(level: *Level, arg: conf.arg_type) void {
|
|||
}
|
||||
|
||||
/// Delete selected cells (set to 0).
|
||||
pub fn delete(level: *Level, arg: conf.arg_type) void {
|
||||
pub fn delete(level: *Level, arg: Parameter.buffer_type) void {
|
||||
var i: u32 = 0;
|
||||
while (i < level.width * level.height) : (i += 1) {
|
||||
if (level.selection[i])
|
||||
|
@ -25,7 +25,7 @@ pub fn delete(level: *Level, arg: conf.arg_type) void {
|
|||
}
|
||||
|
||||
/// Replace selected cells with `arg`.
|
||||
pub fn replace(level: *Level, arg: conf.arg_type) void {
|
||||
pub fn replace(level: *Level, arg: Parameter.buffer_type) void {
|
||||
const casted_arg = @intCast(Level.cell_type, arg);
|
||||
var i: u32 = 0;
|
||||
while (i < level.width * level.height) : (i += 1) {
|
||||
|
|
Loading…
Reference in New Issue