custom backgrounds, audio player better
This commit is contained in:
@@ -6,6 +6,7 @@ use std::fs::{ read_to_string, File };
|
||||
|
||||
use rodio::{ Decoder, OutputStream, Sink, Source };
|
||||
use rand::prelude::*;
|
||||
use audiotags::Tag;
|
||||
|
||||
use ming_wm::window_manager::{ DrawInstructions, WindowLike, WindowLikeType };
|
||||
use ming_wm::messages::{ WindowMessage, WindowMessageResponse };
|
||||
@@ -22,7 +23,7 @@ const LINE_HEIGHT: usize = 18;
|
||||
struct AudioPlayer {
|
||||
dimensions: Dimensions,
|
||||
base_directory: String,
|
||||
queue: Vec<(PathBuf, u64)>,
|
||||
queue: Vec<(PathBuf, u64, Option<String>)>,
|
||||
stream: Option<Box<OutputStream>>,
|
||||
sink: Option<Sink>,
|
||||
command: String,
|
||||
@@ -60,13 +61,17 @@ impl WindowLike for AudioPlayer {
|
||||
}
|
||||
|
||||
fn draw(&self, theme_info: &ThemeInfo) -> Vec<DrawInstructions> {
|
||||
let mut instructions = vec![DrawInstructions::Text([2, self.dimensions[1] - LINE_HEIGHT], "times-new-roman".to_string(), if self.command.len() > 0 { self.command.clone() } else { self.response.clone() }, theme_info.text, theme_info.background, None, None)];
|
||||
let mut instructions = vec![DrawInstructions::Text([2, self.dimensions[1] - LINE_HEIGHT], vec!["times-new-roman".to_string()], if self.command.len() > 0 { self.command.clone() } else { self.response.clone() }, theme_info.text, theme_info.background, None, None)];
|
||||
if let Some(sink) = &self.sink {
|
||||
let current = &self.queue[self.queue.len() - sink.len()];
|
||||
let current_name = current.0.file_name().unwrap().to_string_lossy().into_owned();
|
||||
instructions.push(DrawInstructions::Text([self.dimensions[0] / 2 - current_name.len() * MONO_WIDTH as usize / 2, 2], "times-new-romono".to_string(), current_name.clone(), theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH)));
|
||||
instructions.push(DrawInstructions::Text([self.dimensions[0] / 2 - current_name.len() * MONO_WIDTH as usize / 2, 2], vec!["times-new-romono".to_string(), "shippori-mincho".to_string()], current_name.clone(), theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH)));
|
||||
if let Some(artist) = ¤t.2 {
|
||||
let artist_string = "by ".to_string() + &artist;
|
||||
instructions.push(DrawInstructions::Text([self.dimensions[0] / 2 - artist_string.len() * MONO_WIDTH as usize / 2, LINE_HEIGHT + 2], vec!["times-new-romono".to_string()], artist_string, theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH)));
|
||||
}
|
||||
let time_string = format!("{}/{}", format_seconds(sink.get_pos().as_secs()), format_seconds(current.1));
|
||||
instructions.push(DrawInstructions::Text([self.dimensions[0] / 2 - time_string.len() * MONO_WIDTH as usize / 2, LINE_HEIGHT + 2], "times-new-romono".to_string(), time_string, theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH)));
|
||||
instructions.push(DrawInstructions::Text([self.dimensions[0] / 2 - time_string.len() * MONO_WIDTH as usize / 2, LINE_HEIGHT * 2 + 2], vec!["times-new-romono".to_string()], time_string, theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH)));
|
||||
}
|
||||
//
|
||||
instructions
|
||||
@@ -162,7 +167,7 @@ impl AudioPlayer {
|
||||
for item in &queue {
|
||||
let file = BufReader::new(File::open(item).unwrap());
|
||||
let decoded = Decoder::new(file).unwrap();
|
||||
self.queue.push((item.clone(), decoded.total_duration().unwrap().as_secs()));
|
||||
self.queue.push((item.clone(), decoded.total_duration().unwrap().as_secs(), Tag::new().read_from_path(item.clone()).unwrap().artist().map(|s| s.to_string())));
|
||||
sink.append(decoded);
|
||||
}
|
||||
self.stream = Some(Box::new(stream));
|
||||
|
||||
@@ -4,7 +4,7 @@ use ming_wm::framebuffer::FramebufferInfo;
|
||||
use ming_wm::window_manager::init;
|
||||
|
||||
fn main() {
|
||||
let mut fb = Framebuffer::new("/dev/fb0").unwrap();
|
||||
let fb = Framebuffer::new("/dev/fb0").unwrap();
|
||||
let bytes_per_pixel = (fb.var_screen_info.bits_per_pixel as usize) / 8;
|
||||
let fb_info = FramebufferInfo {
|
||||
byte_len: (fb.var_screen_info.yres_virtual * fb.fix_screen_info.line_length) as usize,
|
||||
|
||||
@@ -303,7 +303,7 @@ impl WindowLike for Malvim {
|
||||
};
|
||||
instructions.extend(vec![
|
||||
DrawInstructions::Rect([used_width, 2], [future_used_width, BAND_HEIGHT - 2], background),
|
||||
DrawInstructions::Text([used_width + 2, 2], "times-new-romono".to_string(), if file_info.changed { "+ ".to_string() } else { String::new() } + &file_info.name, theme_info.alt_text, background, Some(0), Some(MONO_WIDTH)),
|
||||
DrawInstructions::Text([used_width + 2, 2], vec!["times-new-romono".to_string()], if file_info.changed { "+ ".to_string() } else { String::new() } + &file_info.name, theme_info.alt_text, background, Some(0), Some(MONO_WIDTH)),
|
||||
]);
|
||||
used_width = future_used_width;
|
||||
}
|
||||
@@ -321,13 +321,13 @@ impl WindowLike for Malvim {
|
||||
//write line num text (if start of line)
|
||||
let y0 = BAND_HEIGHT + rel_line_num * LINE_HEIGHT + PADDING;
|
||||
if line.0 {
|
||||
instructions.push(DrawInstructions::Text([PADDING, y0], "times-new-romono".to_string(), line.1.to_string(), theme_info.alt_secondary, theme_info.alt_background, Some(0), Some(MONO_WIDTH)));
|
||||
instructions.push(DrawInstructions::Text([PADDING, y0], vec!["times-new-romono".to_string()], line.1.to_string(), theme_info.alt_secondary, theme_info.alt_background, Some(0), Some(MONO_WIDTH)));
|
||||
sub_line_num = 0;
|
||||
}
|
||||
let x1 = current.line_num_width + PADDING * 2;
|
||||
//write actual line
|
||||
//line.2
|
||||
instructions.push(DrawInstructions::Text([x1, y0], "times-new-romono".to_string(), line.2.clone(), theme_info.alt_text, theme_info.alt_background, Some(0), Some(MONO_WIDTH)));
|
||||
instructions.push(DrawInstructions::Text([x1, y0], vec!["times-new-romono".to_string()], line.2.clone(), theme_info.alt_text, theme_info.alt_background, Some(0), Some(MONO_WIDTH)));
|
||||
sub_line_num += 1;
|
||||
let max = sub_line_num * current.max_chars_per_line;
|
||||
let min = max - current.max_chars_per_line;
|
||||
@@ -337,26 +337,26 @@ impl WindowLike for Malvim {
|
||||
instructions.push(DrawInstructions::Rect(top_left, [MONO_WIDTH as usize, LINE_HEIGHT], theme_info.top));
|
||||
//draw the char over it
|
||||
if line.2.len() > 0 {
|
||||
instructions.push(DrawInstructions::Text(top_left, "times-new-romono".to_string(), line.2.chars().nth(current_file.cursor_pos - min).unwrap().to_string(), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH)));
|
||||
instructions.push(DrawInstructions::Text(top_left, vec!["times-new-romono".to_string()], line.2.chars().nth(current_file.cursor_pos - min).unwrap().to_string(), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//bottom blue band stuff
|
||||
//write mode
|
||||
instructions.push(DrawInstructions::Text([0, self.dimensions[1] - BAND_HEIGHT * 2 + 1], "times-new-romono".to_string(), self.mode.to_string(), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH)));
|
||||
instructions.push(DrawInstructions::Text([0, self.dimensions[1] - BAND_HEIGHT * 2 + 1], vec!["times-new-romono".to_string()], self.mode.to_string(), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH)));
|
||||
let file_status;
|
||||
if self.files.len() > 0 {
|
||||
file_status = self.files[self.current_file_index].name.clone();
|
||||
} else {
|
||||
file_status = "No file open".to_string();
|
||||
}
|
||||
instructions.push(DrawInstructions::Text([self.dimensions[0] - file_status.len() * (MONO_WIDTH as usize), self.dimensions[1] - BAND_HEIGHT * 2 + 1], "times-new-romono".to_string(), file_status, theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH)));
|
||||
instructions.push(DrawInstructions::Text([self.dimensions[0] - file_status.len() * (MONO_WIDTH as usize), self.dimensions[1] - BAND_HEIGHT * 2 + 1], vec!["times-new-romono".to_string()], file_status, theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH)));
|
||||
//write command or bottom message
|
||||
if self.mode == Mode::Command {
|
||||
instructions.push(DrawInstructions::Text([0, self.dimensions[1] - BAND_HEIGHT], "times-new-romono".to_string(), ":".to_string() + &self.command.clone().unwrap_or("".to_string()), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH)));
|
||||
instructions.push(DrawInstructions::Text([0, self.dimensions[1] - BAND_HEIGHT], vec!["times-new-romono".to_string()], ":".to_string() + &self.command.clone().unwrap_or("".to_string()), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH)));
|
||||
} else if self.mode == Mode::Normal && self.bottom_message.is_some() {
|
||||
instructions.push(DrawInstructions::Text([0, self.dimensions[1] - BAND_HEIGHT], "times-new-romono".to_string(), self.bottom_message.clone().unwrap(), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH)));
|
||||
instructions.push(DrawInstructions::Text([0, self.dimensions[1] - BAND_HEIGHT], vec!["times-new-romono".to_string()], self.bottom_message.clone().unwrap(), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH)));
|
||||
}
|
||||
instructions
|
||||
}
|
||||
|
||||
@@ -7,21 +7,9 @@ use ming_wm::window_manager::{ DrawInstructions, WindowLike, WindowLikeType };
|
||||
use ming_wm::messages::{ WindowMessage, WindowMessageResponse };
|
||||
use ming_wm::framebuffer::Dimensions;
|
||||
use ming_wm::themes::ThemeInfo;
|
||||
use ming_wm::utils::{ u8_to_hex, hex_to_u8, HEX_CHARS };
|
||||
use ming_wm::ipc::listen;
|
||||
|
||||
const HEX_CHARS: [char; 16] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
|
||||
|
||||
fn u8_to_hex(u: u8) -> String {
|
||||
let mut h = String::new();
|
||||
h.push(HEX_CHARS[(u / 16) as usize]);
|
||||
h.push(HEX_CHARS[(u % 16) as usize]);
|
||||
h
|
||||
}
|
||||
|
||||
fn hex_to_u8(c1: char, c2: char) -> u8 {
|
||||
(HEX_CHARS.iter().position(|c| c == &c1).unwrap() * 16 + HEX_CHARS.iter().position(|c| c == &c2).unwrap()) as u8
|
||||
}
|
||||
|
||||
//16x16 with 40 mines
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -157,8 +145,8 @@ impl WindowLike for Minesweeper {
|
||||
fn draw(&self, theme_info: &ThemeInfo) -> Vec<DrawInstructions> {
|
||||
if self.state == State::Seed {
|
||||
vec![
|
||||
DrawInstructions::Text([4, 4], "times-new-roman".to_string(), "Type in random characters to initalise the seed".to_string(), theme_info.text, theme_info.background, None, None),
|
||||
DrawInstructions::Text([4, 4 + 16], "times-new-roman".to_string(), self.random_chars.clone(), theme_info.text, theme_info.background, None, None),
|
||||
DrawInstructions::Text([4, 4], vec!["times-new-roman".to_string()], "Type in random characters to initalise the seed".to_string(), theme_info.text, theme_info.background, None, None),
|
||||
DrawInstructions::Text([4, 4 + 16], vec!["times-new-roman".to_string()], self.random_chars.clone(), theme_info.text, theme_info.background, None, None),
|
||||
]
|
||||
} else {
|
||||
let mut instructions = vec![
|
||||
@@ -195,7 +183,7 @@ impl WindowLike for Minesweeper {
|
||||
let tile = &self.tiles[y][x];
|
||||
if tile.revealed {
|
||||
if tile.mine {
|
||||
instructions.push(DrawInstructions::Text([x * tile_size + tile_size / 2 + 2, y * tile_size + tile_size / 2], "times-new-roman".to_string(), "x".to_string(), [255, 0, 0], theme_info.background, None, None));
|
||||
instructions.push(DrawInstructions::Text([x * tile_size + tile_size / 2 + 2, y * tile_size + tile_size / 2], vec!["times-new-roman".to_string()], "x".to_string(), [255, 0, 0], theme_info.background, None, None));
|
||||
} else {
|
||||
let color = match tile.touching {
|
||||
1 => [0, 0, 255],
|
||||
@@ -208,7 +196,7 @@ impl WindowLike for Minesweeper {
|
||||
//8
|
||||
_ => [128, 128, 128],
|
||||
};
|
||||
instructions.push(DrawInstructions::Text([x * tile_size + tile_size / 2 + 5, y * tile_size + tile_size / 2 + 2], "times-new-roman".to_string(), tile.touching.to_string(), color, theme_info.background, None, None));
|
||||
instructions.push(DrawInstructions::Text([x * tile_size + tile_size / 2 + 5, y * tile_size + tile_size / 2 + 2], vec!["times-new-roman".to_string()], tile.touching.to_string(), color, theme_info.background, None, None));
|
||||
}
|
||||
} else {
|
||||
let top_left = [x * tile_size + 6, y * tile_size + 5];
|
||||
@@ -226,15 +214,15 @@ impl WindowLike for Minesweeper {
|
||||
//right bottom
|
||||
DrawInstructions::Rect([top_left[0] + tile_size - 4, top_left[1] + 3], [3, tile_size - 4], [128, 128, 128]),
|
||||
//
|
||||
DrawInstructions::Text([x * tile_size + tile_size / 2 - 2, y * tile_size + tile_size / 2], "times-new-roman".to_string(), u8_to_hex((y * 16 + x) as u8), theme_info.text, theme_info.background, None, None),
|
||||
DrawInstructions::Text([x * tile_size + tile_size / 2 - 2, y * tile_size + tile_size / 2], vec!["times-new-roman".to_string()], u8_to_hex((y * 16 + x) as u8), theme_info.text, theme_info.background, None, None),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.state == State::Lost {
|
||||
instructions.extend(vec![DrawInstructions::Text([4, 4], "times-new-roman".to_string(), "You LOST!!! Press a key to play again.".to_string(), theme_info.text, theme_info.background, None, None)]);
|
||||
instructions.extend(vec![DrawInstructions::Text([4, 4], vec!["times-new-roman".to_string()], "You LOST!!! Press a key to play again.".to_string(), theme_info.text, theme_info.background, None, None)]);
|
||||
} else if self.state == State::Won {
|
||||
instructions.extend(vec![DrawInstructions::Text([4, 4], "times-new-roman".to_string(), "You WON!!! Press a key to play again.".to_string(), theme_info.text, theme_info.background, None, None)]);
|
||||
instructions.extend(vec![DrawInstructions::Text([4, 4], vec!["times-new-roman".to_string()], "You WON!!! Press a key to play again.".to_string(), theme_info.text, theme_info.background, None, None)]);
|
||||
}
|
||||
instructions
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ impl WindowLike for Terminal {
|
||||
break;
|
||||
}
|
||||
let line = self.actual_lines[line_num].clone();
|
||||
instructions.push(DrawInstructions::Text([PADDING, text_y], "times-new-romono".to_string(), line, theme_info.alt_text, theme_info.alt_background, Some(0), Some(MONO_WIDTH)));
|
||||
instructions.push(DrawInstructions::Text([PADDING, text_y], vec!["times-new-romono".to_string()], line, theme_info.alt_text, theme_info.alt_background, Some(0), Some(MONO_WIDTH)));
|
||||
text_y += LINE_HEIGHT;
|
||||
}
|
||||
instructions
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::io::{ Read, Write };
|
||||
use ron;
|
||||
|
||||
fn main() {
|
||||
println!("{}", 'だ');
|
||||
println!("a");
|
||||
let mut a = Command::new("cargo").arg("run").arg("-q").arg("--bin").arg("start_menu").stdout(Stdio::piped()).stdin(Stdio::piped()).stderr(Stdio::null()).spawn().unwrap();
|
||||
a.stdin.unwrap().write_all("subtype\n".to_string().as_bytes());
|
||||
|
||||
@@ -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], "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.to_string(), 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], "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.to_string(), theme_info.text, theme_info.background, None, None),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ impl<T: Clone> Component<T> for ToggleButton<T> {
|
||||
//the background if self.draw_bg
|
||||
//DrawInstructions::Rect(),
|
||||
//the text (for now, hardcoded top left)
|
||||
DrawInstructions::Text([self.top_left[0] + 4, self.top_left[1] + (self.size[1] - font_height) / 2], "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.to_string(), theme_info.text, theme_info.background, None, None),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
use std::vec;
|
||||
use std::vec::Vec;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
||||
use dirs::config_dir;
|
||||
|
||||
use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType, TASKBAR_HEIGHT, INDICATOR_HEIGHT };
|
||||
use crate::messages::{ WindowMessage, WindowMessageResponse };
|
||||
use crate::messages::{ WindowMessage, WindowMessageResponse, ShortcutType };
|
||||
use crate::framebuffer::Dimensions;
|
||||
use crate::themes::ThemeInfo;
|
||||
use crate::utils::{ hex_to_u8, is_hex };
|
||||
|
||||
pub struct DesktopBackground {
|
||||
dimensions: Dimensions,
|
||||
current_workspace: u8,
|
||||
}
|
||||
|
||||
impl WindowLike for DesktopBackground {
|
||||
@@ -17,12 +23,41 @@ impl WindowLike for DesktopBackground {
|
||||
self.dimensions = dimensions;
|
||||
WindowMessageResponse::JustRerender
|
||||
},
|
||||
WindowMessage::Shortcut(shortcut) => {
|
||||
match shortcut {
|
||||
ShortcutType::SwitchWorkspace(workspace) => {
|
||||
self.current_workspace = workspace;
|
||||
WindowMessageResponse::JustRerender
|
||||
},
|
||||
_ => WindowMessageResponse::DoNothing,
|
||||
}
|
||||
},
|
||||
_ => WindowMessageResponse::DoNothing,
|
||||
}
|
||||
}
|
||||
|
||||
//simple
|
||||
fn draw(&self, _theme_info: &ThemeInfo) -> Vec<DrawInstructions> {
|
||||
if let Ok(mut file) = File::open(format!("{}/ming-wm/desktop-background", config_dir().unwrap().into_os_string().into_string().unwrap())) {
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
let lines: Vec<&str> = contents.split("\n").collect();
|
||||
if lines.len() > self.current_workspace.into() {
|
||||
let line = lines[self.current_workspace as usize];
|
||||
if line.starts_with("#") && line.len() == 7 {
|
||||
let line_hex = &line[1..];
|
||||
//if all characters are valid hex
|
||||
if line_hex.find(|c| !is_hex(c)).is_none() {
|
||||
let mut chars = line_hex.chars();
|
||||
let color = [hex_to_u8(chars.next().unwrap(), chars.next().unwrap()), hex_to_u8(chars.next().unwrap(), chars.next().unwrap()), hex_to_u8(chars.next().unwrap(), chars.next().unwrap())];
|
||||
return vec![DrawInstructions::Rect([0, 0], self.dimensions, color)];
|
||||
}
|
||||
} else {
|
||||
//first character of line is either r or any other character, but is not part of the path
|
||||
return vec![DrawInstructions::Bmp([0, 0], line[1..].to_string(), line.chars().next().unwrap() == 'r')];
|
||||
}
|
||||
}
|
||||
}
|
||||
vec![DrawInstructions::Rect([0, 0], self.dimensions, [0, 128, 128])]
|
||||
}
|
||||
|
||||
@@ -38,7 +73,10 @@ impl WindowLike for DesktopBackground {
|
||||
|
||||
impl DesktopBackground {
|
||||
pub fn new() -> Self {
|
||||
Self { dimensions: [0, 0] }
|
||||
Self {
|
||||
dimensions: [0, 0],
|
||||
current_workspace: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,11 +50,11 @@ impl WindowLike for LockScreen {
|
||||
fn draw(&self, _theme_info: &ThemeInfo) -> Vec<DrawInstructions> {
|
||||
vec![
|
||||
DrawInstructions::Rect([0, 0], self.dimensions, [0, 0, 0]),
|
||||
DrawInstructions::Text([4, 4], "times-new-roman".to_string(), "The bulldozer outside the kitchen window was quite a big one.".to_string(), [255, 255, 255], [0, 0, 0], None, None),
|
||||
DrawInstructions::Text([4, 4 + 16], "times-new-roman".to_string(), "\"Yellow,\" he thought, and stomped off back to his bedroom to get dressed.".to_string(), [255, 255, 255], [0, 0, 0], None, None),
|
||||
DrawInstructions::Text([4, 4 + 16 * 2], "times-new-roman".to_string(), "He stared at it.".to_string(), [255, 255, 255], [0, 0, 0], None, None),
|
||||
DrawInstructions::Text([4, 4 + 16 * 3], "times-new-roman".to_string(), "Password: ".to_string(), [255, 255, 255], [0, 0, 0], None, None),
|
||||
DrawInstructions::Text([77, 4 + 16 * 3], "times-new-roman".to_string(), "*".repeat(self.input_password.len()), [255, 255, 255], [0, 0, 0], None, None),
|
||||
DrawInstructions::Text([4, 4], vec!["times-new-roman".to_string()], "The bulldozer outside the kitchen window was quite a big one.".to_string(), [255, 255, 255], [0, 0, 0], None, None),
|
||||
DrawInstructions::Text([4, 4 + 16], vec!["times-new-roman".to_string()], "\"Yellow,\" he thought, and stomped off back to his bedroom to get dressed.".to_string(), [255, 255, 255], [0, 0, 0], None, None),
|
||||
DrawInstructions::Text([4, 4 + 16 * 2], vec!["times-new-roman".to_string()], "He stared at it.".to_string(), [255, 255, 255], [0, 0, 0], None, None),
|
||||
DrawInstructions::Text([4, 4 + 16 * 3], vec!["times-new-roman".to_string()], "Password: ".to_string(), [255, 255, 255], [0, 0, 0], None, None),
|
||||
DrawInstructions::Text([77, 4 + 16 * 3], vec!["times-new-roman".to_string()], "*".repeat(self.input_password.len()), [255, 255, 255], [0, 0, 0], None, None),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ impl WindowLike for StartMenu {
|
||||
//background
|
||||
DrawInstructions::Rect([0, 1], [self.dimensions[0] - 1, self.dimensions[1] - 1], theme_info.background),
|
||||
//mingde logo
|
||||
DrawInstructions::Mingde([2, 2]),
|
||||
DrawInstructions::Bmp([2, 2], "./bmps/mingde.bmp".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),
|
||||
];
|
||||
|
||||
@@ -29,7 +29,7 @@ impl WindowLike for WorkspaceIndicator {
|
||||
ShortcutType::SwitchWorkspace(workspace) => {
|
||||
self.current_workspace = workspace;
|
||||
WindowMessageResponse::JustRerender
|
||||
}
|
||||
},
|
||||
_ => WindowMessageResponse::DoNothing,
|
||||
}
|
||||
},
|
||||
@@ -48,9 +48,9 @@ impl WindowLike for WorkspaceIndicator {
|
||||
for w in 0..9 {
|
||||
if w == self.current_workspace as usize {
|
||||
instructions.push(DrawInstructions::Rect([w * WIDTH, 0], [WIDTH, self.dimensions[1]], theme_info.top));
|
||||
instructions.push(DrawInstructions::Text([w * WIDTH + 5, 4], "times-new-roman".to_string(), (w + 1).to_string(), theme_info.top_text, theme_info.top, None, None));
|
||||
instructions.push(DrawInstructions::Text([w * WIDTH + 5, 4], vec!["times-new-roman".to_string()], (w + 1).to_string(), theme_info.top_text, theme_info.top, None, None));
|
||||
} else {
|
||||
instructions.push(DrawInstructions::Text([w * WIDTH + 5, 4], "times-new-roman".to_string(), (w + 1).to_string(), theme_info.text, theme_info.background, None, None));
|
||||
instructions.push(DrawInstructions::Text([w * WIDTH + 5, 4], vec!["times-new-roman".to_string()], (w + 1).to_string(), theme_info.text, theme_info.background, None, None));
|
||||
}
|
||||
}
|
||||
//also add the utc time in the right edge
|
||||
@@ -58,7 +58,7 @@ impl WindowLike for WorkspaceIndicator {
|
||||
let hours = (today_secs / ONE_HOUR).to_string();
|
||||
let minutes = ((today_secs % ONE_HOUR) / ONE_MINUTE).to_string();
|
||||
let time_string = format!("{}:{}~ UTC", if hours.len() == 1 { "0".to_string() + &hours } else { hours }, if minutes.len() == 1 { "0".to_string() + &minutes } else { minutes });
|
||||
instructions.push(DrawInstructions::Text([self.dimensions[0] - 90, 4], "times-new-roman".to_string(), time_string, theme_info.text, theme_info.background, None, None));
|
||||
instructions.push(DrawInstructions::Text([self.dimensions[0] - 90, 4], vec!["times-new-roman".to_string()], time_string, theme_info.text, theme_info.background, None, None));
|
||||
instructions
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use std::vec::Vec;
|
||||
use core::ptr;
|
||||
//use core::ptr;
|
||||
|
||||
use crate::fs::{ get_font_char, get_bmp };
|
||||
use bmp_rust::bmp::BMP;
|
||||
|
||||
use crate::fs::get_font_char_from_fonts;
|
||||
|
||||
pub type Point = [usize; 2]; //x, y
|
||||
pub type Dimensions = [usize; 2]; //width, height
|
||||
@@ -87,7 +89,7 @@ impl FramebufferWriter {
|
||||
for _y in 0..height {
|
||||
self.buffer[start_pos..(start_pos + bytes_per_line)]
|
||||
.copy_from_slice(&bytes[start..(start + bytes_per_line)]);
|
||||
let _ = unsafe { ptr::read_volatile(&self.buffer[start_pos]) };
|
||||
//let _ = unsafe { ptr::read_volatile(&self.buffer[start_pos]) };
|
||||
start += bytes_per_line;
|
||||
start_pos += self.info.stride * self.info.bytes_per_pixel;
|
||||
}
|
||||
@@ -178,16 +180,14 @@ impl FramebufferWriter {
|
||||
|
||||
//text
|
||||
|
||||
//this, draw_char, and get_font_char should be more much optimised
|
||||
pub fn draw_text(&mut self, top_left: Point, font_name: &str, text: &str, color: RGBColor, bg_color: RGBColor, horiz_spacing: usize, mono_width: Option<u8>) {
|
||||
pub fn draw_text(&mut self, top_left: Point, fonts: Vec<String>, text: &str, color: RGBColor, bg_color: RGBColor, horiz_spacing: usize, mono_width: Option<u8>) {
|
||||
let mut top_left = top_left;
|
||||
//todo, config space
|
||||
for c in text.chars() {
|
||||
if c == ' ' {
|
||||
top_left[0] += mono_width.unwrap_or(5) as usize;
|
||||
} else {
|
||||
//so a ? char must be in every font
|
||||
let char_info = get_font_char(&("./bmps/".to_string() + font_name), c).unwrap_or(get_font_char(&("./bmps/".to_string() + font_name), '?').unwrap());
|
||||
let char_info = get_font_char_from_fonts(&fonts, c);
|
||||
let char_width = char_info.1[0].len();
|
||||
let add_after: usize;
|
||||
if let Some(mono_width) = mono_width {
|
||||
@@ -210,13 +210,19 @@ impl FramebufferWriter {
|
||||
|
||||
//bmps
|
||||
|
||||
pub fn _draw_mingde(&mut self, top_left: Point) {
|
||||
//reverse is workaround for when my bmp lib returns rgba instead of bgra
|
||||
pub fn draw_bmp(&mut self, top_left: Point, path: String, reverse: bool) {
|
||||
let b = BMP::new_from_file(&path);
|
||||
let dib_header = b.get_dib_header().unwrap();
|
||||
let pixel_data = b.get_pixel_data().unwrap();
|
||||
let height = dib_header.height as usize;
|
||||
let width = dib_header.width as usize;
|
||||
let mut start_pos;
|
||||
let mingde = get_bmp("./bmps/mingde.bmp");
|
||||
for row in 0..mingde.len() {
|
||||
for row in 0..height {
|
||||
start_pos = ((top_left[1] + row) * self.info.stride + top_left[0]) * self.info.bytes_per_pixel;
|
||||
for color in &mingde[row] {
|
||||
self._draw_pixel(start_pos, [color[0], color[1], color[2]]);
|
||||
for column in 0..width {
|
||||
let color = b.get_color_of_pixel_efficient(column, row, &dib_header, &pixel_data).unwrap();
|
||||
self._draw_pixel(start_pos, if reverse { [color[2], color[1], color[0]] } else { [color[0], color[1], color[2]] });
|
||||
start_pos += self.info.bytes_per_pixel;
|
||||
}
|
||||
}
|
||||
|
||||
59
src/fs.rs
59
src/fs.rs
@@ -1,53 +1,30 @@
|
||||
use std::fs::read_dir;
|
||||
use std::fs::{ read_dir, File };
|
||||
use std::path::PathBuf;
|
||||
use std::io::Read;
|
||||
|
||||
use bmp_rust::bmp::BMP;
|
||||
|
||||
pub fn get_font_char(dir: &str, c: char) -> Option<(char, Vec<Vec<u8>>, u8)> {
|
||||
let c = if c == '/' { '𐘋' } else { c };
|
||||
for entry in read_dir(dir).unwrap() {
|
||||
let path = entry.unwrap().path();
|
||||
let path_chars: Vec<char> = path.file_name().unwrap().to_str().unwrap().to_string().chars().collect();
|
||||
if path_chars[0] == c {
|
||||
let mut ch: Vec<Vec<u8>> = Vec::new();
|
||||
if !path.is_dir() {
|
||||
let b = BMP::new_from_file(&path.clone().into_os_string().into_string().unwrap());
|
||||
let dib_header = b.get_dib_header().unwrap();
|
||||
let width = dib_header.width as usize;
|
||||
let height = dib_header.height as usize;
|
||||
for y in 0..height {
|
||||
let mut row = Vec::new();
|
||||
for x in 0..width {
|
||||
let pixel_color = b.get_color_of_px(x, y).unwrap();
|
||||
//if black, true
|
||||
row.push(pixel_color[3]); //push alpha channel
|
||||
}
|
||||
ch.push(row);
|
||||
}
|
||||
return Some((path_chars[0], ch, path_chars[1].to_digit(10).unwrap() as u8));
|
||||
}
|
||||
fn get_font_char(dir: &str, c: char) -> Option<(char, Vec<Vec<u8>>, u8)> {
|
||||
let c = if c == '/' { '𐘋' } else if c == '.' { '𐘅' } else { c };
|
||||
if let Ok(mut file) = File::open(dir.to_string() + "/" + &c.to_string() + ".alpha") {
|
||||
let mut ch: Vec<Vec<u8>> = Vec::new();
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
let lines: Vec<&str> = contents.split("\n").collect();
|
||||
for l in 1..lines.len() {
|
||||
ch.push(lines[l].split(",").map(|n| n.parse().unwrap()).collect());
|
||||
}
|
||||
return Some((c, ch, lines[0].parse().unwrap()));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
//the Vec<u8> should be [u8; 3] but thats a job for another day
|
||||
pub fn get_bmp(path: &str) -> Vec<Vec<Vec<u8>>> {
|
||||
let mut bmp: Vec<Vec<Vec<u8>>> = Vec::new();
|
||||
let b = BMP::new_from_file(path);
|
||||
let dib_header = b.get_dib_header().unwrap();
|
||||
let width = dib_header.width as usize;
|
||||
let height = dib_header.height as usize;
|
||||
for y in 0..height {
|
||||
let mut row = Vec::new();
|
||||
for x in 0..width {
|
||||
let pixel_color = b.get_color_of_px(x, y).unwrap();
|
||||
//if black, true
|
||||
row.push(vec![pixel_color[0], pixel_color[1], pixel_color[2]]); //push alpha channel
|
||||
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) {
|
||||
return font_char;
|
||||
}
|
||||
bmp.push(row);
|
||||
}
|
||||
bmp
|
||||
//so a ? char must be in every font
|
||||
get_font_char(&("./bmps/".to_string() + &fonts[0]), '?').unwrap()
|
||||
}
|
||||
|
||||
pub fn get_all_files(dir: PathBuf) -> Vec<PathBuf> {
|
||||
|
||||
@@ -27,7 +27,7 @@ pub trait WindowLike {
|
||||
*/
|
||||
|
||||
pub fn listen(mut window_like: impl WindowLike) {
|
||||
let mut stdin = stdin();
|
||||
let stdin = stdin();
|
||||
for line in stdin.lock().lines() {
|
||||
let line = line.unwrap().clone();
|
||||
let mut parts = line.split(" ");
|
||||
|
||||
17
src/utils.rs
17
src/utils.rs
@@ -103,3 +103,20 @@ pub fn format_seconds(seconds: u64) -> String {
|
||||
m + ":" + &s
|
||||
}
|
||||
|
||||
pub const HEX_CHARS: [char; 16] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
|
||||
|
||||
pub fn u8_to_hex(u: u8) -> String {
|
||||
let mut h = String::new();
|
||||
h.push(HEX_CHARS[(u / 16) as usize]);
|
||||
h.push(HEX_CHARS[(u % 16) as usize]);
|
||||
h
|
||||
}
|
||||
|
||||
pub fn hex_to_u8(c1: char, c2: char) -> u8 {
|
||||
(HEX_CHARS.iter().position(|c| c == &c1).unwrap() * 16 + HEX_CHARS.iter().position(|c| c == &c2).unwrap()) as u8
|
||||
}
|
||||
|
||||
pub fn is_hex(c: char) -> bool {
|
||||
HEX_CHARS.iter().position(|hc| hc == &c).is_some()
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@ static WRITER: LazyLock<Mutex<FramebufferWriter>> = LazyLock::new(|| Mutex::new(
|
||||
|
||||
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(), framebuffer_info.height * framebuffer_info.stride * framebuffer_info.bytes_per_pixel);
|
||||
|
||||
@@ -70,9 +72,9 @@ pub fn min(one: usize, two: usize) -> usize {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum DrawInstructions {
|
||||
Rect(Point, Dimensions, RGBColor),
|
||||
Text(Point, String, String, RGBColor, RGBColor, Option<usize>, Option<u8>), //font and text
|
||||
Text(Point, Vec<String>, String, RGBColor, RGBColor, Option<usize>, Option<u8>), //font and text
|
||||
Gradient(Point, Dimensions, RGBColor, RGBColor, usize),
|
||||
Mingde(Point),
|
||||
Bmp(Point, String, bool),
|
||||
Circle(Point, usize, RGBColor),
|
||||
}
|
||||
|
||||
@@ -360,6 +362,9 @@ impl WindowManager {
|
||||
//close start menu if open
|
||||
self.toggle_start_menu(true);
|
||||
self.current_workspace = workspace;
|
||||
//send to desktop background
|
||||
let desktop_background_index = self.window_infos.iter().position(|w| w.window_like.subtype() == WindowLikeType::DesktopBackground).unwrap();
|
||||
self.window_infos[desktop_background_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::SwitchWorkspace(self.current_workspace)));
|
||||
//send to workspace indicator
|
||||
let indicator_index = self.window_infos.iter().position(|w| w.window_like.subtype() == WindowLikeType::WorkspaceIndicator).unwrap();
|
||||
self.focused_id = self.window_infos[indicator_index].id;
|
||||
@@ -600,8 +605,8 @@ impl WindowManager {
|
||||
match instruction {
|
||||
DrawInstructions::Rect(top_left, dimensions, color) => DrawInstructions::Rect(WindowManager::get_true_top_left(top_left, is_window), *dimensions, *color),
|
||||
DrawInstructions::Circle(centre, radius, color) => DrawInstructions::Circle(WindowManager::get_true_top_left(centre, is_window), *radius, *color),
|
||||
DrawInstructions::Text(top_left, font_name, text, color, bg_color, horiz_spacing, mono_width) => DrawInstructions::Text(WindowManager::get_true_top_left(top_left, is_window), font_name.clone(), text.clone(), *color, *bg_color, *horiz_spacing, *mono_width),
|
||||
DrawInstructions::Mingde(top_left) => DrawInstructions::Mingde(WindowManager::get_true_top_left(top_left, is_window)),
|
||||
DrawInstructions::Text(top_left, fonts, text, color, bg_color, horiz_spacing, mono_width) => DrawInstructions::Text(WindowManager::get_true_top_left(top_left, is_window), fonts.clone(), text.clone(), *color, *bg_color, *horiz_spacing, *mono_width),
|
||||
DrawInstructions::Bmp(top_left, path, reverse) => DrawInstructions::Bmp(WindowManager::get_true_top_left(top_left, is_window), path.to_string(), *reverse),
|
||||
DrawInstructions::Gradient(top_left, dimensions, start_color, end_color, steps) => DrawInstructions::Gradient(WindowManager::get_true_top_left(top_left, is_window), *dimensions, *start_color, *end_color, *steps),
|
||||
}
|
||||
}).collect();
|
||||
@@ -614,7 +619,7 @@ impl WindowManager {
|
||||
DrawInstructions::Rect([0, 0], [1, window_dimensions[1]], theme_info.border_left_top),
|
||||
//top
|
||||
DrawInstructions::Rect([1, 1], [window_dimensions[0] - 2, WINDOW_TOP_HEIGHT - 3], theme_info.top),
|
||||
DrawInstructions::Text([4, 4], "times-new-roman".to_string(), window_info.window_like.title().to_string(), theme_info.top_text, theme_info.top, None, None),
|
||||
DrawInstructions::Text([4, 4], vec!["times-new-roman".to_string()], window_info.window_like.title().to_string(), theme_info.top_text, theme_info.top, None, None),
|
||||
//top bottom border
|
||||
DrawInstructions::Rect([1, WINDOW_TOP_HEIGHT - 2], [window_dimensions[0] - 2, 2], theme_info.border_left_top),
|
||||
//right bottom border
|
||||
@@ -646,11 +651,11 @@ impl WindowManager {
|
||||
DrawInstructions::Circle(centre, radius, color) => {
|
||||
window_writer.draw_circle(centre, radius, color);
|
||||
},
|
||||
DrawInstructions::Text(top_left, font_name, text, color, bg_color, horiz_spacing, mono_width) => {
|
||||
window_writer.draw_text(top_left, &font_name, &text, color, bg_color, horiz_spacing.unwrap_or(1), mono_width);
|
||||
DrawInstructions::Text(top_left, fonts, text, color, bg_color, horiz_spacing, mono_width) => {
|
||||
window_writer.draw_text(top_left, fonts, &text, color, bg_color, horiz_spacing.unwrap_or(1), mono_width);
|
||||
},
|
||||
DrawInstructions::Mingde(top_left) => {
|
||||
window_writer._draw_mingde(top_left);
|
||||
DrawInstructions::Bmp(top_left, path, reverse) => {
|
||||
window_writer.draw_bmp(top_left, path, reverse);
|
||||
},
|
||||
DrawInstructions::Gradient(top_left, dimensions, start_color, end_color, steps) => {
|
||||
window_writer.draw_gradient(top_left, dimensions, start_color, end_color, steps);
|
||||
|
||||
Reference in New Issue
Block a user