Skip to content

Instantly share code, notes, and snippets.

@amrutnrp
Last active November 3, 2025 16:10
Show Gist options
  • Select an option

  • Save amrutnrp/f4cbfe379324072c4c6c66e70971f9dc to your computer and use it in GitHub Desktop.

Select an option

Save amrutnrp/f4cbfe379324072c4c6c66e70971f9dc to your computer and use it in GitHub Desktop.
It's a tiny exe file which can be used for - 1. keeping track of important links handy, tools at hand, keeps desktop clean and organized . Made from Rust, exe size 2.2MB, no other dependencies
[package]
name = "scripts_gui"
version = "0.1.0"
edition = "2021"
[dependencies]
fltk = "1.4"
toml = "0.8"
serde = { version = "1.0", features = ["derive"] }
#![windows_subsystem = "windows"]
use fltk::{
app,
button::Button,
enums::{Color, Event, EventState},
prelude::*,
window::Window,
};
use serde::Deserialize;
use std::{fs, process::Command};
#[derive(Debug, Deserialize)]
struct Script {
name: String,
path: String,
exec: String,
}
#[derive(Debug, Deserialize)]
struct Config {
scripts: Vec<Script>,
}
fn main() {
let config_str = fs::read_to_string("scripts.toml").expect("Failed to read config");
let config: Config = toml::from_str(&config_str).expect("Failed to parse TOML");
let app = app::App::default();
app::background(240, 243, 249);
let button_width = 150;
let button_height = 45;
let button_spacing = 10;
let padding = 20;
let scripts = &config.scripts;
let total_scripts = scripts.len();
let max_rows = 5;
let columns = ((total_scripts as f32) / max_rows as f32).ceil() as i32;
let rows = std::cmp::min(total_scripts as i32, max_rows);
let window_width = columns * (button_width + button_spacing) + padding * 2;
let window_height = rows * (button_height + button_spacing) + padding * 2;
let exe_name = std::env::current_exe()
.ok()
.and_then(|p| p.file_stem().map(|s| s.to_string_lossy().into_owned()))
.unwrap_or_else(|| "Script Launcher".to_string());
let mut wind = Window::new(100, 100, window_width, window_height, &*exe_name);
let button_color = Color::from_rgb(153, 217, 234);
for (i, script) in scripts.iter().enumerate() {
let col = (i as i32) / max_rows;
let row = (i as i32) % max_rows;
let x = padding + col * (button_width + button_spacing);
let y = padding + row * (button_height + button_spacing);
let mut btn = Button::new(x, y, button_width, button_height, &*script.name);
btn.set_color(button_color);
btn.set_selection_color(Color::Gray0);
btn.set_label_color(Color::Black);
let path = script.path.clone();
let exec = script.exec.clone();
btn.handle(move |_, ev| {
if ev == Event::Push {
let modifiers = app::event_state();
let ctrl_pressed = modifiers.contains(EventState::Ctrl);
let folder_path = fs::canonicalize(&path)
.expect("Failed to resolve absolute path")
.parent()
.expect("Failed to get parent folder")
.to_path_buf();
if ctrl_pressed {
Command::new("explorer")
.arg(folder_path)
.spawn()
.expect("Failed to open folder");
} else {
Command::new(exec.clone())
.arg(path.clone())
.current_dir(folder_path)
.spawn()
.expect("Failed to execute script");
}
true
} else {
false
}
});
}
wind.end();
wind.show();
app.run().unwrap();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment