hyprshell_config_edit_lib/
util.rs1use crate::structs::ConfigModifier;
2use relm4::gtk::gdk::{Cursor, Key, ModifierType};
3use relm4::gtk::prelude::{Cast, EditableExt, WidgetExt};
4use relm4::{adw, gtk};
5use tracing::{instrument, warn};
7
8pub trait SetTextIfDifferent {
9 fn set_text_if_different(&self, text: &str);
10}
11
12impl SetTextIfDifferent for gtk::Entry {
13 fn set_text_if_different(&self, text: &str) {
14 use relm4::adw::prelude::EditableExt;
15 if self.text() != text {
16 self.set_text(text);
17 }
18 }
19}
20
21impl SetTextIfDifferent for adw::EntryRow {
22 fn set_text_if_different(&self, text: &str) {
23 if self.text() != text {
24 self.set_text(text);
25 }
26 }
27}
28
29pub trait SetCursor {
30 fn set_cursor_by_name(&self, name: &str);
31}
32
33impl SetCursor for gtk::Image {
34 fn set_cursor_by_name(&self, name: &str) {
35 use relm4::adw::prelude::WidgetExt;
36 self.set_cursor(Cursor::from_name(name, None).as_ref());
37 }
38}
39
40pub trait ScrollToPosition {
41 fn scroll_to_pos(&self, pos: usize, animate: bool);
42}
43
44impl ScrollToPosition for adw::Carousel {
45 fn scroll_to_pos(&self, pos: usize, animate: bool) {
46 if let Some(wdg) = self.observe_children().into_iter().flatten().nth(pos)
47 && let Ok(widget) = wdg.downcast::<gtk::Widget>()
48 {
49 let s2 = self.clone();
50 gtk::glib::idle_add_local(move || {
52 s2.scroll_to(&widget, animate);
53 #[allow(clippy::cast_sign_loss)]
54 if s2.position() as usize == pos {
55 gtk::glib::ControlFlow::Break
56 } else {
57 gtk::glib::ControlFlow::Continue
58 }
59 });
60 }
61 }
62}
63
64#[allow(dead_code)]
65pub trait SelectRow {
66 fn select_row_index_opt(&self, index: Option<i32>);
67 fn select_row_index(&self, index: i32);
68}
69
70impl SelectRow for gtk::ListBox {
71 fn select_row_index_opt(&self, index: Option<i32>) {
72 self.unselect_all();
73 if let Some(index) = index {
74 self.select_row_index(index);
75 }
76 }
77
78 fn select_row_index(&self, index: i32) {
79 self.unselect_all();
80 if self.selected_row() != self.row_at_index(index) {
81 if let Some(row) = self.row_at_index(index) {
82 self.select_row(Some(&row));
83 } else {
84 warn!("select_row_index: row not found ({index})");
85 }
86 }
87 }
88}
89
90pub fn handle_key(val: Key, state: ModifierType) -> Option<(String, ConfigModifier, String)> {
91 let key_name = val.name()?;
92 let modifier = match val {
93 Key::Alt_L | Key::Alt_R => ConfigModifier::Alt,
94 Key::Control_L | Key::Control_R => ConfigModifier::Ctrl,
95 Key::Super_L | Key::Super_R => ConfigModifier::Super,
96 _ => match state {
97 ModifierType::NO_MODIFIER_MASK => ConfigModifier::None,
98 ModifierType::ALT_MASK => ConfigModifier::Alt,
99 ModifierType::CONTROL_MASK => ConfigModifier::Ctrl,
100 ModifierType::SUPER_MASK => ConfigModifier::Super,
101 _ => return None,
102 },
103 };
104
105 let label = if modifier == ConfigModifier::None {
106 key_name.to_string()
107 } else {
108 format!("{modifier} + {key_name}")
109 };
110
111 Some((key_name.to_string(), modifier, label))
112}
113
114pub fn default_config() -> config_lib::Config {
115 config_lib::Config {
116 windows: Some(config_lib::Windows::default()),
117 }
118}
119
120#[instrument(level = "trace", ret(level = "trace"))]
121pub fn mod_key_to_accelerator(modifier: ConfigModifier, key: &str) -> String {
122 let key = match &*key.to_lowercase() {
124 "super_l" => "Super_L",
125 "super_r" => "Super_R",
126 "alt_l" => "Alt_L",
127 "alt_r" => "Alt_R",
128 "control_l" => "Control_L",
129 "control_r" => "Control_R",
130 _ => key,
131 };
132
133 if modifier == ConfigModifier::None {
134 key.to_string()
135 } else {
136 format!("<{modifier}>{key}")
137 }
138}
139
140#[instrument(level = "trace", ret(level = "trace"))]
141pub fn mod_key_to_string(modifier: ConfigModifier, key: &str) -> String {
142 if modifier == ConfigModifier::None {
143 key.to_string()
144 } else {
145 format!("{modifier} + {key}")
146 }
147}
148
149#[macro_export]
150macro_rules! flags_csv {
151 ($s:expr, $($field:ident),+ $(,)?) => {{
152 [$( (stringify!($field), $s.$field) ),+]
153 .into_iter()
154 .filter(|(_, v)| *v)
155 .map(|(k, _)| k)
156 .collect::<Vec<&str>>()
157 .join(", ")
158 }};
159}