dynamically find window binaries instead of hardcode
also, terminal compile fix whoops
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 += ©_string;
|
||||
} else {
|
||||
self.current_stdin_input += copy_string;
|
||||
self.current_stdin_input += ©_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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
33
src/fs.rs
33
src/fs.rs
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
16
src/utils.rs
16
src/utils.rs
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user