diff --git a/src/picker/group_box/basics.rs b/src/picker/group_box/basics.rs index 3d7eef89..0493f46b 100644 --- a/src/picker/group_box/basics.rs +++ b/src/picker/group_box/basics.rs @@ -1,11 +1,11 @@ -use super::{PickerAnsiGroup, PickerBasicGroup, PickerGroupBox}; +use super::{picker_ansi_group, picker_numpad_group, PickerBasicGroup, PickerGroupBox}; impl PickerGroupBox { pub fn basics() -> Self { Self::new(vec![ - Box::new(PickerAnsiGroup::new()), + Box::new(picker_ansi_group()), Box::new(PickerBasicGroup::new( - "Other Actions".to_string(), + "Other actions", 4, 1.5, &[ @@ -18,45 +18,22 @@ impl PickerGroupBox { "NONE", ], )), - // TODO numpad + // TODO label? + Box::new(picker_numpad_group()), Box::new(PickerBasicGroup::new( - "Numpad".to_string(), - 6, - 1.0, - &[ - "NUM_LOCK", - "NUM_7", - "NUM_8", - "NUM_9", - "NUM_MINUS", - "NUM_PLUS", - "NUM_SLASH", - "NUM_4", - "NUM_5", - "NUM_6", - "NUM_ASTERISK", - "NUM_ENTER", - "NUM_0", - "NUM_1", - "NUM_2", - "NUM_3", - "NUM_PERIOD", - ], - )), - Box::new(PickerBasicGroup::new( - "Symbols".to_string(), + "Symbols", 6, 1.0, &["NONUS_HASH", "NONUS_BSLASH"], )), Box::new(PickerBasicGroup::new( - "Navigation".to_string(), + "Navigation", 4, 1.0, &["LEFT", "UP", "DOWN", "RIGHT", "HOME", "PGUP", "PGDN", "END"], )), Box::new(PickerBasicGroup::new( - "Media".to_string(), + "Media", 3, 1.0, &[ @@ -69,7 +46,7 @@ impl PickerGroupBox { ], )), Box::new(PickerBasicGroup::new( - "Controls".to_string(), + "Controls", 4, 2.0, &[ @@ -86,13 +63,13 @@ impl PickerGroupBox { ], )), Box::new(PickerBasicGroup::new( - "LED controls".to_string(), + "LED controls", 4, 1.0, &["KBD_TOGGLE", "KBD_UP", "KBD_DOWN", "KBD_BKL", "KBD_COLOR"], )), Box::new(PickerBasicGroup::new( - "Layer keys".to_string(), + "Layer keys", 4, 2.0, &[ diff --git a/src/picker/group_box/extras.rs b/src/picker/group_box/extras.rs index e35c9a68..eea9e1b8 100644 --- a/src/picker/group_box/extras.rs +++ b/src/picker/group_box/extras.rs @@ -4,7 +4,7 @@ impl PickerGroupBox { pub fn extras() -> Self { Self::new(vec![ Box::new(PickerBasicGroup::new( - "Additional Function Keys".to_string(), + "Additional Function Keys", 6, 1.0, &[ @@ -13,7 +13,7 @@ impl PickerGroupBox { ], )), Box::new(PickerBasicGroup::new( - "Mouse Actions".to_string(), + "Mouse Actions", 5, 2.0, &[ diff --git a/src/picker/group_box/group/ansi.rs b/src/picker/group_box/group/ansi.rs index ec5a078f..085e27a8 100644 --- a/src/picker/group_box/group/ansi.rs +++ b/src/picker/group_box/group/ansi.rs @@ -1,16 +1,12 @@ -use gtk::prelude::*; - -use super::{PickerGroup, PickerKey}; - -const KEY_WIDTH: f64 = 48.0; -const KEY_SPACE: f64 = 4.0; +use super::variable_width::{PickerVariableWidthGroup, KEY_SIZE, KEY_SPACE}; +use crate::fl; // A 2U key takes same space as 2 1U including spacing // 2 1.5U keys take same space as 3 1U // Space bar is the same as 3 1U + 1 1.5U to line up with previous row static KEY_WIDTHS: &[(f64, &[&str])] = &[ ( - 1.5 * KEY_WIDTH + 0.5 * KEY_SPACE, + 1.5 * KEY_SIZE + 0.5 * KEY_SPACE, &[ "DEL", "BKSP", @@ -24,10 +20,10 @@ static KEY_WIDTHS: &[(f64, &[&str])] = &[ ], ), ( - 2.0 * KEY_WIDTH + KEY_SPACE, + 2.0 * KEY_SIZE + KEY_SPACE, &["LEFT_SHIFT", "RIGHT_SHIFT", "ENTER"], ), - (4.5 * KEY_WIDTH + 3.5 * KEY_SPACE, &["SPACE"]), + (4.5 * KEY_SIZE + 3.5 * KEY_SPACE, &["SPACE"]), ]; static ROWS: &[&[&str]] = &[ @@ -94,53 +90,12 @@ static ROWS: &[&[&str]] = &[ ], ]; -pub struct PickerAnsiGroup { - keys: Vec, - widget: gtk::Fixed, -} - -impl PickerAnsiGroup { - pub fn new() -> Self { - let mut keys = Vec::new(); - let box_ = gtk::Box::new(gtk::Orientation::Vertical, 0); - - let fixed = gtk::Fixed::new(); - - let mut y = 0; - for row in ROWS { - let mut x = 0; - for name in *row { - let width = KEY_WIDTHS - .iter() - .find_map(|(width, keys)| { - if keys.contains(name) { - Some(*width) - } else { - None - } - }) - .unwrap_or(KEY_WIDTH); - let key = PickerKey::new(name, width / KEY_WIDTH); - fixed.put(&key, x, y); - keys.push(key); - x += width as i32 + 4 - } - y += KEY_WIDTH as i32 + 4; - } - - PickerAnsiGroup { - keys, - widget: fixed, - } - } -} - -impl PickerGroup for PickerAnsiGroup { - fn keys(&self) -> &[PickerKey] { - &self.keys - } - - fn widget(&self) -> >k::Widget { - self.widget.upcast_ref() - } +pub fn picker_ansi_group() -> PickerVariableWidthGroup { + PickerVariableWidthGroup::new( + ROWS, + KEY_WIDTHS, + &[], + None, + Some(&fl!("picker-shift-click")), + ) } diff --git a/src/picker/group_box/group/basic_group.rs b/src/picker/group_box/group/basic_group.rs index 80077dc5..f0fe7ab5 100644 --- a/src/picker/group_box/group/basic_group.rs +++ b/src/picker/group_box/group/basic_group.rs @@ -15,9 +15,9 @@ pub struct PickerBasicGroup { } impl PickerBasicGroup { - pub fn new(name: String, cols: u32, width: f64, key_names: &[&str]) -> Self { + pub fn new(name: &str, cols: u32, width: f64, key_names: &[&str]) -> Self { let label = cascade! { - gtk::Label::new(Some(&name)); + gtk::Label::new(Some(name)); ..set_attributes(Some(&cascade! { pango::AttrList::new(); ..insert(pango::AttrInt::new_weight(pango::Weight::Bold)); @@ -46,7 +46,7 @@ impl PickerBasicGroup { let keys: Vec<_> = key_names .iter() - .map(|name| PickerKey::new(name, width)) + .map(|name| PickerKey::new(name, width, 1.0)) .collect(); for key in &keys { flow_box.add(key); diff --git a/src/picker/group_box/group/international.rs b/src/picker/group_box/group/international.rs index e3e3e693..576b30d8 100644 --- a/src/picker/group_box/group/international.rs +++ b/src/picker/group_box/group/international.rs @@ -35,7 +35,7 @@ pub struct PickerInternationalGroup { } fn row(keys: &mut Vec, keycode: &str, description: &str) -> gtk::Box { - let key = PickerKey::new(keycode, 1.0); + let key = PickerKey::new(keycode, 1.0, 1.0); keys.push(key.clone()); cascade! { gtk::Box::new(gtk::Orientation::Horizontal, 8); diff --git a/src/picker/group_box/group/mod.rs b/src/picker/group_box/group/mod.rs index fdd2efe8..8432401b 100644 --- a/src/picker/group_box/group/mod.rs +++ b/src/picker/group_box/group/mod.rs @@ -1,11 +1,14 @@ use super::super::PickerKey; mod ansi; -pub use ansi::PickerAnsiGroup; +pub use ansi::picker_ansi_group; mod basic_group; pub use basic_group::PickerBasicGroup; mod international; pub use international::PickerInternationalGroup; +mod numpad; +pub use numpad::picker_numpad_group; +mod variable_width; pub trait PickerGroup { fn keys(&self) -> &[PickerKey]; diff --git a/src/picker/group_box/group/numpad.rs b/src/picker/group_box/group/numpad.rs new file mode 100644 index 00000000..a23a5afe --- /dev/null +++ b/src/picker/group_box/group/numpad.rs @@ -0,0 +1,17 @@ +use super::variable_width::{PickerVariableWidthGroup, KEY_SIZE, KEY_SPACE}; + +static KEY_WIDTHS: &[(f64, &[&str])] = &[(2.0 * KEY_SIZE + KEY_SPACE, &["NUM_0"])]; + +static KEY_HEIGHTS: &[(f64, &[&str])] = &[(2.0 * KEY_SIZE + KEY_SPACE, &["NUM_PLUS", "NUM_ENTER"])]; + +static ROWS: &[&[&str]] = &[ + &["NUM_LOCK", "NUM_SLASH", "NUM_ASTERISK", "NUM_MINUS"], + &["NUM_7", "NUM_8", "NUM_9", "NUM_PLUS"], + &["NUM_4", "NUM_5", "NUM_6"], + &["NUM_1", "NUM_2", "NUM_3", "NUM_ENTER"], + &["NUM_0", "NUM_PERIOD"], +]; + +pub fn picker_numpad_group() -> PickerVariableWidthGroup { + PickerVariableWidthGroup::new(ROWS, KEY_WIDTHS, KEY_HEIGHTS, Some("Numpad"), None) +} diff --git a/src/picker/group_box/group/variable_width.rs b/src/picker/group_box/group/variable_width.rs new file mode 100644 index 00000000..4ddaecf4 --- /dev/null +++ b/src/picker/group_box/group/variable_width.rs @@ -0,0 +1,99 @@ +use cascade::cascade; +use gtk::{pango, prelude::*}; + +use super::{PickerGroup, PickerKey}; + +pub const KEY_SIZE: f64 = 48.0; +pub const KEY_SPACE: f64 = 4.0; + +pub struct PickerVariableWidthGroup { + keys: Vec, + widget: gtk::Box, +} + +impl PickerVariableWidthGroup { + pub fn new( + rows: &[&[&str]], + widths: &[(f64, &[&str])], + heights: &[(f64, &[&str])], + label: Option<&str>, + desc: Option<&str>, + ) -> Self { + let mut keys = Vec::new(); + + let vbox = cascade! { + gtk::Box::new(gtk::Orientation::Vertical, 4); + ..show(); + }; + + if let Some(label) = label { + let label = cascade! { + gtk::Label::new(Some(&label)); + ..set_attributes(Some(&cascade! { + pango::AttrList::new(); + ..insert(pango::AttrInt::new_weight(pango::Weight::Bold)); + } )); + ..set_halign(gtk::Align::Start); + ..set_margin_bottom(8); + ..show(); + }; + vbox.add(&label); + } + + let fixed = gtk::Fixed::new(); + vbox.add(&fixed); + + let mut y = 0; + for row in rows { + let mut x = 0; + for name in *row { + let width = widths + .iter() + .find_map(|(width, keys)| { + if keys.contains(name) { + Some(*width) + } else { + None + } + }) + .unwrap_or(KEY_SIZE); + let height = heights + .iter() + .find_map(|(height, keys)| { + if keys.contains(name) { + Some(*height) + } else { + None + } + }) + .unwrap_or(KEY_SIZE); + let key = PickerKey::new(name, width / KEY_SIZE, height / KEY_SIZE); + fixed.put(&key, x, y); + keys.push(key); + x += width as i32 + 4 + } + y += KEY_SIZE as i32 + 4; + } + + if let Some(desc) = desc { + let label = cascade! { + gtk::Label::new(Some(&desc)); + ..set_halign(gtk::Align::Start); + ..show(); + }; + vbox.add(&label); + } + + Self { keys, widget: vbox } + } +} + +impl PickerGroup for PickerVariableWidthGroup { + fn keys(&self) -> &[PickerKey] { + &self.keys + } + + fn widget(&self) -> >k::Widget { + self.widget.upcast_ref() + } +} diff --git a/src/picker/group_box/mod.rs b/src/picker/group_box/mod.rs index ce502120..24737c43 100644 --- a/src/picker/group_box/mod.rs +++ b/src/picker/group_box/mod.rs @@ -191,7 +191,7 @@ impl PickerGroupBox { pub fn set_key_visibility bool>(&self, f: F) { for group in self.inner().groups.iter() { let group_visible = group.keys().iter().fold(false, |group_visible, key| { - key.set_visible(f(&key.name())); + key.set_visible(f(key.name())); group_visible || key.get_visible() }); @@ -202,7 +202,7 @@ impl PickerGroupBox { pub fn set_key_sensitivity bool>(&self, f: F) { for key in self.inner().keys.values() { - key.set_sensitive(f(&key.name())); + key.set_sensitive(f(key.name())); } } diff --git a/src/picker/mod.rs b/src/picker/mod.rs index 5f8194c2..6f48a6aa 100644 --- a/src/picker/mod.rs +++ b/src/picker/mod.rs @@ -188,7 +188,7 @@ impl Picker { self.inner().tap_hold.set_visible(is_qmk); self.inner().stack_switcher.set_visible(is_qmk); self.inner().is_qmk.set(is_qmk); - kb.set_picker(Some(&self)); + kb.set_picker(Some(self)); } *self.inner().keyboard.borrow_mut() = keyboard; diff --git a/src/picker/picker_key.rs b/src/picker/picker_key.rs index 611b25b2..2c78f847 100644 --- a/src/picker/picker_key.rs +++ b/src/picker/picker_key.rs @@ -56,13 +56,13 @@ glib::wrapper! { } impl PickerKey { - pub fn new(name: &str, width: f64) -> Self { + pub fn new(name: &str, width: f64, height: f64) -> Self { let keysym_label = super::SCANCODE_LABELS.get(name).unwrap(); let widget: Self = glib::Object::new(&[]).unwrap(); widget.inner().name.set(name.to_string()); - widget.inner().label.set_label(&keysym_label); - widget.set_size_request((48.0 * width) as i32, 48); + widget.inner().label.set_label(keysym_label); + widget.set_size_request((48.0 * width) as i32, (48.0 * height) as i32); widget } diff --git a/src/picker/tap_hold.rs b/src/picker/tap_hold.rs index 9a9d70dd..6dabf3ae 100644 --- a/src/picker/tap_hold.rs +++ b/src/picker/tap_hold.rs @@ -75,19 +75,19 @@ impl ObjectImpl for TapHoldInner { *widget.inner().keycode.borrow_mut() = Some(name); widget.update(); })); - ..set_key_visibility(|name| is_qmk_basic(name)); + ..set_key_visibility(is_qmk_basic); }; let hold_group_box = cascade! { PickerGroupBox::new(vec![ Box::new(PickerBasicGroup::new( - "Modifiers".to_string(), + "Modifiers", 4, 1.5, MODIFIERS, )), Box::new(PickerBasicGroup::new( - "Layer Keys".to_string(), + "Layer Keys", 4, 1.5, LAYERS, @@ -103,7 +103,7 @@ impl ObjectImpl for TapHoldInner { } Hold::Mods(new_mods) } else { - let n = LAYERS.iter().position(|x| *x == &name).unwrap() as u8; + let n = LAYERS.iter().position(|x| *x == name).unwrap() as u8; Hold::Layer(n) }; widget.inner().hold.set(new_hold); @@ -111,6 +111,7 @@ impl ObjectImpl for TapHoldInner { })); }; + // TODO indent cascade! { widget; ..set_spacing(8); @@ -123,10 +124,14 @@ impl ObjectImpl for TapHoldInner { })); ..set_halign(gtk::Align::Start); }); - ..add(&hold_group_box); + ..add(cascade! { + &hold_group_box; + ..set_margin_start(8); + }); ..add(&cascade! { gtk::Label::new(Some(&fl!("tap-hold-multiple-mod"))); ..set_halign(gtk::Align::Start); + ..set_margin_start(8); }); // XXX grey? ..add(&cascade! { @@ -137,7 +142,10 @@ impl ObjectImpl for TapHoldInner { })); ..set_halign(gtk::Align::Start); }); - ..add(&picker_group_box); + ..add(cascade! { + &picker_group_box; + ..set_margin_start(8); + }); }; self.hold_group_box.set(hold_group_box);