From 8b55f41470066041f7337211447bfae67526d227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=98=A4=EB=B3=91=EC=A4=80?= Date: Wed, 1 May 2024 05:07:22 +0900 Subject: [PATCH] add: client display position setup --- src/client.rs | 141 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/utils.rs | 36 ++++++++++++- 2 files changed, 172 insertions(+), 5 deletions(-) diff --git a/src/client.rs b/src/client.rs index 9fab348..776e9c2 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::io::{Error, ErrorKind::*, Read, Write}; +use std::io::{stdout, Error, ErrorKind::*, Read, Write}; use std::{fs, net::TcpStream}; use std::{mem, u32}; @@ -75,10 +75,143 @@ impl Client { Ok(()) } - fn set_display_position(&mut self, previous: Vec) { - let mut disp = &self.displays; + fn set_display_position(&mut self, server_conf: Vec) { + let displays = &mut self.displays; + + let file = config_dir!("client").join("client_config.json"); + + if file.exists() { + let json = match fs::read_to_string(file) { + Ok(json) => json, + Err(_) => { + eprint!("[WRN] invalid client_config.json"); + return prompt_display_position(displays, server_conf); + } + }; + + let config: Vec = match serde_json::from_str(&json) { + Ok(vec) => vec, + Err(_) => { + eprint!("[WRN] invalid client_config.json"); + return prompt_display_position(displays, server_conf); + } + }; + + /* check all displays in config are correct */ + let mut cnt = 0; + + for disp in displays.iter() { + for conf in config.iter() { + // the only param that could identify displays + if disp.name == conf.name { + cnt += 1; + continue; + } + } + } + + if cnt != displays.len() { + eprint!("[WRN] client_config.json does not match with current system displays"); + return prompt_display_position(displays, server_conf); + } + + /* set positions with config; misconfigurations will be checked in the server */ + for disp in displays.iter_mut() { + for conf in config.iter() { + if disp.name == conf.name { + disp.x = conf.x; + disp.y = conf.y; + continue; + } + } + } + } else { + // config not exists + return prompt_display_position(displays, server_conf); + } + } +} + +fn prompt_display_position(displays: &mut Vec, server_conf: Vec) { + println!("\n########## display position setup ##########"); + println!("[INF] current server displays:"); + + for (i, d) in server_conf.iter().enumerate() { + println!( + " [{:2}] x: {:4}, y: {:4}, width: {:4}, height: {:4}", + i, d.x, d.y, d.width, d.height + ); + } + + println!("\n[INF] please enter the attach position of the each display"); + println!("[INF] (x, y) is the coordinate of the upper left corner of the display"); + + let mut i = 0; + let tot = displays.len(); - // ! TODO + while i < tot { + let d = displays.get_mut(i).unwrap(); + println!( + "[{:2}/{}] {} - width: {:4}, height: {:4}", + i, tot, d.name, d.width, d.height + ); + + print!(" x coordinate: "); + stdout().flush().unwrap(); + + match stdin_i32() { + Ok(x) => d.x = x, + Err(_) => { + eprintln!(" [ERR] invalid input"); + continue; + } + } + + print!(" y coordinate: "); + stdout().flush().unwrap(); + + match stdin_i32() { + Ok(y) => d.y = y, + Err(_) => { + eprintln!(" [ERR] invalid input"); + continue; + } + } + + // confirm input + loop { + print!( + "[CONFIRM] {} - x: {}, y: {}, width: {:4}, height: {:4} [y/n/p]: ", + d.name, d.x, d.y, d.width, d.height + ); + stdout().flush().unwrap(); + + let ch = match stdin_char() { + Ok(ch) => ch, + Err(_) => { + continue; + } + }; + + match ch { + 'y' => { + i += 1; // next display + break; + } + 'n' => { + break; // current display again + } + 'p' => { + if i > 0 { + i -= 1; // previous display + } + break; + } + _ => { + continue; + } + } + } } } diff --git a/src/utils.rs b/src/utils.rs index 8d29d6e..bb812aa 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,3 +1,6 @@ +use std::io::stdin; +use std::io::{Error, ErrorKind::*}; + use display_info::DisplayInfo; use serde::{Deserialize, Serialize}; @@ -15,6 +18,36 @@ pub fn print_displays() { } } +pub fn stdin_i32() -> Result { + let mut input = String::new(); + + if let Err(_) = stdin().read_line(&mut input) { + return Err(Error::new(InvalidInput, "stdin read failure")); + }; + + match input.trim().parse() { + Ok(i) => Ok(i), + Err(_) => { + return Err(Error::new(InvalidInput, "invalid input")); + } + } +} + +pub fn stdin_char() -> Result { + let mut input = String::new(); + + if let Err(_) = stdin().read_line(&mut input) { + return Err(Error::new(InvalidInput, "stdin read failure")); + }; + + match input.trim().parse() { + Ok(i) => Ok(i), + Err(_) => { + return Err(Error::new(InvalidInput, "invalid input")); + } + } +} + #[macro_export] macro_rules! config_dir { ($subpath: expr) => {{ @@ -23,7 +56,8 @@ macro_rules! config_dir { ProjectDirs::from("", "luftaquila", "transistor") .unwrap() .data_local_dir() - .to_path_buf().join($subpath) + .to_path_buf() + .join($subpath) }}; }