Merge branch 'center' into 'master'

Center views relative to layout space

See merge request Librem5/squeekboard!326
This commit is contained in:
Dorota Czaplejewicz
2020-02-09 20:34:31 +00:00
4 changed files with 99 additions and 65 deletions

View File

@ -424,8 +424,8 @@ impl Layout {
)} )}
); );
let views = HashMap::from_iter( let views: Vec<_> = self.views.iter()
self.views.iter().map(|(name, view)| { .map(|(name, view)| {
let rows = view.iter().map(|row| { let rows = view.iter().map(|row| {
let buttons = row.split_ascii_whitespace() let buttons = row.split_ascii_whitespace()
.map(|name| { .map(|name| {
@ -439,8 +439,7 @@ impl Layout {
&mut warning_handler, &mut warning_handler,
)) ))
}); });
::layout::Row { layout::Row {
angle: 0,
buttons: add_offsets( buttons: add_offsets(
buttons, buttons,
|button| button.size.width, |button| button.size.width,
@ -453,8 +452,25 @@ impl Layout {
name.clone(), name.clone(),
layout::View::new(rows) layout::View::new(rows)
) )
}) }).collect();
);
// Center views on the same point.
let views = {
let total_size = layout::View::calculate_super_size(
views.iter().map(|(_name, view)| view).collect()
);
HashMap::from_iter(views.into_iter().map(|(name, view)| (
name,
(
layout::c::Point {
x: (total_size.width - view.get_width()) / 2.0,
y: (total_size.height - view.get_height()) / 2.0,
},
view,
),
)))
};
( (
Ok(::layout::LayoutData { Ok(::layout::LayoutData {
@ -751,7 +767,7 @@ mod tests {
.build(ProblemPanic).0 .build(ProblemPanic).0
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
out.views["base"] out.views["base"].1
.get_rows()[0].1 .get_rows()[0].1
.buttons[0].1 .buttons[0].1
.label, .label,
@ -766,7 +782,7 @@ mod tests {
.build(ProblemPanic).0 .build(ProblemPanic).0
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
out.views["base"] out.views["base"].1
.get_rows()[0].1 .get_rows()[0].1
.buttons[0].1 .buttons[0].1
.label, .label,
@ -782,7 +798,7 @@ mod tests {
.build(ProblemPanic).0 .build(ProblemPanic).0
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
out.views["base"] out.views["base"].1
.get_rows()[0].1 .get_rows()[0].1
.buttons[0].1 .buttons[0].1
.state.borrow() .state.borrow()

View File

@ -48,21 +48,18 @@ 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) };
let view = layout.get_current_view(); layout.foreach_visible_button(|offset, button| {
for (row_offset, row) in &view.get_rows() { let state = RefCell::borrow(&button.state).clone();
for (x_offset, button) in &row.buttons { let locked = state.action.is_active(&layout.current_view);
let state = RefCell::borrow(&button.state).clone(); if state.pressed == keyboard::PressType::Pressed || locked {
let locked = state.action.is_active(&layout.current_view); render_button_at_position(
if state.pressed == keyboard::PressType::Pressed || locked { renderer, &cr,
render_button_at_position( offset,
renderer, &cr, button.as_ref(),
row_offset + Point { x: *x_offset, y: 0.0 }, state.pressed, locked,
button.as_ref(), );
state.pressed, locked,
);
}
} }
} })
} }
#[no_mangle] #[no_mangle]
@ -74,17 +71,15 @@ 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) };
let view = layout.get_current_view();
for (row_offset, row) in &view.get_rows() { layout.foreach_visible_button(|offset, button| {
for (x_offset, button) in &row.buttons { render_button_at_position(
render_button_at_position( renderer, &cr,
renderer, &cr, offset,
row_offset + Point { x: *x_offset, y: 0.0 }, button.as_ref(),
button.as_ref(), keyboard::PressType::Released, false,
keyboard::PressType::Released, false, );
); })
}
}
} }
} }

View File

@ -329,11 +329,8 @@ pub mod c {
Point { x: x_widget, y: y_widget } Point { x: x_widget, y: y_widget }
); );
let state = { let state = layout.find_button_by_position(point)
let view = layout.get_current_view(); .map(|place| place.button.state.clone());
view.find_button_by_position(point)
.map(|place| place.button.state.clone())
};
if let Some(state) = state { if let Some(state) = state {
seat::handle_press_key( seat::handle_press_key(
@ -374,8 +371,7 @@ pub mod c {
let pressed = layout.pressed_keys.clone(); let pressed = layout.pressed_keys.clone();
let button_info = { let button_info = {
let view = layout.get_current_view(); let place = layout.find_button_by_position(point);
let place = view.find_button_by_position(point);
place.map(|place| {( place.map(|place| {(
place.button.state.clone(), place.button.state.clone(),
place.button.clone(), place.button.clone(),
@ -486,8 +482,6 @@ pub struct Button {
pub struct Row { pub struct Row {
/// Buttons together with their offset from the left /// Buttons together with their offset from the left
pub buttons: Vec<(f64, Box<Button>)>, pub buttons: Vec<(f64, Box<Button>)>,
/// Angle is not really used anywhere...
pub angle: i32,
} }
impl Row { impl Row {
@ -554,14 +548,14 @@ impl View {
}) })
} }
fn get_width(&self) -> f64 { pub fn get_width(&self) -> f64 {
// No need to call `get_rows()`, // No need to call `get_rows()`,
// as the biggest row is the most far reaching in both directions // as the biggest row is the most far reaching in both directions
// because they are all centered. // because they are all centered.
find_max_double(self.rows.iter(), |(_offset, row)| row.get_width()) find_max_double(self.rows.iter(), |(_offset, row)| row.get_width())
} }
fn get_height(&self) -> f64 { pub fn get_height(&self) -> f64 {
self.rows.iter().next_back() self.rows.iter().next_back()
.map(|(y_offset, row)| row.get_height() + y_offset) .map(|(y_offset, row)| row.get_height() + y_offset)
.unwrap_or(0.0) .unwrap_or(0.0)
@ -578,6 +572,21 @@ impl View {
row, row,
)}).collect() )}).collect()
} }
/// Returns a size which contains all the views
/// if they are all centered on the same point.
pub fn calculate_super_size(views: Vec<&View>) -> Size {
Size {
height: find_max_double(
views.iter(),
|view| view.get_height(),
),
width: find_max_double(
views.iter(),
|view| view.get_width(),
),
}
}
} }
/// The physical characteristic of layout for the purpose of styling /// The physical characteristic of layout for the purpose of styling
@ -605,7 +614,8 @@ pub struct Layout {
// Views own the actual buttons which have state // Views own the actual buttons which have state
// Maybe they should own UI only, // Maybe they should own UI only,
// and keys should be owned by a dedicated non-UI-State? // and keys should be owned by a dedicated non-UI-State?
pub views: HashMap<String, View>, /// Point is the offset within the layout
pub views: HashMap<String, (c::Point, View)>,
// Non-UI stuff // Non-UI stuff
/// xkb keymap applicable to the contained keys. Unchangeable /// xkb keymap applicable to the contained keys. Unchangeable
@ -623,7 +633,8 @@ pub struct Layout {
/// A builder structure for picking up layout data from storage /// A builder structure for picking up layout data from storage
pub struct LayoutData { pub struct LayoutData {
pub views: HashMap<String, View>, /// Point is the offset within layout
pub views: HashMap<String, (c::Point, View)>,
pub keymap_str: CString, pub keymap_str: CString,
pub margins: Margins, pub margins: Margins,
} }
@ -653,8 +664,13 @@ impl Layout {
} }
} }
pub fn get_current_view_position(&self) -> &(c::Point, View) {
&self.views
.get(&self.current_view).expect("Selected nonexistent view")
}
pub fn get_current_view(&self) -> &View { pub fn get_current_view(&self) -> &View {
self.views.get(&self.current_view).expect("Selected nonexistent view") &self.views.get(&self.current_view).expect("Selected nonexistent view").1
} }
fn set_view(&mut self, view: String) -> Result<(), NoSuchView> { fn set_view(&mut self, view: String) -> Result<(), NoSuchView> {
@ -668,16 +684,9 @@ impl Layout {
/// Calculates size without margins /// Calculates size without margins
fn calculate_inner_size(&self) -> Size { fn calculate_inner_size(&self) -> Size {
Size { View::calculate_super_size(
height: find_max_double( self.views.iter().map(|(_, (_offset, v))| v).collect()
self.views.iter(), )
|(_name, view)| view.get_height(),
),
width: find_max_double(
self.views.iter(),
|(_name, view)| view.get_width(),
),
}
} }
/// Size including margins /// Size including margins
@ -713,6 +722,25 @@ impl Layout {
}) })
} }
fn find_button_by_position(&self, point: c::Point) -> Option<ButtonPlace> {
let (offset, layout) = self.get_current_view_position();
layout.find_button_by_position(point - offset)
}
pub fn foreach_visible_button<F>(&self, mut f: F)
where F: FnMut(c::Point, &Box<Button>)
{
let (view_offset, view) = self.get_current_view_position();
for (row_offset, row) in &view.get_rows() {
for (x_offset, button) in &row.buttons {
let offset = view_offset
+ row_offset.clone()
+ c::Point { x: *x_offset, y: 0.0 };
f(offset, button);
}
}
}
pub fn get_locked_keys(&self) -> Vec<Rc<RefCell<KeyState>>> { pub fn get_locked_keys(&self) -> Vec<Rc<RefCell<KeyState>>> {
let mut out = Vec::new(); let mut out = Vec::new();
let view = self.get_current_view(); let view = self.get_current_view();
@ -780,7 +808,6 @@ mod procedures {
let row = Row { let row = Row {
buttons: vec!((0.1, button)), buttons: vec!((0.1, button)),
angle: 0,
}; };
let view = View { let view = View {
@ -853,7 +880,6 @@ mod seat {
// This is guaranteed because pressing a lock button unlocks all others. // This is guaranteed because pressing a lock button unlocks all others.
// TODO: Make some broader guarantee about the resulting view, // TODO: Make some broader guarantee about the resulting view,
// e.g. by maintaining a stack of stuck keys. // e.g. by maintaining a stack of stuck keys.
// FIXME: This doesn't record changes in layout.locked_keys
#[must_use] #[must_use]
fn unstick_locks(layout: &mut Layout) -> ViewChange { fn unstick_locks(layout: &mut Layout) -> ViewChange {
let mut new_view = None; let mut new_view = None;
@ -1010,7 +1036,6 @@ mod test {
( (
0.0, 0.0,
Row { Row {
angle: 0,
buttons: vec![( buttons: vec![(
0.0, 0.0,
Box::new(Button { Box::new(Button {
@ -1023,7 +1048,6 @@ mod test {
( (
10.0, 10.0,
Row { Row {
angle: 0,
buttons: vec![( buttons: vec![(
0.0, 0.0,
Box::new(Button { Box::new(Button {
@ -1047,7 +1071,6 @@ mod test {
( (
0.0, 0.0,
Row { Row {
angle: 0,
buttons: vec![( buttons: vec![(
0.0, 0.0,
Box::new(Button { Box::new(Button {
@ -1071,7 +1094,7 @@ mod test {
bottom: 1.0, bottom: 1.0,
}, },
views: hashmap! { views: hashmap! {
String::new() => view, String::new() => (c::Point { x: 0.0, y: 0.0 }, view),
}, },
}; };
assert_eq!( assert_eq!(

View File

@ -60,7 +60,7 @@ fn check_layout(layout: Layout) {
let state = xkb::State::new(&keymap); let state = xkb::State::new(&keymap);
// "Press" each button with keysyms // "Press" each button with keysyms
for view in layout.views.values() { for (_pos, view) in layout.views.values() {
for (_y, row) in &view.get_rows() { for (_y, row) in &view.get_rows() {
for (_x, button) in &row.buttons { for (_x, button) in &row.buttons {
let keystate = button.state.borrow(); let keystate = button.state.borrow();