Unselection modes for mouse and keyboard (#2)

This commit is contained in:
KikooDX 2021-02-26 13:12:29 +01:00
parent 4fb7d33645
commit a3a4483a44
7 changed files with 59 additions and 32 deletions

View File

@ -20,8 +20,8 @@ https://builds.sr.ht/~kikoodx/kble
## Manual compilation
Build requirements: [Zig](https://ziglang.org/download/) master branch,
[raylib](https://www.raylib.com).
For Arch users, `zig-dev-bin` and `zig-git` are available in the AUR.
[raylib](https://www.raylib.com). For Arch users, I made
[`kble-git`](https://aur.archlinux.org/packages/kble-git/) available in the AUR.
```sh
$ # Clone this repository
$ git clone https://git.sr.ht/~kikoodx/kble && cd kble
@ -79,14 +79,16 @@ Modes:
* `<return>`: normal mode, default
* `i`: free selection mode
* `v`: rectangle selection mode
* `I`: free unselection mode
* `V`: rectangle unselection mode
* `c`: camera mode [not implemented]
# Mouse control
Right click and left click are the same, except right click reset
selection before taking effect.
* Click: free selection.
* Shift + Click: rectangle selection.
* Click while selecting: end selection.
# Default mouse control
* Right click: free selection.
* Shift + left click: rectangle selection.
* Right click: libre unselection.
* Shift + right click: rectangle unselection.
* Left or right click while un·selecting: end selection.
# License
Copyright (c) 2021 KikooDX

View File

@ -143,6 +143,14 @@ pub const ActionsDef = .{
.category = ActionCat.mode,
.next_mode = Mode.rectangle,
},
.mode_unselect = Action{
.category = ActionCat.mode,
.next_mode = Mode.unselect,
},
.mode_unrectangle = Action{
.category = ActionCat.mode,
.next_mode = Mode.unrectangle,
},
.mode_camera = Action{
.category = ActionCat.mode,
.next_mode = Mode.camera,

View File

@ -37,6 +37,8 @@ pub const theme = .{
.normal = ray.GRAY,
.select = ray.BLUE,
.select_rect = ray.SKYBLUE,
.unselect = ray.RED,
.unrectangle = ray.PINK,
.camera = ray.PURPLE,
},
};

View File

@ -19,16 +19,21 @@ pub fn cursor(scale: scaling.scale_type, offset: Vec2, pos: Vec2, mode: Mode) vo
.normal => conf.theme.mode.normal,
.select => conf.theme.mode.select,
.rectangle => conf.theme.mode.select_rect,
.unselect => conf.theme.mode.unselect,
.unrectangle => conf.theme.mode.unrectangle,
.camera => conf.theme.mode.camera,
};
ray.DrawRectangleLines(x, y, scale, scale, color);
}
/// Draw rectangle selection preview.
pub fn rectangle_selection(scale: scaling.scale_type, offset: Vec2, rect: Rect) void {
pub fn rectangle_selection(scale: scaling.scale_type, offset: Vec2, rect: Rect, sel: bool) 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, conf.theme.mode.select_rect);
ray.DrawRectangleLines(x, y, w, h, if (sel)
conf.theme.mode.select_rect
else
conf.theme.mode.unrectangle);
}

View File

@ -111,6 +111,8 @@ pub fn main() void {
default_bindings['\n'] = &ActionsDef.mode_normal;
default_bindings['i'] = &ActionsDef.mode_select;
default_bindings['v'] = &ActionsDef.mode_rectangle;
default_bindings['I'] = &ActionsDef.mode_unselect;
default_bindings['V'] = &ActionsDef.mode_unrectangle;
default_bindings['c'] = &ActionsDef.mode_camera;
// Map user bindings.
comptime {
@ -158,7 +160,7 @@ pub fn main() void {
// TODO: move everything from this to a function (for config and macros support).
const action: actions.Action = bindings[key].*;
const apply_selection: bool = (mode == Mode.select);
const apply_selection: bool = (mode == .select);
switch (action.category) {
.none => std.log.info("No action bound to {}.", .{key}),
@ -183,13 +185,13 @@ pub fn main() void {
},
.mode => {
// Rectangle selection!
if (mode == Mode.rectangle) {
if (mode == .rectangle or mode == .unrectangle) {
const selection = Rect.init_from_vec2(cursor, cursor_before);
level.select_rect(selection, true);
level.select_rect(selection, mode == .rectangle);
}
cursor_before = cursor; // Save position before selection.
mode = action.next_mode;
if (mode == Mode.select) // Select first tile.
if (mode == .select) // Select first tile.
level.select_cell(cursor, true);
},
}
@ -217,12 +219,12 @@ pub fn main() void {
// When end selection event, get out of current mode and apply changes if necessary.
if (end_sel_event and mouse.mode != Mouse.MouseMode.idle) {
defer mouse.mode = Mouse.MouseMode.wait;
defer mouse.mode = .wait;
// Select area.
if (mouse.mode == Mouse.MouseMode.rect_sel) {
if (mouse.mode == .rect_sel or mouse.mode == .unrect_sel) {
const selection = Rect.init_from_vec2(mouse.start_pos, mouse.pos);
level.select_rect(selection, true);
level.select_rect(selection, mouse.mode == .rect_sel);
}
}
@ -235,22 +237,23 @@ pub fn main() void {
ray.IsKeyDown(ray.KEY_RIGHT_SHIFT);
if (click) { // Switch mode.
cursor = mouse.pos;
// Reset selection on right click.
if (right_click) {
verbs.clear_selection(&level, 1);
}
// Set position.
mouse.start_pos = mouse.pos;
mouse.mode = if (mod_rect_sel)
// If right click then un<mode>
mouse.mode = if (right_click and mod_rect_sel)
Mouse.MouseMode.unrect_sel
else if (right_click and !mod_rect_sel)
Mouse.MouseMode.unsel
else if (mod_rect_sel)
Mouse.MouseMode.rect_sel
else
Mouse.MouseMode.sel;
}
},
// Select stuff under the cursor.
.sel => {
.sel, .unsel => {
cursor = mouse.pos;
level.select_cell(mouse.pos, true);
level.select_cell(mouse.pos, mouse.mode == .sel);
},
else => {},
}
@ -263,8 +266,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));
if (mode == Mode.rectangle or mode == Mode.unrectangle)
draw.rectangle_selection(scale, camera, Rect.init_from_vec2(cursor, cursor_before), mode == .rectangle);
if (conf.mouse_enabled)
mouse.draw(scale, camera);
}

View File

@ -8,5 +8,7 @@ pub const Mode = enum {
normal, // move cursor and do stuff
select, // same, but select while doing so
rectangle, // same, but select as a rectangle
unselect, // remove from selection instead of adding to it
unrectangle, // same as above for rectangle
camera, // move camera instead
};

View File

@ -20,6 +20,8 @@ pub const MouseMode = enum {
idle,
sel,
rect_sel,
unsel,
unrect_sel,
};
mode: MouseMode, // State.
@ -38,16 +40,19 @@ pub fn init() Self {
/// Draw cursor or preview rectangle selection depending on mode.
pub fn draw(self: *Self, scale: scaling.scale_type, offset: Vec2) void {
switch (self.mode) {
MouseMode.sel => {
// Cell size cursor.
.idle, .wait, .sel, .unsel => {
const x = (self.pos.x - offset.y) * scale;
const y = (self.pos.y - offset.y) * scale;
ray.DrawRectangleLines(x, y, scale, scale, conf.theme.mode.select);
ray.DrawRectangleLines(x, y, scale, scale, switch (self.mode) {
.sel => conf.theme.mode.select,
.unsel => conf.theme.mode.unselect,
else => conf.theme.mode.normal,
});
},
MouseMode.rect_sel => {
.rect_sel, .unrect_sel => {
const rect = Rect.init_from_vec2(self.pos, self.start_pos);
draw_fn.rectangle_selection(scale, offset, rect);
draw_fn.rectangle_selection(scale, offset, rect, self.mode == .rect_sel);
},
else => {},
}
}