docs, password config, help, about

render -> draw, file explorer, writer is RefCell
This commit is contained in:
stjet
2025-01-01 09:38:11 +00:00
parent acdb59d668
commit 03f1d649e0
34 changed files with 542 additions and 152 deletions

View File

@@ -35,11 +35,11 @@ impl WindowLike for AudioPlayer {
match message {
WindowMessage::Init(dimensions) => {
self.dimensions = dimensions;
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
WindowMessage::ChangeDimensions(dimensions) => {
self.dimensions = dimensions;
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
WindowMessage::KeyPress(key_press) => {
if key_press.key == '𐘂' { //the enter key
@@ -52,7 +52,7 @@ impl WindowLike for AudioPlayer {
} else {
self.command += &key_press.key.to_string();
}
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
_ => {
WindowMessageResponse::DoNothing

View File

@@ -16,9 +16,6 @@ struct DirectoryChild {
override_name: Option<String>,
path: PathBuf,
is_file: bool,
//can only be true if dir
//if true, means the contents of this dir should be visible too, even though it isn't the current path. like a tree
tree_open: bool,
}
#[derive(Default)]
@@ -38,11 +35,11 @@ impl WindowLike for FileExplorer {
self.current_path = PathBuf::from("/");
self.dimensions = dimensions;
self.current_dir_contents = self.get_current_dir_contents();
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
WindowMessage::ChangeDimensions(dimensions) => {
self.dimensions = dimensions;
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
WindowMessage::KeyPress(key_press) => {
if key_press.key == '𐘂' { //the enter key
@@ -53,7 +50,7 @@ impl WindowLike for FileExplorer {
self.current_dir_contents = self.get_current_dir_contents();
self.position = 0;
self.top_position = 0;
return WindowMessageResponse::JustRerender;
return WindowMessageResponse::JustRedraw;
}
}
WindowMessageResponse::DoNothing
@@ -74,15 +71,16 @@ impl WindowLike for FileExplorer {
}
}
//calculate position
let max_height = self.dimensions[1] - HEIGHT;
if self.position > self.top_position {
let current_height = (self.position - self.top_position) * HEIGHT;
if current_height > self.dimensions[1] {
self.top_position += (current_height - self.dimensions[1]) / HEIGHT + 1;
self.top_position += (current_height - max_height) / HEIGHT + 1;
}
} else {
self.top_position = self.position;
};
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
} else {
WindowMessageResponse::DoNothing
}
@@ -93,10 +91,10 @@ impl WindowLike for FileExplorer {
fn draw(&self, theme_info: &ThemeInfo) -> Vec<DrawInstructions> {
let mut instructions = Vec::new();
//top bar with path name and editing
//
//top bar with path name
instructions.push(DrawInstructions::Text([5, 0], vec!["times-new-roman".to_string(), "shippori-mincho".to_string()], "Current: ".to_string() + &self.current_path.to_string_lossy().to_string(), theme_info.text, theme_info.background, None, None));
//the actual files and directories
let mut start_y = 0;
let mut start_y = HEIGHT;
let mut i = self.top_position;
for entry in self.current_dir_contents.iter().skip(self.top_position) {
if start_y > self.dimensions[1] {
@@ -149,7 +147,6 @@ impl FileExplorer {
contents.push(DirectoryChild {
override_name: Some("..".to_string()),
is_file: false,
tree_open: false,
path: self.current_path.parent().unwrap().to_owned(),
});
}
@@ -158,7 +155,6 @@ impl FileExplorer {
DirectoryChild {
override_name: None,
is_file: path.is_file(),
tree_open: false,
path,
}
}));

View File

@@ -87,7 +87,7 @@ impl WindowLike for Malvim {
match message {
WindowMessage::Init(dimensions) => {
self.dimensions = dimensions;
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
WindowMessage::KeyPress(key_press) => {
let mut changed = true;
@@ -304,11 +304,11 @@ impl WindowLike for Malvim {
}
}
self.calc_top_line_pos();
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
WindowMessage::ChangeDimensions(dimensions) => {
self.dimensions = dimensions;
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
WindowMessage::Shortcut(shortcut) => {
match shortcut {
@@ -329,7 +329,7 @@ impl WindowLike for Malvim {
self.calc_top_line_pos();
self.calc_current(); //too over zealous but whatever
self.files[self.current_file_index].changed = true;
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
} else {
WindowMessageResponse::DoNothing
}

View File

@@ -44,7 +44,7 @@ impl WindowLike for Minesweeper {
match message {
WindowMessage::Init(dimensions) => {
self.dimensions = dimensions;
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
WindowMessage::KeyPress(key_press) => {
if self.state == State::Seed {
@@ -58,7 +58,7 @@ impl WindowLike for Minesweeper {
self.random_chars.push(key_press.key);
}
}
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
} else if self.state == State::BeforePlaying || self.state == State::Playing {
if key_press.key == '𐘁' { //backspace
self.first_char = '\0';
@@ -125,7 +125,7 @@ impl WindowLike for Minesweeper {
self.state = State::Won;
}
}
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
} else {
WindowMessageResponse::DoNothing
}

View File

@@ -59,7 +59,7 @@ impl WindowLike for Reversi {
self.dimensions = dimensions;
self.new_tiles();
self.valid_moves = self.get_valid_moves();
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
WindowMessage::KeyPress(key_press) => {
if let Ok(n) = key_press.key.to_string().parse::<u8>() {
@@ -82,7 +82,7 @@ impl WindowLike for Reversi {
} else if key_press.key == '𐘁' { //backspace
self.current_number = None;
}
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
_ => WindowMessageResponse::DoNothing,
}

View File

@@ -44,11 +44,11 @@ impl WindowLike for Terminal {
self.current_path = "/".to_string();
self.lines = vec!["Mingde Terminal".to_string(), "".to_string()];
self.calc_actual_lines();
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
WindowMessage::ChangeDimensions(dimensions) => {
self.dimensions = dimensions;
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
WindowMessage::KeyPress(key_press) => {
if self.state == State::Input {
@@ -68,7 +68,7 @@ impl WindowLike for Terminal {
}
self.calc_actual_lines();
self.actual_line_num = self.actual_lines.len().checked_sub(self.get_max_lines()).unwrap_or(0);
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
} else if key_press.key.len_utf8() == 1 {
//update
let running_process = self.running_process.as_mut().unwrap();
@@ -85,7 +85,7 @@ impl WindowLike for Terminal {
}
self.state = State::Input;
self.calc_actual_lines();
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
} else {
//still running
WindowMessageResponse::DoNothing
@@ -101,15 +101,15 @@ impl WindowLike for Terminal {
//kills and running_process is now None
let _ = self.running_process.take().unwrap().kill();
self.state = State::Input;
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
} else if self.state == State::Input && (key_press.key == 'p' || key_press.key == 'n') {
//only the last command is saved unlike other terminals. good enough for me
if key_press.key == 'p' && self.last_command.is_some() {
self.current_input = self.last_command.clone().unwrap();
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
} else if key_press.key == 'n' {
self.current_input = String::new();
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
} else {
WindowMessageResponse::DoNothing
}

View File

@@ -1,11 +0,0 @@
use std::process::{ Command, Stdio };
use std::io::{ Read, Write };
use ron;
use ming_wm::messages::WindowMessage;
fn main() {
println!("{}", ron::to_string(&WindowMessage::Init([100,100])).unwrap());
//println!("{}", &ron::to_string(&[122, 400]).unwrap());
}

View File

@@ -11,7 +11,7 @@ pub struct HighlightButton<T> {
name_: String,
top_left: Point,
size: Dimensions,
text: &'static str,
text: String,
pub highlighted: bool,
click_return: T,
toggle_highlight_return: T, //also unhighlight return
@@ -38,12 +38,12 @@ impl<T: Clone> Component<T> for HighlightButton<T> {
vec![
//highlight background
DrawInstructions::Rect(self.top_left, self.size, theme_info.top),
DrawInstructions::Text([self.top_left[0] + 4, self.top_left[1] + (self.size[1] - font_height) / 2], vec!["times-new-roman".to_string()], self.text.to_string(), theme_info.top_text, theme_info.top, None, None),
DrawInstructions::Text([self.top_left[0] + 4, self.top_left[1] + (self.size[1] - font_height) / 2], vec!["times-new-roman".to_string()], self.text.clone(), theme_info.top_text, theme_info.top, None, None),
]
} else {
vec![
DrawInstructions::Rect(self.top_left, self.size, theme_info.background),
DrawInstructions::Text([self.top_left[0] + 4, self.top_left[1] + (self.size[1] - font_height) / 2], vec!["times-new-roman".to_string()], self.text.to_string(), theme_info.text, theme_info.background, None, None),
DrawInstructions::Text([self.top_left[0] + 4, self.top_left[1] + (self.size[1] - font_height) / 2], vec!["times-new-roman".to_string()], self.text.clone(), theme_info.text, theme_info.background, None, None),
]
}
}
@@ -63,7 +63,7 @@ impl<T: Clone> Component<T> for HighlightButton<T> {
}
impl<T> HighlightButton<T> {
pub fn new(name_: String, top_left: Point, size: Dimensions, text: &'static str, click_return: T, toggle_highlight_return: T, highlighted: bool) -> Self {
pub fn new(name_: String, top_left: Point, size: Dimensions, text: String, click_return: T, toggle_highlight_return: T, highlighted: bool) -> Self {
Self {
name_,
top_left,

View File

@@ -6,6 +6,7 @@ use crate::window_manager::DrawInstructions;
pub mod toggle_button;
pub mod highlight_button;
pub mod paragraph;
pub trait Component<T> {
fn handle_message(&mut self, message: WindowMessage) -> Option<T>;

View File

@@ -0,0 +1,91 @@
use std::vec;
use std::vec::Vec;
use crate::components::Component;
use crate::framebuffer::{ Dimensions, Point };
use crate::themes::ThemeInfo;
use crate::messages::WindowMessage;
use crate::window_manager::DrawInstructions;
use crate::utils::calc_actual_lines;
const MONO_WIDTH: u8 = 10;
const LINE_HEIGHT: usize = 18;
pub struct Paragraph<T> {
name_: String,
actual_lines: Vec<(bool, usize, String)>, //first, line #, actual line
top_left: Point,
size: Dimensions,
line_pos: usize,
key_return: T,
}
impl<T: Copy> Component<T> for Paragraph<T> {
fn handle_message(&mut self, message: WindowMessage) -> Option<T> {
if let WindowMessage::KeyPress(key_press) = message {
if key_press.key == 'j' {
//down
if self.line_pos != self.actual_lines.len() - 1 {
self.line_pos += 1;
}
Some(self.key_return)
} else if key_press.key == 'k' {
//up
if self.line_pos != 0 {
self.line_pos -= 1;
}
Some(self.key_return)
} else {
None
}
} else {
None
}
}
fn draw(&self, theme_info: &ThemeInfo) -> Vec<DrawInstructions> {
let mut instructions = Vec::new();
let max_lines = self.size[1] / LINE_HEIGHT;
let mut start_y = self.top_left[1];
for line in self.actual_lines.iter().skip(self.line_pos).take(max_lines) {
instructions.push(DrawInstructions::Text([self.top_left[0], start_y], vec!["times-new-romono".to_string()], line.2.clone(), theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH)));
start_y += LINE_HEIGHT;
}
instructions
}
//properties
fn focusable(&self) -> bool {
true
}
fn clickable(&self) -> bool {
false
}
fn name(&self) -> &String {
&self.name_
}
}
impl<T> Paragraph<T> {
pub fn new(name_: String, top_left: Point, size: Dimensions, text: String, key_return: T) -> Self {
let mut s = Self {
name_,
actual_lines: Vec::new(),
top_left,
size,
line_pos: 0,
key_return,
};
s.new_text(text);
s
}
pub fn new_text(&mut self, text: String) {
let max_chars_per_line = self.size[0] / MONO_WIDTH as usize;
let lines: Vec<String> = text.split("\n").map(|s| s.to_string()).collect();
self.actual_lines = calc_actual_lines(lines.iter(), max_chars_per_line, true);
}
}

View File

@@ -7,12 +7,6 @@ use crate::themes::ThemeInfo;
use crate::messages::WindowMessage;
use crate::window_manager::DrawInstructions;
//we need a text width and height measure function first
pub enum ToggleButtonAlignment {
Centre,
Left,
}
pub struct ToggleButton<T> {
name_: String,
top_left: Point,
@@ -20,7 +14,6 @@ pub struct ToggleButton<T> {
text: String,
draw_bg: bool,
pub inverted: bool, //whether is it clicked or not
alignment: ToggleButtonAlignment,
click_return: T,
unclick_return: T,
}
@@ -73,7 +66,7 @@ impl<T: Clone> Component<T> for ToggleButton<T> {
}
impl<T> ToggleButton<T> {
pub fn new(name_: String, top_left: Point, size: Dimensions, text: String, click_return: T, unclick_return: T, draw_bg: bool, alignment: Option<ToggleButtonAlignment>) -> Self {
pub fn new(name_: String, top_left: Point, size: Dimensions, text: String, click_return: T, unclick_return: T, draw_bg: bool) -> Self {
Self {
name_,
top_left,
@@ -83,7 +76,6 @@ impl<T> ToggleButton<T> {
unclick_return,
draw_bg,
inverted: false,
alignment: alignment.unwrap_or(ToggleButtonAlignment::Centre),
}
}
}

62
src/essential/about.rs Normal file
View File

@@ -0,0 +1,62 @@
use std::vec::Vec;
use std::boxed::Box;
use std::fs::read_to_string;
use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType };
use crate::messages::{ WindowMessage, WindowMessageResponse };
use crate::framebuffer::Dimensions;
use crate::themes::ThemeInfo;
use crate::components::Component;
use crate::components::paragraph::Paragraph;
pub struct About {
dimensions: Dimensions,
components: Vec<Box<dyn Component<()> + Send>>,
}
impl WindowLike for About {
fn handle_message(&mut self, message: WindowMessage) -> WindowMessageResponse {
match message {
WindowMessage::Init(dimensions) => {
self.dimensions = dimensions;
self.components.push(Box::new(Paragraph::new("help".to_string(), [2, 2], [self.dimensions[0] - 4, self.dimensions[1] - 4], read_to_string("docs/system/README.md").unwrap_or("docs/system/README.md not found".to_string()), ())));
WindowMessageResponse::JustRedraw
},
WindowMessage::KeyPress(key_press) => {
if self.components[0].handle_message(WindowMessage::KeyPress(key_press)).is_some() {
WindowMessageResponse::JustRedraw
} else {
WindowMessageResponse::DoNothing
}
},
_ => WindowMessageResponse::DoNothing
}
}
fn draw(&self, theme_info: &ThemeInfo) -> Vec<DrawInstructions> {
self.components[0].draw(theme_info)
}
//properties
fn title(&self) -> String {
"About".to_string()
}
fn subtype(&self) -> WindowLikeType {
WindowLikeType::Window
}
fn ideal_dimensions(&self, _dimensions: Dimensions) -> Dimensions {
[500, 600]
}
}
impl About {
pub fn new() -> Self {
Self {
dimensions: [0, 0],
components: Vec::new(),
}
}
}

View File

@@ -21,13 +21,13 @@ impl WindowLike for DesktopBackground {
match message {
WindowMessage::Init(dimensions) => {
self.dimensions = dimensions;
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
WindowMessage::Shortcut(shortcut) => {
match shortcut {
ShortcutType::SwitchWorkspace(workspace) => {
self.current_workspace = workspace;
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
_ => WindowMessageResponse::DoNothing,
}

89
src/essential/help.rs Normal file
View File

@@ -0,0 +1,89 @@
use std::vec::Vec;
use std::boxed::Box;
use std::fs::{ read_to_string, read_dir };
use std::path::PathBuf;
use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType };
use crate::messages::{ WindowMessage, WindowMessageResponse };
use crate::framebuffer::Dimensions;
use crate::themes::ThemeInfo;
use crate::components::paragraph::Paragraph;
use crate::components::Component;
pub struct Help {
dimensions: Dimensions,
file_index: usize,
files: Vec<PathBuf>,
paragraph: Option<Box<Paragraph<()>>>,
}
impl WindowLike for Help {
fn handle_message(&mut self, message: WindowMessage) -> WindowMessageResponse {
match message {
WindowMessage::Init(dimensions) => {
self.dimensions = dimensions;
self.paragraph = Some(Box::new(Paragraph::new("help".to_string(), [2, 22], [self.dimensions[0] - 4, self.dimensions[1] - 24], "Press the 'h' and 'l' keys to read the different help pages".to_string(), ())));
WindowMessageResponse::JustRedraw
},
WindowMessage::KeyPress(key_press) => {
if key_press.key == 'h' || key_press.key == 'l' {
if key_press.key == 'h' {
if self.file_index == 0 {
self.file_index = self.files.len() - 1;
} else {
self.file_index -= 1;
}
} else {
if self.file_index == self.files.len() - 1 {
self.file_index = 0;
} else {
self.file_index += 1;
}
}
self.paragraph.as_mut().unwrap().new_text(read_to_string(self.files[self.file_index].clone()).unwrap());
WindowMessageResponse::JustRedraw
} else if self.paragraph.as_mut().unwrap().handle_message(WindowMessage::KeyPress(key_press)).is_some() {
WindowMessageResponse::JustRedraw
} else {
WindowMessageResponse::DoNothing
}
},
_ => WindowMessageResponse::DoNothing
}
}
fn draw(&self, theme_info: &ThemeInfo) -> Vec<DrawInstructions> {
let mut instructions = vec![DrawInstructions::Text([2, 2], vec!["times-new-romono".to_string()], self.files[self.file_index].clone().file_name().unwrap().to_string_lossy().to_string(), theme_info.text, theme_info.background, Some(0), None)];
instructions.extend(self.paragraph.as_ref().unwrap().draw(theme_info));
instructions
}
//properties
fn title(&self) -> String {
"About".to_string()
}
fn subtype(&self) -> WindowLikeType {
WindowLikeType::Window
}
fn ideal_dimensions(&self, _dimensions: Dimensions) -> Dimensions {
[500, 600]
}
}
impl Help {
pub fn new() -> Self {
let mut files = vec![PathBuf::from("docs/system/shortcuts.md")];
for entry in read_dir("docs/window-likes").unwrap() {
files.push(entry.unwrap().path());
}
Self {
dimensions: [0, 0],
file_index: 0,
files,
paragraph: None,
}
}
}

View File

@@ -7,7 +7,9 @@ use crate::messages::{ WindowMessage, WindowMessageResponse, WindowManagerReques
use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType };
use blake2::{ Blake2b512, Digest };
const PASSWORD_HASH: [u8; 64] = [220, 88, 183, 188, 240, 27, 107, 181, 58, 191, 198, 170, 114, 38, 7, 148, 6, 179, 75, 128, 231, 171, 172, 220, 85, 38, 36, 113, 116, 146, 70, 197, 163, 179, 158, 192, 130, 53, 247, 48, 47, 209, 95, 96, 179, 211, 4, 122, 254, 127, 21, 165, 139, 199, 151, 226, 216, 176, 123, 41, 194, 221, 58, 69];
include!(concat!(env!("OUT_DIR"), "/password.rs"));
//const PASSWORD_HASH: [u8; 64] = [220, 88, 183, 188, 240, 27, 107, 181, 58, 191, 198, 170, 114, 38, 7, 148, 6, 179, 75, 128, 231, 171, 172, 220, 85, 38, 36, 113, 116, 146, 70, 197, 163, 179, 158, 192, 130, 53, 247, 48, 47, 209, 95, 96, 179, 211, 4, 122, 254, 127, 21, 165, 139, 199, 151, 226, 216, 176, 123, 41, 194, 221, 58, 69];
pub struct LockScreen {
dimensions: Dimensions,
@@ -19,28 +21,28 @@ impl WindowLike for LockScreen {
match message {
WindowMessage::Init(dimensions) => {
self.dimensions = dimensions;
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
WindowMessage::KeyPress(key_press) => {
if key_press.key == '𐘂' { //the enter key
//check password
let mut hasher = Blake2b512::new();
hasher.update(self.input_password.as_bytes());
hasher.update((self.input_password.clone() + "salt?sorrycryptographers").as_bytes());
if hasher.finalize() == PASSWORD_HASH.into() {
WindowMessageResponse::Request(WindowManagerRequest::Unlock)
} else {
self.input_password = String::new();
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
}
} else if key_press.key == '𐘁' { //backspace
let p_len = self.input_password.len();
if p_len != 0 {
self.input_password = self.input_password[..p_len - 1].to_string();
}
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
} else {
self.input_password += &key_press.key.to_string();
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
}
},
_ => WindowMessageResponse::DoNothing,

View File

@@ -4,3 +4,6 @@ pub mod lock_screen;
pub mod workspace_indicator;
pub mod start_menu;
pub mod about;
pub mod help;

View File

@@ -1,5 +1,3 @@
#![allow(warnings)]
use std::vec;
use std::vec::Vec;
use std::boxed::Box;
@@ -10,9 +8,6 @@ use crate::framebuffer::Dimensions;
use crate::themes::ThemeInfo;
use crate::components::Component;
use crate::components::highlight_button::HighlightButton;
use crate::ipc::listen;
//todo: move to essential
static CATEGORIES: [&'static str; 9] = ["About", "Utils", "Games", "Editing", "Files", "System", "Misc", "Help", "Logout"];
@@ -39,7 +34,7 @@ impl WindowLike for StartMenu {
self.dimensions = dimensions;
self.y_each = (self.dimensions[1] - 1) / CATEGORIES.len();
self.add_category_components();
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
WindowMessage::KeyPress(key_press) => {
//up and down
@@ -62,7 +57,7 @@ impl WindowLike for StartMenu {
self.old_focus = self.current_focus.to_string();
self.current_focus = self.components[current_focus_index].name().to_string();
self.components[current_focus_index].handle_message(WindowMessage::Focus);
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
} else if key_press.key == '𐘂' { //the enter key
let focus_index = self.get_focus_index();
if let Some(focus_index) = focus_index {
@@ -79,7 +74,7 @@ impl WindowLike for StartMenu {
self.old_focus = self.current_focus.clone();
self.current_focus = self.components[current_focus_index + n_index].name().to_string();
self.components[current_focus_index + n_index].handle_message(WindowMessage::Focus);
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
} else {
WindowMessageResponse::DoNothing
}
@@ -135,11 +130,14 @@ impl StartMenu {
StartMenuMessage::CategoryClick(name) => {
if name == "Logout" {
WindowMessageResponse::Request(WindowManagerRequest::Lock)
} else if name == "About" || name == "Help" {
//todo above: also do the same for Help
WindowMessageResponse::Request(WindowManagerRequest::OpenWindow(name.to_string()))
} else {
self.current_focus = "Back".to_string();
self.components = vec![
Box::new(HighlightButton::new(
"Back".to_string(), [42, 1], [self.dimensions[0] - 42 - 1, self.y_each], "Back", StartMenuMessage::Back, StartMenuMessage::ChangeAcknowledge, true
"Back".to_string(), [42, 1], [self.dimensions[0] - 42 - 1, self.y_each], "Back".to_string(), StartMenuMessage::Back, StartMenuMessage::ChangeAcknowledge, true
))
];
//add window buttons
@@ -157,10 +155,10 @@ impl StartMenu {
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, StartMenuMessage::WindowClick(w_name), StartMenuMessage::ChangeAcknowledge, false
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
)));
}
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
}
},
StartMenuMessage::WindowClick(name) => {
@@ -169,15 +167,15 @@ impl StartMenu {
},
StartMenuMessage::Back => {
self.add_category_components();
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
StartMenuMessage::ChangeAcknowledge => {
//
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
}
} else {
//maybe should be JustRerender?
//maybe should be JustRedraw?
WindowMessageResponse::DoNothing
}
}
@@ -188,7 +186,7 @@ impl StartMenu {
for c in 0..CATEGORIES.len() {
let name = CATEGORIES[c];
self.components.push(Box::new(HighlightButton::new(
name.to_string(), [42, self.y_each * c + 1], [self.dimensions[0] - 42 - 1, self.y_each], name, StartMenuMessage::CategoryClick(name), StartMenuMessage::ChangeAcknowledge, c == 0
name.to_string(), [42, self.y_each * c + 1], [self.dimensions[0] - 42 - 1, self.y_each], name.to_string(), StartMenuMessage::CategoryClick(name), StartMenuMessage::ChangeAcknowledge, c == 0
)));
}
}
@@ -198,7 +196,3 @@ impl StartMenu {
}
}
pub fn main() {
listen(StartMenu::new());
}

View File

@@ -7,7 +7,7 @@ use crate::messages::{ WindowMessage, WindowMessageResponse, WindowManagerReques
use crate::framebuffer::Dimensions;
use crate::themes::ThemeInfo;
use crate::components::Component;
use crate::components::toggle_button::{ ToggleButton, ToggleButtonAlignment };
use crate::components::toggle_button::ToggleButton;
const PADDING: usize = 4;
const META_WIDTH: usize = 175; //of the window button
@@ -33,9 +33,9 @@ impl WindowLike for Taskbar {
WindowMessage::Init(dimensions) => {
self.dimensions = dimensions;
self.components = vec![
Box::new(ToggleButton::new("start-button".to_string(), [PADDING, PADDING], [44, self.dimensions[1] - (PADDING * 2)], "Start".to_string(), TaskbarMessage::ShowStartMenu, TaskbarMessage::HideStartMenu, false, Some(ToggleButtonAlignment::Left))),
Box::new(ToggleButton::new("start-button".to_string(), [PADDING, PADDING], [44, self.dimensions[1] - (PADDING * 2)], "Start".to_string(), TaskbarMessage::ShowStartMenu, TaskbarMessage::HideStartMenu, false)),
];
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
WindowMessage::Shortcut(shortcut) => {
match shortcut {
@@ -52,7 +52,7 @@ impl WindowLike for Taskbar {
InfoType::WindowsInWorkspace(windows, focused_id) => {
self.windows_in_workspace = windows;
self.focused_id = focused_id;
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
}
_ => WindowMessageResponse::DoNothing,
}
@@ -80,7 +80,7 @@ impl WindowLike for Taskbar {
}
let info = &self.windows_in_workspace[wi];
let name = &info.1;
let mut b = ToggleButton::new(name.to_string() + "-window", [PADDING * 2 + 44 + (META_WIDTH + PADDING) * wi, PADDING], [META_WIDTH, self.dimensions[1] - (PADDING * 2)], name.to_string(), TaskbarMessage::Nothing, TaskbarMessage::Nothing, false, Some(ToggleButtonAlignment::Left));
let mut b = ToggleButton::new(name.to_string() + "-window", [PADDING * 2 + 44 + (META_WIDTH + PADDING) * wi, PADDING], [META_WIDTH, self.dimensions[1] - (PADDING * 2)], name.to_string(), TaskbarMessage::Nothing, TaskbarMessage::Nothing, false);
b.inverted = info.0 == self.focused_id;
instructions.extend(b.draw(theme_info));
}
@@ -119,7 +119,7 @@ impl Taskbar {
_ => WindowMessageResponse::DoNothing,
}
} else {
//maybe should be JustRerender?
//maybe should be JustRedraw?
WindowMessageResponse::DoNothing
}
}

View File

@@ -22,13 +22,13 @@ impl WindowLike for WorkspaceIndicator {
match message {
WindowMessage::Init(dimensions) => {
self.dimensions = dimensions;
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
WindowMessage::Shortcut(shortcut) => {
match shortcut {
ShortcutType::SwitchWorkspace(workspace) => {
self.current_workspace = workspace;
WindowMessageResponse::JustRerender
WindowMessageResponse::JustRedraw
},
_ => WindowMessageResponse::DoNothing,
}

View File

@@ -43,7 +43,7 @@ impl fmt::Debug for WindowManagerRequest{
#[derive(PartialEq, Debug, Serialize, Deserialize)]
pub enum WindowMessageResponse {
Request(WindowManagerRequest),
JustRerender,
JustRedraw,
DoNothing,
}

View File

@@ -24,7 +24,7 @@ impl WindowLike for ProxyWindowLike {
let _ = stdin.write_all(("handle_message ".to_string() + &ron::to_string(&message).unwrap() + "\n").as_bytes());
}
let output = self.read_line();
ron::from_str(&output).unwrap_or(WindowMessageResponse::JustRerender)
ron::from_str(&output).unwrap_or(WindowMessageResponse::JustRedraw)
}
fn draw(&self, theme_info: &ThemeInfo) -> Vec<DrawInstructions> {

View File

@@ -3,9 +3,9 @@ use std::vec;
use std::collections::{ HashMap, VecDeque };
use std::fmt;
use std::boxed::Box;
use std::sync::{ LazyLock, Mutex };
use std::io::{ stdin, stdout, Write };
use std::process::exit;
use std::cell::RefCell;
use linux_framebuffer::Framebuffer;
use termion::input::TermRead;
@@ -23,24 +23,26 @@ use crate::essential::taskbar::Taskbar;
use crate::essential::lock_screen::LockScreen;
use crate::essential::workspace_indicator::WorkspaceIndicator;
use crate::essential::start_menu::StartMenu;
use crate::logging::log;
use crate::essential::about::About;
use crate::essential::help::Help;
//use crate::logging::log;
pub const TASKBAR_HEIGHT: usize = 38;
pub const INDICATOR_HEIGHT: usize = 20;
const WINDOW_TOP_HEIGHT: usize = 26;
static WRITER: LazyLock<Mutex<FramebufferWriter>> = LazyLock::new(|| Mutex::new(Default::default()));
pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) {
let dimensions = [framebuffer_info.width, framebuffer_info.height];
println!("bg: {}x{}", dimensions[0], dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT);
WRITER.lock().unwrap().init(framebuffer_info.clone());
let mut writer: FramebufferWriter = Default::default();
let mut wm: WindowManager = WindowManager::new(framebuffer, dimensions);
writer.init(framebuffer_info.clone());
wm.render(None, false);
let mut wm: WindowManager = WindowManager::new(writer, framebuffer, dimensions);
wm.draw(None, false);
let stdin = stdin().lock();
let mut stdout = stdout().into_raw_mode().unwrap();
@@ -52,8 +54,8 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) {
for c in stdin.keys() {
if let Some(kc) = key_to_char(c.unwrap()) {
//do not allow exit when locked unless debugging
//if kc == KeyChar::Alt('e') {
if kc == KeyChar::Alt('e') && !wm.locked {
//if kc == KeyChar::Alt('E') {
if kc == KeyChar::Alt('E') && !wm.locked {
write!(stdout, "{}", cursor::Show).unwrap();
stdout.suspend_raw_mode().unwrap();
exit(0);
@@ -130,6 +132,7 @@ impl fmt::Debug for WindowLikeInfo {
}
pub struct WindowManager {
writer: RefCell<FramebufferWriter>,
id_count: usize,
window_infos: Vec<WindowLikeInfo>,
dimensions: Dimensions,
@@ -144,8 +147,9 @@ pub struct WindowManager {
//1 is up, 2 is down
impl WindowManager {
pub fn new(framebuffer: Framebuffer, dimensions: Dimensions) -> Self {
pub fn new(writer: FramebufferWriter, framebuffer: Framebuffer, dimensions: Dimensions) -> Self {
let mut wm = WindowManager {
writer: RefCell::new(writer),
id_count: 0,
window_infos: Vec::new(),
dimensions,
@@ -186,7 +190,7 @@ impl WindowManager {
self.window_infos.iter().position(|w| w.id == self.focused_id)
}
//should return an iterator but fuck it!
//used to return Vec<&WindowLikeInfo>, doesn't anymore for good reason
fn get_windows_in_workspace(&self, include_non_window: bool) -> Vec<&WindowLikeInfo> {
self.window_infos.iter().filter(|w| {
match w.workspace {
@@ -303,7 +307,7 @@ impl WindowManager {
//send to taskbar
press_response = self.toggle_start_menu(false);
if press_response != WindowMessageResponse::Request(WindowManagerRequest::CloseStartMenu) {
//only thing that needs to be rerendered is the start menu and taskbar
//only thing that needs to be redrawed is the start menu and taskbar
let start_menu_id = self.id_count + 1;
let taskbar_id = self.window_infos.iter().find(|w| w.window_like.subtype() == WindowLikeType::Taskbar).unwrap().id;
redraw_ids = Some(vec![start_menu_id, taskbar_id]);
@@ -354,7 +358,7 @@ impl WindowManager {
}
}
if changed {
press_response = WindowMessageResponse::JustRerender;
press_response = WindowMessageResponse::JustRedraw;
//avoid drawing everything under the moving window, much more efficient
use_saved_buffer = true;
redraw_ids = Some(vec![self.focused_id]);
@@ -375,7 +379,7 @@ impl WindowManager {
self.focused_id = self.window_infos[indicator_index].id;
self.window_infos[indicator_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::SwitchWorkspace(self.current_workspace)));
self.taskbar_update_windows();
press_response = WindowMessageResponse::JustRerender;
press_response = WindowMessageResponse::JustRedraw;
}
},
&ShortcutType::MoveWindowToWorkspace(workspace) => {
@@ -384,7 +388,7 @@ impl WindowManager {
if self.window_infos[focused_index].window_like.subtype() == WindowLikeType::Window {
self.window_infos[focused_index].workspace = Workspace::Workspace(workspace);
self.taskbar_update_windows();
press_response = WindowMessageResponse::JustRerender;
press_response = WindowMessageResponse::JustRedraw;
}
}
}
@@ -411,7 +415,7 @@ impl WindowManager {
//elevate it to the top
self.move_index_to_top(new_focus_index);
self.taskbar_update_windows();
press_response = WindowMessageResponse::JustRerender;
press_response = WindowMessageResponse::JustRedraw;
break;
} else if new_focus_index == current_index {
break; //did a full loop, found no windows
@@ -423,7 +427,7 @@ impl WindowManager {
if self.window_infos[focused_index].window_like.subtype() == WindowLikeType::Window {
self.window_infos.remove(focused_index);
self.taskbar_update_windows();
press_response = WindowMessageResponse::JustRerender;
press_response = WindowMessageResponse::JustRedraw;
}
}
},
@@ -432,7 +436,7 @@ impl WindowManager {
let window_dimensions = &self.window_infos[focused_index].dimensions;
self.window_infos[focused_index].top_left = [self.dimensions[0] / 2 - window_dimensions[0] / 2, self.dimensions[1] / 2 - window_dimensions[1] / 2];
use_saved_buffer = true;
press_response = WindowMessageResponse::JustRerender;
press_response = WindowMessageResponse::JustRedraw;
}
},
&ShortcutType::FullscreenWindow => {
@@ -451,7 +455,7 @@ impl WindowManager {
new_dimensions = self.window_infos[focused_index].dimensions;
}
self.window_infos[focused_index].window_like.handle_message(WindowMessage::ChangeDimensions([new_dimensions[0], new_dimensions[1] - WINDOW_TOP_HEIGHT]));
press_response = WindowMessageResponse::JustRerender;
press_response = WindowMessageResponse::JustRedraw;
}
}
},
@@ -465,7 +469,7 @@ impl WindowManager {
let new_dimensions = [self.dimensions[0] / 2, self.dimensions[1] - INDICATOR_HEIGHT - TASKBAR_HEIGHT];
self.window_infos[focused_index].dimensions = new_dimensions;
self.window_infos[focused_index].window_like.handle_message(WindowMessage::ChangeDimensions([new_dimensions[0], new_dimensions[1] - WINDOW_TOP_HEIGHT]));
press_response = WindowMessageResponse::JustRerender;
press_response = WindowMessageResponse::JustRedraw;
}
}
},
@@ -503,10 +507,10 @@ impl WindowManager {
key: c,
})
});
//at most, only the focused window needs to be rerendered
//at most, only the focused window needs to be redrawed
redraw_ids = Some(vec![self.window_infos[focused_index].id]);
//requests can result in window openings and closings, etc
if press_response != WindowMessageResponse::JustRerender {
if press_response != WindowMessageResponse::JustRedraw {
redraw_ids = None;
}
}
@@ -521,7 +525,7 @@ impl WindowManager {
WindowMessageResponse::Request(request) => self.handle_request(request),
_ => {},
};
self.render(redraw_ids, use_saved_buffer);
self.draw(redraw_ids, use_saved_buffer);
}
}
@@ -541,6 +545,8 @@ impl WindowManager {
"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,
};
if w.is_none() {
@@ -581,7 +587,6 @@ impl WindowManager {
},
WindowManagerRequest::ClipboardCopy(content) => {
self.clipboard = Some(content);
log(&format!("{:?}", self.clipboard));
},
};
}
@@ -591,18 +596,18 @@ impl WindowManager {
}
//another issue with a huge vector of draw instructions; it takes up heap memory
pub fn render(&mut self, maybe_redraw_ids: Option<Vec<usize>>, use_saved_buffer: bool) {
pub fn draw(&mut self, maybe_redraw_ids: Option<Vec<usize>>, use_saved_buffer: bool) {
let theme_info = get_theme_info(&self.theme).unwrap();
//use in conjunction with redraw ids, so a window moving can work without redrawing everything,
//can just redraw the saved state + window
if use_saved_buffer {
WRITER.lock().unwrap().write_saved_buffer_to_raw();
self.writer.borrow_mut().write_saved_buffer_to_raw();
}
//get windows to redraw
let redraw_ids = maybe_redraw_ids.unwrap_or(Vec::new());
let redraw_windows = self.get_windows_in_workspace(true);
let maybe_length = redraw_windows.len();
let redraw_windows = redraw_windows.iter().filter(|w| {
let all_in_workspace = self.get_windows_in_workspace(true);
let maybe_length = all_in_workspace.len();
let redraw_windows = all_in_workspace.iter().filter(|w| {
//basically, maybe_redraw_ids was None
if redraw_ids.len() > 0 {
redraw_ids.contains(&w.id)
@@ -614,7 +619,6 @@ impl WindowManager {
let max_index = if redraw_ids.len() > 0 { redraw_ids.len() } else { maybe_length } - 1;
let mut w_index = 0;
for window_info in redraw_windows {
//unsafe { SERIAL1.lock().write_text(&format!("{:?}\n", &window_info.window_like.subtype())); }
let window_dimensions = if window_info.fullscreen {
[self.dimensions[0], self.dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT]
} else {
@@ -625,7 +629,7 @@ impl WindowManager {
if is_window {
//if this is the top most window to draw, snapshot
if w_index == max_index && !use_saved_buffer && redraw_ids.len() == 0 {
WRITER.lock().unwrap().save_buffer();
self.writer.borrow_mut().save_buffer();
}
//offset top left by the window top height for windows (because windows can't draw in that region)
instructions = instructions.iter().map(|instruction| {
@@ -654,7 +658,7 @@ impl WindowManager {
DrawInstructions::Rect([1, window_dimensions[1] - 1], [window_dimensions[0] - 1, 1], theme_info.border_right_bottom),
]);
}
let mut framebuffer_info = WRITER.lock().unwrap().get_info();
let mut framebuffer_info = self.writer.borrow().get_info();
let bytes_per_pixel = framebuffer_info.bytes_per_pixel;
let window_width = window_dimensions[0];
let window_height = window_dimensions[1];
@@ -690,9 +694,9 @@ impl WindowManager {
},
}
}
WRITER.lock().unwrap().draw_buffer(window_info.top_left, window_dimensions[1], window_dimensions[0] * bytes_per_pixel, &window_writer.get_buffer());
self.writer.borrow_mut().draw_buffer(window_info.top_left, window_dimensions[1], window_dimensions[0] * bytes_per_pixel, &window_writer.get_buffer());
w_index += 1;
}
self.framebuffer.write_frame(WRITER.lock().unwrap().get_buffer());
self.framebuffer.write_frame(self.writer.borrow().get_buffer());
}
}