use nimbus roman, theme config, lto
license, philosophy, more shippori chars, slight code shuffling
This commit is contained in:
@@ -61,22 +61,22 @@ impl WindowLike for AudioPlayer {
|
||||
}
|
||||
|
||||
fn draw(&self, theme_info: &ThemeInfo) -> Vec<DrawInstructions> {
|
||||
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)];
|
||||
let mut instructions = vec![DrawInstructions::Text([2, self.dimensions[1] - LINE_HEIGHT], vec!["nimbus-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 {
|
||||
if sink.len() > 0 {
|
||||
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], vec!["times-new-romono".to_string(), "shippori-mincho".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!["nimbus-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)));
|
||||
instructions.push(DrawInstructions::Text([self.dimensions[0] / 2 - artist_string.len() * MONO_WIDTH as usize / 2, LINE_HEIGHT + 2], vec!["nimbus-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 + 2], vec!["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!["nimbus-romono".to_string()], time_string, theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH)));
|
||||
}
|
||||
} else {
|
||||
instructions.push(DrawInstructions::Text([2, 2], vec!["times-new-roman".to_string()], "type to write commands, enter to execute.".to_string(), theme_info.text, theme_info.background, None, None));
|
||||
instructions.push(DrawInstructions::Text([2, 2 + LINE_HEIGHT], vec!["times-new-roman".to_string()], "See help in start menu for commands.".to_string(), theme_info.text, theme_info.background, None, None));
|
||||
instructions.push(DrawInstructions::Text([2, 2], vec!["nimbus-roman".to_string()], "type to write commands, enter to execute.".to_string(), theme_info.text, theme_info.background, None, None));
|
||||
instructions.push(DrawInstructions::Text([2, 2 + LINE_HEIGHT], vec!["nimbus-roman".to_string()], "See help in start menu for commands.".to_string(), theme_info.text, theme_info.background, None, None));
|
||||
}
|
||||
//
|
||||
instructions
|
||||
@@ -157,7 +157,7 @@ impl AudioPlayer {
|
||||
if line.ends_with("/*") {
|
||||
queue.extend(get_all_files(concat_paths(&self.base_directory, &line[..line.len() - 2]).unwrap()));
|
||||
} else if line.len() > 0 {
|
||||
queue.push(concat_paths(&self.base_directory, &(line.to_owned() + ".mp3")).unwrap());
|
||||
queue.push(concat_paths(&self.base_directory, &(line.to_owned() + if line.ends_with(".mp3") { "" } else { ".mp3" })).unwrap());
|
||||
}
|
||||
}
|
||||
queue
|
||||
@@ -171,7 +171,8 @@ impl AudioPlayer {
|
||||
self.queue = Vec::new();
|
||||
for item in &queue {
|
||||
let file = BufReader::new(File::open(item).unwrap());
|
||||
let decoded = Decoder::new(file).unwrap();
|
||||
//slightly faster for mp3s? since it doesn't need to check if it is .wav, etc. but maybe not
|
||||
let decoded = if item.ends_with(".mp3") { Decoder::new_mp3(file) } else { Decoder::new(file) }.unwrap();
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ impl WindowLike for FileExplorer {
|
||||
let mut instructions = Vec::new();
|
||||
if self.state == State::List {
|
||||
//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));
|
||||
instructions.push(DrawInstructions::Text([5, 0], vec!["nimbus-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 = HEIGHT;
|
||||
let mut i = self.top_position;
|
||||
@@ -128,7 +128,7 @@ impl WindowLike for FileExplorer {
|
||||
} else {
|
||||
name.unwrap()
|
||||
};
|
||||
instructions.push(DrawInstructions::Text([5, start_y], vec!["times-new-roman".to_string(), "shippori-mincho".to_string()], name, if is_selected { theme_info.top_text } else { theme_info.text }, if is_selected { theme_info.top } else { theme_info.background }, None, None));
|
||||
instructions.push(DrawInstructions::Text([5, start_y], vec!["nimbus-roman".to_string(), "shippori-mincho".to_string()], name, if is_selected { theme_info.top_text } else { theme_info.text }, if is_selected { theme_info.top } else { theme_info.background }, None, None));
|
||||
start_y += HEIGHT;
|
||||
i += 1;
|
||||
}
|
||||
@@ -136,7 +136,7 @@ impl WindowLike for FileExplorer {
|
||||
let metadata = self.metadata.clone().unwrap();
|
||||
let mut start_y = HEIGHT;
|
||||
let bytes_len = metadata.len();
|
||||
instructions.push(DrawInstructions::Text([5, start_y], vec!["times-new-roman".to_string()], format!("Size: {} mb ({} b)", bytes_len / (1024_u64).pow(2), bytes_len), theme_info.text, theme_info.background, None, None));
|
||||
instructions.push(DrawInstructions::Text([5, start_y], vec!["nimbus-roman".to_string()], format!("Size: {} mb ({} b)", bytes_len / (1024_u64).pow(2), bytes_len), theme_info.text, theme_info.background, None, None));
|
||||
start_y += HEIGHT;
|
||||
//todo: other stuff
|
||||
}
|
||||
|
||||
149
src/bin/main.rs
149
src/bin/main.rs
@@ -1,7 +1,150 @@
|
||||
use linux_framebuffer::Framebuffer;
|
||||
use std::process::{ Command, Stdio };
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use std::io::{ stdin, stdout, BufReader, BufRead, Write };
|
||||
use std::process::exit;
|
||||
use std::env;
|
||||
|
||||
use ming_wm::framebuffer::FramebufferInfo;
|
||||
use ming_wm::window_manager::init;
|
||||
use linux_framebuffer::Framebuffer;
|
||||
use termion::input::TermRead;
|
||||
use termion::raw::IntoRawMode;
|
||||
use termion::{ clear, cursor };
|
||||
|
||||
use ming_wm::framebuffer::{ FramebufferWriter, FramebufferInfo };
|
||||
use ming_wm::window_manager::{ WindowManager, KeyChar };
|
||||
use ming_wm::utils::key_to_char;
|
||||
use ming_wm::messages::*;
|
||||
|
||||
pub enum ThreadMessage {
|
||||
KeyChar(KeyChar),
|
||||
Touch(usize, usize),
|
||||
Clear,
|
||||
Exit,
|
||||
}
|
||||
|
||||
fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) {
|
||||
let args: Vec<_> = env::args().collect();
|
||||
|
||||
let rotate = args.contains(&"rotate".to_string());
|
||||
|
||||
let framebuffer_info = if rotate {
|
||||
FramebufferInfo {
|
||||
byte_len: framebuffer_info.byte_len,
|
||||
width: framebuffer_info.height,
|
||||
height: framebuffer_info.width,
|
||||
bytes_per_pixel: framebuffer_info.bytes_per_pixel,
|
||||
stride: framebuffer_info.height,
|
||||
old_stride: Some(framebuffer_info.stride),
|
||||
}
|
||||
} else {
|
||||
framebuffer_info
|
||||
};
|
||||
|
||||
let dimensions = [framebuffer_info.width, framebuffer_info.height];
|
||||
|
||||
let grayscale = args.contains(&"grayscale".to_string()) || args.contains(&"greyscale".to_string());
|
||||
|
||||
let mut writer: FramebufferWriter = FramebufferWriter::new(grayscale);
|
||||
|
||||
writer.init(framebuffer_info.clone());
|
||||
|
||||
let mut wm: WindowManager = WindowManager::new(writer, framebuffer, dimensions, rotate, grayscale);
|
||||
|
||||
let mut stdout = stdout().into_raw_mode().unwrap();
|
||||
|
||||
write!(stdout, "{}", clear::All).unwrap();
|
||||
|
||||
write!(stdout, "{}", cursor::Hide).unwrap();
|
||||
|
||||
stdout.flush().unwrap();
|
||||
|
||||
wm.draw(None, false);
|
||||
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
let tx1 = tx.clone();
|
||||
|
||||
//read key presses
|
||||
thread::spawn(move || {
|
||||
let stdin = stdin().lock();
|
||||
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') {
|
||||
tx.send(ThreadMessage::Exit).unwrap();
|
||||
} else {
|
||||
tx.send(ThreadMessage::KeyChar(kc)).unwrap();
|
||||
}
|
||||
}
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
}
|
||||
});
|
||||
|
||||
let touch = args.contains(&"touch".to_string());
|
||||
|
||||
//read touchscreen presses (hopefully)
|
||||
thread::spawn(move || {
|
||||
//spawn evtest, parse it for touch coords
|
||||
if touch {
|
||||
let mut evtest = Command::new("evtest").arg("/dev/input/by-path/first-touchscreen").stdout(Stdio::piped()).spawn().unwrap();
|
||||
let reader = BufReader::new(evtest.stdout.as_mut().unwrap());
|
||||
let mut x: Option<usize> = None;
|
||||
let mut y: Option<usize> = None;
|
||||
for line in reader.lines() {
|
||||
let line = line.unwrap();
|
||||
if line.contains(&"ABS_X), value ") || line.contains(&"ABS_Y), value ") {
|
||||
let value: Vec<_> = line.split("), value ").collect();
|
||||
let value = value[value.len() - 1].parse::<usize>().unwrap();
|
||||
if line.contains(&"ABS_X") {
|
||||
x = Some(value);
|
||||
} else {
|
||||
y = Some(value);
|
||||
}
|
||||
if x.is_some() && y.is_some() {
|
||||
let (x2, y2) = if rotate {
|
||||
(y.unwrap(), dimensions[0] - x.unwrap())
|
||||
} else {
|
||||
(x.unwrap(), y.unwrap())
|
||||
};
|
||||
//top right, clear
|
||||
//useful sometimes, I think.
|
||||
if x2 > dimensions[0] - 100 && y2 < 100 {
|
||||
tx1.send(ThreadMessage::Clear).unwrap();
|
||||
}
|
||||
tx1.send(ThreadMessage::Touch(x2, y2)).unwrap();
|
||||
x = None;
|
||||
y = None;
|
||||
}
|
||||
}
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
}
|
||||
}
|
||||
});
|
||||
if touch {
|
||||
//opens osk
|
||||
wm.handle_message(WindowManagerMessage::Touch(1, 1));
|
||||
}
|
||||
|
||||
for message in rx {
|
||||
match message {
|
||||
ThreadMessage::KeyChar(kc) => wm.handle_message(WindowManagerMessage::KeyChar(kc.clone())),
|
||||
ThreadMessage::Touch(x, y) => wm.handle_message(WindowManagerMessage::Touch(x, y)),
|
||||
ThreadMessage::Clear => {
|
||||
write!(stdout, "{}", clear::All).unwrap();
|
||||
stdout.flush().unwrap();
|
||||
},
|
||||
ThreadMessage::Exit => {
|
||||
if !wm.locked {
|
||||
write!(stdout, "{}", cursor::Show).unwrap();
|
||||
stdout.suspend_raw_mode().unwrap();
|
||||
exit(0);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let fb = Framebuffer::new("/dev/fb0").unwrap();
|
||||
|
||||
@@ -14,7 +14,7 @@ use ming_wm::ipc::listen;
|
||||
const MONO_WIDTH: u8 = 10;
|
||||
const LINE_HEIGHT: usize = 18;
|
||||
const PADDING: usize = 2;
|
||||
const BAND_HEIGHT: usize = 18;
|
||||
const BAND_HEIGHT: usize = 19;
|
||||
|
||||
struct FileInfo {
|
||||
pub name: String,
|
||||
@@ -185,7 +185,7 @@ impl WindowLike for Malvim {
|
||||
self.state = State::None;
|
||||
} else if self.state == State::Maybeg {
|
||||
if key_press.key == 'g' {
|
||||
current_file.line_pos = self.maybe_num.unwrap_or(0);
|
||||
current_file.line_pos = self.maybe_num.unwrap_or(1) - 1;
|
||||
if current_file.line_pos >= current_file.content.len() {
|
||||
current_file.line_pos = current_file.content.len() - 1;
|
||||
}
|
||||
@@ -372,7 +372,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], 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)),
|
||||
DrawInstructions::Text([used_width + 2, 2], vec!["nimbus-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;
|
||||
}
|
||||
@@ -390,13 +390,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], vec!["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!["nimbus-romono".to_string()], (line.1 + 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], vec!["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!["nimbus-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;
|
||||
@@ -406,26 +406,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, 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)));
|
||||
instructions.push(DrawInstructions::Text(top_left, vec!["nimbus-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], vec!["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 + 2], vec!["nimbus-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], vec!["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 + 2], vec!["nimbus-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], 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)));
|
||||
instructions.push(DrawInstructions::Text([0, self.dimensions[1] - BAND_HEIGHT + 2], vec!["nimbus-romono".to_string()], ":".to_string() + &self.command.clone().unwrap_or("".to_string()), theme_info.top_text, theme_info.alt_background, 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], vec!["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 + 2], vec!["nimbus-romono".to_string()], self.bottom_message.clone().unwrap(), theme_info.top_text, theme_info.alt_background, Some(0), Some(MONO_WIDTH)));
|
||||
}
|
||||
instructions
|
||||
}
|
||||
|
||||
@@ -145,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], 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),
|
||||
DrawInstructions::Text([4, 4], vec!["nimbus-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!["nimbus-roman".to_string()], self.random_chars.clone(), theme_info.text, theme_info.background, None, None),
|
||||
]
|
||||
} else {
|
||||
let mut instructions = vec![
|
||||
@@ -183,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], vec!["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!["nimbus-roman".to_string()], "x".to_string(), [255, 0, 0], theme_info.background, None, None));
|
||||
} else {
|
||||
let color = match tile.touching {
|
||||
1 => [0, 0, 255],
|
||||
@@ -196,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], vec!["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!["nimbus-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];
|
||||
@@ -214,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], vec!["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!["nimbus-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], vec!["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!["nimbus-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], 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.extend(vec![DrawInstructions::Text([4, 4], vec!["nimbus-roman".to_string()], "You WON!!! Press a key to play again.".to_string(), theme_info.text, theme_info.background, None, None)]);
|
||||
}
|
||||
instructions
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ impl WindowLike for Reversi {
|
||||
for x in 0..8 {
|
||||
let tile = &self.tiles[y][x];
|
||||
if tile == &Tile::Empty {
|
||||
instructions.push(DrawInstructions::Text([x * square_width + square_width / 2, y * square_width + square_width / 2], vec!["times-new-roman".to_string()], format!("{}{}", y, x), theme_info.text, REVERSI_GREEN, None, None));
|
||||
instructions.push(DrawInstructions::Text([x * square_width + square_width / 2, y * square_width + square_width / 2], vec!["nimbus-roman".to_string()], format!("{}{}", y, x), theme_info.text, REVERSI_GREEN, None, None));
|
||||
if valid_moves_contains(&self.valid_moves, &[x, y]).is_some() {
|
||||
//yellow border
|
||||
instructions.extend([
|
||||
@@ -161,7 +161,7 @@ impl WindowLike for Reversi {
|
||||
}
|
||||
if self.state != State::InProgress {
|
||||
instructions.push(DrawInstructions::Rect([0, 0], [self.dimensions[0], 25], theme_info.background));
|
||||
instructions.push(DrawInstructions::Text([4, 4], vec!["times-new-roman".to_string()], if self.state == State::WhiteWin {
|
||||
instructions.push(DrawInstructions::Text([4, 4], vec!["nimbus-roman".to_string()], if self.state == State::WhiteWin {
|
||||
"White wins, press any key to restart"
|
||||
} else if self.state == State::BlackWin {
|
||||
"Black wins, press any key to restart"
|
||||
|
||||
@@ -69,7 +69,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::JustRedraw
|
||||
} else if key_press.key.len_utf8() == 1 {
|
||||
} else {
|
||||
//update
|
||||
let running_process = self.running_process.as_mut().unwrap();
|
||||
if let Some(status) = running_process.try_wait().unwrap() {
|
||||
@@ -90,10 +90,6 @@ impl WindowLike for Terminal {
|
||||
//still running
|
||||
WindowMessageResponse::DoNothing
|
||||
}
|
||||
} else {
|
||||
//esc key (crash happens if esc key is entered and deleted, so prevent it from being entered)
|
||||
//but if we want to support eg Chinese we need to properly handle multi-byte chars (todo)
|
||||
WindowMessageResponse::DoNothing
|
||||
}
|
||||
},
|
||||
WindowMessage::CtrlKeyPress(key_press) => {
|
||||
@@ -133,7 +129,7 @@ impl WindowLike for Terminal {
|
||||
break;
|
||||
}
|
||||
let line = self.actual_lines[line_num].clone();
|
||||
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)));
|
||||
instructions.push(DrawInstructions::Text([PADDING, text_y], vec!["nimbus-romono".to_string()], line, theme_info.alt_text, theme_info.alt_background, Some(0), Some(MONO_WIDTH)));
|
||||
text_y += LINE_HEIGHT;
|
||||
}
|
||||
instructions
|
||||
|
||||
@@ -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.clone(), 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!["nimbus-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.clone(), 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!["nimbus-roman".to_string()], self.text.clone(), theme_info.text, theme_info.background, None, None),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ impl<T: Copy> Component<T> for Paragraph<T> {
|
||||
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)));
|
||||
instructions.push(DrawInstructions::Text([self.top_left[0], start_y], vec!["nimbus-romono".to_string()], line.2.clone(), theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH)));
|
||||
start_y += LINE_HEIGHT;
|
||||
}
|
||||
instructions
|
||||
|
||||
@@ -37,7 +37,7 @@ impl<T: Clone> Component<T> for PressButton<T> {
|
||||
DrawInstructions::Rect([self.top_left[0], self.top_left[1] + self.size[1]], [self.size[0], 1], theme_info.border_right_bottom),
|
||||
DrawInstructions::Rect([self.top_left[0] + self.size[0], self.top_left[1]], [1, self.size[1]], theme_info.border_right_bottom),
|
||||
//assume normal background colour
|
||||
DrawInstructions::Text([self.top_left[0] + half, self.top_left[1] + 8], vec!["times-new-romono".to_string()], self.text.clone(), theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH)),
|
||||
DrawInstructions::Text([self.top_left[0] + half, self.top_left[1] + 8], vec!["nimbus-romono".to_string()], self.text.clone(), theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH)),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ pub struct ToggleButton<T> {
|
||||
top_left: Point,
|
||||
size: Dimensions,
|
||||
text: String,
|
||||
draw_bg: bool,
|
||||
pub inverted: bool, //whether is it clicked or not
|
||||
click_return: T,
|
||||
unclick_return: T,
|
||||
@@ -47,7 +46,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], 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!["nimbus-roman".to_string()], self.text.to_string(), theme_info.text, theme_info.background, None, None),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -66,7 +65,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) -> Self {
|
||||
pub fn new(name_: String, top_left: Point, size: Dimensions, text: String, click_return: T, unclick_return: T) -> Self {
|
||||
Self {
|
||||
name_,
|
||||
top_left,
|
||||
@@ -74,7 +73,6 @@ impl<T> ToggleButton<T> {
|
||||
text,
|
||||
click_return,
|
||||
unclick_return,
|
||||
draw_bg,
|
||||
inverted: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ impl WindowLike for Help {
|
||||
}
|
||||
|
||||
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)];
|
||||
let mut instructions = vec![DrawInstructions::Text([2, 2], vec!["nimbus-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
|
||||
}
|
||||
|
||||
@@ -52,11 +52,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], 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),
|
||||
DrawInstructions::Text([4, 4], vec!["nimbus-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!["nimbus-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!["nimbus-roman".to_string()], "He stared at it.".to_string(), [255, 255, 255], [0, 0, 0], None, None),
|
||||
DrawInstructions::Text([4, 4 + 16 * 3], vec!["nimbus-roman".to_string()], "Password: ".to_string(), [255, 255, 255], [0, 0, 0], None, None),
|
||||
DrawInstructions::Text([85, 4 + 16 * 3], vec!["nimbus-roman".to_string()], "*".repeat(self.input_password.len()), [255, 255, 255], [0, 0, 0], None, None),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,8 @@ impl WindowLike for OnscreenKeyboard {
|
||||
},
|
||||
KeyResponse::SwitchBoard => {
|
||||
self.board = self.board.inc();
|
||||
WindowMessageResponse::DoNothing
|
||||
self.set_key_components();
|
||||
WindowMessageResponse::JustRedraw
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@ enum StartMenuMessage {
|
||||
ChangeAcknowledge,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct StartMenu {
|
||||
dimensions: Dimensions,
|
||||
components: Vec<Box<dyn Component<StartMenuMessage> + Send>>,
|
||||
current_focus: String,
|
||||
old_focus: String,
|
||||
y_each: usize,
|
||||
}
|
||||
|
||||
@@ -54,7 +54,6 @@ impl WindowLike for StartMenu {
|
||||
old_focus_index - 1
|
||||
}
|
||||
};
|
||||
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::JustRedraw
|
||||
@@ -68,15 +67,28 @@ impl WindowLike for StartMenu {
|
||||
}
|
||||
} else {
|
||||
let current_focus_index = self.get_focus_index().unwrap();
|
||||
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) {
|
||||
//now old focus, not current focus
|
||||
self.components[current_focus_index].handle_message(WindowMessage::Unfocus);
|
||||
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::JustRedraw
|
||||
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) {
|
||||
//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();
|
||||
self.components[current_focus_index + n_index].handle_message(WindowMessage::Focus);
|
||||
WindowMessageResponse::JustRedraw
|
||||
} else {
|
||||
WindowMessageResponse::DoNothing
|
||||
}
|
||||
} else {
|
||||
WindowMessageResponse::DoNothing
|
||||
//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) {
|
||||
//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();
|
||||
self.components[current_focus_index - n_index - 1].handle_message(WindowMessage::Focus);
|
||||
WindowMessageResponse::JustRedraw
|
||||
} else {
|
||||
WindowMessageResponse::DoNothing
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -115,13 +127,7 @@ impl WindowLike for StartMenu {
|
||||
|
||||
impl StartMenu {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
dimensions: [0, 0],
|
||||
components: Vec::new(),
|
||||
current_focus: String::new(), //placeholder, will be set in init
|
||||
old_focus: String::new(),
|
||||
y_each: 0, //will be set in add_category_components
|
||||
}
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn handle_start_menu_message(&mut self, message: Option<StartMenuMessage>) -> WindowMessageResponse {
|
||||
|
||||
@@ -33,7 +33,7 @@ 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)),
|
||||
Box::new(ToggleButton::new("start-button".to_string(), [PADDING, PADDING], [44, self.dimensions[1] - (PADDING * 2)], "Start".to_string(), TaskbarMessage::ShowStartMenu, TaskbarMessage::HideStartMenu)),
|
||||
];
|
||||
WindowMessageResponse::JustRedraw
|
||||
},
|
||||
@@ -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);
|
||||
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);
|
||||
b.inverted = info.0 == self.focused_id;
|
||||
instructions.extend(b.draw(theme_info));
|
||||
}
|
||||
|
||||
@@ -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], vec!["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!["nimbus-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], vec!["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!["nimbus-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], vec!["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!["nimbus-roman".to_string()], time_string, theme_info.text, theme_info.background, None, None));
|
||||
instructions
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,13 @@ fn color_with_alpha(color: RGBColor, bg_color: RGBColor, alpha: u8) -> RGBColor
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
fn color_to_grayscale(color: RGBColor) -> RGBColor {
|
||||
//0.3, 0.6, 0.1 weighting
|
||||
let gray = color[0] / 10 * 3 + color[1] / 10 * 6 + color[2] / 10;
|
||||
[gray; 3]
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct FramebufferInfo {
|
||||
pub byte_len: usize,
|
||||
pub width: usize,
|
||||
@@ -47,9 +53,20 @@ pub struct FramebufferWriter {
|
||||
buffer: Vec<u8>,
|
||||
saved_buffer: Option<Vec<u8>>,
|
||||
rotate_buffer: Option<Vec<u8>>,
|
||||
grayscale: bool,
|
||||
}
|
||||
|
||||
impl FramebufferWriter {
|
||||
pub fn new(grayscale: bool) -> Self {
|
||||
Self {
|
||||
info: Default::default(),
|
||||
buffer: Vec::new(),
|
||||
saved_buffer: None,
|
||||
rotate_buffer: None,
|
||||
grayscale,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(&mut self, info: FramebufferInfo) {
|
||||
self.info = info;
|
||||
self.buffer = vec![0; self.info.byte_len];
|
||||
@@ -89,6 +106,7 @@ impl FramebufferWriter {
|
||||
|
||||
fn _draw_pixel(&mut self, start_pos: usize, color: RGBColor) {
|
||||
let color = [color[2], color[1], color[0]];
|
||||
let color = if self.grayscale { color_to_grayscale(color) } else { color };
|
||||
self.buffer[start_pos..(start_pos + 3)]
|
||||
.copy_from_slice(&color[..]);
|
||||
}
|
||||
@@ -138,6 +156,7 @@ impl FramebufferWriter {
|
||||
//shapes
|
||||
|
||||
pub fn draw_rect(&mut self, top_left: Point, dimensions: Dimensions, color: RGBColor) {
|
||||
let color = if self.grayscale { color_to_grayscale(color) } else { color };
|
||||
let line_bytes = if self.info.bytes_per_pixel > 3 {
|
||||
[color[2], color[1], color[0], 255].repeat(dimensions[0])
|
||||
} else {
|
||||
@@ -184,6 +203,7 @@ impl FramebufferWriter {
|
||||
} else {
|
||||
color = [(start_color[0] as f32 + (delta_r * s as f32)) as u8, (start_color[1] as f32 + (delta_g * s as f32)) as u8, (start_color[2] as f32 + (delta_b * s as f32)) as u8];
|
||||
};
|
||||
let color = if self.grayscale { color_to_grayscale(color) } else { color };
|
||||
let line_bytes = if self.info.bytes_per_pixel > 3 {
|
||||
[color[2], color[1], color[0], 255].repeat(dimensions[0])
|
||||
} else {
|
||||
@@ -248,14 +268,3 @@ impl FramebufferWriter {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FramebufferWriter {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
info: Default::default(),
|
||||
buffer: Vec::new(),
|
||||
saved_buffer: None,
|
||||
rotate_buffer: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ fn get_font_char(dir: &str, c: char) -> Option<(char, Vec<Vec<u8>>, u8)> {
|
||||
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());
|
||||
//.unwrap_or(0) is important because zeroes are just empty
|
||||
ch.push(lines[l].split(",").map(|n| n.parse().unwrap_or(0)).collect());
|
||||
}
|
||||
return Some((c, ch, lines[0].parse().unwrap()));
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@ pub fn listen(mut window_like: impl WindowLike) {
|
||||
let arg = &parts.collect::<Vec<&str>>().join(" ");
|
||||
let output = match method {
|
||||
"handle_message" => {
|
||||
log(arg);
|
||||
format!("{}", &window_like.handle_message(WindowMessage::deserialize(arg).unwrap()).serialize())
|
||||
},
|
||||
"draw" => {
|
||||
|
||||
@@ -104,10 +104,3 @@ pub enum WindowMessage {
|
||||
//
|
||||
}
|
||||
|
||||
pub enum ThreadMessage {
|
||||
KeyChar(KeyChar),
|
||||
Touch(usize, usize),
|
||||
Clear,
|
||||
Exit,
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ use std::process::{ Command, Child, Stdio };
|
||||
use std::io::{ BufReader, BufRead, Write };
|
||||
use std::cell::RefCell;
|
||||
use std::path::Path;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType };
|
||||
use crate::messages::{ WindowMessage, WindowMessageResponse };
|
||||
@@ -11,7 +10,6 @@ use crate::framebuffer::Dimensions;
|
||||
use crate::themes::ThemeInfo;
|
||||
use crate::serialize::{ Serializable, DrawInstructionsVec };
|
||||
|
||||
|
||||
pub struct ProxyWindowLike {
|
||||
process: RefCell<Child>,
|
||||
}
|
||||
|
||||
@@ -449,9 +449,9 @@ fn draw_instructions_serialize_deserialize() {
|
||||
use std::vec;
|
||||
let instructions = vec![
|
||||
DrawInstructions::Rect([15, 24], [100, 320], [255, 0, 128]),
|
||||
DrawInstructions::Text([0, 158], vec!["times-new-roman".to_string(), "shippori-mincho".to_string()], "Test test 1234 testing\nmictest / mictest is this thing\non?".to_string(), [12, 36, 108], [128, 128, 128], Some(1), None),
|
||||
DrawInstructions::Text([0, 158], vec!["nimbus-roman".to_string(), "shippori-mincho".to_string()], "Test test 1234 testing\nmictest / mictest is this thing\non?".to_string(), [12, 36, 108], [128, 128, 128], Some(1), None),
|
||||
DrawInstructions::Gradient([0, 500], [750, 125], [255, 255, 255], [0, 0, 0], 12),
|
||||
DrawInstructions::Text([123, 999], vec!["times-new-romono".to_string()], "print!(\"{}\", variable_name);".to_string(), [12, 36, 108], [128, 128, 128], Some(44), Some(200)),
|
||||
DrawInstructions::Text([123, 999], vec!["nimbus-romono".to_string()], "print!(\"{}\", variable_name);".to_string(), [12, 36, 108], [128, 128, 128], Some(44), Some(200)),
|
||||
DrawInstructions::Bmp([55, 98], "mingde".to_string(), true),
|
||||
DrawInstructions::Bmp([55, 98], "wooooo".to_string(), false),
|
||||
DrawInstructions::Circle([0, 1], 19, [128, 128, 128]),
|
||||
@@ -460,8 +460,8 @@ fn draw_instructions_serialize_deserialize() {
|
||||
assert!(serialized == DrawInstructionsVec::deserialize(&serialized).unwrap().serialize());
|
||||
let instructions = vec![
|
||||
DrawInstructions::Rect([0, 0], [410, 410], [0, 0, 0]),
|
||||
DrawInstructions::Text([4, 4], vec!["times-new-romono".to_string()], "Mingde Terminal".to_string(), [255, 255, 255], [0, 0, 0], Some(0), Some(10)),
|
||||
DrawInstructions::Text([4, 34], vec!["times-new-romono".to_string()], "$ a".to_string(), [255, 255, 255], [0, 0, 0], Some(0), Some(10)),
|
||||
DrawInstructions::Text([4, 4], vec!["nimbus-romono".to_string()], "Mingde Terminal".to_string(), [255, 255, 255], [0, 0, 0], Some(0), Some(10)),
|
||||
DrawInstructions::Text([4, 34], vec!["nimbus-romono".to_string()], "$ a".to_string(), [255, 255, 255], [0, 0, 0], Some(0), Some(10)),
|
||||
];
|
||||
let serialized = instructions.serialize() + "\n";
|
||||
assert!(serialized[..serialized.len() - 1] == DrawInstructionsVec::deserialize(&serialized).unwrap().serialize());
|
||||
|
||||
@@ -4,7 +4,24 @@ use crate::framebuffer::RGBColor;
|
||||
pub enum Themes {
|
||||
#[default]
|
||||
Standard,
|
||||
//
|
||||
Night,
|
||||
Industrial,
|
||||
Forest,
|
||||
Royal,
|
||||
//Parchment,
|
||||
}
|
||||
|
||||
impl Themes {
|
||||
pub fn from_str(name: &str) -> Option<Self> {
|
||||
match name {
|
||||
"Standard" => Some(Themes::Standard),
|
||||
"Night" => Some(Themes::Night),
|
||||
"Industrial" => Some(Themes::Industrial),
|
||||
"Forest" => Some(Themes::Forest),
|
||||
"Royal" => Some(Themes::Royal),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -20,7 +37,8 @@ pub struct ThemeInfo {
|
||||
pub alt_secondary: RGBColor,
|
||||
}
|
||||
|
||||
const THEME_INFOS: [(Themes, ThemeInfo); 1] = [
|
||||
//besides standard, these themes aren't great, I know
|
||||
const THEME_INFOS: [(Themes, ThemeInfo); 5] = [
|
||||
(Themes::Standard, ThemeInfo {
|
||||
top: [0, 0, 128],
|
||||
background: [192, 192, 192],
|
||||
@@ -31,8 +49,52 @@ const THEME_INFOS: [(Themes, ThemeInfo); 1] = [
|
||||
alt_background: [0, 0, 0],
|
||||
alt_text: [255, 255, 255],
|
||||
alt_secondary: [128, 128, 128],
|
||||
//
|
||||
}),
|
||||
(Themes::Night, ThemeInfo {
|
||||
top: [0, 0, 0],
|
||||
background: [34, 34, 34],
|
||||
border_left_top: [239, 239, 239],
|
||||
border_right_bottom: [0, 0, 0],
|
||||
text: [239, 239, 239],
|
||||
top_text: [239, 239, 239],
|
||||
alt_background: [0, 0, 0],
|
||||
alt_text: [239, 239, 239],
|
||||
alt_secondary: [128, 128, 128],
|
||||
}),
|
||||
(Themes::Industrial, ThemeInfo {
|
||||
top: [40, 40, 40],
|
||||
background: [160, 160, 160],
|
||||
border_left_top: [255, 255, 255],
|
||||
border_right_bottom: [0, 0, 0],
|
||||
text: [0, 0, 0],
|
||||
top_text: [255, 255, 255],
|
||||
alt_background: [0, 0, 0],
|
||||
alt_text: [255, 255, 255],
|
||||
alt_secondary: [128, 128, 128],
|
||||
}),
|
||||
(Themes::Forest, ThemeInfo {
|
||||
top: [0, 128, 0],
|
||||
background: [192, 192, 192],
|
||||
border_left_top: [255, 255, 255],
|
||||
border_right_bottom: [0, 0, 0],
|
||||
text: [0, 0, 0],
|
||||
top_text: [255, 255, 255],
|
||||
alt_background: [0, 0, 0],
|
||||
alt_text: [255, 255, 255],
|
||||
alt_secondary: [128, 128, 128],
|
||||
}),
|
||||
(Themes::Royal, ThemeInfo {
|
||||
top: [128, 0, 128],
|
||||
background: [192, 192, 192],
|
||||
border_left_top: [255, 255, 255],
|
||||
border_right_bottom: [0, 0, 0],
|
||||
text: [0, 0, 0],
|
||||
top_text: [255, 255, 255],
|
||||
alt_background: [0, 0, 0],
|
||||
alt_text: [255, 255, 255],
|
||||
alt_secondary: [128, 128, 128],
|
||||
}),
|
||||
//
|
||||
];
|
||||
|
||||
pub fn get_theme_info(theme: &Themes) -> Option<ThemeInfo> {
|
||||
|
||||
@@ -3,23 +3,16 @@ use std::vec;
|
||||
use std::collections::{ HashMap, VecDeque };
|
||||
use std::fmt;
|
||||
use std::boxed::Box;
|
||||
use std::io::{ stdin, stdout, BufReader, BufRead, Write };
|
||||
use std::process::exit;
|
||||
use std::cell::RefCell;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use std::env;
|
||||
use std::process::{ Command, Stdio };
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
||||
use linux_framebuffer::Framebuffer;
|
||||
use termion::input::TermRead;
|
||||
use termion::raw::IntoRawMode;
|
||||
use termion::{ clear, cursor };
|
||||
use dirs::config_dir;
|
||||
|
||||
use crate::framebuffer::{ FramebufferWriter, FramebufferInfo, Point, Dimensions, RGBColor };
|
||||
use crate::framebuffer::{ FramebufferWriter, Point, Dimensions, RGBColor };
|
||||
use crate::themes::{ ThemeInfo, Themes, get_theme_info };
|
||||
use crate::utils::{ min, key_to_char, point_inside };
|
||||
use crate::utils::{ min, point_inside };
|
||||
use crate::messages::*;
|
||||
use crate::proxy_window_like::ProxyWindowLike;
|
||||
use crate::essential::desktop_background::DesktopBackground;
|
||||
@@ -45,129 +38,6 @@ pub enum KeyChar {
|
||||
Ctrl(char),
|
||||
}
|
||||
|
||||
pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) {
|
||||
let args: Vec<_> = env::args().collect();
|
||||
|
||||
let rotate = args.contains(&"rotate".to_string());
|
||||
|
||||
let framebuffer_info = if rotate {
|
||||
FramebufferInfo {
|
||||
byte_len: framebuffer_info.byte_len,
|
||||
width: framebuffer_info.height,
|
||||
height: framebuffer_info.width,
|
||||
bytes_per_pixel: framebuffer_info.bytes_per_pixel,
|
||||
stride: framebuffer_info.height,
|
||||
old_stride: Some(framebuffer_info.stride),
|
||||
}
|
||||
} else {
|
||||
framebuffer_info
|
||||
};
|
||||
|
||||
let dimensions = [framebuffer_info.width, framebuffer_info.height];
|
||||
|
||||
println!("bg: {}x{}", dimensions[0], dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT);
|
||||
|
||||
let mut writer: FramebufferWriter = Default::default();
|
||||
|
||||
writer.init(framebuffer_info.clone());
|
||||
|
||||
let mut wm: WindowManager = WindowManager::new(writer, framebuffer, dimensions, rotate);
|
||||
|
||||
let mut stdout = stdout().into_raw_mode().unwrap();
|
||||
|
||||
write!(stdout, "{}", clear::All).unwrap();
|
||||
|
||||
write!(stdout, "{}", cursor::Hide).unwrap();
|
||||
|
||||
stdout.flush().unwrap();
|
||||
|
||||
wm.draw(None, false);
|
||||
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
let tx1 = tx.clone();
|
||||
|
||||
//read key presses
|
||||
thread::spawn(move || {
|
||||
let stdin = stdin().lock();
|
||||
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') {
|
||||
tx.send(ThreadMessage::Exit).unwrap();
|
||||
} else {
|
||||
tx.send(ThreadMessage::KeyChar(kc)).unwrap();
|
||||
}
|
||||
}
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
}
|
||||
});
|
||||
|
||||
let touch = args.contains(&"touch".to_string());
|
||||
|
||||
//read touchscreen presses (hopefully)
|
||||
thread::spawn(move || {
|
||||
//spawn evtest, parse it for touch coords
|
||||
if touch {
|
||||
let mut evtest = Command::new("evtest").arg("/dev/input/by-path/first-touchscreen").stdout(Stdio::piped()).spawn().unwrap();
|
||||
let reader = BufReader::new(evtest.stdout.as_mut().unwrap());
|
||||
let mut x: Option<usize> = None;
|
||||
let mut y: Option<usize> = None;
|
||||
for line in reader.lines() {
|
||||
let line = line.unwrap();
|
||||
if line.contains(&"ABS_X), value ") || line.contains(&"ABS_Y), value ") {
|
||||
let value: Vec<_> = line.split("), value ").collect();
|
||||
let value = value[value.len() - 1].parse::<usize>().unwrap();
|
||||
if line.contains(&"ABS_X") {
|
||||
x = Some(value);
|
||||
} else {
|
||||
y = Some(value);
|
||||
}
|
||||
if x.is_some() && y.is_some() {
|
||||
let (x2, y2) = if rotate {
|
||||
(y.unwrap(), dimensions[1] - x.unwrap())
|
||||
} else {
|
||||
(x.unwrap(), y.unwrap())
|
||||
};
|
||||
//top right, clear
|
||||
//useful sometimes, I think.
|
||||
if x2 > dimensions[0] - 100 && y2 < 100 {
|
||||
tx1.send(ThreadMessage::Clear).unwrap();
|
||||
}
|
||||
tx1.send(ThreadMessage::Touch(x2, y2)).unwrap();
|
||||
x = None;
|
||||
y = None;
|
||||
}
|
||||
}
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
}
|
||||
}
|
||||
});
|
||||
if touch {
|
||||
//opens osk
|
||||
wm.handle_message(WindowManagerMessage::Touch(1, 1));
|
||||
}
|
||||
|
||||
for message in rx {
|
||||
match message {
|
||||
ThreadMessage::KeyChar(kc) => wm.handle_message(WindowManagerMessage::KeyChar(kc.clone())),
|
||||
ThreadMessage::Touch(x, y) => wm.handle_message(WindowManagerMessage::Touch(x, y)),
|
||||
ThreadMessage::Clear => {
|
||||
write!(stdout, "{}", clear::All).unwrap();
|
||||
stdout.flush().unwrap();
|
||||
},
|
||||
ThreadMessage::Exit => {
|
||||
if !wm.locked {
|
||||
write!(stdout, "{}", cursor::Show).unwrap();
|
||||
stdout.suspend_raw_mode().unwrap();
|
||||
exit(0);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DrawInstructions {
|
||||
Rect(Point, Dimensions, RGBColor),
|
||||
@@ -231,6 +101,7 @@ impl fmt::Debug for WindowLikeInfo {
|
||||
pub struct WindowManager {
|
||||
writer: RefCell<FramebufferWriter>,
|
||||
rotate: bool,
|
||||
grayscale: bool,
|
||||
id_count: usize,
|
||||
window_infos: Vec<WindowLikeInfo>,
|
||||
osk: Option<WindowLikeInfo>,
|
||||
@@ -246,15 +117,17 @@ pub struct WindowManager {
|
||||
//1 is up, 2 is down
|
||||
|
||||
impl WindowManager {
|
||||
pub fn new(writer: FramebufferWriter, framebuffer: Framebuffer, dimensions: Dimensions, rotate: bool) -> Self {
|
||||
pub fn new(writer: FramebufferWriter, framebuffer: Framebuffer, dimensions: Dimensions, rotate: bool, grayscale: bool) -> Self {
|
||||
//println!("bg: {}x{}", dimensions[0], dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT);
|
||||
let mut wm = WindowManager {
|
||||
writer: RefCell::new(writer),
|
||||
rotate,
|
||||
grayscale,
|
||||
id_count: 0,
|
||||
window_infos: Vec::new(),
|
||||
osk: None,
|
||||
dimensions,
|
||||
theme: Themes::Standard,
|
||||
theme: Default::default(),
|
||||
focused_id: 0,
|
||||
locked: false,
|
||||
current_workspace: 0,
|
||||
@@ -262,6 +135,7 @@ impl WindowManager {
|
||||
clipboard: None,
|
||||
};
|
||||
wm.lock();
|
||||
wm.change_theme();
|
||||
wm
|
||||
}
|
||||
|
||||
@@ -320,6 +194,18 @@ impl WindowManager {
|
||||
self.add_window_like(Box::new(WorkspaceIndicator::new()), [0, 0], None);
|
||||
}
|
||||
|
||||
fn change_theme(&mut self) {
|
||||
self.theme = Default::default();
|
||||
if let Ok(mut file) = File::open(format!("{}/ming-wm/themes", 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() {
|
||||
self.theme = Themes::from_str(lines[self.current_workspace as usize]).unwrap_or(Default::default());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if off_only is true, also handle request
|
||||
//written confusingly but it works I promise
|
||||
fn toggle_start_menu(&mut self, off_only: bool) -> WindowMessageResponse {
|
||||
@@ -478,6 +364,8 @@ impl WindowManager {
|
||||
//close start menu if open
|
||||
self.toggle_start_menu(true);
|
||||
self.current_workspace = workspace;
|
||||
//change theme
|
||||
self.change_theme();
|
||||
//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)));
|
||||
@@ -795,7 +683,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], vec!["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!["nimbus-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
|
||||
@@ -812,7 +700,7 @@ impl WindowManager {
|
||||
framebuffer_info.stride = window_width;
|
||||
framebuffer_info.byte_len = window_width * window_height * bytes_per_pixel;
|
||||
//make a writer just for the window
|
||||
let mut window_writer: FramebufferWriter = Default::default();
|
||||
let mut window_writer: FramebufferWriter = FramebufferWriter::new(self.grayscale);
|
||||
window_writer.init(framebuffer_info);
|
||||
for instruction in instructions {
|
||||
//unsafe { SERIAL1.lock().write_text(&format!("{:?}\n", instruction)); }
|
||||
|
||||
Reference in New Issue
Block a user