From 40b79f620936b312a8e67bf3005f8df4e0539811 Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Sun, 2 Feb 2020 17:52:02 +0000 Subject: [PATCH] layout: Center views relative to each other and the layout bounds --- src/data.rs | 31 +++++++++++++++++++------ src/drawing.rs | 12 ++++++---- src/layout.rs | 62 +++++++++++++++++++++++++++++++------------------- src/tests.rs | 2 +- 4 files changed, 72 insertions(+), 35 deletions(-) diff --git a/src/data.rs b/src/data.rs index 777aebc5..9723688e 100644 --- a/src/data.rs +++ b/src/data.rs @@ -417,8 +417,8 @@ impl Layout { )} ); - let views = HashMap::from_iter( - self.views.iter().map(|(name, view)| { + let views: Vec<_> = self.views.iter() + .map(|(name, view)| { let rows = view.iter().map(|row| { let buttons = row.split_ascii_whitespace() .map(|name| { @@ -445,8 +445,25 @@ impl Layout { name.clone(), 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 { @@ -742,7 +759,7 @@ mod tests { .build(ProblemPanic).0 .unwrap(); assert_eq!( - out.views["base"] + out.views["base"].1 .get_rows()[0].1 .buttons[0].1 .label, @@ -757,7 +774,7 @@ mod tests { .build(ProblemPanic).0 .unwrap(); assert_eq!( - out.views["base"] + out.views["base"].1 .get_rows()[0].1 .buttons[0].1 .label, @@ -773,7 +790,7 @@ mod tests { .build(ProblemPanic).0 .unwrap(); assert_eq!( - out.views["base"] + out.views["base"].1 .get_rows()[0].1 .buttons[0].1 .state.borrow() diff --git a/src/drawing.rs b/src/drawing.rs index ead516a7..33fcdc07 100644 --- a/src/drawing.rs +++ b/src/drawing.rs @@ -47,14 +47,16 @@ mod c { let layout = unsafe { &mut *layout }; let cr = unsafe { cairo::Context::from_raw_none(cr) }; - let view = layout.get_current_view(); + let (view_offset, view) = layout.get_current_view_position(); for (row_offset, row) in &view.get_rows() { for (x_offset, button) in &row.buttons { let state = RefCell::borrow(&button.state).clone(); if state.pressed == keyboard::PressType::Pressed || state.locked { render_button_at_position( renderer, &cr, - row_offset + Point { x: *x_offset, y: 0.0 }, + view_offset + + row_offset.clone() + + Point { x: *x_offset, y: 0.0 }, button.as_ref(), state.pressed, state.locked, ); @@ -72,12 +74,14 @@ mod c { ) { let layout = unsafe { &mut *layout }; let cr = unsafe { cairo::Context::from_raw_none(cr) }; - let view = layout.get_current_view(); + let (view_offset, view) = layout.get_current_view_position(); for (row_offset, row) in &view.get_rows() { for (x_offset, button) in &row.buttons { render_button_at_position( renderer, &cr, - row_offset + Point { x: *x_offset, y: 0.0 }, + view_offset + + row_offset.clone() + + Point { x: *x_offset, y: 0.0 }, button.as_ref(), keyboard::PressType::Released, false, ); diff --git a/src/layout.rs b/src/layout.rs index 763da87a..8fb2f4b8 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -329,11 +329,8 @@ pub mod c { Point { x: x_widget, y: y_widget } ); - let state = { - let view = layout.get_current_view(); - view.find_button_by_position(point) - .map(|place| place.button.state.clone()) - }; + let state = layout.find_button_by_position(point) + .map(|place| place.button.state.clone()); if let Some(state) = state { seat::handle_press_key( @@ -374,8 +371,7 @@ pub mod c { let pressed = layout.pressed_keys.clone(); let button_info = { - let view = layout.get_current_view(); - let place = view.find_button_by_position(point); + let place = layout.find_button_by_position(point); place.map(|place| {( place.button.state.clone(), place.button.clone(), @@ -552,14 +548,14 @@ impl View { }) } - fn get_width(&self) -> f64 { + pub fn get_width(&self) -> f64 { // No need to call `get_rows()`, // as the biggest row is the most far reaching in both directions // because they are all centered. 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() .map(|(y_offset, row)| row.get_height() + y_offset) .unwrap_or(0.0) @@ -576,6 +572,21 @@ impl View { row, )}).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 @@ -603,7 +614,8 @@ pub struct Layout { // Views own the actual buttons which have state // Maybe they should own UI only, // and keys should be owned by a dedicated non-UI-State? - pub views: HashMap, + /// Point is the offset within the layout + pub views: HashMap, // Non-UI stuff /// xkb keymap applicable to the contained keys. Unchangeable @@ -622,7 +634,8 @@ pub struct Layout { /// A builder structure for picking up layout data from storage pub struct LayoutData { - pub views: HashMap, + /// Point is the offset within layout + pub views: HashMap, pub keymap_str: CString, pub margins: Margins, } @@ -653,8 +666,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 { - self.views.get(&self.current_view).expect("Selected nonexistent view") + &self.get_current_view_position().1 } fn set_view(&mut self, view: String) -> Result<(), NoSuchView> { @@ -668,16 +686,9 @@ impl Layout { /// Calculates size without margins fn calculate_inner_size(&self) -> Size { - Size { - height: find_max_double( - self.views.iter(), - |(_name, view)| view.get_height(), - ), - width: find_max_double( - self.views.iter(), - |(_name, view)| view.get_width(), - ), - } + View::calculate_super_size( + self.views.iter().map(|(_, (_offset, v))| v).collect() + ) } /// Size including margins @@ -712,6 +723,11 @@ impl Layout { scale: 1.0, }) } + + fn find_button_by_position(&self, point: c::Point) -> Option { + let (offset, layout) = self.get_current_view_position(); + layout.find_button_by_position(point - offset) + } } mod procedures { @@ -1068,7 +1084,7 @@ mod test { bottom: 1.0, }, views: hashmap! { - String::new() => view, + String::new() => (c::Point { x: 0.0, y: 0.0 }, view), }, }; assert_eq!( diff --git a/src/tests.rs b/src/tests.rs index 568fe29a..c2967e30 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -60,7 +60,7 @@ fn check_layout(layout: Layout) { let state = xkb::State::new(&keymap); // "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 (_x, button) in &row.buttons { let keystate = button.state.borrow();