Skip to content

Commit 85a0c5b

Browse files
committed
improv: Use a pure Rust method for Keyboard instead of .ui
Adds a `DerefCell` struct to use in place of `gtk::TemplateChild`.
1 parent f6328d5 commit 85a0c5b

File tree

4 files changed

+125
-114
lines changed

4 files changed

+125
-114
lines changed

src/application/keyboard.rs

Lines changed: 93 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use glib::object::WeakRef;
33
use glib::subclass;
44
use gtk::prelude::*;
55
use gtk::subclass::prelude::*;
6-
use once_cell::unsync::OnceCell;
76
use std::{
87
cell::{
98
Cell,
@@ -22,6 +21,7 @@ use std::{
2221

2322
use crate::{
2423
DaemonBoard,
24+
DerefCell,
2525
KeyboardColorButton,
2626
KeyMap,
2727
};
@@ -34,24 +34,20 @@ use super::{
3434
Picker,
3535
};
3636

37-
#[derive(Default, gtk::CompositeTemplate)]
37+
#[derive(Default)]
3838
pub struct KeyboardInner {
39-
#[template_child]
40-
action_group: TemplateChild<gio::SimpleActionGroup>,
41-
board: OnceCell<DaemonBoard>,
42-
board_name: OnceCell<String>,
43-
default_layout: OnceCell<KeyMap>,
44-
keymap: OnceCell<HashMap<String, u16>>,
45-
keys: OnceCell<Rc<[Key]>>,
39+
action_group: DerefCell<gio::SimpleActionGroup>,
40+
board: DerefCell<DaemonBoard>,
41+
board_name: DerefCell<String>,
42+
default_layout: DerefCell<KeyMap>,
43+
keymap: DerefCell<HashMap<String, u16>>,
44+
keys: DerefCell<Rc<[Key]>>,
4645
page: Cell<Page>,
4746
picker: RefCell<WeakRef<Picker>>,
4847
selected: Cell<Option<usize>>,
49-
#[template_child]
50-
color_button_bin: TemplateChild<gtk::Frame>,
51-
#[template_child]
52-
brightness_scale: TemplateChild<gtk::Scale>,
53-
#[template_child]
54-
stack: TemplateChild<gtk::Stack>,
48+
color_button_bin: DerefCell<gtk::Frame>,
49+
brightness_scale: DerefCell<gtk::Scale>,
50+
stack: DerefCell<gtk::Stack>,
5551
}
5652

5753
impl ObjectSubclass for KeyboardInner {
@@ -66,66 +62,100 @@ impl ObjectSubclass for KeyboardInner {
6662

6763
glib::object_subclass!();
6864

69-
fn class_init(klass: &mut Self::Class) {
70-
klass.set_template(include_bytes!("keyboard.ui"));
71-
Self::bind_template_children(klass);
72-
}
73-
7465
fn new() -> Self {
7566
Self::default()
7667
}
7768
}
7869

7970
impl ObjectImpl for KeyboardInner {
8071
fn constructed(&self, keyboard: &Keyboard) {
81-
keyboard.init_template();
8272
self.parent_constructed(keyboard);
8373

84-
self.action_group.add_action(&cascade! {
74+
let stack = cascade! {
75+
gtk::Stack::new();
76+
..set_transition_duration(0);
77+
..connect_property_visible_child_notify(
78+
clone!(@weak keyboard => move |stack| {
79+
let page = stack
80+
.get_visible_child()
81+
.map(|c| c.downcast_ref::<KeyboardLayer>().unwrap().page());
82+
83+
println!("{:?}", page);
84+
let last_layer = keyboard.layer();
85+
keyboard.inner().page.set(page.unwrap_or(Page::Layer1));
86+
if keyboard.layer() != last_layer {
87+
keyboard.set_selected(keyboard.selected());
88+
}
89+
})
90+
);
91+
};
92+
93+
let brightness_scale = cascade! {
94+
gtk::Scale::with_range(gtk::Orientation::Horizontal, 0., 100., 1.);
95+
..set_halign(gtk::Align::Fill);
96+
..set_size_request(200, 0);
97+
};
98+
brightness_scale.connect_value_changed(
99+
clone!(@weak keyboard => move |this| {
100+
let value = this.get_value() as i32;
101+
if let Err(err) = keyboard.board().set_brightness(value) {
102+
eprintln!("{}", err);
103+
}
104+
println!("{}", value);
105+
})
106+
);
107+
108+
// XXX add support to ColorButton for changing keyboard
109+
let color_button_bin = cascade! {
110+
gtk::Frame::new(None);
111+
..set_shadow_type(gtk::ShadowType::None);
112+
..set_valign(gtk::Align::Center);
113+
};
114+
115+
cascade! {
116+
keyboard;
117+
..set_orientation(gtk::Orientation::Vertical);
118+
..set_spacing(8);
119+
..add(&cascade! {
120+
gtk::Box::new(gtk::Orientation::Horizontal, 8);
121+
..add(&cascade! {
122+
gtk::Label::new(Some("Brightness:"));
123+
..set_halign(gtk::Align::Start);
124+
});
125+
..add(&brightness_scale);
126+
..add(&cascade! {
127+
gtk::Label::new(Some("Color:"));
128+
..set_halign(gtk::Align::Start);
129+
});
130+
..add(&color_button_bin);
131+
});
132+
..add(&stack);
133+
};
134+
135+
let action_group = gio::SimpleActionGroup::new();
136+
action_group.add_action(&cascade! {
85137
gio::SimpleAction::new("load", None);
86138
..connect_activate(clone!(@weak keyboard => move |_, _| {
87139
keyboard.load();
88140
}));
89141
});
90-
91-
self.action_group.add_action(&cascade! {
142+
action_group.add_action(&cascade! {
92143
gio::SimpleAction::new("save", None);
93144
..connect_activate(clone!(@weak keyboard => move |_, _| {
94145
keyboard.save();
95146
}));
96147
});
97-
98-
self.action_group.add_action(&cascade! {
148+
action_group.add_action(&cascade! {
99149
gio::SimpleAction::new("reset", None);
100150
..connect_activate(clone!(@weak keyboard => move |_, _| {
101151
keyboard.reset();
102152
}));
103153
});
104154

105-
self.stack.connect_property_visible_child_notify(
106-
clone!(@weak keyboard => move |stack| {
107-
let page = stack
108-
.get_visible_child()
109-
.map(|c| c.downcast_ref::<KeyboardLayer>().unwrap().page());
110-
111-
println!("{:?}", page);
112-
let last_layer = keyboard.layer();
113-
keyboard.inner().page.set(page.unwrap_or(Page::Layer1));
114-
if keyboard.layer() != last_layer {
115-
keyboard.set_selected(keyboard.selected());
116-
}
117-
})
118-
);
119-
120-
self.brightness_scale.connect_value_changed(
121-
clone!(@weak keyboard => move |this| {
122-
let value = this.get_value() as i32;
123-
if let Err(err) = keyboard.board().set_brightness(value) {
124-
eprintln!("{}", err);
125-
}
126-
println!("{}", value);
127-
})
128-
);
155+
self.action_group.set(action_group);
156+
self.color_button_bin.set(color_button_bin);
157+
self.brightness_scale.set(brightness_scale);
158+
self.stack.set(stack);
129159
}
130160

131161
fn properties() -> &'static [glib::ParamSpec] {
@@ -219,11 +249,11 @@ impl Keyboard {
219249
}
220250
}
221251

222-
let _ = keyboard.inner().keys.set(keys.into_boxed_slice().into());
223-
let _ = keyboard.inner().board.set(board);
224-
let _ = keyboard.inner().board_name.set(board_name.to_string());
225-
let _ = keyboard.inner().keymap.set(layout.keymap);
226-
let _ = keyboard.inner().default_layout.set(layout.default);
252+
keyboard.inner().keys.set(keys.into_boxed_slice().into());
253+
keyboard.inner().board.set(board);
254+
keyboard.inner().board_name.set(board_name.to_string());
255+
keyboard.inner().keymap.set(layout.keymap);
256+
keyboard.inner().default_layout.set(layout.default);
227257

228258
let color_button = KeyboardColorButton::new(keyboard.board().clone());
229259
keyboard.inner().color_button_bin.add(&color_button);
@@ -272,19 +302,19 @@ impl Keyboard {
272302
}
273303

274304
fn board_name(&self) -> &str {
275-
self.inner().board_name.get().unwrap()
305+
&self.inner().board_name
276306
}
277307

278308
fn board(&self) -> &DaemonBoard {
279-
self.inner().board.get().unwrap()
309+
&self.inner().board
280310
}
281311

282312
fn keymap(&self) -> &HashMap<String, u16> {
283-
self.inner().keymap.get().unwrap()
313+
&self.inner().keymap
284314
}
285315

286316
fn default_layout(&self) -> &KeyMap {
287-
self.inner().default_layout.get().unwrap()
317+
&self.inner().default_layout
288318
}
289319

290320
fn window(&self) -> Option<gtk::Window> {
@@ -311,8 +341,8 @@ impl Keyboard {
311341
self.keymap().contains_key(scancode_name)
312342
}
313343

314-
fn keys(&self) -> &[Key] {
315-
self.inner().keys.get().unwrap()
344+
pub fn keys(&self) -> &Rc<[Key]> {
345+
&self.inner().keys
316346
}
317347

318348
pub fn keymap_set(&self, key_index: usize, layer: usize, scancode_name: &str) {
@@ -343,7 +373,7 @@ impl Keyboard {
343373

344374
pub fn export_keymap(&self) -> KeyMap {
345375
let mut map = HashMap::new();
346-
for key in self.keys() {
376+
for key in self.keys().iter() {
347377
let scancodes = key.scancodes.borrow();
348378
let scancodes = scancodes.iter().map(|s| s.1.clone()).collect();
349379
map.insert(key.logical_name.clone(), scancodes);
@@ -441,11 +471,10 @@ impl Keyboard {
441471
}
442472

443473
fn add_pages(&self) {
444-
let keys = self.inner().keys.get().unwrap();
445474
let stack = &*self.inner().stack;
446475

447476
for (i, page) in Page::iter_all().enumerate() {
448-
let keyboard_layer = KeyboardLayer::new(page, keys.clone());
477+
let keyboard_layer = KeyboardLayer::new(page, self.keys().clone());
449478
self.bind_property("selected", &keyboard_layer, "selected")
450479
.flags(glib::BindingFlags::BIDIRECTIONAL)
451480
.build();

src/application/keyboard.ui

Lines changed: 0 additions & 50 deletions
This file was deleted.

src/deref_cell.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Wrapper around `OnceCell` implementing `Deref`, and thus also panicking
2+
// when not set (or set twice).
3+
//
4+
// To be used in place of `gtk::TemplateChild`, but without xml.
5+
6+
use once_cell::unsync::OnceCell;
7+
8+
pub struct DerefCell<T>(OnceCell<T>);
9+
10+
impl<T> DerefCell<T> {
11+
pub fn set(&self, value: T) {
12+
if self.0.set(value).is_err() {
13+
panic!("Initialized twice");
14+
}
15+
}
16+
}
17+
18+
impl<T> Default for DerefCell<T> {
19+
fn default() -> Self {
20+
Self(OnceCell::default())
21+
}
22+
}
23+
24+
impl <T> std::ops::Deref for DerefCell<T> {
25+
type Target = T;
26+
27+
fn deref(&self) -> &T {
28+
self.0.get().unwrap()
29+
}
30+
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod choose_color;
88
mod color;
99
mod color_circle;
1010
mod color_wheel;
11+
mod deref_cell;
1112
mod keyboard_backlight_widget;
1213
mod keyboard_color_button;
1314
mod keymap;
@@ -17,6 +18,7 @@ use crate::{
1718
color_circle::*,
1819
choose_color::*,
1920
daemon::*,
21+
deref_cell::*,
2022
keyboard_color_button::*,
2123
keymap::*,
2224
};

0 commit comments

Comments
 (0)