From 74c5ef4a51685630f873538468c21378584a851c Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Sat, 1 Oct 2022 13:37:35 +0000 Subject: [PATCH] layout: Separate button info from state Splitting out state into a dedicated place lets keep all the immutable metadata in one place, and all state in another. --- src/data/parsing.rs | 28 ++++------ src/drawing.rs | 2 +- src/keyboard.rs | 17 +++--- src/layout.rs | 130 +++++++++++++++++++++++--------------------- src/tests.rs | 3 +- src/util.rs | 12 ---- 6 files changed, 92 insertions(+), 100 deletions(-) diff --git a/src/data/parsing.rs b/src/data/parsing.rs index 4e113433..6586e567 100644 --- a/src/data/parsing.rs +++ b/src/data/parsing.rs @@ -17,13 +17,12 @@ use xkbcommon::xkb; use super::{ Error, LoadError }; use ::action; -use ::keyboard::{ - KeyState, PressType, +use crate::keyboard::{ + Key, KeyState, PressType, generate_keymaps, generate_keycodes, KeyCode, FormattingError }; use ::layout; use ::logging; -use ::util::hash_map_map; use ::resources; // traits, derives @@ -183,7 +182,7 @@ impl Layout { extract_symbol_names(&button_actions) ); - let button_states = HashMap::::from_iter( + let button_states = HashMap::::from_iter( button_actions.into_iter().map(|(name, action)| { let keycodes = match &action { ::action::Action::Submit { text: _, keys } => { @@ -208,8 +207,7 @@ impl Layout { }; ( name.into(), - KeyState { - pressed: PressType::Released, + Key { keycodes, action, } @@ -222,13 +220,7 @@ impl Layout { Ok(v) => v, }; - let button_states_cache = hash_map_map( - button_states, - |name, state| {( - name, - Rc::new(RefCell::new(state)) - )} - ); + let button_states_cache = button_states; let views: Vec<_> = self.views.iter() .map(|(name, view)| { @@ -461,7 +453,7 @@ fn create_button( button_info: &HashMap, outlines: &HashMap, name: &str, - state: Rc>, + data: Key, warning_handler: &mut H, ) -> ::layout::Button { let cname = CString::new(name.clone()) @@ -523,7 +515,11 @@ fn create_button( height: outline.height, }, label: label, - state: state, + action: data.action, + keycodes: data.keycodes, + state: Rc::new( + RefCell::new(KeyState { pressed: PressType::Released }) + ), } } @@ -677,7 +673,6 @@ mod tests { out.views["base"].1 .get_rows()[0].1 .get_buttons()[0].1 - .state.borrow() .keycodes.len(), 2 ); @@ -694,7 +689,6 @@ mod tests { out.views["base"].1 .get_rows()[0].1 .get_buttons()[0].1 - .state.borrow() .keycodes.len(), 1 ); diff --git a/src/drawing.rs b/src/drawing.rs index 7d62ed48..a87d1f5e 100644 --- a/src/drawing.rs +++ b/src/drawing.rs @@ -88,7 +88,7 @@ mod c { let state = RefCell::borrow(&button.state).clone(); let locked = LockedStyle::from_action( - &state.action, + &button.action, &active_modifiers, layout.get_view_latched(), &layout.state.current_view, diff --git a/src/keyboard.rs b/src/keyboard.rs index da650c55..6380d353 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -1,6 +1,8 @@ /*! State of the emulated keyboard and keys. * Regards the keyboard as if it was composed of switches. */ +use crate::action::Action; +use crate::util; use std::cell::RefCell; use std::collections::HashMap; use std::fmt; @@ -10,9 +12,6 @@ use std::ptr; use std::rc::Rc; use std::string::FromUtf8Error; -use ::action::Action; -use ::util; - // Traits use std::io::Write; use std::iter::{ FromIterator, IntoIterator }; @@ -24,7 +23,7 @@ pub enum PressType { } /// The extended, unambiguous layout-keycode -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct KeyCode { pub code: u32, pub keymap_idx: usize, @@ -53,15 +52,19 @@ bitflags!{ #[derive(Clone, PartialEq)] pub struct KeyStateId(*const KeyState); -#[derive(Debug, Clone)] -pub struct KeyState { - pub pressed: PressType, +#[derive(Clone)] +pub struct Key { /// A cache of raw keycodes derived from Action::Submit given a keymap pub keycodes: Vec, /// Static description of what the key does when pressed or released pub action: Action, } +#[derive(Debug, Clone)] +pub struct KeyState { + pub pressed: PressType, +} + impl KeyState { #[must_use] pub fn into_released(self) -> KeyState { diff --git a/src/layout.rs b/src/layout.rs index fee28b06..33a98794 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -29,7 +29,7 @@ use crate::action::Action; use crate::actors; use crate::drawing; use crate::float_ord::FloatOrd; -use crate::keyboard::KeyState; +use crate::keyboard::{KeyState, KeyCode}; use crate::logging; use crate::popover; use crate::receiver; @@ -466,7 +466,7 @@ pub enum Label { IconName(CString), } -/// The graphical representation of a button +/// The definition of an interactive button #[derive(Clone, Debug)] pub struct Button { /// ID string, e.g. for CSS @@ -476,7 +476,12 @@ pub struct Button { pub size: Size, /// The name of the visual class applied pub outline_name: CString, - /// current state, shared with other buttons + // action-related stuff + /// A cache of raw keycodes derived from Action::Submit given a keymap + pub keycodes: Vec, + /// Static description of what the key does when pressed or released + pub action: Action, + /// Current state, shared with other buttons pub state: Rc>, } @@ -489,7 +494,7 @@ impl Button { } } -/// The graphical representation of a row of buttons +/// The representation of a row of buttons #[derive(Clone, Debug)] pub struct Row { /// Buttons together with their offset from the left relative to the row. @@ -758,10 +763,14 @@ impl fmt::Display for NoSuchView { impl LayoutData { fn get_key(&self, button: &ButtonPosition) -> Option<&Rc>> { + self.get_button(button).map(|button| &button.state) + } + + fn get_button(&self, button: &ButtonPosition) -> Option<&Button> { let (_, view) = self.views.get(&button.view)?; let (_, row) = view.rows.get(button.row)?; let (_, key) = row.buttons.get(button.position_in_row)?; - Some(&key.state) + Some(key) } /// Calculates size without margins @@ -1029,7 +1038,10 @@ mod procedures { let state = make_state(); let state_clone = state.clone(); - let button = make_button_with_state("1".into(), state); + let button = Box::new(Button { + state, + ..make_button("1".into()) + }); let button_ptr = as_ptr(&button); let row = Row::new(vec!((0.1, button))); @@ -1078,12 +1090,13 @@ mod seat { "Button {:?} was already pressed", button, ); } else { - layout.state.pressed_buttons.push(button); + layout.state.pressed_buttons.push(button.clone()); } let key: KeyState = { RefCell::borrow(rckey).clone() }; - let action = key.action.clone(); + let button = layout.shape.get_button(&button).unwrap(); + let action = button.action.clone(); match action { Action::Submit { text: Some(text), @@ -1091,7 +1104,7 @@ mod seat { } => submission.handle_press( KeyState::get_id(rckey), SubmitData::Text(&text), - &key.keycodes, + &button.keycodes, time, ), Action::Submit { @@ -1100,13 +1113,13 @@ mod seat { } => submission.handle_press( KeyState::get_id(rckey), SubmitData::Keycodes, - &key.keycodes, + &button.keycodes, time, ), Action::Erase => submission.handle_press( KeyState::get_id(rckey), SubmitData::Erase, - &key.keycodes, + &button.keycodes, time, ), _ => {}, @@ -1125,12 +1138,13 @@ mod seat { // and passed always. manager: Option<(&actors::popover::State, receiver::State)>, rckey: &Rc>, - button: ButtonPosition, + button_pos: ButtonPosition, ) { let key: KeyState = { RefCell::borrow(rckey).clone() }; - let action = key.action.clone(); + let button = layout.shape.get_button(&button_pos).unwrap(); + let action = button.action.clone(); layout.apply_view_transition(&action); @@ -1188,11 +1202,12 @@ mod seat { }; // Apply state changes - let pos = layout.state.pressed_buttons.iter().position(|b| b == &button); + let pos = layout.state.pressed_buttons.iter() + .position(|b| b == &button_pos); if let Some(pos) = pos { layout.state.pressed_buttons.remove(pos); } else { - log_print!(logging::Level::Bug, "No button to remove from pressed list: {:?}", button); + log_print!(logging::Level::Bug, "No button to remove from pressed list: {:?}", button_pos); } // Commit activated button state changes RefCell::replace(rckey, key); @@ -1204,33 +1219,26 @@ mod test { use super::*; use std::ffi::CString; - use ::keyboard::PressType; + use crate::keyboard::{PressType, KeyState}; - pub fn make_state_with_action(action: Action) - -> Rc> - { - Rc::new(RefCell::new(::keyboard::KeyState { + pub fn make_state() -> Rc> { + Rc::new(RefCell::new(KeyState { pressed: PressType::Released, - keycodes: Vec::new(), - action, })) } - pub fn make_state() -> Rc> { - make_state_with_action(Action::SetView("default".into())) - } - - pub fn make_button_with_state( + pub fn make_button( name: String, - state: Rc>, - ) -> Box