summaryrefslogtreecommitdiffstats
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs136
1 files changed, 136 insertions, 0 deletions
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 @@
1mod x11;
2mod keymap;
3mod layout;
4mod ui;
5
6use eframe::egui;
7
8struct XkbPreviewApp {
9 key_data: Option<keymap::KeyData>,
10 x11_conn: Option<x11::X11Connection>,
11 selected_level: usize,
12 active_level: usize,
13 active_group: usize,
14 error: Option<String>,
15}
16
17impl Default for XkbPreviewApp {
18 fn default() -> Self {
19 Self {
20 key_data: None,
21 x11_conn: None,
22 selected_level: 0,
23 active_level: 0,
24 active_group: 0,
25 error: None,
26 }
27 }
28}
29
30impl eframe::App for XkbPreviewApp {
31 fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
32 if self.key_data.is_none() && self.error.is_none() {
33 match load_keyboard() {
34 Ok(data) => self.key_data = Some(data),
35 Err(e) => self.error = Some(e),
36 }
37 }
38
39 if self.x11_conn.is_none() {
40 self.x11_conn = x11::X11Connection::open();
41 }
42
43 if let Some(ref conn) = self.x11_conn {
44 let mask = conn.modifier_mask();
45 self.active_level = keymap::level_from_x11_modmask(mask);
46 self.active_group = conn.active_group();
47 }
48
49 ui::render(
50 ui,
51 &self.key_data,
52 &mut self.selected_level,
53 self.active_level,
54 self.active_group,
55 &self.error,
56 );
57 }
58}
59
60fn load_keyboard() -> Result<keymap::KeyData, String> {
61 let names = x11::get_xkb_rule_names().unwrap_or_default();
62 keymap::compile_keymap(&names)
63}
64
65fn main() -> eframe::Result {
66 let options = eframe::NativeOptions {
67 viewport: egui::ViewportBuilder::default()
68 .with_inner_size([980.0, 560.0]),
69 ..Default::default()
70 };
71 eframe::run_native(
72 "xkbpreview",
73 options,
74 Box::new(|cc| {
75 setup_fonts(&cc.egui_ctx);
76 Ok(Box::new(XkbPreviewApp::default()))
77 }),
78 )
79}
80
81fn setup_fonts(ctx: &egui::Context) {
82 let mut fonts = egui::FontDefinitions::default();
83
84 let font_candidates = [
85 "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
86 "/usr/share/fonts/dejavu/DejaVuSans.ttf",
87 "/usr/share/fonts/truetype/dejavu/DejaVuSans-Regular.ttf",
88 "/usr/share/fonts/dejavu/DejaVuSans-Regular.ttf",
89 "/usr/share/fonts/TTF/DejaVuSans.ttf",
90 "/usr/share/fonts/truetype/noto/NotoSans-Regular.ttf",
91 "/usr/share/fonts/noto/NotoSans-Regular.ttf",
92 "/usr/share/fonts/opentype/noto/NotoSans-Regular.ttf",
93 ];
94
95 let mut loaded = false;
96 for path in &font_candidates {
97 if let Ok(data) = std::fs::read(path) {
98 fonts
99 .font_data
100 .insert("fallback_font".into(), egui::FontData::from_owned(data).into());
101 fonts
102 .families
103 .entry(egui::FontFamily::Proportional)
104 .or_default()
105 .push("fallback_font".into());
106 loaded = true;
107 break;
108 }
109 }
110
111 if !loaded {
112 if let Ok(home) = std::env::var("HOME") {
113 let user_candidates = [
114 format!("{}/.fonts/DejaVuSans.ttf", home),
115 format!("{}/.local/share/fonts/DejaVuSans.ttf", home),
116 format!("{}/.fonts/NotoSans-Regular.ttf", home),
117 format!("{}/.local/share/fonts/NotoSans-Regular.ttf", home),
118 ];
119 for path in &user_candidates {
120 if let Ok(data) = std::fs::read(path) {
121 fonts
122 .font_data
123 .insert("fallback_font".into(), egui::FontData::from_owned(data).into());
124 fonts
125 .families
126 .entry(egui::FontFamily::Proportional)
127 .or_default()
128 .push("fallback_font".into());
129 break;
130 }
131 }
132 }
133 }
134
135 ctx.set_fonts(fonts);
136}