dynamically find window binaries instead of hardcode

also, terminal compile fix whoops
This commit is contained in:
stjet
2025-03-02 07:45:36 +00:00
parent 1a5eba7191
commit 1b9922d70f
18 changed files with 172 additions and 81 deletions

View File

@@ -242,6 +242,8 @@ impl AudioPlayer {
if new_path.exists() {
self.base_directory = new_path.to_str().unwrap().to_string();
return "Set new base directory".to_string();
} else {
return "Failed to set new base directory".to_string();
}
}
}

View File

@@ -11,7 +11,7 @@ use std::fmt;
use pty_process::blocking;
use ming_wm::window_manager::{ DrawInstructions, WindowLike, WindowLikeType };
use ming_wm::messages::{ WindowMessage, WindowMessageResponse };
use ming_wm::messages::{ WindowMessage, WindowMessageResponse, ShortcutType };
use ming_wm::framebuffer::Dimensions;
use ming_wm::themes::ThemeInfo;
use ming_wm::utils::{ concat_paths, Substring };
@@ -202,9 +202,9 @@ impl WindowLike for Terminal {
ShortcutType::ClipboardPaste(copy_string) => {
if self.mode == Mode::Input || self.mode == Mode::Stdin {
if self.mode == Mode::Input {
self.current_input += copy_string;
self.current_input += &copy_string;
} else {
self.current_stdin_input += copy_string;
self.current_stdin_input += &copy_string;
}
self.calc_actual_lines();
WindowMessageResponse::JustRedraw
@@ -224,7 +224,7 @@ impl WindowLike for Terminal {
DrawInstructions::Rect([0, 0], self.dimensions, theme_info.alt_background),
];
//add the visible lines of text
let end_line = self.actual_line_num + self.get_max_lines() - 1;
let end_line = self.actual_line_num + self.get_max_lines();
let mut text_y = PADDING;
for line_num in self.actual_line_num..end_line {
if line_num == self.actual_lines.len() {
@@ -261,7 +261,7 @@ impl Terminal {
}
fn get_max_lines(&self) -> usize {
(self.dimensions[1] - PADDING * 2) / LINE_HEIGHT
(self.dimensions[1] - PADDING * 2 - LINE_HEIGHT) / LINE_HEIGHT
}
fn process_command(&mut self) -> Mode {

View File

@@ -11,7 +11,7 @@ pub struct HighlightButton<T> {
name_: String,
top_left: Point,
size: Dimensions,
text: String,
pub text: String,
pub highlighted: bool,
click_return: T,
toggle_highlight_return: T, //also unhighlight return

View File

@@ -38,3 +38,12 @@ pub fn config_dir() -> Option<PathBuf> {
}
}
pub fn exe_dir(add: Option<&str>) -> PathBuf {
let mut exe_dir = env::current_exe().unwrap();
exe_dir.pop();
if let Some(add) = add {
exe_dir.push(add);
}
exe_dir
}

View File

@@ -6,15 +6,17 @@ use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType };
use crate::messages::{ WindowMessage, WindowMessageResponse, WindowManagerRequest };
use crate::framebuffer::Dimensions;
use crate::themes::ThemeInfo;
use crate::fs::{ ExeWindowInfos, get_all_executable_windows };
use crate::components::Component;
use crate::components::highlight_button::HighlightButton;
use crate::dirs::exe_dir;
static CATEGORIES: [&'static str; 9] = ["About", "Utils", "Games", "Editing", "Files", "Internet", "Misc", "Help", "Logout"];
#[derive(Clone)]
enum StartMenuMessage {
CategoryClick(&'static str),
WindowClick(&'static str),
WindowClick(String),
Back,
ChangeAcknowledge,
}
@@ -22,7 +24,8 @@ enum StartMenuMessage {
#[derive(Default)]
pub struct StartMenu {
dimensions: Dimensions,
components: Vec<Box<dyn Component<StartMenuMessage> + Send>>,
executable_windows: ExeWindowInfos,
components: Vec<Box<HighlightButton<StartMenuMessage>>>,
current_focus: String,
y_each: usize,
}
@@ -34,6 +37,7 @@ impl WindowLike for StartMenu {
self.dimensions = dimensions;
self.y_each = (self.dimensions[1] - 1) / CATEGORIES.len();
self.add_category_components();
self.executable_windows = get_all_executable_windows();
WindowMessageResponse::JustRedraw
},
WindowMessage::KeyPress(key_press) => {
@@ -69,7 +73,7 @@ impl WindowLike for StartMenu {
let current_focus_index = self.get_focus_index().unwrap();
if key_press.key.is_lowercase() {
//look forwards to see category/window that starts with that char
if let Some(n_index) = self.components[current_focus_index..].iter().position(|c| c.name().chars().next().unwrap_or('𐘂').to_lowercase().next().unwrap() == key_press.key) {
if let Some(n_index) = self.components[current_focus_index..].iter().position(|c| c.text.chars().next().unwrap_or('𐘂').to_lowercase().next().unwrap() == key_press.key) {
//now old focus, not current focus
self.components[current_focus_index].handle_message(WindowMessage::Unfocus);
self.current_focus = self.components[current_focus_index + n_index].name().to_string();
@@ -80,7 +84,7 @@ impl WindowLike for StartMenu {
}
} else {
//look backwards to see category/window that starts with that char
if let Some(n_index) = self.components[..current_focus_index].iter().rev().position(|c| c.name().chars().next().unwrap_or('𐘂').to_uppercase().next().unwrap() == key_press.key) {
if let Some(n_index) = self.components[..current_focus_index].iter().rev().position(|c| c.text.chars().next().unwrap_or('𐘂').to_uppercase().next().unwrap() == key_press.key) {
//now old focus, not current focus
self.components[current_focus_index].handle_message(WindowMessage::Unfocus);
self.current_focus = self.components[current_focus_index - n_index - 1].name().to_string();
@@ -105,7 +109,7 @@ impl WindowLike for StartMenu {
//background
DrawInstructions::Rect([0, 1], [self.dimensions[0] - 1, self.dimensions[1] - 1], theme_info.background),
//mingde logo
DrawInstructions::Bmp([2, 2], "./bmps/mingde.bmp".to_string(), false),
DrawInstructions::Bmp([2, 2], exe_dir(Some("bmps/mingde.bmp")).to_string_lossy().to_string(), false),
//I truly don't know why, it should be - 44 but - 30 seems to work better :shrug:
DrawInstructions::Gradient([2, 42], [40, self.dimensions[1] - 30], [255, 201, 14], [225, 219, 77], 15),
];
@@ -147,22 +151,12 @@ impl StartMenu {
))
];
//add window buttons
let mut to_add: Vec<&str> = Vec::new();
if name == "Games" {
to_add.extend(["Minesweeper", "Reversi"]);
} else if name == "Editing" {
to_add.push("Malvim");
} else if name == "Utils" {
to_add.push("Terminal");
} else if name == "Files" {
to_add.extend(["File Explorer", "Audio Player"]);
}
//
for a in 0..to_add.len() {
let w_name = to_add[a];
self.components.push(Box::new(HighlightButton::new(
w_name.to_string(), [42, (a + 1) * self.y_each], [self.dimensions[0] - 42 - 1, self.y_each], w_name.to_string(), StartMenuMessage::WindowClick(w_name), StartMenuMessage::ChangeAcknowledge, false
)));
if let Some(to_add) = self.executable_windows.get(&("ming".to_string() + name)) {
for a in 0..to_add.len() {
self.components.push(Box::new(HighlightButton::new(
to_add[a].1.to_string(), [42, (a + 1) * self.y_each], [self.dimensions[0] - 42 - 1, self.y_each], to_add[a].0.to_string(), StartMenuMessage::WindowClick(to_add[a].1.clone()), StartMenuMessage::ChangeAcknowledge, false
)));
}
}
WindowMessageResponse::JustRedraw
}

View File

@@ -1,6 +1,10 @@
use std::fs::{ read_dir, File };
use std::path::PathBuf;
use std::io::Read;
use std::collections::HashMap;
use crate::dirs;
use crate::utils::get_rest_of_split;
fn get_font_char(dir: &str, c: char) -> Option<(char, Vec<Vec<u8>>, u8)> {
let c = if c == '/' { '𐘋' } else if c == '\\' { '𐚆' } else if c == '.' { '𐘅' } else { c };
@@ -20,12 +24,14 @@ fn get_font_char(dir: &str, c: char) -> Option<(char, Vec<Vec<u8>>, u8)> {
pub fn get_font_char_from_fonts(fonts: &[String], c: char) -> (char, Vec<Vec<u8>>, u8) {
for font in fonts {
if let Some(font_char) = get_font_char(&("./bmps/".to_string() + font), c) {
let p = dirs::exe_dir(Some(&("bmps/".to_string() + &font))).to_string_lossy().to_string();
if let Some(font_char) = get_font_char(&p, c) {
return font_char;
}
}
let p = dirs::exe_dir(Some(&("bmps/".to_string() + &fonts[0]))).to_string_lossy().to_string();
//so a ? char must be in every font
get_font_char(&("./bmps/".to_string() + &fonts[0]), '?').unwrap()
get_font_char(&p, '?').unwrap()
}
pub fn get_all_files(dir: PathBuf) -> Vec<PathBuf> {
@@ -41,3 +47,26 @@ pub fn get_all_files(dir: PathBuf) -> Vec<PathBuf> {
files
}
//Category, Vec<Display name, file name>
pub type ExeWindowInfos = HashMap<String, Vec<(String, String)>>;
//well, doesn't actually look to see if its executable. Just if it contains a _ and has no file extension, and is a file
pub fn get_all_executable_windows() -> ExeWindowInfos {
let mut exes = HashMap::new();
for entry in read_dir(dirs::exe_dir(None)).unwrap() {
let pb = entry.unwrap().path();
if pb.is_file() && pb.extension().is_none() {
let parts = pb.file_stem().unwrap().to_string_lossy().to_string();
let mut parts = parts.split('_');
let category = parts.next().unwrap();
let display = get_rest_of_split(&mut parts, Some(" "));
let file_name = pb.file_name().unwrap().to_string_lossy().to_string();
if display != String::new() && category.starts_with("ming") {
let pair = (display, file_name);
exes.entry(category.to_string()).and_modify(|v: &mut Vec<(String, String)>| (*v).push(pair.clone())).or_insert(vec![pair]);
}
}
}
exes
}

View File

@@ -2,12 +2,12 @@ use std::vec::Vec;
use std::process::{ Command, Child, Stdio };
use std::io::{ BufReader, BufRead, Write };
use std::cell::RefCell;
use std::path::Path;
use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType };
use crate::messages::{ WindowMessage, WindowMessageResponse };
use crate::framebuffer::Dimensions;
use crate::themes::ThemeInfo;
use crate::dirs;
use crate::serialize::{ Serializable, DrawInstructionsVec };
pub struct ProxyWindowLike {
@@ -74,18 +74,10 @@ impl Drop for ProxyWindowLike {
}
impl ProxyWindowLike {
pub fn new(command: &mut Command) -> Self {
pub fn new(name: &str) -> Self {
let loc = dirs::exe_dir(Some(name)).to_string_lossy().to_string();
ProxyWindowLike {
process: RefCell::new(command.stdout(Stdio::piped()).stdin(Stdio::piped()).stderr(Stdio::null()).spawn().unwrap()),
}
}
pub fn new_rust(file: &str) -> Self {
let loc = format!("./target/release/{}", file);
if Path::new(&loc).exists() {
ProxyWindowLike::new(Command::new(loc).stdout(Stdio::piped()).stdin(Stdio::piped()).stderr(Stdio::null()))
} else {
ProxyWindowLike::new(Command::new("cargo").arg("run").arg("--quiet").arg("--release").arg("--bin").arg(file).stdout(Stdio::piped()).stdin(Stdio::piped()).stderr(Stdio::null()))
process: RefCell::new(Command::new(loc).stdout(Stdio::piped()).stdin(Stdio::piped()).stderr(Stdio::null()).spawn().unwrap()),
}
}

View File

@@ -4,6 +4,7 @@ use crate::themes::ThemeInfo;
use crate::messages::{ WindowMessageResponse, WindowManagerRequest, KeyPress, WindowMessage, Direction, ShortcutType, InfoType };
use crate::window_manager::{ KeyChar, DrawInstructions, WindowLikeType };
use crate::framebuffer::Dimensions;
use crate::utils::get_rest_of_split;
//serde + ron but worse! yay
//not same as ron - simplified
@@ -33,21 +34,6 @@ fn option_to_string<T: Display>(option: &Option<T>) -> String {
}
}
fn get_rest_of_split(split: &mut dyn Iterator<Item = &str>, sep: Option<&str>) -> String {
let mut rest = String::new();
let mut n = split.next();
loop {
rest += &n.unwrap();
n = split.next();
if n.is_some() {
rest += sep.unwrap_or("");
} else {
break;
}
}
rest
}
fn get_color(serialized: &str) -> Result<[u8; 3], ()> {
let rgb = serialized.split("\x1F");
let mut color = [0; 3];

View File

@@ -157,3 +157,19 @@ pub fn point_inside(point: Point, top_left: Point, size: Dimensions) -> bool {
x >= x2 && y >= y2 && x <= x3 && y <= y3
}
pub fn get_rest_of_split(split: &mut dyn Iterator<Item = &str>, sep: Option<&str>) -> String {
let mut rest = String::new();
let mut n = split.next();
loop {
if n.is_none() {
break;
}
rest += &n.unwrap();
n = split.next();
if n.is_some() && sep.is_some() {
rest += sep.unwrap();
}
}
rest
}

View File

@@ -633,16 +633,10 @@ impl WindowManager {
return;
}
let w: Option<WindowBox> = match w.as_str() {
"Minesweeper" => Some(Box::new(ProxyWindowLike::new_rust("minesweeper"))),
"Reversi" => Some(Box::new(ProxyWindowLike::new_rust("reversi"))),
"Malvim" => Some(Box::new(ProxyWindowLike::new_rust("malvim"))),
"Terminal" => Some(Box::new(ProxyWindowLike::new_rust("terminal"))),
"Audio Player" => Some(Box::new(ProxyWindowLike::new_rust("audio_player"))),
"File Explorer" => Some(Box::new(ProxyWindowLike::new_rust("file_explorer"))),
"StartMenu" => Some(Box::new(StartMenu::new())),
"About" => Some(Box::new(About::new())),
"Help" => Some(Box::new(Help::new())),
_ => None,
_ => Some(Box::new(ProxyWindowLike::new(&w))),
};
if w.is_none() {
return;