diff --git a/src/conf.zig b/src/conf.zig index 526f5fb..3cedd48 100644 --- a/src/conf.zig +++ b/src/conf.zig @@ -5,4 +5,7 @@ // included in all copies and substantial portions of the software. //! Values and types used by different files and that don't fit in any. /// Number passed to commands. -pub const arg_type = u16; +pub const arg_type: type = u16; +pub const mouse_enabled: bool = true; +pub const mouse_left_btn: c_int = 0; +pub const mouse_right_btn: c_int = 1; diff --git a/src/level.zig b/src/level.zig index d08bc4c..4b22064 100644 --- a/src/level.zig +++ b/src/level.zig @@ -102,7 +102,7 @@ pub fn draw_selection(self: *Self, scale: u16, offset: Vec2) void { } /// Set the `state` of a cell at `cursor` if possible -fn select_cell(self: *Self, cursor: Vec2, state: bool) void { +pub fn select_cell(self: *Self, cursor: Vec2, state: bool) void { const target: u32 = @intCast(u32, cursor.y) * self.width + @intCast(u32, cursor.x); if (target < self.width * self.height and target >= 0) self.selection[target] = state; @@ -118,7 +118,7 @@ fn select_clear(self: *Self, state: bool) void { } /// Change state of all the cells in the rectangle range. -fn select_rect(self: *Self, rect: Rect, state: bool) void { +pub fn select_rect(self: *Self, rect: Rect, state: bool) void { var cx: Rect.int_type = rect.left_x; while (cx <= rect.right_x) { defer cx += 1; diff --git a/src/main.zig b/src/main.zig index 4cf30c2..4fc58f0 100644 --- a/src/main.zig +++ b/src/main.zig @@ -8,9 +8,13 @@ const ray = @cImport({ }); const std = @import("std"); const maxInt = std.math.maxInt; +const log = std.log.info; +const conf = @import("conf.zig"); const Level = @import("level.zig"); const Vec2 = @import("vec2.zig"); +const Rect = @import("rect.zig"); +const Mouse = @import("mouse.zig"); const movement = @import("movement.zig"); const scaling = @import("scaling.zig"); const actions = @import("actions.zig"); @@ -43,6 +47,9 @@ pub fn main() !void { // Init scale, used by drawing code. var scale: scaling.scale_type = scaling.scale_default; + // Create mouse. + var mouse: Mouse = Mouse.init(); + // Create cursor. var cursor: Vec2 = Vec2.init(0, 0); @@ -132,6 +139,66 @@ pub fn main() !void { } } + // Mouse operations. + if (conf.mouse_enabled) { + // Update position. + { + // Set mouse offset. + ray.SetMouseOffset(camera.x, camera.y); + // Set mouse scaling. + ray.SetMouseScale(1.0 / @intToFloat(f32, scale), 1.0 / @intToFloat(f32, scale)); + + mouse.pos.x = @intCast(u16, ray.GetMouseX()); + mouse.pos.y = @intCast(u16, ray.GetMouseY()); + } + + const left_press: bool = ray.IsMouseButtonPressed(conf.mouse_left_btn); + const left_release: bool = ray.IsMouseButtonReleased(conf.mouse_left_btn); + const right_press: bool = ray.IsMouseButtonPressed(conf.mouse_right_btn); + + // State machine. + switch (mouse.mode) { + // See if can switch mode. + .idle => { + const mod_rect_sel: bool = ray.IsKeyDown(ray.KEY_LEFT_SHIFT) or + ray.IsKeyDown(ray.KEY_RIGHT_SHIFT); + if (left_press) { // Switch mode. + cursor = mouse.pos; + mouse.start_pos = mouse.pos; + mouse.mode = if (mod_rect_sel) + Mouse.MouseMode.rect_sel + else + Mouse.MouseMode.sel; + } + }, + // Select stuff under the cursor. + .sel => { + cursor = mouse.pos; + level.select_cell(mouse.pos, true); + }, + // Rectangle selection, see `left_release` for handling. + .rect_sel => {}, + } + + // If left button is released, get out of current mode and apply changes if necessary. + if (left_release) { + defer mouse.mode = Mouse.MouseMode.idle; + defer cursor = mouse.pos; + + // Select area. + if (mouse.mode == Mouse.MouseMode.rect_sel) { + const selection = Rect.init_from_vec2(mouse.start_pos, mouse.pos); + level.select_rect(selection, true); + } + } + + // Reset selection on right click. + if (right_press) { + cursor = mouse.pos; + level.apply_selection_update(movement.move_but_dont(&cursor, 1, true)); + } + } + ray.BeginDrawing(); defer ray.EndDrawing(); diff --git a/src/mouse.zig b/src/mouse.zig new file mode 100644 index 0000000..f0b551a --- /dev/null +++ b/src/mouse.zig @@ -0,0 +1,29 @@ +// 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. +//! Mouse (eurk) logic and operations. +const std = @import("std"); + +const Vec2 = @import("vec2.zig"); + +const Self = @This(); + +pub const MouseMode = enum { + idle, + sel, + rect_sel, +}; + +mode: MouseMode, // State. +pos: Vec2, // Where the cursor is. +start_pos: Vec2, // Used for rectangle selection. + +pub fn init() Self { + return Self{ + .mode = MouseMode.idle, // state + .pos = Vec2{ .x = 0, .y = 0 }, + .start_pos = Vec2{ .x = 0, .y = 0 }, + }; +} diff --git a/src/scaling.zig b/src/scaling.zig index 3b9d506..523cc86 100644 --- a/src/scaling.zig +++ b/src/scaling.zig @@ -8,7 +8,7 @@ const std = @import("std"); const expect = std.testing.expect; const maxInt = std.math.maxInt; -pub const scale_type = u16; +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);