Compare commits

...
Sign in to create a new pull request.

3 commits

Author SHA1 Message Date
0b2a3991ed format 2025-04-23 21:47:34 +02:00
324d16cfc2 clippy auto fixes 2025-04-23 21:47:23 +02:00
f4348599f6 convert to macroquad and make it compile 2025-04-23 21:45:32 +02:00
15 changed files with 1037 additions and 1104 deletions

387
Cargo.lock generated
View file

@ -3,13 +3,16 @@
version = 4
[[package]]
name = "aho-corasick"
version = "1.1.3"
name = "adler2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "allocator-api2"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "arboard"
@ -33,24 +36,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bindgen"
version = "0.70.1"
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"itertools",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn",
]
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
@ -68,22 +57,16 @@ dependencies = [
]
[[package]]
name = "cc"
version = "1.1.24"
name = "bytemuck"
version = "1.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938"
dependencies = [
"shlex",
]
checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540"
[[package]]
name = "cexpr"
version = "0.6.0"
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cfg-if"
@ -91,17 +74,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "clipboard-win"
version = "5.4.0"
@ -112,19 +84,25 @@ dependencies = [
]
[[package]]
name = "cmake"
version = "0.1.51"
name = "color_quant"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "crc32fast"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
"cc",
"cfg-if",
]
[[package]]
name = "either"
version = "1.13.0"
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
@ -142,6 +120,41 @@ version = "3.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f"
[[package]]
name = "fdeflate"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
dependencies = [
"simd-adler32",
]
[[package]]
name = "flate2"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "fontdue"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e57e16b3fe8ff4364c0661fdaac543fb38b29ea9bc9c2f45612d90adf931d2b"
dependencies = [
"hashbrown",
"ttf-parser",
]
[[package]]
name = "gethostname"
version = "0.4.3"
@ -153,18 +166,33 @@ dependencies = [
]
[[package]]
name = "glob"
version = "0.3.1"
name = "glam"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
checksum = "9e05e7e6723e3455f4818c7b26e855439f7546cf617ef669d1adedb8669e5cb9"
[[package]]
name = "itertools"
version = "0.12.1"
name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
dependencies = [
"either",
"allocator-api2",
"equivalent",
"foldhash",
]
[[package]]
name = "image"
version = "0.24.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d"
dependencies = [
"bytemuck",
"byteorder",
"color_quant",
"num-traits",
"png",
]
[[package]]
@ -179,16 +207,6 @@ version = "0.2.159"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
[[package]]
name = "libloading"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
dependencies = [
"cfg-if",
"windows-targets 0.52.6",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.14"
@ -211,12 +229,41 @@ version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "macroquad"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2befbae373456143ef55aa93a73594d080adfb111dc32ec96a1123a3e4ff4ae"
dependencies = [
"fontdue",
"glam",
"image",
"macroquad_macro",
"miniquad",
"quad-rand",
]
[[package]]
name = "macroquad_macro"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64b1d96218903768c1ce078b657c0d5965465c95a60d2682fd97443c9d2483dd"
[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
dependencies = [
"libc",
]
[[package]]
name = "marble-machinations"
version = "0.3.3"
dependencies = [
"arboard",
"raylib",
"macroquad",
"serde",
"serde_json",
]
@ -228,19 +275,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
name = "miniquad"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
checksum = "2fb3e758e46dbc45716a8a49ca9edc54b15bcca826277e80b1f690708f67f9e3"
dependencies = [
"libc",
"ndk-sys",
"objc-rs",
"winapi",
]
[[package]]
name = "nom"
version = "7.1.3"
name = "miniz_oxide"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [
"memchr",
"minimal-lexical",
"adler2",
"simd-adler32",
]
[[package]]
name = "ndk-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121"
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "objc-rs"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64a1e7069a2525126bf12a9f1f7916835fafade384fb27cabf698e745e2a1eb8"
dependencies = [
"malloc_buf",
]
[[package]]
@ -265,7 +342,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff"
dependencies = [
"bitflags",
"bitflags 2.6.0",
"block2",
"libc",
"objc2",
@ -281,7 +358,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef"
dependencies = [
"bitflags",
"bitflags 2.6.0",
"block2",
"objc2",
"objc2-foundation",
@ -311,7 +388,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
dependencies = [
"bitflags",
"bitflags 2.6.0",
"block2",
"libc",
"objc2",
@ -323,7 +400,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
dependencies = [
"bitflags",
"bitflags 2.6.0",
"block2",
"objc2",
"objc2-foundation",
@ -335,7 +412,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
dependencies = [
"bitflags",
"bitflags 2.6.0",
"block2",
"objc2",
"objc2-foundation",
@ -366,19 +443,16 @@ dependencies = [
]
[[package]]
name = "paste"
version = "1.0.15"
name = "png"
version = "0.17.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "prettyplease"
version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba"
checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
dependencies = [
"proc-macro2",
"syn",
"bitflags 1.3.2",
"crc32fast",
"fdeflate",
"flate2",
"miniz_oxide",
]
[[package]]
@ -390,6 +464,12 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "quad-rand"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a651516ddc9168ebd67b24afd085a718be02f8858fe406591b013d101ce2f40"
[[package]]
name = "quote"
version = "1.0.37"
@ -399,81 +479,22 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "raylib"
version = "5.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5c54335590d1b6e6fbdbccee09dafdfd76a1111fc3c709eca949e71e81f7a8a"
dependencies = [
"cfg-if",
"paste",
"raylib-sys",
"seq-macro",
"thiserror",
]
[[package]]
name = "raylib-sys"
version = "5.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ce5adc950b042db67f1f78f24f7e76563652ce24db032afe9ca9e534d8b7a13"
dependencies = [
"bindgen",
"cc",
"cmake",
]
[[package]]
name = "redox_syscall"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
dependencies = [
"bitflags",
"bitflags 2.6.0",
]
[[package]]
name = "regex"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.38.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
dependencies = [
"bitflags",
"bitflags 2.6.0",
"errno",
"libc",
"linux-raw-sys",
@ -492,12 +513,6 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "seq-macro"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc"
[[package]]
name = "serde"
version = "1.0.210"
@ -531,10 +546,10 @@ dependencies = [
]
[[package]]
name = "shlex"
version = "1.3.0"
name = "simd-adler32"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
name = "smallvec"
@ -554,24 +569,10 @@ dependencies = [
]
[[package]]
name = "thiserror"
version = "1.0.69"
name = "ttf-parser"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8"
[[package]]
name = "unicode-ident"
@ -579,6 +580,28 @@ version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.52.0"

View file

@ -6,7 +6,8 @@ default-run = "marble-machinations"
[dependencies]
arboard = { version = "3.4.1", default-features = false }
raylib = "5.5"
macroquad = "0.4"
# raylib = "5.5"
serde = { version = "1.0.210", features = ["derive"] }
serde_json = "1.0.128"

View file

@ -1,8 +1,4 @@
use raylib::{
color::Color,
drawing::{RaylibDraw, RaylibDrawHandle},
math::Vector2,
};
use macroquad::{color::colors, prelude::*};
use serde::{Deserialize, Serialize};
use crate::{
@ -71,18 +67,18 @@ impl Board {
}
}
pub fn draw_comments(&self, d: &mut RaylibDrawHandle, offset: Vector2, scale: f32) {
let tile_size = (TILE_TEXTURE_SIZE * scale) as i32;
let font_size = 10 * (scale as i32).max(1);
let line_space = 12 * (scale as i32).max(1);
pub fn draw_comments(&self, offset: Vec2, scale: f32) {
let tile_size = TILE_TEXTURE_SIZE * scale;
let font_size = 10. * scale.max(1.);
let line_space = 12. * scale.max(1.);
for comment in &self.comments {
let x = comment.x * tile_size + offset.x as i32;
let y = comment.y * tile_size + offset.y as i32;
let y = y + (tile_size - font_size) / 2; // center vertically in the grid row
let x = comment.x as f32 * tile_size + offset.x;
let y = comment.y as f32 * tile_size + offset.y;
let y = y + (tile_size - font_size) / 2.; // center vertically in the grid row
for (i, line) in comment.text.lines().enumerate() {
let y = y + line_space * i as i32;
d.draw_text(line, x, y, font_size, Color::ORANGE);
let y = y + line_space * i as f32;
draw_text(line, x, y, font_size, colors::ORANGE);
}
}
}

View file

@ -1,4 +1,4 @@
use raylib::prelude::*;
use macroquad::{color::colors, prelude::*};
use serde::{Deserialize, Serialize};
use crate::{
@ -17,7 +17,7 @@ pub struct Config {
#[serde(default)]
pub show_power_direction: bool,
#[serde(skip)]
scroll_offset: u32,
scroll_offset: f32,
}
pub enum MenuReturn {
@ -29,38 +29,38 @@ pub enum MenuReturn {
impl Config {
#[must_use]
pub fn draw_edit(&mut self, d: &mut RaylibDrawHandle, globals: &mut Globals) -> MenuReturn {
pub fn draw_edit(&mut self, globals: &mut Globals) -> MenuReturn {
match globals.mouse.scroll() {
Some(Scroll::Down) => self.scroll_offset += 64,
Some(Scroll::Up) => self.scroll_offset = self.scroll_offset.saturating_sub(64),
Some(Scroll::Down) => self.scroll_offset += 64.,
Some(Scroll::Up) => self.scroll_offset = (self.scroll_offset - 64.).max(0.),
None => (),
}
let mut y = -(self.scroll_offset as i32) + 15;
d.draw_text("Settings", 16, y, 30, FG_CHAPTER_TITLE);
y += 40;
let mut y = -self.scroll_offset + 15.;
draw_text("Settings", 16., y, 30., FG_CHAPTER_TITLE);
y += 40.;
if text_button(d, &globals.mouse, 10, y, 80, "apply") {
if text_button(&globals.mouse, 10., y, 80., "apply") {
return MenuReturn::StaySave;
}
if text_button(d, &globals.mouse, 100, y, 80, "done") {
if text_button(&globals.mouse, 100., y, 80., "done") {
return MenuReturn::ReturnSave;
}
if text_button(d, &globals.mouse, 190, y, 80, "cancel") {
if text_button(&globals.mouse, 190., y, 80., "cancel") {
return MenuReturn::ReturnCancel;
}
y += 40;
y += 40.;
let mut toggle = |value, text| {
toggle_button((d, &globals.mouse), 10, y, 30, 30, value);
d.draw_text(text, 50, y + 5, 20, Color::WHITE);
y += 40;
toggle_button(&globals.mouse, 10., y, 30., 30., value);
draw_text(text, 50., y + 5., 20., colors::WHITE);
y += 40.;
};
toggle(&mut self.show_power_direction, "show power directions");
toggle(&mut self.show_debug_timing, "show debug timing");
// self.input.update(d);
self.input.draw_edit(d, globals, y);
self.input.draw_edit(globals, y);
MenuReturn::Stay
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,17 +1,12 @@
use std::{collections::BTreeMap, mem::transmute, vec};
use raylib::{
color::Color,
drawing::{RaylibDraw, RaylibDrawHandle},
ffi::{KeyboardKey, MouseButton},
RaylibHandle,
};
use macroquad::{color::colors, prelude::*};
use serde::{Deserialize, Serialize};
use crate::{
theme::{BG_DARK, BG_LIGHT},
ui::text_button,
util::{rect, screen_centered_rect},
util::{draw_rectangle_rec, screen_centered_rect},
Globals,
};
@ -132,89 +127,89 @@ enum BindingEdit {
}
impl Input {
pub fn draw_edit(&mut self, d: &mut RaylibDrawHandle, globals: &mut Globals, mut y: i32) {
pub fn draw_edit(&mut self, globals: &mut Globals, mut y: f32) {
if self.editing_binding.is_some() {
globals.mouse.clear();
}
let buttons_x = 220;
let binding_text_x = buttons_x + 135;
let buttons_x = 220.;
let binding_text_x = buttons_x + 135.;
for action_index in 0..ActionId::SIZE {
let action = ActionId::from_usize(action_index).unwrap();
// if self.action_states[action_index] == BindingState::Pressed {
// d.draw_rectangle(200, y, 20, 20, Color::LIMEGREEN);
// draw_rectangle(200, y, 20, 20, colors::LIMEGREEN);
// }
d.draw_text(&format!("{action:?}"), 16, y, 20, Color::ORANGE);
draw_text(&format!("{action:?}"), 16., y, 20., colors::ORANGE);
for (binding_index, binding) in self.action_bindings[action_index].iter().enumerate() {
if text_button(d, &globals.mouse, buttons_x, y, 80, "remove") {
if text_button(&globals.mouse, buttons_x, y, 80., "remove") {
self.action_bindings[action_index].remove(binding_index);
self.update_modifier_blocks();
return;
}
if text_button(d, &globals.mouse, buttons_x + 85, y, 45, "edit") {
if text_button(&globals.mouse, buttons_x + 85., y, 45., "edit") {
self.editing_binding = Some((action, binding_index, BindingEdit::Init));
}
//
let trigger = format!("{:?}", binding.trigger);
let mut x = binding_text_x;
d.draw_text(&trigger, x, y + 5, 20, Color::LIMEGREEN);
x += 10 + d.measure_text(&trigger, 20);
draw_text(&trigger, x, y + 5., 20., colors::GREEN);
x += 10. + measure_text(&trigger, None, 20, 1.).width;
//
let modifiers = format!("{:?}", binding.modifiers);
d.draw_text(&modifiers, x, y + 5, 20, Color::LIGHTBLUE);
x += 10 + d.measure_text(&modifiers, 20);
draw_text(&modifiers, x, y + 5., 20., colors::BLUE);
x += 10. + measure_text(&modifiers, None, 20, 1.).width;
//
let conflicts = conflicts(&self.action_bindings, binding, action);
if !conflicts.is_empty() {
let conflict_text = format!("also used by: {conflicts:?}");
d.draw_text(&conflict_text, x, y + 5, 20, Color::ORANGERED);
x += 10 + d.measure_text(&conflict_text, 20);
draw_text(&conflict_text, x, y + 5., 20., colors::ORANGE);
x += 10. + measure_text(&conflict_text, None, 20, 1.).width
}
//
if !binding.blocking_modifiers.is_empty() {
let blocking_text = format!("not while: {:?}", binding.blocking_modifiers);
d.draw_text(&blocking_text, x, y + 5, 20, Color::GRAY);
draw_text(&blocking_text, x, y + 5., 20., colors::GRAY);
}
y += 32;
y += 32.;
}
if text_button(d, &globals.mouse, buttons_x, y, 130, "add binding") {
if text_button(&globals.mouse, buttons_x, y, 130., "add binding") {
self.editing_binding = Some((
action,
self.action_bindings[action_index].len(),
BindingEdit::Init,
));
}
y += 45;
y += 45.;
}
if let Some((action, binding_index, edit_state)) = &mut self.editing_binding {
globals.mouse.update(d);
let border = screen_centered_rect(d, 408, 128);
d.draw_rectangle_rec(border, BG_LIGHT);
let bounds = screen_centered_rect(d, 400, 120);
d.draw_rectangle_rec(bounds, BG_DARK);
let x = bounds.x as i32;
let y = bounds.y as i32;
d.draw_text(
globals.mouse.update();
let border = screen_centered_rect(408., 128.);
draw_rectangle_rec(border, BG_LIGHT);
let bounds = screen_centered_rect(400., 120.);
draw_rectangle_rec(bounds, BG_DARK);
let x = bounds.x;
let y = bounds.y;
draw_text(
&format!("editing binding for {action:?}"),
x + 10,
y + 5,
20,
Color::WHITE,
x + 10.,
y + 5.,
20.,
colors::WHITE,
);
let y = y + 30;
let ok_btn_x = x + 10;
let ok_btn_y = y + 40;
let ok_btn_width = 80;
let ok_btn_rect = rect(ok_btn_x, ok_btn_y, ok_btn_width, 30);
let y = y + 30.;
let ok_btn_x = x + 10.;
let ok_btn_y = y + 40.;
let ok_btn_width = 80.;
let ok_btn_rect = Rect::new(ok_btn_x, ok_btn_y, ok_btn_width, 30.);
for key_index in 0..Button::SIZE {
let key = Button::from_usize(key_index).unwrap();
match edit_state {
BindingEdit::Init => {
if key.just_pressed(d) {
if key.just_pressed() {
*edit_state = BindingEdit::Adding(Binding {
blocking_modifiers: Vec::new(),
modifiers: Vec::new(),
@ -223,12 +218,12 @@ impl Input {
}
}
BindingEdit::Adding(binding) => {
if key.just_pressed(d) {
if key.just_pressed() {
if key != binding.trigger && !binding.modifiers.contains(&key) {
binding.modifiers.push(binding.trigger);
binding.trigger = key;
}
} else if key.released(d) {
} else if key.released() {
if let Some(i) = binding.modifiers.iter().position(|&k| k == key) {
binding.modifiers.remove(i);
binding.modifiers.push(binding.trigger);
@ -240,7 +235,7 @@ impl Input {
BindingEdit::Releasing(_binding) => {
let clicking_ok =
globals.mouse.is_over(ok_btn_rect) && key == Button::MouseLeft;
if key.just_pressed(d) && !clicking_ok {
if key.just_pressed() && !clicking_ok {
*edit_state = BindingEdit::Adding(Binding {
blocking_modifiers: Vec::new(),
modifiers: Vec::new(),
@ -253,25 +248,25 @@ impl Input {
if let BindingEdit::Adding(b) | BindingEdit::Releasing(b) = &edit_state {
let colour = if matches!(edit_state, BindingEdit::Releasing(_)) {
Color::GREEN
colors::GREEN
} else {
Color::ORANGE
colors::ORANGE
};
let text = format!("{:?} + {:?}", b.modifiers, b.trigger);
d.draw_text(&text, x + 5, y + 5, 20, colour);
draw_text(&text, x + 5., y + 5., 20., colour);
let conflicts = conflicts(&self.action_bindings, b, *action);
if !conflicts.is_empty() {
d.draw_text(
draw_text(
&format!("conflicts: {conflicts:?}"),
x + 200,
y + 40,
20,
Color::ORANGERED,
x + 200.,
y + 40.,
20.,
colors::ORANGE,
);
}
}
if text_button(d, &globals.mouse, ok_btn_x, ok_btn_y, ok_btn_width, "ok") {
if text_button(&globals.mouse, ok_btn_x, ok_btn_y, ok_btn_width, "ok") {
if let BindingEdit::Releasing(binding) = edit_state {
let binding_list = &mut self.action_bindings[*action as usize];
if *binding_index < binding_list.len() {
@ -283,17 +278,17 @@ impl Input {
self.update_modifier_blocks();
}
}
if text_button(d, &globals.mouse, x + 100, y + 40, 80, "cancel") {
if text_button(&globals.mouse, x + 100., y + 40., 80., "cancel") {
self.editing_binding = None;
}
}
}
pub fn update(&mut self, rl: &RaylibHandle) {
pub fn update(&mut self) {
for i in 0..Button::SIZE {
let button = Button::from_usize(i).unwrap();
let state = &mut self.key_states[i];
*state = if button.is_down(rl) {
*state = if button.is_down() {
match state {
BindingState::Off | BindingState::Released => BindingState::Pressed,
BindingState::Pressed | BindingState::Held => BindingState::Held,
@ -464,10 +459,10 @@ enum Button {
MouseLeft,
MouseRight,
MouseMiddle,
Mouse3,
Mouse4,
Mouse5,
Mouse6,
// Mouse3,
// Mouse4,
// Mouse5,
// Mouse6,
Apostrophe,
Comma,
Minus,
@ -574,14 +569,12 @@ enum Button {
KpEnter,
KpEqual,
Back,
VolumeUp,
VolumeDown,
//
_EnumSize,
}
enum RlInput {
Key(KeyboardKey),
Key(KeyCode),
Mouse(MouseButton),
}
@ -596,146 +589,143 @@ impl Button {
}
}
fn is_down(self, rl: &RaylibHandle) -> bool {
fn is_down(self) -> bool {
match self.to_raylib() {
RlInput::Key(key) => rl.is_key_down(key),
RlInput::Mouse(btn) => rl.is_mouse_button_down(btn),
RlInput::Key(key) => is_key_down(key),
RlInput::Mouse(btn) => is_mouse_button_down(btn),
}
}
fn just_pressed(self, rl: &RaylibHandle) -> bool {
fn just_pressed(self) -> bool {
match self.to_raylib() {
RlInput::Key(key) => rl.is_key_pressed(key),
RlInput::Mouse(btn) => rl.is_mouse_button_pressed(btn),
RlInput::Key(key) => is_key_pressed(key),
RlInput::Mouse(btn) => is_mouse_button_pressed(btn),
}
}
fn released(self, rl: &RaylibHandle) -> bool {
fn released(self) -> bool {
match self.to_raylib() {
RlInput::Key(key) => rl.is_key_released(key),
RlInput::Mouse(btn) => rl.is_mouse_button_released(btn),
RlInput::Key(key) => is_key_released(key),
RlInput::Mouse(btn) => is_mouse_button_released(btn),
}
}
fn to_raylib(self) -> RlInput {
use KeyboardKey::*;
use RlInput::*;
match self {
Button::MouseLeft => Mouse(MouseButton::MOUSE_BUTTON_LEFT),
Button::MouseRight => Mouse(MouseButton::MOUSE_BUTTON_RIGHT),
Button::MouseMiddle => Mouse(MouseButton::MOUSE_BUTTON_MIDDLE),
Button::Mouse3 => Mouse(MouseButton::MOUSE_BUTTON_SIDE),
Button::Mouse4 => Mouse(MouseButton::MOUSE_BUTTON_EXTRA),
Button::Mouse5 => Mouse(MouseButton::MOUSE_BUTTON_FORWARD),
Button::Mouse6 => Mouse(MouseButton::MOUSE_BUTTON_BACK),
Button::Apostrophe => Key(KEY_APOSTROPHE),
Button::Comma => Key(KEY_COMMA),
Button::Minus => Key(KEY_MINUS),
Button::Period => Key(KEY_PERIOD),
Button::Slash => Key(KEY_SLASH),
Button::Zero => Key(KEY_ZERO),
Button::One => Key(KEY_ONE),
Button::Two => Key(KEY_TWO),
Button::Three => Key(KEY_THREE),
Button::Four => Key(KEY_FOUR),
Button::Five => Key(KEY_FIVE),
Button::Six => Key(KEY_SIX),
Button::Seven => Key(KEY_SEVEN),
Button::Eight => Key(KEY_EIGHT),
Button::Nine => Key(KEY_NINE),
Button::Semicolon => Key(KEY_SEMICOLON),
Button::Equal => Key(KEY_EQUAL),
Button::A => Key(KEY_A),
Button::B => Key(KEY_B),
Button::C => Key(KEY_C),
Button::D => Key(KEY_D),
Button::E => Key(KEY_E),
Button::F => Key(KEY_F),
Button::G => Key(KEY_G),
Button::H => Key(KEY_H),
Button::I => Key(KEY_I),
Button::J => Key(KEY_J),
Button::K => Key(KEY_K),
Button::L => Key(KEY_L),
Button::M => Key(KEY_M),
Button::N => Key(KEY_N),
Button::O => Key(KEY_O),
Button::P => Key(KEY_P),
Button::Q => Key(KEY_Q),
Button::R => Key(KEY_R),
Button::S => Key(KEY_S),
Button::T => Key(KEY_T),
Button::U => Key(KEY_U),
Button::V => Key(KEY_V),
Button::W => Key(KEY_W),
Button::X => Key(KEY_X),
Button::Y => Key(KEY_Y),
Button::Z => Key(KEY_Z),
Button::LeftBracket => Key(KEY_LEFT_BRACKET),
Button::Backslash => Key(KEY_BACKSLASH),
Button::RightBracket => Key(KEY_RIGHT_BRACKET),
Button::Grave => Key(KEY_GRAVE),
Button::Space => Key(KEY_SPACE),
Button::Escape => Key(KEY_ESCAPE),
Button::Enter => Key(KEY_ENTER),
Button::Tab => Key(KEY_TAB),
Button::Backspace => Key(KEY_BACKSPACE),
Button::Insert => Key(KEY_INSERT),
Button::Delete => Key(KEY_DELETE),
Button::Right => Key(KEY_RIGHT),
Button::Left => Key(KEY_LEFT),
Button::Down => Key(KEY_DOWN),
Button::Up => Key(KEY_UP),
Button::PageUp => Key(KEY_PAGE_UP),
Button::PageDown => Key(KEY_PAGE_DOWN),
Button::Home => Key(KEY_HOME),
Button::End => Key(KEY_END),
Button::CapsLock => Key(KEY_CAPS_LOCK),
Button::ScrollLock => Key(KEY_SCROLL_LOCK),
Button::NumLock => Key(KEY_NUM_LOCK),
Button::PrintScreen => Key(KEY_PRINT_SCREEN),
Button::Pause => Key(KEY_PAUSE),
Button::F1 => Key(KEY_F1),
Button::F2 => Key(KEY_F2),
Button::F3 => Key(KEY_F3),
Button::F4 => Key(KEY_F4),
Button::F5 => Key(KEY_F5),
Button::F6 => Key(KEY_F6),
Button::F7 => Key(KEY_F7),
Button::F8 => Key(KEY_F8),
Button::F9 => Key(KEY_F9),
Button::F10 => Key(KEY_F10),
Button::F11 => Key(KEY_F11),
Button::F12 => Key(KEY_F12),
Button::LShift => Key(KEY_LEFT_SHIFT),
Button::LCtrl => Key(KEY_LEFT_CONTROL),
Button::LAlt => Key(KEY_LEFT_ALT),
Button::LeftSuper => Key(KEY_LEFT_SUPER),
Button::RShift => Key(KEY_RIGHT_SHIFT),
Button::RCtrl => Key(KEY_RIGHT_CONTROL),
Button::RAlt => Key(KEY_RIGHT_ALT),
Button::RightSuper => Key(KEY_RIGHT_SUPER),
Button::Menu => Key(KEY_KB_MENU),
Button::Kp0 => Key(KEY_KP_0),
Button::Kp1 => Key(KEY_KP_1),
Button::Kp2 => Key(KEY_KP_2),
Button::Kp3 => Key(KEY_KP_3),
Button::Kp4 => Key(KEY_KP_4),
Button::Kp5 => Key(KEY_KP_5),
Button::Kp6 => Key(KEY_KP_6),
Button::Kp7 => Key(KEY_KP_7),
Button::Kp8 => Key(KEY_KP_8),
Button::Kp9 => Key(KEY_KP_9),
Button::KpDecimal => Key(KEY_KP_DECIMAL),
Button::KpDivide => Key(KEY_KP_DIVIDE),
Button::KpMultiply => Key(KEY_KP_MULTIPLY),
Button::KpSubtract => Key(KEY_KP_SUBTRACT),
Button::KpAdd => Key(KEY_KP_ADD),
Button::KpEnter => Key(KEY_KP_ENTER),
Button::KpEqual => Key(KEY_KP_EQUAL),
Button::Back => Key(KEY_BACK),
Button::VolumeUp => Key(KEY_VOLUME_UP),
Button::VolumeDown => Key(KEY_VOLUME_DOWN),
Button::MouseLeft => Mouse(MouseButton::Left),
Button::MouseRight => Mouse(MouseButton::Right),
Button::MouseMiddle => Mouse(MouseButton::Middle),
// Button::Mouse3 => Mouse(MouseButton::MOUSE_BUTTON_SIDE),
// Button::Mouse4 => Mouse(MouseButton::MOUSE_BUTTON_EXTRA),
// Button::Mouse5 => Mouse(MouseButton::MOUSE_BUTTON_FORWARD),
// Button::Mouse6 => Mouse(MouseButton::MOUSE_BUTTON_BACK),
Button::Apostrophe => Key(KeyCode::Apostrophe),
Button::Comma => Key(KeyCode::Comma),
Button::Minus => Key(KeyCode::Minus),
Button::Period => Key(KeyCode::Period),
Button::Slash => Key(KeyCode::Slash),
Button::Zero => Key(KeyCode::Key0),
Button::One => Key(KeyCode::Key1),
Button::Two => Key(KeyCode::Key2),
Button::Three => Key(KeyCode::Key3),
Button::Four => Key(KeyCode::Key4),
Button::Five => Key(KeyCode::Key5),
Button::Six => Key(KeyCode::Key6),
Button::Seven => Key(KeyCode::Key7),
Button::Eight => Key(KeyCode::Key8),
Button::Nine => Key(KeyCode::Key9),
Button::Semicolon => Key(KeyCode::Semicolon),
Button::Equal => Key(KeyCode::Equal),
Button::A => Key(KeyCode::A),
Button::B => Key(KeyCode::B),
Button::C => Key(KeyCode::C),
Button::D => Key(KeyCode::D),
Button::E => Key(KeyCode::E),
Button::F => Key(KeyCode::F),
Button::G => Key(KeyCode::G),
Button::H => Key(KeyCode::H),
Button::I => Key(KeyCode::I),
Button::J => Key(KeyCode::J),
Button::K => Key(KeyCode::K),
Button::L => Key(KeyCode::L),
Button::M => Key(KeyCode::M),
Button::N => Key(KeyCode::N),
Button::O => Key(KeyCode::O),
Button::P => Key(KeyCode::P),
Button::Q => Key(KeyCode::Q),
Button::R => Key(KeyCode::R),
Button::S => Key(KeyCode::S),
Button::T => Key(KeyCode::T),
Button::U => Key(KeyCode::U),
Button::V => Key(KeyCode::V),
Button::W => Key(KeyCode::W),
Button::X => Key(KeyCode::X),
Button::Y => Key(KeyCode::Y),
Button::Z => Key(KeyCode::Z),
Button::LeftBracket => Key(KeyCode::LeftBracket),
Button::Backslash => Key(KeyCode::Backslash),
Button::RightBracket => Key(KeyCode::RightBracket),
Button::Grave => Key(KeyCode::GraveAccent),
Button::Space => Key(KeyCode::Space),
Button::Escape => Key(KeyCode::Escape),
Button::Enter => Key(KeyCode::Enter),
Button::Tab => Key(KeyCode::Tab),
Button::Backspace => Key(KeyCode::Backspace),
Button::Insert => Key(KeyCode::Insert),
Button::Delete => Key(KeyCode::Delete),
Button::Right => Key(KeyCode::Right),
Button::Left => Key(KeyCode::Left),
Button::Down => Key(KeyCode::Down),
Button::Up => Key(KeyCode::Up),
Button::PageUp => Key(KeyCode::PageUp),
Button::PageDown => Key(KeyCode::PageDown),
Button::Home => Key(KeyCode::Home),
Button::End => Key(KeyCode::End),
Button::CapsLock => Key(KeyCode::CapsLock),
Button::ScrollLock => Key(KeyCode::ScrollLock),
Button::NumLock => Key(KeyCode::NumLock),
Button::PrintScreen => Key(KeyCode::PrintScreen),
Button::Pause => Key(KeyCode::Pause),
Button::F1 => Key(KeyCode::F1),
Button::F2 => Key(KeyCode::F2),
Button::F3 => Key(KeyCode::F3),
Button::F4 => Key(KeyCode::F4),
Button::F5 => Key(KeyCode::F5),
Button::F6 => Key(KeyCode::F6),
Button::F7 => Key(KeyCode::F7),
Button::F8 => Key(KeyCode::F8),
Button::F9 => Key(KeyCode::F9),
Button::F10 => Key(KeyCode::F10),
Button::F11 => Key(KeyCode::F11),
Button::F12 => Key(KeyCode::F12),
Button::LShift => Key(KeyCode::LeftShift),
Button::LCtrl => Key(KeyCode::LeftControl),
Button::LAlt => Key(KeyCode::LeftAlt),
Button::LeftSuper => Key(KeyCode::LeftSuper),
Button::RShift => Key(KeyCode::RightShift),
Button::RCtrl => Key(KeyCode::RightControl),
Button::RAlt => Key(KeyCode::RightAlt),
Button::RightSuper => Key(KeyCode::RightSuper),
Button::Menu => Key(KeyCode::Menu),
Button::Kp0 => Key(KeyCode::Kp0),
Button::Kp1 => Key(KeyCode::Kp1),
Button::Kp2 => Key(KeyCode::Kp2),
Button::Kp3 => Key(KeyCode::Kp3),
Button::Kp4 => Key(KeyCode::Kp4),
Button::Kp5 => Key(KeyCode::Kp5),
Button::Kp6 => Key(KeyCode::Kp6),
Button::Kp7 => Key(KeyCode::Kp7),
Button::Kp8 => Key(KeyCode::Kp8),
Button::Kp9 => Key(KeyCode::Kp9),
Button::KpDecimal => Key(KeyCode::KpDecimal),
Button::KpDivide => Key(KeyCode::KpDivide),
Button::KpMultiply => Key(KeyCode::KpMultiply),
Button::KpSubtract => Key(KeyCode::KpSubtract),
Button::KpAdd => Key(KeyCode::KpAdd),
Button::KpEnter => Key(KeyCode::KpEnter),
Button::KpEqual => Key(KeyCode::KpEqual),
Button::Back => Key(KeyCode::Back),
Button::_EnumSize => unreachable!(),
}
}

View file

@ -15,7 +15,7 @@ use std::fs;
use arboard::Clipboard;
use config::Config;
use input::ActionId;
use raylib::{texture::Texture2D, RaylibHandle};
use macroquad::prelude::*;
use util::{userdata_dir, MouseInput, Textures};
// use util::MouseInput;
@ -29,11 +29,11 @@ pub struct Globals {
}
impl Globals {
pub fn new(rl: &mut RaylibHandle, thread: &raylib::prelude::RaylibThread) -> Self {
pub async fn new() -> Self {
let mut textures = Textures::default();
textures.load_dir("assets", rl, thread);
textures.load_dir("assets/tiles", rl, thread);
textures.load_dir("assets/digits", rl, thread);
textures.load_dir("assets").await;
textures.load_dir("assets/tiles").await;
textures.load_dir("assets/digits").await;
let config_path = userdata_dir().join(CONFIG_FILE_NAME);
let mut config: Config = fs::read_to_string(config_path)
@ -52,9 +52,9 @@ impl Globals {
}
}
pub fn update(&mut self, rl: &RaylibHandle) {
self.config.input.update(rl);
self.mouse.update(rl);
pub fn update(&mut self) {
self.config.input.update();
self.mouse.update();
}
pub fn is_pressed(&self, action: ActionId) -> bool {

View file

@ -4,7 +4,7 @@ use std::{
io::Write,
};
use raylib::prelude::*;
use macroquad::{color::colors, miniquad::window::set_mouse_cursor, prelude::*};
use marble_machinations::*;
@ -20,7 +20,7 @@ const TITLE_TEXT: &str = concat!("Marble Machinations v", env!("CARGO_PKG_VERSIO
struct Game {
chapters: Vec<Chapter>,
level_scroll: i32,
level_scroll: f32,
solutions: HashMap<String, Vec<Solution>>,
open_editor: Option<Editor>,
selected_level: (usize, usize),
@ -32,45 +32,43 @@ struct Game {
edit_settings: Option<Config>,
}
fn main() {
let (mut rl, thread) = raylib::init().resizable().title(TITLE_TEXT).build();
rl.set_target_fps(60);
rl.set_window_min_size(640, 480);
rl.set_mouse_cursor(MouseCursor::MOUSE_CURSOR_CROSSHAIR);
rl.set_exit_key(None);
rl.set_trace_log(TraceLogLevel::LOG_WARNING);
#[macroquad::main("what does thsi doa")]
async fn main() {
// let (mut rl, thread) = raylib::init().resizable().title(TITLE_TEXT).build();
// set_target_fps(60);
// set_window_min_size(640, 480);
set_mouse_cursor(miniquad::CursorIcon::Crosshair);
let mut game = Game::new(&mut rl, &thread);
game.run(&mut rl, &thread);
let mut game = Game::new().await;
game.run().await
}
impl Game {
fn new(rl: &mut RaylibHandle, thread: &RaylibThread) -> Self {
async fn new() -> Self {
let solutions = get_solutions();
let chapters = get_chapters(&solutions);
Self {
chapters,
level_scroll: 0,
level_scroll: 0.,
solutions,
open_editor: None,
selected_level: (0, 0),
selected_solution: 0,
delete_solution: None,
editing_solution_name: false,
level_desc_text: ShapedText::new(20),
globals: Globals::new(rl, thread),
level_desc_text: ShapedText::new(20.),
globals: Globals::new().await,
edit_settings: None,
}
}
fn run(&mut self, rl: &mut RaylibHandle, thread: &RaylibThread) {
while !rl.window_should_close() {
let mut d = rl.begin_drawing(thread);
self.globals.update(&d);
async fn run(&mut self) {
loop {
self.globals.update();
if let Some(editor) = &mut self.open_editor {
editor.update(&d, &mut self.globals);
editor.draw(&mut d, &mut self.globals);
editor.update(&mut self.globals);
editor.draw(&mut self.globals);
match editor.get_exit_state() {
ExitState::Dont => (),
ExitState::ExitAndSave => {
@ -90,8 +88,8 @@ impl Game {
}
}
} else if let Some(config) = &mut self.edit_settings {
d.clear_background(BG_DARK);
match config.draw_edit(&mut d, &mut self.globals) {
clear_background(BG_DARK);
match config.draw_edit(&mut self.globals) {
config::MenuReturn::Stay => (),
config::MenuReturn::StaySave => {
self.globals.config = config.clone();
@ -105,65 +103,65 @@ impl Game {
config::MenuReturn::ReturnCancel => self.edit_settings = None,
}
} else {
self.draw(&mut d);
self.draw();
}
next_frame().await
}
}
fn draw(&mut self, d: &mut RaylibDrawHandle) {
d.clear_background(BG_DARK);
fn draw(&mut self) {
clear_background(BG_DARK);
let mut tooltip = Tooltip::default();
tooltip.init_frame(d);
tooltip.init_frame();
d.draw_text(
draw_text(
TITLE_TEXT,
d.get_screen_width() - 275,
d.get_screen_height() - 20,
20,
Color::GRAY,
screen_width() - 275.,
screen_height() - 20.,
20.,
colors::GRAY,
);
let level_list_width = (d.get_screen_width() / 3).min(400);
let screen_height = d.get_screen_height();
d.draw_rectangle(0, 0, level_list_width, screen_height, BG_MEDIUM);
let level_list_width = (screen_width() / 3.).min(400.);
draw_rectangle(0., 0., level_list_width, screen_height(), BG_MEDIUM);
if text_button(
d,
&self.globals.mouse,
d.get_screen_width() - 100,
d.get_screen_height() - 70,
90,
screen_width() - 100.,
screen_height() - 70.,
90.,
"settings",
) {
self.edit_settings = Some(self.globals.config.clone());
}
const ENTRY_SPACING: i32 = 65;
let fit_on_screen = (d.get_screen_height() / ENTRY_SPACING) as usize;
const ENTRY_SPACING: f32 = 65.;
let fit_on_screen = (screen_height() / ENTRY_SPACING) as usize;
let max_scroll = self
.chapters
.iter()
.map(|c| 1 + if c.visible { c.levels.len() } else { 0 })
.sum::<usize>()
.saturating_sub(fit_on_screen) as i32
.saturating_sub(fit_on_screen) as f32
* ENTRY_SPACING;
if self.globals.mouse.pos().x < level_list_width as f32 {
if self.globals.mouse.pos().x < level_list_width {
if self.globals.mouse.scroll() == Some(Scroll::Down) && self.level_scroll < max_scroll {
self.level_scroll += ENTRY_SPACING;
}
if self.globals.mouse.scroll() == Some(Scroll::Up) && self.level_scroll > 0 {
if self.globals.mouse.scroll() == Some(Scroll::Up) && self.level_scroll > 0. {
self.level_scroll -= ENTRY_SPACING;
}
}
let mut y = 10 - self.level_scroll;
let mut y = 10. - self.level_scroll;
for (chapter_i, chapter) in self.chapters.iter_mut().enumerate() {
let bounds = rect(5, y - 5, level_list_width - 10, ENTRY_SPACING - 5);
d.draw_rectangle_rec(bounds, BG_DARK);
d.draw_text(&chapter.title, 10, y, 30, FG_CHAPTER_TITLE);
let bounds = Rect::new(5., y - 5., level_list_width - 10., ENTRY_SPACING - 5.);
draw_rectangle_rec(bounds, BG_DARK);
draw_text(&chapter.title, 10., y, 30., FG_CHAPTER_TITLE);
let subtitle = format!("{} levels", chapter.levels.len());
d.draw_text(&subtitle, 10, y + 30, 20, Color::WHITE);
draw_text(&subtitle, 10., y + 30., 20., colors::WHITE);
y += ENTRY_SPACING;
let clicked_this =
self.globals.mouse.left_click() && self.globals.mouse.is_over(bounds);
@ -177,7 +175,7 @@ impl Game {
}
for (level_index, level) in chapter.levels.iter().enumerate() {
let bounds = rect(5, y - 5, level_list_width - 10, ENTRY_SPACING - 5);
let bounds = Rect::new(5., y - 5., level_list_width - 10., ENTRY_SPACING - 5.);
let clicked_this =
self.globals.mouse.left_click() && self.globals.mouse.is_over(bounds);
@ -191,18 +189,18 @@ impl Game {
self.selected_solution = solutions.len().saturating_sub(1);
}
}
d.draw_rectangle_rec(
draw_rectangle_rec(
bounds,
widget_bg(self.selected_level == (chapter_i, level_index)),
);
let mut title_color = Color::WHITE;
let mut title_color = colors::WHITE;
if let Some(solutions) = self.solutions.get(level.id()) {
if solutions.iter().any(|s| s.score.is_some()) {
title_color = Color::LIGHTGREEN;
title_color = colors::GREEN;
}
}
d.draw_text(level.name(), 10, y, 30, title_color);
draw_text(level.name(), 10., y, 30., title_color);
let solution_count = self
.solutions
.get(level.id())
@ -210,11 +208,11 @@ impl Game {
.unwrap_or_default();
let subtext = format!("solutions: {solution_count}");
let subtext_color = if solution_count > 0 {
Color::GOLD
colors::GOLD
} else {
Color::LIGHTGRAY
colors::LIGHTGRAY
};
d.draw_text(&subtext, 10, y + 30, 20, subtext_color);
draw_text(&subtext, 10., y + 30., 20., subtext_color);
y += ENTRY_SPACING;
}
}
@ -224,25 +222,31 @@ impl Game {
.get(self.selected_level.0)
.and_then(|c| c.levels.get(self.selected_level.1))
{
d.draw_text(level.name(), level_list_width + 10, 10, 40, Color::CYAN);
d.draw_text(level.id(), level_list_width + 10, 50, 10, Color::GRAY);
draw_text(
level.name(),
level_list_width + 10.,
10.,
40.,
colors::SKYBLUE,
);
draw_text(level.id(), level_list_width + 10., 50., 10., colors::GRAY);
let mut y = 70;
let mut y = 70.;
self.level_desc_text.set_text(level.description());
self.level_desc_text
.update_width(d, d.get_render_width() - level_list_width - 30);
self.level_desc_text.draw(d, level_list_width + 10, y);
y += self.level_desc_text.height() + 10;
.update_width(screen_width() - level_list_width - 30.);
self.level_desc_text.draw(level_list_width + 10., y);
y += self.level_desc_text.height() + 10.;
if let Some(solutions) = self.solutions.get_mut(level.id()) {
let solution_entry_height = 40;
let entry_width = 200;
let solution_entry_height = 40.;
let entry_width = 200.;
let mut solution_y = y;
for (solution_index, solution) in solutions.iter().enumerate() {
if simple_option_button(
(d, &self.globals.mouse),
rect(
level_list_width + 10,
&self.globals.mouse,
Rect::new(
level_list_width + 10.,
solution_y,
entry_width,
solution_entry_height,
@ -253,40 +257,39 @@ impl Game {
self.editing_solution_name = false;
}
let name_color = if solution.score.is_some() {
Color::LIME
colors::LIME
} else {
Color::ORANGE
colors::ORANGE
};
d.draw_text(
draw_text(
&solution.name,
level_list_width + 15,
solution_y + 5,
20,
level_list_width + 15.,
solution_y + 5.,
20.,
name_color,
);
d.draw_text(
draw_text(
&solution.score_text(),
level_list_width + 15,
solution_y + 25,
10,
Color::WHITE,
level_list_width + 15.,
solution_y + 25.,
10.,
colors::WHITE,
);
if tex32_button(
(d, &self.globals.mouse),
(level_list_width + entry_width + 15, solution_y + 4),
&self.globals.mouse,
(level_list_width + entry_width + 15., solution_y + 4.),
self.globals.get_tex("cancel"),
(&mut tooltip, "delete"),
) {
self.delete_solution = Some(solution_index);
}
solution_y += solution_entry_height + 10;
solution_y += solution_entry_height + 10.;
}
let next_id = get_free_id(solutions, Solution::id);
if text_button(
d,
&self.globals.mouse,
level_list_width + 10,
level_list_width + 10.,
solution_y,
entry_width,
"new solution",
@ -297,24 +300,23 @@ impl Game {
if let Some(i) = self.delete_solution {
let text = format!("really delete solution '{}'?", &solutions[i].name);
let y = (solution_y + 40).max(240);
let x = level_list_width + 10;
d.draw_text(&text, x, y, 20, Color::ORANGE);
if text_button(d, &self.globals.mouse, x, y + 30, 100, "yes") {
let y = (solution_y + 40.).max(240.);
let x = level_list_width + 10.;
draw_text(&text, x, y, 20., colors::ORANGE);
if text_button(&self.globals.mouse, x, y + 30., 100., "yes") {
solutions[i].remove_file();
solutions.remove(i);
self.delete_solution = None;
}
if text_button(d, &self.globals.mouse, x + 110, y + 30, 100, "no") {
if text_button(&self.globals.mouse, x + 110., y + 30., 100., "no") {
self.delete_solution = None;
}
}
if let Some(solution) = solutions.get_mut(self.selected_solution) {
let column_x = level_list_width + entry_width + 56;
let bounds = Rectangle::new(column_x as f32, y as f32, 220., 30.);
let column_x = level_list_width + entry_width + 56.;
let bounds = Rect::new(column_x, y, 220., 30.);
if text_input(
d,
&mut self.globals,
bounds,
&mut solution.name,
@ -325,18 +327,18 @@ impl Game {
solution.save();
}
let id_text = format!("{}", solution.id());
d.draw_text(&id_text, column_x, y + 35, 10, Color::GRAY);
draw_text(&id_text, column_x, y + 35., 10., colors::GRAY);
if text_button(d, &self.globals.mouse, column_x, y + 50, 220, "clone") {
if text_button(&self.globals.mouse, column_x, y + 50., 220., "clone") {
let cloned = solution.new_copy(next_id);
self.selected_solution = solutions.len();
solutions.push(cloned);
return;
}
if text_button(d, &self.globals.mouse, column_x, y + 85, 220, "edit") {
if text_button(&self.globals.mouse, column_x, y + 85., 220., "edit") {
let mut editor = Editor::new(solution.clone(), level.clone());
editor.center_view(d);
editor.center_view();
self.open_editor = Some(editor);
}
}
@ -344,7 +346,7 @@ impl Game {
self.solutions.insert(level.id().to_owned(), Vec::new());
}
}
tooltip.draw(d);
tooltip.draw();
}
fn save_config(&self) {

View file

@ -1,4 +1,4 @@
use raylib::prelude::*;
use macroquad::prelude::*;
pub mod grid;
pub mod pos;
@ -99,26 +99,23 @@ impl Machine {
self.input = bytes;
}
pub fn draw_marble_values(
&self,
d: &mut RaylibDrawHandle,
textures: &Textures,
offset: Vector2,
scale: f32,
) {
let tile_size = (TILE_TEXTURE_SIZE * scale) as i32;
pub fn draw_marble_values(&self, textures: &Textures, offset: Vec2, scale: f32) {
let tile_size = TILE_TEXTURE_SIZE * scale;
for marble in &self.marbles {
let x = marble.x;
let y = marble.y;
if let Some(tile) = self.grid.get(*marble) {
let px = x as i32 * tile_size + offset.x as i32;
let py = y as i32 * tile_size + offset.y as i32;
let px = x as f32 * tile_size + offset.x;
let py = y as f32 * tile_size + offset.y;
if let Tile::Marble { value, dir } = tile {
let texture = textures.get(dir.arrow_texture_name());
let pos = Vector2::new(px as f32, py as f32);
let faded_white = Color::new(255, 255, 255, 100);
d.draw_texture_ex(texture, pos, 0., scale, faded_white);
draw_usize_small(d, textures, value as usize, px, py, scale);
let tex = textures.get(dir.arrow_texture_name());
let faded_white = Color::from_rgba(255, 255, 255, 100);
let params = DrawTextureParams {
dest_size: Some(Vec2::new(tex.width() * scale, tex.height() * scale)),
..Default::default()
};
draw_texture_ex(tex, px, py, faded_white, params);
draw_usize_small(textures, value as usize, px, py, scale);
}
}
}
@ -544,10 +541,10 @@ impl Machine {
let val_b = self.grid.get_or_blank(pos_b).read_value();
let result = match comp {
Comparison::LessThan => val_a < val_b,
Comparison::GreaterThan => val_a > val_b,
Comparison::Equal => val_a == val_b,
Comparison::NotEqual => val_a != val_b,
Comp::LessThan => val_a < val_b,
Comp::GreaterThan => val_a > val_b,
Comp::Equal => val_a == val_b,
Comp::NotEqual => val_a != val_b,
};
if result {
match self.grid.get_mut(front_pos) {

View file

@ -1,4 +1,4 @@
use raylib::prelude::*;
use macroquad::prelude::*;
use serde::{Deserialize, Serialize};
use super::{tile::*, Pos, PosInt};
@ -285,44 +285,43 @@ impl Grid {
out
}
pub fn draw(
&self,
d: &mut RaylibDrawHandle,
textures: &Textures,
offset: Vector2,
scale: f32,
power_directions: bool,
) {
pub fn draw(&self, textures: &Textures, offset: Vec2, scale: f32, power_directions: bool) {
let tile_size = (TILE_TEXTURE_SIZE * scale) as i32;
let start_x = (-offset.x as i32) / tile_size - 1;
let tiles_width = d.get_screen_width() / tile_size + 3;
let tiles_width = screen_width() as i32 / tile_size + 3;
let start_y = (-offset.y as i32) / tile_size - 1;
let tiles_height = d.get_screen_height() / tile_size + 3;
let tiles_height = screen_height() as i32 / tile_size + 3;
for x in start_x..(start_x + tiles_width) {
for y in start_y..(start_y + tiles_height) {
let px = x * tile_size + offset.x as i32;
let py = y * tile_size + offset.y as i32;
let px = (x * tile_size) as f32 + offset.x;
let py = (y * tile_size) as f32 + offset.y;
if let Some(tile) = self.get((x, y).into()) {
let texname = tile.texture();
if texname.is_empty() {
continue;
}
let texture = textures.get(texname);
draw_scaled_texture(d, texture, px, py, scale);
draw_scaled_texture(texture, px, py, scale);
if power_directions {
if let Tile::Powerable(_, state) = &tile {
for dir in Direction::ALL {
if state.get_dir(dir) {
let texture = textures.get(dir.debug_arrow_texture_name());
draw_scaled_texture(d, texture, px, py, scale);
draw_scaled_texture(texture, px, py, scale);
}
}
}
}
} else {
d.draw_rectangle(px, py, tile_size, tile_size, Color::new(0, 0, 0, 80));
draw_rectangle(
px,
py,
tile_size as _,
tile_size as _,
Color::from_rgba(0, 0, 0, 80),
);
}
}
}

View file

@ -1,6 +1,6 @@
use std::ops::Add;
use raylib::prelude::*;
use macroquad::prelude::*;
use serde::{Deserialize, Serialize};
pub type PosInt = i16;
@ -12,8 +12,8 @@ pub struct Pos {
}
impl Pos {
pub const fn to_vec(self) -> Vector2 {
Vector2 {
pub const fn to_vec(self) -> Vec2 {
Vec2 {
x: self.x as f32,
y: self.y as f32,
}
@ -52,8 +52,8 @@ impl From<(i32, i32)> for Pos {
}
}
impl From<Vector2> for Pos {
fn from(vec: Vector2) -> Self {
impl From<Vec2> for Pos {
fn from(vec: Vec2) -> Self {
Self {
x: vec.x as PosInt,
y: vec.y as PosInt,

View file

@ -31,7 +31,7 @@ pub enum OpenTile {
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PTile {
Comparator(Comparison),
Comparator(Comp),
Math(MathOp),
Silo,
Flipper,
@ -59,7 +59,7 @@ pub enum MathOp {
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Comparison {
pub enum Comp {
LessThan,
GreaterThan,
Equal,
@ -99,10 +99,10 @@ impl Tile {
'v' => Tile::Arrow(Direction::Down),
'<' => Tile::Arrow(Direction::Left),
'>' => Tile::Arrow(Direction::Right),
'=' => Tile::Powerable(PTile::Comparator(Comparison::Equal), Power::OFF),
'!' => Tile::Powerable(PTile::Comparator(Comparison::NotEqual), Power::OFF),
'L' => Tile::Powerable(PTile::Comparator(Comparison::LessThan), Power::OFF),
'G' => Tile::Powerable(PTile::Comparator(Comparison::GreaterThan), Power::OFF),
'=' => Tile::Powerable(PTile::Comparator(Comp::Equal), Power::OFF),
'!' => Tile::Powerable(PTile::Comparator(Comp::NotEqual), Power::OFF),
'L' => Tile::Powerable(PTile::Comparator(Comp::LessThan), Power::OFF),
'G' => Tile::Powerable(PTile::Comparator(Comp::GreaterThan), Power::OFF),
'I' | 'P' => Tile::Powerable(PTile::IO, Power::OFF),
'F' => Tile::Powerable(PTile::Flipper, Power::OFF),
'A' => Tile::Powerable(PTile::Math(MathOp::Add), Power::OFF),
@ -141,10 +141,10 @@ impl Tile {
},
Tile::Powerable(tile, _) => match tile {
PTile::Comparator(comp) => match comp {
Comparison::LessThan => 'L',
Comparison::GreaterThan => 'G',
Comparison::Equal => '=',
Comparison::NotEqual => '!',
Comp::LessThan => 'L',
Comp::GreaterThan => 'G',
Comp::Equal => '=',
Comp::NotEqual => '!',
},
PTile::Math(math) => match math {
MathOp::Add => 'A',
@ -453,49 +453,49 @@ impl MathOp {
}
}
impl Comparison {
impl Comp {
pub const fn human_name(self) -> &'static str {
match self {
Comparison::LessThan => "Comparator: Less than",
Comparison::GreaterThan => "Comparator: Greater than",
Comparison::Equal => "Comparator: Equal",
Comparison::NotEqual => "Comparator: Not Equal",
Comp::LessThan => "Comparator: Less than",
Comp::GreaterThan => "Comparator: Greater than",
Comp::Equal => "Comparator: Equal",
Comp::NotEqual => "Comparator: Not Equal",
}
}
pub const fn texture_name_on(self) -> &'static str {
match self {
Comparison::LessThan => "lt_on",
Comparison::GreaterThan => "gt_on",
Comparison::Equal => "eq_on",
Comparison::NotEqual => "neq_on",
Comp::LessThan => "lt_on",
Comp::GreaterThan => "gt_on",
Comp::Equal => "eq_on",
Comp::NotEqual => "neq_on",
}
}
pub const fn texture_name_off(self) -> &'static str {
match self {
Comparison::LessThan => "lt_off",
Comparison::GreaterThan => "gt_off",
Comparison::Equal => "eq_off",
Comparison::NotEqual => "neq_off",
Comp::LessThan => "lt_off",
Comp::GreaterThan => "gt_off",
Comp::Equal => "eq_off",
Comp::NotEqual => "neq_off",
}
}
pub fn next(&mut self) {
*self = match self {
Comparison::LessThan => Comparison::GreaterThan,
Comparison::GreaterThan => Comparison::Equal,
Comparison::Equal => Comparison::NotEqual,
Comparison::NotEqual => Comparison::LessThan,
Comp::LessThan => Comp::GreaterThan,
Comp::GreaterThan => Comp::Equal,
Comp::Equal => Comp::NotEqual,
Comp::NotEqual => Comp::LessThan,
}
}
pub fn prev(&mut self) {
*self = match self {
Comparison::LessThan => Comparison::NotEqual,
Comparison::GreaterThan => Comparison::LessThan,
Comparison::Equal => Comparison::GreaterThan,
Comparison::NotEqual => Comparison::Equal,
Comp::LessThan => Comp::NotEqual,
Comp::GreaterThan => Comp::LessThan,
Comp::Equal => Comp::GreaterThan,
Comp::NotEqual => Comp::Equal,
}
}
}

View file

@ -1,4 +1,4 @@
use raylib::prelude::*;
use macroquad::prelude::*;
pub const TILE_TEXTURE_SIZE: f32 = 16.0;
@ -12,6 +12,8 @@ pub const BG_WIDGET: Color = gray(64);
pub const BG_WIDGET_ACTIVE: Color = rgb(80, 120, 180);
pub const FG_MARBLE_VALUE: Color = rgb(255, 80, 40);
pub const FG_CHAPTER_TITLE: Color = rgb(255, 160, 40);
pub const SLIDER_FILL: Color = rgb(255, 160, 40);
pub const LIGHTBLUE: Color = rgb(80, 190, 230);
pub const fn widget_bg(highlight: bool) -> Color {
if highlight {
@ -22,9 +24,9 @@ pub const fn widget_bg(highlight: bool) -> Color {
}
pub const fn rgb(r: u8, g: u8, b: u8) -> Color {
Color::new(r, g, b, 255)
Color::from_rgba(r, g, b, 255)
}
pub const fn gray(value: u8) -> Color {
Color::new(value, value, value, 255)
Color::from_rgba(value, value, value, 255)
}

298
src/ui.rs
View file

@ -2,25 +2,25 @@ use std::ops::Range;
use crate::{
theme::*,
util::{draw_scaled_texture, rect, MouseInput, Scroll, Textures},
util::{draw_rectangle_rec, draw_scaled_texture, MouseInput, Scroll, Textures},
Globals,
};
use raylib::prelude::*;
use macroquad::{color::colors, prelude::*};
#[derive(Debug)]
pub struct ShapedText {
text: String,
max_width: i32,
font_size: i32,
max_width: f32,
font_size: f32,
lines: Vec<Range<usize>>,
}
impl ShapedText {
pub fn new(font_size: i32) -> Self {
pub fn new(font_size: f32) -> Self {
Self {
text: String::new(),
font_size,
max_width: 500,
max_width: 500.,
lines: Vec::new(),
}
}
@ -32,11 +32,11 @@ impl ShapedText {
}
}
pub fn height(&self) -> i32 {
self.font_size * self.lines.len() as i32
pub fn height(&self) -> f32 {
self.font_size * self.lines.len() as f32
}
pub fn update_width(&mut self, d: &RaylibHandle, width: i32) {
pub fn update_width(&mut self, width: f32) {
if self.max_width == width && !self.lines.is_empty() {
return;
}
@ -48,7 +48,7 @@ impl ShapedText {
for (i, c) in self.text.char_indices() {
if c == ' ' {
let line = &self.text[line_start..i];
let new_line_length = d.measure_text(line, self.font_size);
let new_line_length = measure_text(line, None, self.font_size as _, 1.).width;
if new_line_length <= self.max_width {
line_end = i;
} else {
@ -58,7 +58,7 @@ impl ShapedText {
}
if c == '\n' {
let line = &self.text[line_start..i];
let new_line_length = d.measure_text(line, self.font_size);
let new_line_length = measure_text(line, None, self.font_size as _, 1.).width;
if new_line_length <= self.max_width {
self.lines.push(line_start..i);
line_end = i + 1;
@ -73,7 +73,7 @@ impl ShapedText {
}
let i = self.text.len();
let line = &self.text[line_start..i];
let new_line_length = d.measure_text(line, self.font_size);
let new_line_length = measure_text(line, None, self.font_size as _, 1.).width;
if new_line_length <= self.max_width {
self.lines.push(line_start..i);
} else {
@ -82,12 +82,12 @@ impl ShapedText {
}
}
pub fn draw(&self, d: &mut RaylibDrawHandle, x: i32, y: i32) {
// d.draw_rectangle(x, y, self.max_width, 4, Color::RED);
pub fn draw(&self, x: f32, y: f32) {
// draw_rectangle(x, y, self.max_width, 4, Color::RED);
for (i, line) in self.lines.iter().enumerate() {
let line = &self.text[line.clone()];
let line_y = y + self.font_size * i as i32;
d.draw_text(line, x, line_y, self.font_size, Color::WHITE);
let line_y = y + self.font_size * i as f32;
draw_text(line, x, line_y, self.font_size, colors::WHITE);
}
}
}
@ -95,25 +95,25 @@ impl ShapedText {
#[derive(Debug, Default)]
pub struct Tooltip {
text: Option<&'static str>,
mouse_x: i32,
mouse_y: i32,
screen_width: i32,
screen_height: i32,
mouse_x: f32,
mouse_y: f32,
screen_width: f32,
screen_height: f32,
}
impl Tooltip {
pub fn init_frame(&mut self, d: &RaylibHandle) {
let p = d.get_mouse_position();
pub fn init_frame(&mut self) {
let (mouse_x, mouse_y) = mouse_position();
*self = Self {
text: None,
mouse_x: p.x as i32,
mouse_y: p.y as i32,
screen_width: d.get_screen_width(),
screen_height: d.get_screen_height(),
mouse_x,
mouse_y,
screen_width: screen_width(),
screen_height: screen_height(),
};
}
pub fn add(&mut self, x: i32, y: i32, width: i32, height: i32, text: &'static str) {
pub fn add(&mut self, x: f32, y: f32, width: f32, height: f32, text: &'static str) {
if self.mouse_x >= x
&& self.mouse_y >= y
&& self.mouse_x <= (x + width)
@ -127,122 +127,91 @@ impl Tooltip {
self.text = None;
}
pub fn add_rec(&mut self, bounds: Rectangle, text: &'static str) {
self.add(
bounds.x as i32,
bounds.y as i32,
bounds.width as i32,
bounds.height as i32,
text,
);
pub fn add_rec(&mut self, bounds: Rect, text: &'static str) {
self.add(bounds.x, bounds.y, bounds.w, bounds.h, text);
}
pub fn draw(&self, d: &mut RaylibDrawHandle) {
pub fn draw(&self) {
if let Some(text) = self.text {
let font_size = 20;
let margin = 4;
let text_width = d.measure_text(text, font_size);
let font_size = 20.0;
let margin = 4.0;
let text_width = measure_text(text, None, font_size as _, 1.).width;
let x = self
.mouse_x
.min(self.screen_width - text_width - margin * 2);
.min(self.screen_width - text_width - margin * 2.);
let y = self
.mouse_y
.min(self.screen_height - font_size - margin * 2);
d.draw_rectangle(
.min(self.screen_height - font_size - margin * 2.);
draw_rectangle(
x,
y,
text_width + margin * 2,
font_size + margin * 2,
text_width + margin * 2.,
font_size + margin * 2.,
BG_LIGHT,
);
d.draw_text(text, x + margin, y + margin, font_size, Color::WHITE);
draw_text(text, x + margin, y + margin, font_size, colors::WHITE);
}
}
}
pub fn toggle_button(
(d, mouse): (&mut RaylibDrawHandle, &MouseInput),
x: i32,
y: i32,
width: i32,
height: i32,
val: &mut bool,
) {
let margin = 5;
pub fn toggle_button(mouse: &MouseInput, x: f32, y: f32, width: f32, height: f32, val: &mut bool) {
let margin = 5.;
let mouse_pos = mouse.pos();
let bounds = rect(x, y, width, height);
let bounds = Rect::new(x, y, width, height);
let hover = bounds.check_collision_point_rec(mouse_pos);
d.draw_rectangle(x, y, width, height, widget_bg(hover));
let hover = bounds.contains(mouse_pos);
draw_rectangle(x, y, width, height, widget_bg(hover));
let pressed = hover && mouse.left_click();
if pressed {
*val = !*val;
}
if *val {
d.draw_rectangle(
draw_rectangle(
x + margin,
y + margin,
width - margin * 2,
height - margin * 2,
Color::WHITE,
width - margin * 2.,
height - margin * 2.,
colors::WHITE,
);
}
}
pub fn simple_button(
(d, mouse): (&mut RaylibDrawHandle, &MouseInput),
x: i32,
y: i32,
width: i32,
height: i32,
) -> bool {
pub fn simple_button(mouse: &MouseInput, x: f32, y: f32, width: f32, height: f32) -> bool {
let mouse_pos = mouse.pos();
let bounds = rect(x, y, width, height);
let hover = bounds.check_collision_point_rec(mouse_pos);
let bounds = Rect::new(x, y, width, height);
let hover = bounds.contains(mouse_pos);
let pressed = hover && mouse.left_click();
d.draw_rectangle(x, y, width, height, widget_bg(hover));
draw_rectangle(x, y, width, height, widget_bg(hover));
pressed
}
pub fn text_button(
d: &mut RaylibDrawHandle,
mouse: &MouseInput,
x: i32,
y: i32,
width: i32,
text: &str,
) -> bool {
let font_size = 20;
let margin = font_size / 4;
let height = font_size + margin * 2;
let clicked = simple_button((d, mouse), x, y, width, height);
d.draw_text(text, x + margin, y + margin, font_size, Color::WHITE);
pub fn text_button(mouse: &MouseInput, x: f32, y: f32, width: f32, text: &str) -> bool {
let font_size = 20.;
let margin = font_size / 4.;
let height = font_size + margin * 2.;
let clicked = simple_button(mouse, x, y, width, height);
draw_text(text, x + margin, y + margin, font_size, colors::WHITE);
clicked
}
pub fn tex32_button(
(d, mouse): (&mut RaylibDrawHandle, &MouseInput),
(x, y): (i32, i32),
mouse: &MouseInput,
(x, y): (f32, f32),
texture: &Texture2D,
(tooltip, text): (&mut Tooltip, &'static str),
) -> bool {
let size = 32;
let clicked = simple_button((d, mouse), x, y, 32, 32);
draw_scaled_texture(d, texture, x, y, 2.);
let size = 32.;
let clicked = simple_button(mouse, x, y, size, size);
draw_scaled_texture(texture, x, y, 2.);
tooltip.add(x, y, size, size, text);
clicked
}
pub fn simple_option_button<T>(
(d, mouse): (&mut RaylibDrawHandle, &MouseInput),
bounds: Rectangle,
option: T,
current: &mut T,
) -> bool
pub fn simple_option_button<T>(mouse: &MouseInput, bounds: Rect, option: T, current: &mut T) -> bool
where
T: PartialEq,
{
d.draw_rectangle_rec(bounds, widget_bg(&option == current));
draw_rectangle_rec(bounds, widget_bg(&option == current));
let mut changed = false;
if mouse.left_click() && mouse.is_over(bounds) && current != &option {
*current = option;
@ -252,42 +221,33 @@ where
}
pub fn text_input(
d: &mut RaylibDrawHandle,
globals: &mut Globals,
bounds: Rectangle,
bounds: Rect,
text: &mut String,
is_selected: &mut bool,
max_len: usize,
editable: bool,
) -> bool {
let mut changed = false;
let font_size = 20;
d.draw_rectangle_rec(bounds, widget_bg(*is_selected));
d.draw_rectangle_rec(
Rectangle::new(
bounds.x + 2.,
bounds.y + bounds.height - 5.,
bounds.width - 4.,
3.,
),
let font_size = 20.;
draw_rectangle_rec(bounds, widget_bg(*is_selected));
draw_rectangle(
bounds.x + 2.,
bounds.y + bounds.h - 5.,
bounds.w - 4.,
3.,
BG_DARK,
);
d.draw_text(
text,
bounds.x as i32 + 4,
bounds.y as i32 + 4,
font_size,
Color::WHITE,
);
draw_text(text, bounds.x + 4., bounds.y + 4., font_size, colors::WHITE);
// blinking cursor
if *is_selected && d.get_time().fract() < 0.5 {
let width = d.measure_text(text, font_size);
d.draw_rectangle(
bounds.x as i32 + 6 + width,
bounds.y as i32 + 4,
2,
if *is_selected && get_time().fract() < 0.5 {
let width = measure_text(text, None, font_size as _, 1.).width;
draw_rectangle(
bounds.x + 6. + width,
bounds.y + 4.,
2.,
font_size,
Color::WHITE,
colors::WHITE,
);
};
if editable && globals.mouse.left_click() && (globals.mouse.is_over(bounds) || *is_selected) {
@ -296,13 +256,13 @@ pub fn text_input(
if *is_selected {
globals.config.input.in_text_edit = true;
if d.is_key_pressed(KeyboardKey::KEY_ESCAPE) || d.is_key_pressed(KeyboardKey::KEY_ENTER) {
if is_key_pressed(KeyCode::Escape) || is_key_pressed(KeyCode::Enter) {
*is_selected = false;
}
if d.is_key_pressed(KeyboardKey::KEY_BACKSPACE) && !text.is_empty() {
if is_key_pressed(KeyCode::Backspace) && !text.is_empty() {
changed = true;
text.pop();
if d.is_key_down(KeyboardKey::KEY_LEFT_CONTROL) {
if is_key_down(KeyCode::LeftControl) {
while let Some(c) = text.pop() {
if c == ' ' {
break;
@ -311,12 +271,7 @@ pub fn text_input(
}
}
if text.len() < max_len {
let char_code = unsafe { ffi::GetCharPressed() };
let c = if char_code > 0 {
char::from_u32(char_code as u32)
} else {
None
};
let c = get_char_pressed();
if let Some(c) = c {
changed = true;
text.push(c);
@ -327,8 +282,8 @@ pub fn text_input(
}
pub fn scrollable_texture_option_button<T>(
(d, mouse): (&mut RaylibDrawHandle, &MouseInput),
pos: Vector2,
mouse: &MouseInput,
pos: Vec2,
texture: &Texture2D,
option: T,
current: &mut T,
@ -338,13 +293,8 @@ pub fn scrollable_texture_option_button<T>(
where
T: PartialEq,
{
let bounds = Rectangle {
x: pos.x,
y: pos.y,
width: 32. + border * 2.,
height: 32. + border * 2.,
};
d.draw_rectangle_rec(
let bounds = Rect::new(pos.x, pos.y, 32. + border * 2., 32. + border * 2.);
draw_rectangle_rec(
bounds,
if &option == current {
BG_WIDGET_ACTIVE
@ -352,12 +302,16 @@ where
gray(16)
},
);
d.draw_texture_ex(
let params = DrawTextureParams {
dest_size: Some(Vec2::splat(32.)),
..Default::default()
};
draw_texture_ex(
texture,
pos + Vector2::new(border, border),
0.,
32. / texture.width as f32,
Color::WHITE,
pos.x + border,
pos.y + border,
colors::WHITE,
params,
);
if clicked_override {
*current = option;
@ -371,34 +325,32 @@ where
}
pub fn draw_usize(
d: &mut RaylibDrawHandle,
textures: &Textures,
mut number: usize,
(x, y): (i32, i32),
digits: i32,
scale: i32,
(x, y): (f32, f32),
digits: u8,
scale: f32,
) {
for i in 0..digits {
d.draw_rectangle(x + 10 * i * scale, y, 8 * scale, 16 * scale, BG_LIGHT);
draw_rectangle(
x + 10. * i as f32 * scale,
y,
8. * scale,
16. * scale,
BG_LIGHT,
);
}
let mut i = 0;
while (number != 0 || i == 0) && i < digits {
let texture = textures.get(&format!("digit_{}", number % 10));
let x = x + (digits - i - 1) * 10 * scale;
draw_scaled_texture(d, texture, x, y, scale as f32);
let x = x + (digits - i - 1) as f32 * 10. * scale;
draw_scaled_texture(texture, x, y, scale);
number /= 10;
i += 1;
}
}
pub fn draw_usize_small(
d: &mut RaylibDrawHandle,
textures: &Textures,
mut num: usize,
mut x: i32,
y: i32,
scale: f32,
) {
pub fn draw_usize_small(textures: &Textures, mut num: usize, mut x: f32, y: f32, scale: f32) {
const MAX_DIGITS: usize = 8;
let mut digits = [0; MAX_DIGITS];
let mut i = 0;
@ -409,31 +361,29 @@ pub fn draw_usize_small(
}
let texture = textures.get("digits_small");
for &digit in &digits[(MAX_DIGITS - i)..] {
let source = Rectangle::new(4. * digit as f32, 0., 4., 6.);
let dest = Rectangle::new(x as f32, y as f32, 4. * scale, 6. * scale);
d.draw_texture_pro(texture, source, dest, Vector2::zero(), 0., FG_MARBLE_VALUE);
x += 4 * scale as i32;
let source = Rect::new(4. * digit as f32, 0., 4., 6.);
let params = DrawTextureParams {
dest_size: Some(Vec2::new(4. * scale, 6. * scale)),
source: Some(source),
..Default::default()
};
draw_texture_ex(texture, x, y, FG_MARBLE_VALUE, params);
x += 4. * scale;
}
}
pub fn slider(
(d, mouse): (&mut RaylibDrawHandle, &MouseInput),
bounds: Rectangle,
value: &mut u8,
min: u8,
max: u8,
) -> bool {
pub fn slider(mouse: &MouseInput, bounds: Rect, value: &mut u8, min: u8, max: u8) -> bool {
// draw state
// the +1 makes the lowest state look slightly filled and the max state fully filled
let percent = (*value - min + 1) as f32 / (max - min + 1) as f32;
d.draw_rectangle_rec(bounds, BG_WIDGET);
draw_rectangle_rec(bounds, BG_WIDGET);
let mut filled_bounds = bounds;
filled_bounds.width *= percent;
d.draw_rectangle_rec(filled_bounds, Color::CYAN);
filled_bounds.w *= percent;
draw_rectangle_rec(filled_bounds, SLIDER_FILL);
// interaction
if mouse.is_over(bounds) {
if mouse.left_hold() {
let percent = (mouse.pos().x - bounds.x) / bounds.width;
let percent = (mouse.pos().x - bounds.x) / bounds.w;
let new_value = min + (percent * (max - min + 1) as f32) as u8;
if *value != new_value {
*value = new_value;

View file

@ -1,6 +1,6 @@
use std::{collections::HashMap, fs::read_dir, path::PathBuf};
use raylib::prelude::*;
use macroquad::{color::colors, prelude::*};
#[derive(Default)]
pub struct Textures {
@ -8,14 +8,13 @@ pub struct Textures {
}
impl Textures {
pub fn load_dir(&mut self, folder: &str, rl: &mut RaylibHandle, thread: &RaylibThread) {
pub async fn load_dir(&mut self, folder: &str) {
for d in read_dir(folder).unwrap().flatten() {
let path = d.path();
if path.is_file() {
let name = path.file_stem().unwrap().to_string_lossy();
let texture = rl
.load_texture(thread, &format!("{folder}/{name}.png"))
.unwrap();
let texture = load_texture(&format!("{folder}/{name}.png")).await.unwrap();
self.map.insert(name.to_string(), texture);
}
}
@ -32,15 +31,24 @@ pub fn userdata_dir() -> PathBuf {
PathBuf::from("user")
}
pub fn draw_scaled_texture(
d: &mut RaylibDrawHandle,
texture: &Texture2D,
x: i32,
y: i32,
scale: f32,
) {
let pos = Vector2::new(x as f32, y as f32);
d.draw_texture_ex(texture, pos, 0., scale, Color::WHITE);
pub fn draw_rectangle_rec(bounds: Rect, color: Color) {
draw_rectangle(bounds.x, bounds.y, bounds.w, bounds.h, color);
}
pub fn draw_scaled_texture_c(texture: &Texture2D, x: f32, y: f32, scale: f32, color: Color) {
let params = DrawTextureParams {
dest_size: Some(Vec2::new(texture.width() * scale, texture.height() * scale)),
..Default::default()
};
draw_texture_ex(texture, x, y, color, params);
}
pub fn draw_scaled_texture(texture: &Texture2D, x: f32, y: f32, scale: f32) {
let params = DrawTextureParams {
dest_size: Some(Vec2::new(texture.width() * scale, texture.height() * scale)),
..Default::default()
};
draw_texture_ex(texture, x, y, colors::WHITE, params);
}
pub fn get_free_id<T>(items: &[T], id_fn: fn(&T) -> usize) -> usize {
@ -51,31 +59,21 @@ pub fn get_free_id<T>(items: &[T], id_fn: fn(&T) -> usize) -> usize {
id
}
pub fn screen_centered_rect(rl: &RaylibHandle, width: i32, height: i32) -> Rectangle {
let w = rl.get_screen_width();
let h = rl.get_screen_height();
Rectangle {
x: (w / 2 - width / 2) as f32,
y: (h / 2 - height / 2) as f32,
width: width as f32,
height: height as f32,
}
pub fn screen_centered_rect(width: f32, height: f32) -> Rect {
let w = screen_width();
let h = screen_height();
Rect::new(w / 2. - width / 2., h / 2. - height / 2., width, height)
}
pub fn screen_centered_rect_dyn(rl: &RaylibHandle, margin_x: i32, margin_y: i32) -> Rectangle {
let w = rl.get_screen_width();
let h = rl.get_screen_height();
Rectangle {
x: margin_x as f32,
y: margin_y as f32,
width: (w - margin_x * 2) as f32,
height: (h - margin_y * 2) as f32,
}
pub fn screen_centered_rect_dyn(margin_x: f32, margin_y: f32) -> Rect {
let w = screen_width();
let h = screen_height();
Rect::new(margin_x, margin_y, w - margin_x * 2., h - margin_y * 2.)
}
#[derive(Debug, Default)]
pub struct MouseInput {
pos: Vector2,
pos: Vec2,
left_click: bool,
left_hold: bool,
left_release: bool,
@ -84,24 +82,24 @@ pub struct MouseInput {
}
impl MouseInput {
pub fn update(&mut self, rl: &RaylibHandle) {
self.pos = rl.get_mouse_position();
self.left_click = rl.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_LEFT);
self.left_hold = rl.is_mouse_button_down(MouseButton::MOUSE_BUTTON_LEFT);
self.left_release = rl.is_mouse_button_released(MouseButton::MOUSE_BUTTON_LEFT);
self.right_hold = rl.is_mouse_button_down(MouseButton::MOUSE_BUTTON_RIGHT);
self.scroll = get_scroll(rl);
pub fn update(&mut self) {
self.pos = mouse_position().into();
self.left_click = is_mouse_button_pressed(MouseButton::Left);
self.left_hold = is_mouse_button_down(MouseButton::Left);
self.left_release = is_mouse_button_released(MouseButton::Left);
self.right_hold = is_mouse_button_down(MouseButton::Right);
self.scroll = get_scroll();
}
pub fn is_over(&self, rect: Rectangle) -> bool {
rect.check_collision_point_rec(self.pos)
pub fn is_over(&self, rect: Rect) -> bool {
rect.contains(self.pos)
}
pub fn clear(&mut self) {
*self = Self::default();
}
pub fn pos(&self) -> Vector2 {
pub fn pos(&self) -> Vec2 {
self.pos
}
@ -132,9 +130,9 @@ pub enum Scroll {
Down,
}
pub fn get_scroll(rl: &RaylibHandle) -> Option<Scroll> {
pub fn get_scroll() -> Option<Scroll> {
const SCROLL_THRESHOLD: f32 = 0.5;
let value = rl.get_mouse_wheel_move();
let value = mouse_wheel().0;
if value > SCROLL_THRESHOLD {
Some(Scroll::Up)
} else if value < -SCROLL_THRESHOLD {
@ -143,7 +141,3 @@ pub fn get_scroll(rl: &RaylibHandle) -> Option<Scroll> {
None
}
}
pub fn rect(x: i32, y: i32, width: i32, height: i32) -> Rectangle {
Rectangle::new(x as f32, y as f32, width as f32, height as f32)
}