Crates.io | laststraw |
lib.rs | laststraw |
version | |
source | src |
created_at | 2025-01-30 00:30:21.833714 |
updated_at | 2025-02-02 00:27:04.879345 |
description | A lightweight GUI Rust framework for quick desktop applications. |
homepage | |
repository | https://github.com/had2020/Last-Straw |
max_upload_size | |
id | 1535985 |
Cargo.toml error: | TOML parse error at line 18, column 1 | 18 | autolib = false | ^^^^^^^ unknown field `autolib`, expected one of `name`, `version`, `edition`, `authors`, `description`, `readme`, `license`, `repository`, `homepage`, `documentation`, `build`, `resolver`, `links`, `default-run`, `default_dash_run`, `rust-version`, `rust_dash_version`, `rust_version`, `license-file`, `license_dash_file`, `license_file`, `licenseFile`, `license_capital_file`, `forced-target`, `forced_dash_target`, `autobins`, `autotests`, `autoexamples`, `autobenches`, `publish`, `metadata`, `keywords`, `categories`, `exclude`, `include` |
size | 0 |
Ideomatic Simple GUI framework with only Minifb and Freetype-sys
Enjoyed the project? Leaving a Star means the world âïļ
firstly this libary depends on the developer installing freetype2
Installing C library freetype in package manager for ðĶ Rust.
$ macos ð
brew install freetype
$ Linux ð§
sudo apt-get install libfreetype6-dev
$ Windows ðŠ
ð Note: you will likely need to use GNUWin32 to compile, or someother package manager like Choco! Read: https://github.com/PistonDevelopers/freetype-sys?tab=readme-ov-file for more
Or with the Choco package manager.
choco install freetype
Installing the Crate.
cargo add laststraw
use laststraw::*;
fn main() {
let mut app = App::new(500, 500, "test"); // app variable, must be only a single one named app, which is mutable.
asx!({ // runs every frame while, app.should_close == false.
single_line_text(&mut app, position!(20.0, 20.0, 40.0), "Hello"); // shows Hello on the screen
set_next_button(&mut app, position!(30.0, 30.0, 30.0)); // this code is layer dependent
set_next_button_text(&mut app, "helq");
button!({
single_line_text(
&mut app,
position!(20.0, 20.0, 40.0),
"You clicked the button",
);
println!("Button press logged!");
});
});
println!("app closed after window code."); // last line of code, like in a normal rust program, EVEN if the user exited with exit button.
// FAILS only if force exit by task manager alike program.
}
Make sure to add dependencies in Cargo.toml
cargo add freetype-rs@0.37.0
cargo add minifb@0.27.0
cargo add rusttype@0.9.3
cargo add quote@1.0.38
cargo add syn@2.0.92 --features full
firstly, I use the App stuct to hold all of are current app window's infomation, i.e, size height, and some more that were needed from the minifb framework. A variable must be set with the name app and the impl of new. Just like the code seen below.
let mut app = App::new(500, 500, "test");
asx is similar in dioxus and react. Every frame it will print "app_loop". Code here is looped, here is where you can add UI elements like single_line_text();
asx!({ println!("app_loop") })
Any element must be declared inside the asx!
Gui elements are layered as they are declared, the lowest is at the top. For example multi_line_text(), would be furtherest to the back.
asx!({
set_window_color(&mut app, "Obsidian"); // undermost layer
let lines: Vec<&str> = vec!["Apple fruit", "Banana", "Cherry pie", "Oreos"];
multi_line_text(&mut app, position!(100.0, 100.0, 50.0), 50.0, lines); // topmost layer
})
used for setting location of a element on the screen. Made up of X: Height, Y: Weight, and Scale.
You can make one the position macro as seen below, or just write out the stuct for readablity.
position!(20.0, 20.0, 40.0)
OR
Position { x: 10.0, y: 10.0, scale: 50.0, }
for readablity
if app variables are updated, then we need to own a mut borrow, &mut app. Other's only borrow ownership like checking for input_pressed().
single_line_text(&mut app, position!(20.0, 20.0, 40.0), "You pressed space");
let lines: Vec<&str> = vec!["Apple fruit", "Banana", "Cherry pie", "Oreos"]; // every new line is a index
multi_line_text(&mut app, position!(100.0, 100.0, 50.0), 50.0, lines); // lines needs index in a Vec<&str>
Proc Macro which only runs the code inside one clicked. Similar to asx!
button!({
println!("button is pressed");
});
let texty: String = editable_lines(
&mut app, // mut app stuct variable created by new impl on App.
position!(100.0, 50.0, 50.0), // position struct created by macro.
"enter:", // preluding text.
"Blue", // color of the boarder.
false, // if you wish for only single line input.
);
place before a Interactable text element to set initial text, which stays after clicking the element.
pub fn set_next_input_init_text(app: &mut App, init_text: &str) {
if app.already_set_initial_text == true {
app.multi_line_storing[app.current_text_edit_id][1] = init_text.to_string();
}
}
if input_pressed(&app, "space") {
single_line_text(&mut app, position!(20.0, 20.0, 40.0), "Hello");
}
TIP make sure this is the futherest back, because it writes over the whole screen buffer. Sets the color of the background.
set_window_color(&mut app, "Obsidian");
Note: this is optional, and used to reduce CPU usage for much heavy apps, with many elements.
limit_fps(&mut app, 60.0); // a nice 60 frames per a second, 30-60 is a good number.
app.should_close = true; // closes app at line.
This is a example of a base plate for a app, in this framework.
use laststraw::*;
fn main() {
let mut app = App::new(500, 500, "test"); // app variable, must be only a single one named app, which is mutable.
asx!({ // runs every frame while, app.should_close == false.
single_line_text(&mut app, position!(20.0, 20.0, 40.0), "Hello"); // shows Hello on the screen
if input_pressed(&app, "esc") { // if the esc key is pressed the inside code runs.
app.should_close = true; // stops the asx loop to end.
}
});
println!("app closed after window code."); // last line of code, like in a normal rust program, EVEN if the user exited with exit button.
// FAILS only if force exit by task manager alike program.
}
ðĢ Symbol | ðŪ Key Mapping |
---|---|
â esc | Key::Escape |
1ïļâĢ 1 | Key::Key1 |
2ïļâĢ 2 | Key::Key2 |
3ïļâĢ 3 | Key::Key3 |
4ïļâĢ 4 | Key::Key4 |
5ïļâĢ 5 | Key::Key5 |
6ïļâĢ 6 | Key::Key6 |
7ïļâĢ 7 | Key::Key7 |
8ïļâĢ 8 | Key::Key8 |
9ïļâĢ 9 | Key::Key9 |
0ïļâĢ 0 | Key::Key0 |
ð °ïļ a | Key::A |
ð ąïļ b | Key::B |
ðĻ c | Key::C |
ðĐ d | Key::D |
ðŠ e | Key::E |
ðŦ f | Key::F |
ðŽ g | Key::G |
ð h | Key::H |
ðŪ i | Key::I |
ðŊ j | Key::J |
ð° k | Key::K |
ðą l | Key::L |
ðē m | Key::M |
ðģ n | Key::N |
ðī o | Key::O |
ð ŋïļ p | Key::P |
ðķ q | Key::Q |
ð· r | Key::R |
ðļ s | Key::S |
ðđ t | Key::T |
ðš u | Key::U |
ðŧ v | Key::V |
ðž w | Key::W |
â x | Key::X |
ðū y | Key::Y |
ðŋ z | Key::Z |
âĢ space | Key::Space |
âĩ enter | Key::Enter |
âĨ tab | Key::Tab |
âŦ backspace | Key::Backspace |
âïļ left | Key::Left |
âķïļ right | Key::Right |
ðž up | Key::Up |
ð― down | Key::Down |
⧠left_shift | Key::LeftShift |
⧠right_shift | Key::RightShift |
â left_ctrl | Key::LeftCtrl |
â right_ctrl | Key::RightCtrl |
â left_alt | Key::LeftAlt |
â right_alt | Key::RightAlt |
ðĒ ; | Key::Semicolon |
ðïļ ' | Key::Apostrophe |
ðĨ , | Key::Comma |
. | Key::Period |
â / | Key::Slash |
⎠backslash | Key::Backslash |
ðïļ left_bracket | Key::LeftBracket |
ð right_bracket | Key::RightBracket |
â - | Key::Minus |
â + | Key::Equal |
ð caps_lock | Key::CapsLock |
ð scroll_lock | Key::ScrollLock |
ðĒ num_lock | Key::NumLock |
âļïļ pause | Key::Pause |
ðïļ insert | Key::Insert |
ð home | Key::Home |
ð page_up | Key::PageUp |
ðïļ delete | Key::Delete |
ð end | Key::End |
ð page_down | Key::PageDown |
ð f1 | Key::F1 |
ðïļ f2 | Key::F2 |
ðĒ f3 | Key::F3 |
ðĒ f4 | Key::F4 |
ðĒ f5 | Key::F5 |
ðĒ f6 | Key::F6 |
ðĒ f7 | Key::F7 |
ðĒ f8 | Key::F8 |
ðĒ f9 | Key::F9 |
ðĒ f10 | Key::F10 |
ðĒ f11 | Key::F11 |
ðĒ f12 | Key::F12 |
Color Name | Hex Code |
---|---|
Green ðĒ | 0xFF00FF00 |
Red ðī | 0xFFFF0000 |
Blue ðĩ | 0xFF0000FF |
Yellow ðĄ | 0xFFFFFF00 |
Cyan ðĶ | 0xFF00FFFF |
Magenta ð | 0xFFFF00FF |
White ⊠| 0xFFFFFFFF |
Black âŦ | 0xFF000000 |
Gray ðĐķ | 0xFF808080 |
Orange ð | 0xFFFFA500 |
Purple ðĢ | 0xFF800080 |
Pink ðļ | 0xFFFFC0CB |
Brown ðĪ | 0xFFA52A2A |
Light Gray ðŠķ | 0xFFD3D3D3 |
Light Blue ð | 0xFFADD8E6 |
Dark Blue ðīââ ïļ | 0xFF00008B |
Beige ðĪ | 0xFFF5F5DC |
Teal ð | 0xFF008080 |
Lavender ðū | 0xFFE6E6FA |
Ivory ðïļ | 0xFFFFFFF0 |
Mint ðŋ | 0xFF98FF98 |
Coral ð | 0xFFFF7F50 |
Navy â | 0xFF000080 |
Sky Blue âïļ | 0xFF87CEEB |
Sea Green ð | 0xFF2E8B57 |
Forest Green ðē | 0xFF228B22 |
Dark Gray ðĪ | 0xFFA9A9A9 |
Slate Gray ðïļ | 0xFF708090 |
Charcoal ð | 0xFF36454F |
Jet Black ðķïļ | 0xFF343434 |
Gunmetal ðŦ | 0xFF2A3439 |
Dark Slate Blue ð | 0xFF483D8B |
Midnight Blue ð | 0xFF191970 |
Deep Navy ðģïļ | 0xFF1B1F3B |
Dark Olive Green ðŋ | 0xFF556B2F |
Deep Forest Green ðģ | 0xFF1A2E1A |
Maroon ð· | 0xFF800000 |
Deep Burgundy ð | 0xFF4A0000 |
Dark Chocolate ðŦ | 0xFF3E2723 |
Dark Copper ðš | 0xFF4E3629 |
Onyx ð | 0xFF353839 |
Obsidian ð | 0xFF1C1C1C |
Default (Invalid) | 0xFFFFC0CB |
This app code showcases all the elements in use, you can refer to it when using this framework.
use laststraw::*;
fn main() {
let mut app = App::new(500, 500, "test");
asx!({
set_window_color(&mut app, "Obsidian"); // is layored so this is back
if input_pressed(&app, "esc") {
app.should_close = true;
}
if input_pressed(&app, "space") {
single_line_text(&mut app, position!(20.0, 20.0, 40.0), "You pressed space");
}
let lines: Vec<&str> = vec!["Apple fruit", "Banana", "Cherry pie", "Oreos"];
multi_line_text(&mut app, position!(100.0, 100.0, 50.0), 50.0, lines);
set_next_button(&mut app, position!(30.0, 30.0, 30.0));
set_next_button_text(&mut app, "helq");
button!({
single_line_text(
&mut app,
position!(20.0, 20.0, 40.0),
"You clicked the button",
);
});
let texty = editable_lines(
&mut app,
position!(100.0, 50.0, 50.0),
"enter:",
"Blue",
false,
);
single_line_text(&mut app, position!(20.0, 20.0, 40.0), &texty); // you can acess the value later, will be empty, never recived input
limit_fps(&mut app, 60.0);
});
println!("app closed after window code.");
}
I took lots of inspiration from Rust Frameworks like Dioxus and Tauri Frameworks. The main problem for my with these frameworks, is that desktop apps, acted like mini web browsers.
This meant I had to tailer my code to not interact with the hardware, like a website, with static files. I just needed a framework that had buttons and multiline text to enter and display. Just something to make a basic text editer.
I like the features of Iced, but I wanted a more light CPU, based framework. That could also be cross compatible. I also wanted easy to read variable names, as once someone learns them, they can just macrofi them.
I also wished it to be easyer for people new to Rust to be able to make Apps. As I belive people like projects they can see rendered on their screen more.
Hopfully, this project makes some dev happy to keep their Rust app low level.
Since, this is my first published crate framework, I expect their might be bugs. Feel free to open an issue or anything, if you belive you can do the code better. I would love to learn any new ideas, to make this framework better!