Cleaned up code, implemented rectangle selection.

This commit is contained in:
KikooDX 2021-02-02 14:49:50 +01:00
parent 20c4d8ca1a
commit 989502edf9
7 changed files with 53 additions and 47 deletions

View File

@ -5,6 +5,7 @@ This is a work in progress program in unusable state.
# Short term design decisions
Subject to change.
* Efficiency, simplicity and clarity are key goals.
* Fully keyboard driven modal editing. Mouse support is secondary.
* GUI application made in [Zig](https://ziglang.org/) with
[raylib](https://www.raylib.com/).
@ -44,7 +45,7 @@ Verbs:
Modes:
* `<return>`: normal mode, default
* `i`: free selection mode
* `v`: rectangle selection mode [not implemented]
* `v`: rectangle selection mode
* `c`: camera mode [not implemented]
# Mouse control

View File

@ -25,7 +25,7 @@ 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, bool) movement.SelectionUpdate = movement.move_left,
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,
next_mode: Mode = Mode.normal,

View File

@ -8,6 +8,7 @@ const ray = @cImport({
});
const Vec2 = @import("vec2.zig");
const Rect = @import("rect.zig");
const scaling = @import("scaling.zig");
const Mode = @import("modes.zig").Mode;
@ -23,3 +24,12 @@ pub fn cursor(scale: scaling.scale_type, offset: Vec2, pos: Vec2, mode: Mode) vo
};
ray.DrawRectangleLines(x, y, scale, scale, color);
}
/// Draw rectangle selection preview.
pub fn rectangle_selection(scale: scaling.scale_type, offset: Vec2, rect: Rect) void {
const x = (rect.left_x - offset.x) * scale;
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);
}

View File

@ -135,12 +135,6 @@ pub fn select_rect(self: *Self, rect: Rect, state: bool) void {
/// Apply selection update to selection *kof*.
pub fn apply_selection_update(self: *Self, selection_update: SelectionUpdate) void {
// The update is exclusive, forget everything before it.
if (selection_update.exclusive) {
// Clear selection.
self.select_clear(false);
}
// Apply changes.
self.select_rect(selection_update.area, selection_update.state);
}

View File

@ -17,6 +17,7 @@ const Rect = @import("rect.zig");
const Mouse = @import("mouse.zig");
const draw = @import("draw.zig");
const movement = @import("movement.zig");
const verbs = @import("verbs.zig");
const scaling = @import("scaling.zig");
const actions = @import("actions.zig");
const ActionsDef = actions.ActionsDef;
@ -45,16 +46,19 @@ pub fn main() void {
// Create camera.
// TODO: Can't move camera, implement camera mode.
var camera: Vec2 = Vec2.init(0, 0);
var camera: Vec2 = comptime Vec2.init(0, 0);
// Init scale, used by drawing code.
var scale: scaling.scale_type = scaling.scale_default;
// Create mouse.
var mouse: Mouse = Mouse.init();
var mouse: Mouse = comptime Mouse.init();
// Create cursor.
var cursor: Vec2 = Vec2.init(0, 0);
var cursor: Vec2 = comptime Vec2.init(0, 0);
// Used by rectangle selection mode.
var cursor_before: Vec2 = comptime Vec2.init(0, 0);
// Set default mode.
var mode: Mode = Mode.normal;
@ -132,14 +136,13 @@ 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, exclusive_movement);
action.function_move(&cursor, 1);
if (apply_selection and selection_update.active) {
level.apply_selection_update(selection_update);
}
@ -151,6 +154,12 @@ pub fn main() void {
scale = action.function_scale(scale);
},
.mode => {
// Rectangle selection!
if (mode == Mode.rectangle) {
const selection = Rect.init_from_vec2(cursor, cursor_before);
level.select_rect(selection, true);
}
cursor_before = cursor; // Save position before selection.
mode = action.next_mode;
},
}
@ -193,7 +202,7 @@ pub fn main() void {
cursor = mouse.pos;
// Reset selection on right click.
if (right_click) {
level.apply_selection_update(movement.move_but_dont(&cursor, 1, true));
verbs.clear_selection(&level, 1);
}
// Set position.
mouse.start_pos = mouse.pos;
@ -219,6 +228,8 @@ pub fn main() void {
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);
}

View File

@ -12,11 +12,10 @@ const std = @import("std");
const Vec2 = @import("vec2.zig");
const Rect = @import("rect.zig");
const scaling = @import("scaling.zig");
const draw_fn = @import("draw.zig");
const Self = @This();
const preview_color = ray.SKYBLUE;
pub const MouseMode = enum {
wait, // Skip one turn.
idle,
@ -43,15 +42,11 @@ 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, preview_color);
ray.DrawRectangleLines(x, y, scale, scale, ray.SKYBLUE);
},
MouseMode.rect_sel => {
const rect = Rect.init_from_vec2(self.pos, self.start_pos);
const x = (rect.left_x - offset.x) * scale;
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, preview_color);
draw_fn.rectangle_selection(scale, offset, rect);
},
else => {},
}

View File

@ -17,13 +17,12 @@ const maxIntVec2 = comptime maxInt(Vec2.int_type);
/// Describe changes to make on selection.
pub const SelectionUpdate = struct {
active: bool,
exclusive: bool,
area: Rect,
state: bool,
};
/// Universal move system, prefer direction wrappers.
fn move(cursor: *Vec2, arg: conf.arg_type, exclusive_selection: bool, dx: i2, dy: i2) SelectionUpdate {
fn move(cursor: *Vec2, arg: conf.arg_type, dx: i2, dy: i2) SelectionUpdate {
const before: Vec2 = cursor.*;
if (dx > 0) {
@ -51,58 +50,54 @@ fn move(cursor: *Vec2, arg: conf.arg_type, exclusive_selection: bool, dx: i2, dy
return SelectionUpdate{
.active = true,
.exclusive = exclusive_selection,
.area = if (exclusive_selection)
Rect.init_from_vec2(cursor.*, cursor.*)
else
Rect.init_from_vec2(before, cursor.*),
.area = Rect.init_from_vec2(before, cursor.*),
.state = true,
};
}
/// Just don't move.
pub fn move_but_dont(cursor: *Vec2, arg: conf.arg_type, exclusive_selection: bool) SelectionUpdate {
return move(cursor, arg, exclusive_selection, 0, 0);
pub fn move_but_dont(cursor: *Vec2, arg: conf.arg_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, exclusive_selection: bool) SelectionUpdate {
return move(cursor, arg, exclusive_selection, -1, 0);
pub fn move_left(cursor: *Vec2, arg: conf.arg_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, exclusive_selection: bool) SelectionUpdate {
return move(cursor, arg, exclusive_selection, 1, 0);
pub fn move_right(cursor: *Vec2, arg: conf.arg_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, exclusive_selection: bool) SelectionUpdate {
return move(cursor, arg, exclusive_selection, 0, -1);
pub fn move_up(cursor: *Vec2, arg: conf.arg_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, exclusive_selection: bool) SelectionUpdate {
return move(cursor, arg, exclusive_selection, 0, 1);
pub fn move_down(cursor: *Vec2, arg: conf.arg_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, exclusive_selection: bool) SelectionUpdate {
return move(cursor, arg, exclusive_selection, -1, -1);
pub fn move_up_left(cursor: *Vec2, arg: conf.arg_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, exclusive_selection: bool) SelectionUpdate {
return move(cursor, arg, exclusive_selection, 1, -1);
pub fn move_up_right(cursor: *Vec2, arg: conf.arg_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, exclusive_selection: bool) SelectionUpdate {
return move(cursor, arg, exclusive_selection, -1, 1);
pub fn move_down_left(cursor: *Vec2, arg: conf.arg_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, exclusive_selection: bool) SelectionUpdate {
return move(cursor, arg, exclusive_selection, 1, 1);
pub fn move_down_right(cursor: *Vec2, arg: conf.arg_type) SelectionUpdate {
return move(cursor, arg, 1, 1);
}
test "move left" {