layout: Put all button state into active_buttons

Ths gets rid of Rc<RefCell<>> sharing of state, which can be hard to keep track of.
In addition, there's no longer any duplication of button state.
This commit is contained in:
Dorota Czaplejewicz
2022-10-01 12:48:52 +00:00
parent 74c5ef4a51
commit 952ec805ed
4 changed files with 188 additions and 218 deletions

View File

@ -4,12 +4,10 @@
/*! Parsing of the data files containing layouts */ /*! Parsing of the data files containing layouts */
use std::cell::RefCell;
use std::collections::{ HashMap, HashSet }; use std::collections::{ HashMap, HashSet };
use std::ffi::CString; use std::ffi::CString;
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc;
use std::vec::Vec; use std::vec::Vec;
use xkbcommon::xkb; use xkbcommon::xkb;
@ -18,8 +16,7 @@ use super::{ Error, LoadError };
use ::action; use ::action;
use crate::keyboard::{ use crate::keyboard::{
Key, KeyState, PressType, Key, generate_keymaps, generate_keycodes, KeyCode, FormattingError
generate_keymaps, generate_keycodes, KeyCode, FormattingError
}; };
use ::layout; use ::layout;
use ::logging; use ::logging;
@ -517,9 +514,6 @@ fn create_button<H: logging::Handler>(
label: label, label: label,
action: data.action, action: data.action,
keycodes: data.keycodes, keycodes: data.keycodes,
state: Rc::new(
RefCell::new(KeyState { pressed: PressType::Released })
),
} }
} }

View File

@ -1,11 +1,10 @@
/*! Drawing the UI */ /*! Drawing the UI */
use cairo; use cairo;
use std::cell::RefCell;
use ::action::{ Action, Modifier }; use ::action::{ Action, Modifier };
use ::keyboard; use ::keyboard;
use ::layout::{ Button, Label, LatchedState, Layout }; use crate::layout::{ Button, ButtonPosition, Label, LatchedState, Layout };
use ::layout::c::{ Bounds, EekGtkKeyboard, Point }; use ::layout::c::{ Bounds, EekGtkKeyboard, Point };
use ::submission::c::Submission as CSubmission; use ::submission::c::Submission as CSubmission;
@ -84,8 +83,15 @@ mod c {
let cr = unsafe { cairo::Context::from_raw_none(cr) }; let cr = unsafe { cairo::Context::from_raw_none(cr) };
let active_modifiers = submission.get_active_modifiers(); let active_modifiers = submission.get_active_modifiers();
layout.foreach_visible_button(|offset, button| { layout.foreach_visible_button(|offset, button, (row, position_in_row)| {
let state = RefCell::borrow(&button.state).clone(); // TODO: this iterator copies string indices way too much.
// For efficiency, it would be better to draw pressed buttons from the list first,
// and then iterate the rest without having to look up their indices.
let state = layout.state.active_buttons.get(&ButtonPosition {
view: layout.state.current_view.clone(),
row,
position_in_row,
});
let locked = LockedStyle::from_action( let locked = LockedStyle::from_action(
&button.action, &button.action,
@ -116,7 +122,7 @@ mod c {
let layout = unsafe { &mut *layout }; let layout = unsafe { &mut *layout };
let cr = unsafe { cairo::Context::from_raw_none(cr) }; let cr = unsafe { cairo::Context::from_raw_none(cr) };
layout.foreach_visible_button(|offset, button| { layout.foreach_visible_button(|offset, button, _index| {
render_button_at_position( render_button_at_position(
renderer, &cr, renderer, &cr,
offset, offset,

View File

@ -2,14 +2,13 @@
* Regards the keyboard as if it was composed of switches. */ * Regards the keyboard as if it was composed of switches. */
use crate::action::Action; use crate::action::Action;
use crate::layout;
use crate::util; use crate::util;
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::io; use std::io;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
use std::rc::Rc;
use std::string::FromUtf8Error; use std::string::FromUtf8Error;
// Traits // Traits
@ -48,9 +47,16 @@ bitflags!{
} }
/// When the submitted actions of keys need to be tracked, /// When the submitted actions of keys need to be tracked,
/// they need a stable, comparable ID /// they need a stable, comparable ID.
/// With layout::ButtonPosition, the IDs are unique within layouts.
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub struct KeyStateId(*const KeyState); pub struct KeyStateId(layout::ButtonPosition);
impl From<&layout::ButtonPosition> for KeyStateId {
fn from(v: &layout::ButtonPosition) -> Self {
Self(v.clone())
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct Key { pub struct Key {
@ -81,12 +87,6 @@ impl KeyState {
..self ..self
} }
} }
/// KeyStates instances are the unique identifiers of pressed keys,
/// and the actions submitted with them.
pub fn get_id(keystate: &Rc<RefCell<KeyState>>) -> KeyStateId {
KeyStateId(keystate.as_ptr() as *const KeyState)
}
} }
/// Sorts an iterator by converting it to a Vector and back /// Sorts an iterator by converting it to a Vector and back

View File

@ -17,19 +17,17 @@
* and let the renderer scale and center it within the widget. * and let the renderer scale and center it within the widget.
*/ */
use std::cell::RefCell;
use std::cmp; use std::cmp;
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::CString; use std::ffi::CString;
use std::fmt; use std::fmt;
use std::rc::Rc;
use std::vec::Vec; use std::vec::Vec;
use crate::action::Action; use crate::action::Action;
use crate::actors; use crate::actors;
use crate::drawing; use crate::drawing;
use crate::float_ord::FloatOrd; use crate::float_ord::FloatOrd;
use crate::keyboard::{KeyState, KeyCode}; use crate::keyboard::{KeyState, KeyCode, PressType};
use crate::logging; use crate::logging;
use crate::popover; use crate::popover;
use crate::receiver; use crate::receiver;
@ -39,7 +37,6 @@ use crate::util::find_max_double;
use crate::imservice::ContentPurpose; use crate::imservice::ContentPurpose;
// Traits // Traits
use std::borrow::Borrow;
use crate::logging::Warn; use crate::logging::Warn;
/// Gathers stuff defined in C or called by C /// Gathers stuff defined in C or called by C
@ -238,20 +235,17 @@ pub mod c {
// The list must be copied, // The list must be copied,
// because it will be mutated in the loop // because it will be mutated in the loop
for button in layout.state.pressed_buttons.clone() { let pressed_buttons
if let Some(key) = layout.shape.get_key(&button).map(|k| k.clone()) { = layout.state.active_buttons.clone();
seat::handle_release_key( for (button, _key_state) in pressed_buttons.iter_pressed() {
layout, seat::handle_release_key(
&mut submission, layout,
Some(&ui_backend), &mut submission,
time, Some(&ui_backend),
Some((&popover_state, app_state.clone())), time,
&key, Some((&popover_state, app_state.clone())),
button, button,
); );
} else {
log_print!(logging::Level::Bug, "Failed to find button at position {:?}", button);
}
} }
drawing::queue_redraw(ui_keyboard); drawing::queue_redraw(ui_keyboard);
} }
@ -269,21 +263,16 @@ pub mod c {
let mut submission = submission.borrow_mut(); let mut submission = submission.borrow_mut();
// The list must be copied, // The list must be copied,
// because it will be mutated in the loop // because it will be mutated in the loop
for button in layout.state.pressed_buttons.clone() { let pressed_buttons = layout.state.active_buttons.clone();
if let Some(key) = layout.shape.get_key(&button) { for (button, _key_state) in pressed_buttons.iter_pressed() {
let key: &Rc<RefCell<KeyState>> = key.borrow(); seat::handle_release_key(
seat::handle_release_key( layout,
layout, &mut submission,
&mut submission, None, // don't update UI
None, // don't update UI Timestamp(time),
Timestamp(time), None, // don't switch layouts
None, // don't switch layouts button,
&mut key.clone(), );
button,
);
} else {
log_print!(logging::Level::Bug, "Failed to find button at position {:?}", button);
}
} }
} }
@ -304,10 +293,9 @@ pub mod c {
Point { x: x_widget, y: y_widget } Point { x: x_widget, y: y_widget }
); );
let state = layout.find_button_by_position(point) let index = layout.find_index_by_position(point);
.map(|(button, index)| (button.state.clone(), index));
if let Some((state, (row, position_in_row))) = state { if let Some((row, position_in_row)) = index {
let button = ButtonPosition { let button = ButtonPosition {
view: layout.state.current_view.clone(), view: layout.state.current_view.clone(),
row, row,
@ -317,8 +305,7 @@ pub mod c {
layout, layout,
&mut submission, &mut submission,
Timestamp(time), Timestamp(time),
&state, &button,
button,
); );
// maybe TODO: draw on the display buffer here // maybe TODO: draw on the display buffer here
drawing::queue_redraw(ui_keyboard); drawing::queue_redraw(ui_keyboard);
@ -359,34 +346,29 @@ pub mod c {
Point { x: x_widget, y: y_widget } Point { x: x_widget, y: y_widget }
); );
let pressed = layout.state.pressed_buttons.clone(); let pressed_buttons = layout.state.active_buttons.clone();
let button_info = { let pressed_buttons = pressed_buttons.iter_pressed();
let place = layout.find_button_by_position(point); let button_info = layout.find_index_by_position(point);
place.map(|(button, index)| {(
button.state.clone(),
index,
)})
};
if let Some((state, (row, position_in_row))) = button_info { if let Some((row, position_in_row)) = button_info {
let current_pos = ButtonPosition {
view: layout.state.current_view.clone(),
row,
position_in_row,
};
let mut found = false; let mut found = false;
for button in pressed { for (button, _key_state) in pressed_buttons {
if let Some(key) = layout.shape.get_key(&button).map(|k| k.clone()) { if button == &current_pos {
if Rc::ptr_eq(&state, &key) { found = true;
found = true;
} else {
seat::handle_release_key(
layout,
&mut submission,
Some(&ui_backend),
time,
Some((&popover_state, app_state.clone())),
&key,
button,
);
}
} else { } else {
log_print!(logging::Level::Bug, "Failed to find button at position {:?}", button); seat::handle_release_key(
layout,
&mut submission,
Some(&ui_backend),
time,
Some((&popover_state, app_state.clone())),
button,
);
} }
} }
if !found { if !found {
@ -399,8 +381,7 @@ pub mod c {
layout, layout,
&mut submission, &mut submission,
time, time,
&state, &button,
button,
); );
// maybe TODO: draw on the display buffer here // maybe TODO: draw on the display buffer here
unsafe { unsafe {
@ -408,20 +389,15 @@ pub mod c {
} }
} }
} else { } else {
for button in pressed { for (button, _key_state) in pressed_buttons {
if let Some(key) = layout.shape.get_key(&button).map(|k| k.clone()) { seat::handle_release_key(
seat::handle_release_key( layout,
layout, &mut submission,
&mut submission, Some(&ui_backend),
Some(&ui_backend), time,
time, Some((&popover_state, app_state.clone())),
Some((&popover_state, app_state.clone())), button,
&key, );
button,
);
} else {
log_print!(logging::Level::Bug, "Failed to find button at position {:?}", button);
}
} }
} }
drawing::queue_redraw(ui_keyboard); drawing::queue_redraw(ui_keyboard);
@ -467,7 +443,7 @@ pub enum Label {
} }
/// The definition of an interactive button /// The definition of an interactive button
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq)]
pub struct Button { pub struct Button {
/// ID string, e.g. for CSS /// ID string, e.g. for CSS
pub name: CString, pub name: CString,
@ -481,8 +457,6 @@ pub struct Button {
pub keycodes: Vec<KeyCode>, pub keycodes: Vec<KeyCode>,
/// Static description of what the key does when pressed or released /// Static description of what the key does when pressed or released
pub action: Action, pub action: Action,
/// Current state, shared with other buttons
pub state: Rc<RefCell<KeyState>>,
} }
impl Button { impl Button {
@ -694,16 +668,49 @@ pub struct Layout {
} }
/// Button position for the pressed buttons list /// Button position for the pressed buttons list
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ButtonPosition { pub struct ButtonPosition {
// There's only ever going to be a handul of pressed buttons, // There's only ever going to be a handul of pressed buttons,
// so as inefficient as String is, it won't make a difference. // so as inefficient as String is, it won't make a difference.
// In the worst case, views can turn into indices in the description. // In the worst case, views can turn into indices in the description.
view: String, pub view: String,
/// Index to the view's row. /// Index to the view's row.
row: usize, pub row: usize,
/// Index to the row's button. /// Index to the row's button.
position_in_row: usize, pub position_in_row: usize,
}
#[derive(Clone)]
pub struct ActiveButtons(HashMap<ButtonPosition, KeyState>);
enum Presence {
Missing,
Present,
}
static RELEASED: KeyState = KeyState { pressed: PressType::Released };
impl ActiveButtons {
fn insert(&mut self, button: ButtonPosition, state: KeyState) -> Presence {
match self.0.insert(button, state) {
Some(_) => Presence::Present,
None => Presence::Missing,
}
}
pub fn get(&self, button: &ButtonPosition) -> &KeyState {
self.0.get(button)
.unwrap_or(&RELEASED)
}
fn remove(&mut self, button: &ButtonPosition) -> Presence {
match self.0.remove(button) {
Some(_) => Presence::Present,
None => Presence::Missing,
}
}
fn iter_pressed(&self) -> impl Iterator<Item=(&ButtonPosition, &KeyState)> {
self.0.iter().filter(|(_p, s)| s.pressed == PressType::Pressed)
}
} }
/// Changeable state that can't be derived from the definition of the layout. /// Changeable state that can't be derived from the definition of the layout.
@ -721,7 +728,11 @@ pub struct LayoutState {
// through all buttons of the current view anyway. // through all buttons of the current view anyway.
// When the list tracks actual location, // When the list tracks actual location,
// it becomes possible to place popovers and other UI accurately. // it becomes possible to place popovers and other UI accurately.
pub pressed_buttons: Vec<ButtonPosition>, /// Buttons not in this list are in their base state:
/// not pressed.
/// Latched/locked appearance is derived from current view
/// and button metadata.
pub active_buttons: ActiveButtons,
} }
/// A builder structure for picking up layout data from storage /// A builder structure for picking up layout data from storage
@ -762,10 +773,6 @@ impl fmt::Display for NoSuchView {
impl LayoutData { impl LayoutData {
fn get_key(&self, button: &ButtonPosition) -> Option<&Rc<RefCell<KeyState>>> {
self.get_button(button).map(|button| &button.state)
}
fn get_button(&self, button: &ButtonPosition) -> Option<&Button> { fn get_button(&self, button: &ButtonPosition) -> Option<&Button> {
let (_, view) = self.views.get(&button.view)?; let (_, view) = self.views.get(&button.view)?;
let (_, row) = view.rows.get(button.row)?; let (_, row) = view.rows.get(button.row)?;
@ -835,7 +842,7 @@ impl Layout {
state: LayoutState { state: LayoutState {
current_view: "base".to_owned(), current_view: "base".to_owned(),
view_latched: LatchedState::Not, view_latched: LatchedState::Not,
pressed_buttons: Vec::new(), active_buttons: ActiveButtons(HashMap::new()),
}, },
} }
} }
@ -863,23 +870,27 @@ impl Layout {
pub fn get_view_latched(&self) -> &LatchedState { pub fn get_view_latched(&self) -> &LatchedState {
&self.state.view_latched &self.state.view_latched
} }
/// Returns index too /// Returns index within current view
fn find_button_by_position(&self, point: c::Point) -> Option<(&Button, (usize, usize))> { fn find_index_by_position(&self, point: c::Point) -> Option<(usize, usize)> {
let (offset, layout) = self.get_current_view_position(); let (offset, view) = self.get_current_view_position();
layout.find_button_by_position(point - offset) view.find_button_by_position(point - offset)
.map(|(_b, i)| i)
} }
/// Returns index within current view too.
pub fn foreach_visible_button<F>(&self, mut f: F) pub fn foreach_visible_button<F>(&self, mut f: F)
where F: FnMut(c::Point, &Box<Button>) where F: FnMut(c::Point, &Box<Button>, (usize, usize))
{ {
let (view_offset, view) = self.get_current_view_position(); let (view_offset, view) = self.get_current_view_position();
for (row_offset, row) in view.get_rows() { let rows = view.get_rows().iter().enumerate();
for (x_offset, button) in &row.buttons { for (row_idx, (row_offset, row)) in rows {
let buttons = row.buttons.iter().enumerate();
for (button_idx, (x_offset, button)) in buttons {
let offset = view_offset let offset = view_offset
+ row_offset.clone() + row_offset.clone()
+ c::Point { x: *x_offset, y: 0.0 }; + c::Point { x: *x_offset, y: 0.0 };
f(offset, button); f(offset, button, (row_idx, button_idx));
} }
} }
} }
@ -999,25 +1010,18 @@ mod procedures {
type Place<'v> = (c::Point, &'v Box<Button>); type Place<'v> = (c::Point, &'v Box<Button>);
/// Finds all buttons referring to the key in `state`, /// Finds the canvas offset of the button.
/// together with their offsets within the view. pub fn find_button_place<'v>(
pub fn find_key_places<'v, 's>(
view: &'v View, view: &'v View,
state: &'s Rc<RefCell<KeyState>> (row, position_in_row): (usize, usize),
) -> Vec<Place<'v>> { ) -> Option<Place<'v>> {
view.get_rows().iter().flat_map(|(row_offset, row)| { let (row_offset, row) = view.get_rows().get(row)?;
row.buttons.iter() let (x_offset, button) = row.get_buttons()
.filter_map(move |(x_offset, button)| { .get(position_in_row)?;
if Rc::ptr_eq(&button.state, state) { Some((
Some(( row_offset + c::Point { x: *x_offset, y: 0.0 },
row_offset + c::Point { x: *x_offset, y: 0.0 }, button,
button, ))
))
} else {
None
}
})
}).collect()
} }
#[cfg(test)] #[cfg(test)]
@ -1026,41 +1030,27 @@ mod procedures {
use ::layout::test::*; use ::layout::test::*;
/// Checks whether the path points to the same boxed instances. /// Checks indexing of buttons
/// The instance constraint will be droppable
/// when C stops holding references to the data
#[test] #[test]
fn view_has_button() { fn view_has_button() {
fn as_ptr<T>(v: &Box<T>) -> *const T { let button = Box::new(make_button("1".into()));
v.as_ref() as *const T
}
let state = make_state();
let state_clone = state.clone();
let button = Box::new(Button {
state,
..make_button("1".into())
});
let button_ptr = as_ptr(&button);
let row = Row::new(vec!((0.1, button))); let row = Row::new(vec!((0.1, button)));
let view = View::new(vec!((1.2, row))); let view = View::new(vec!((1.2, row)));
assert_eq!( assert_eq!(
find_key_places(&view, &state_clone.clone()).into_iter() find_button_place(&view, (0, 0)),
.map(|(place, button)| { (place, as_ptr(button)) }) Some((
.collect::<Vec<_>>(), c::Point { x: 0.1, y: 1.2 },
vec!( &Box::new(make_button("1".into())),
(c::Point { x: 0.1, y: 1.2 }, button_ptr) ))
)
); );
let view = View::new(vec![]); let view = View::new(vec![]);
assert_eq!( assert_eq!(
find_key_places(&view, &state_clone.clone()).is_empty(), find_button_place(&view, (0, 0)),
true None,
); );
} }
} }
@ -1079,30 +1069,18 @@ mod seat {
layout: &mut Layout, layout: &mut Layout,
submission: &mut Submission, submission: &mut Submission,
time: Timestamp, time: Timestamp,
rckey: &Rc<RefCell<KeyState>>, button_pos: &ButtonPosition,
button: ButtonPosition,
) { ) {
let find = layout.state.pressed_buttons.iter() let find = layout.state.active_buttons.get(button_pos);
.position(|b| b == &button);
if let Some(_) = find { let button = layout.shape.get_button(button_pos).unwrap();
log_print!(
logging::Level::Bug,
"Button {:?} was already pressed", button,
);
} else {
layout.state.pressed_buttons.push(button.clone());
}
let key: KeyState = {
RefCell::borrow(rckey).clone()
};
let button = layout.shape.get_button(&button).unwrap();
let action = button.action.clone(); let action = button.action.clone();
match action { match action {
Action::Submit { Action::Submit {
text: Some(text), text: Some(text),
keys: _, keys: _,
} => submission.handle_press( } => submission.handle_press(
KeyState::get_id(rckey), button_pos.into(),
SubmitData::Text(&text), SubmitData::Text(&text),
&button.keycodes, &button.keycodes,
time, time,
@ -1111,20 +1089,31 @@ mod seat {
text: None, text: None,
keys: _, keys: _,
} => submission.handle_press( } => submission.handle_press(
KeyState::get_id(rckey), button_pos.into(),
SubmitData::Keycodes, SubmitData::Keycodes,
&button.keycodes, &button.keycodes,
time, time,
), ),
Action::Erase => submission.handle_press( Action::Erase => submission.handle_press(
KeyState::get_id(rckey), button_pos.into(),
SubmitData::Erase, SubmitData::Erase,
&button.keycodes, &button.keycodes,
time, time,
), ),
_ => {}, _ => {},
}; };
RefCell::replace(rckey, key.into_pressed());
if let KeyState { pressed: PressType::Pressed } = find {
log_print!(
logging::Level::Bug,
"Button {:?} was already pressed", button_pos,
);
} else {
layout.state.active_buttons.insert(
button_pos.clone(),
KeyState { pressed: PressType::Pressed },
);
}
} }
pub fn handle_release_key( pub fn handle_release_key(
@ -1137,30 +1126,23 @@ mod seat {
// Eventually, it should be used for sumitting button events, // Eventually, it should be used for sumitting button events,
// and passed always. // and passed always.
manager: Option<(&actors::popover::State, receiver::State)>, manager: Option<(&actors::popover::State, receiver::State)>,
rckey: &Rc<RefCell<KeyState>>, button_pos: &ButtonPosition,
button_pos: ButtonPosition,
) { ) {
let key: KeyState = {
RefCell::borrow(rckey).clone()
};
let button = layout.shape.get_button(&button_pos).unwrap(); let button = layout.shape.get_button(&button_pos).unwrap();
let action = button.action.clone(); let action = button.action.clone();
layout.apply_view_transition(&action); layout.apply_view_transition(&action);
// update
let key = key.into_released();
// process non-view switching // process non-view switching
match action { match action {
Action::Submit { text: _, keys: _ } Action::Submit { text: _, keys: _ }
| Action::Erase | Action::Erase
=> { => {
submission.handle_release(KeyState::get_id(rckey), time); submission.handle_release(button_pos.into(), time);
}, },
Action::ApplyModifier(modifier) => { Action::ApplyModifier(modifier) => {
// FIXME: key id is unneeded with stateless locks // FIXME: key id is unneeded with stateless locks
let key_id = KeyState::get_id(rckey); let key_id = button_pos.into();
let gets_locked = !submission.is_modifier_active(modifier); let gets_locked = !submission.is_modifier_active(modifier);
match gets_locked { match gets_locked {
true => submission.handle_add_modifier( true => submission.handle_add_modifier(
@ -1175,13 +1157,11 @@ mod seat {
// only show when layout manager is available // only show when layout manager is available
if let Some((manager, app_state)) = manager { if let Some((manager, app_state)) = manager {
let view = layout.get_current_view(); let view = layout.get_current_view();
let places = ::layout::procedures::find_key_places( let place = procedures::find_button_place(
view, &rckey, view, (button_pos.row, button_pos.position_in_row),
); );
// Getting first item will cause mispositioning
// with more than one button with the same key if let Some((position, button)) = place {
// on the keyboard.
if let Some((position, button)) = places.get(0) {
let bounds = c::Bounds { let bounds = c::Bounds {
x: position.x, x: position.x,
y: position.y, y: position.y,
@ -1202,15 +1182,12 @@ mod seat {
}; };
// Apply state changes // Apply state changes
let pos = layout.state.pressed_buttons.iter() if let Presence::Missing = layout.state.active_buttons.remove(&button_pos) {
.position(|b| b == &button_pos); log_print!(
if let Some(pos) = pos { logging::Level::Bug,
layout.state.pressed_buttons.remove(pos); "No button to remove from pressed list: {:?}", button_pos
} else { );
log_print!(logging::Level::Bug, "No button to remove from pressed list: {:?}", button_pos);
} }
// Commit activated button state changes
RefCell::replace(rckey, key);
} }
} }
@ -1221,12 +1198,6 @@ mod test {
use std::ffi::CString; use std::ffi::CString;
use crate::keyboard::{PressType, KeyState}; use crate::keyboard::{PressType, KeyState};
pub fn make_state() -> Rc<RefCell<KeyState>> {
Rc::new(RefCell::new(KeyState {
pressed: PressType::Released,
}))
}
pub fn make_button( pub fn make_button(
name: String, name: String,
) -> Button { ) -> Button {
@ -1237,7 +1208,6 @@ mod test {
label: Label::Text(CString::new(name).unwrap()), label: Label::Text(CString::new(name).unwrap()),
action: Action::SetView("default".into()), action: Action::SetView("default".into()),
keycodes: Vec::new(), keycodes: Vec::new(),
state: make_state(),
} }
} }
@ -1306,7 +1276,7 @@ mod test {
state: LayoutState { state: LayoutState {
current_view: "base".into(), current_view: "base".into(),
view_latched: LatchedState::Not, view_latched: LatchedState::Not,
pressed_buttons: Vec::new(), active_buttons: ActiveButtons(HashMap::new()),
}, },
shape: LayoutData { shape: LayoutData {
keymaps: Vec::new(), keymaps: Vec::new(),
@ -1386,7 +1356,7 @@ mod test {
state: LayoutState { state: LayoutState {
current_view: "base".into(), current_view: "base".into(),
view_latched: LatchedState::Not, view_latched: LatchedState::Not,
pressed_buttons: Vec::new(), active_buttons: ActiveButtons(HashMap::new()),
}, },
shape: LayoutData { shape: LayoutData {
keymaps: Vec::new(), keymaps: Vec::new(),
@ -1457,7 +1427,7 @@ mod test {
state: LayoutState { state: LayoutState {
current_view: "base".into(), current_view: "base".into(),
view_latched: LatchedState::Not, view_latched: LatchedState::Not,
pressed_buttons: Vec::new(), active_buttons: ActiveButtons(HashMap::new()),
}, },
shape: LayoutData { shape: LayoutData {
keymaps: Vec::new(), keymaps: Vec::new(),