From 247d2805db0c1b686ef4c6cc0f786ff416aeb7e3 Mon Sep 17 00:00:00 2001 From: salmonik Date: Sat, 11 Jul 2026 01:46:59 +0200 Subject: init --- src/main.rs | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 src/main.rs (limited to 'src/main.rs') diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..7a814c1 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,136 @@ +mod x11; +mod keymap; +mod layout; +mod ui; + +use eframe::egui; + +struct XkbPreviewApp { + key_data: Option, + x11_conn: Option, + selected_level: usize, + active_level: usize, + active_group: usize, + error: Option, +} + +impl Default for XkbPreviewApp { + fn default() -> Self { + Self { + key_data: None, + x11_conn: None, + selected_level: 0, + active_level: 0, + active_group: 0, + error: None, + } + } +} + +impl eframe::App for XkbPreviewApp { + fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) { + if self.key_data.is_none() && self.error.is_none() { + match load_keyboard() { + Ok(data) => self.key_data = Some(data), + Err(e) => self.error = Some(e), + } + } + + if self.x11_conn.is_none() { + self.x11_conn = x11::X11Connection::open(); + } + + if let Some(ref conn) = self.x11_conn { + let mask = conn.modifier_mask(); + self.active_level = keymap::level_from_x11_modmask(mask); + self.active_group = conn.active_group(); + } + + ui::render( + ui, + &self.key_data, + &mut self.selected_level, + self.active_level, + self.active_group, + &self.error, + ); + } +} + +fn load_keyboard() -> Result { + let names = x11::get_xkb_rule_names().unwrap_or_default(); + keymap::compile_keymap(&names) +} + +fn main() -> eframe::Result { + let options = eframe::NativeOptions { + viewport: egui::ViewportBuilder::default() + .with_inner_size([980.0, 560.0]), + ..Default::default() + }; + eframe::run_native( + "xkbpreview", + options, + Box::new(|cc| { + setup_fonts(&cc.egui_ctx); + Ok(Box::new(XkbPreviewApp::default())) + }), + ) +} + +fn setup_fonts(ctx: &egui::Context) { + let mut fonts = egui::FontDefinitions::default(); + + let font_candidates = [ + "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", + "/usr/share/fonts/dejavu/DejaVuSans.ttf", + "/usr/share/fonts/truetype/dejavu/DejaVuSans-Regular.ttf", + "/usr/share/fonts/dejavu/DejaVuSans-Regular.ttf", + "/usr/share/fonts/TTF/DejaVuSans.ttf", + "/usr/share/fonts/truetype/noto/NotoSans-Regular.ttf", + "/usr/share/fonts/noto/NotoSans-Regular.ttf", + "/usr/share/fonts/opentype/noto/NotoSans-Regular.ttf", + ]; + + let mut loaded = false; + for path in &font_candidates { + if let Ok(data) = std::fs::read(path) { + fonts + .font_data + .insert("fallback_font".into(), egui::FontData::from_owned(data).into()); + fonts + .families + .entry(egui::FontFamily::Proportional) + .or_default() + .push("fallback_font".into()); + loaded = true; + break; + } + } + + if !loaded { + if let Ok(home) = std::env::var("HOME") { + let user_candidates = [ + format!("{}/.fonts/DejaVuSans.ttf", home), + format!("{}/.local/share/fonts/DejaVuSans.ttf", home), + format!("{}/.fonts/NotoSans-Regular.ttf", home), + format!("{}/.local/share/fonts/NotoSans-Regular.ttf", home), + ]; + for path in &user_candidates { + if let Ok(data) = std::fs::read(path) { + fonts + .font_data + .insert("fallback_font".into(), egui::FontData::from_owned(data).into()); + fonts + .families + .entry(egui::FontFamily::Proportional) + .or_default() + .push("fallback_font".into()); + break; + } + } + } + } + + ctx.set_fonts(fonts); +} -- cgit v1.2.3