From dd21bfed8da8ba58683416df0407f1fc0bc2dd86 Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Sat, 7 Dec 2019 17:10:47 +0000 Subject: [PATCH 1/3] positioning: Calculate sizes instead of storing, move position out of widgets Sizes of widgets can be derived, so storing them was only for C compatibility. Similar with storing position inside of widgets. Some layout margin and scaling changes could be introduced, meaning a possibility of visual differences. --- eek/eek-renderer.c | 47 ----- eek/eek-xml-layout.c | 1 - src/data.rs | 99 +++++++---- src/drawing.rs | 24 +-- src/layout.h | 3 - src/layout.rs | 402 ++++++++++++++++++++----------------------- src/tests.rs | 4 +- src/util.rs | 12 ++ 8 files changed, 273 insertions(+), 319 deletions(-) diff --git a/eek/eek-renderer.c b/eek/eek-renderer.c index 2c30a062..c1301c99 100644 --- a/eek/eek-renderer.c +++ b/eek/eek-renderer.c @@ -498,53 +498,6 @@ eek_renderer_get_icon_surface (const gchar *icon_name, return surface; } -static gboolean -sign (EekPoint *p1, EekPoint *p2, EekPoint *p3) -{ - // FIXME: what is this actually checking? - return (p1->x - p3->x) * (p2->y - p3->y) - - (p2->x - p3->x) * (p1->y - p3->y); -} - -uint32_t -eek_are_bounds_inside (EekBounds bounds, EekPoint point, EekPoint origin, int32_t angle) -{ - EekPoint points[4]; - gboolean b1, b2, b3; - - points[0].x = bounds.x; - points[0].y = bounds.y; - points[1].x = points[0].x + bounds.width; - points[1].y = points[0].y; - points[2].x = points[1].x; - points[2].y = points[1].y + bounds.height; - points[3].x = points[0].x; - points[3].y = points[2].y; - - for (unsigned i = 0; i < G_N_ELEMENTS(points); i++) { - eek_point_rotate (&points[i], angle); - points[i].x += origin.x; - points[i].y += origin.y; - } - - b1 = sign (&point, &points[0], &points[1]) < 0.0; - b2 = sign (&point, &points[1], &points[2]) < 0.0; - b3 = sign (&point, &points[2], &points[0]) < 0.0; - - if (b1 == b2 && b2 == b3) { - return 1; - } - - b1 = sign (&point, &points[2], &points[3]) < 0.0; - b2 = sign (&point, &points[3], &points[0]) < 0.0; - b3 = sign (&point, &points[0], &points[2]) < 0.0; - - if (b1 == b2 && b2 == b3) { - return 1; - } - return 0; -} - struct transformation eek_renderer_get_transformation (EekRenderer *renderer) { struct transformation failed = {0}; diff --git a/eek/eek-xml-layout.c b/eek/eek-xml-layout.c index 300d463b..81d0302a 100644 --- a/eek/eek-xml-layout.c +++ b/eek/eek-xml-layout.c @@ -34,6 +34,5 @@ eek_xml_layout_real_create_keyboard (const char *keyboard_type, enum squeek_arrangement_kind t) { struct squeek_layout *layout = squeek_load_layout(keyboard_type, t); - squeek_layout_place_contents(layout); return level_keyboard_new(manager, layout); } diff --git a/src/data.rs b/src/data.rs index cc02948d..54636f57 100644 --- a/src/data.rs +++ b/src/data.rs @@ -17,6 +17,7 @@ use ::keyboard::{ KeyState, PressType, generate_keymap, generate_keycodes, FormattingError }; +use ::layout; use ::layout::ArrangementKind; use ::resources; use ::util::c::as_str; @@ -215,6 +216,7 @@ fn load_layout_data_with_fallback( #[derive(Debug, Deserialize, PartialEq)] #[serde(deny_unknown_fields)] pub struct Layout { + /// FIXME: deprecate in favor of margins bounds: Bounds, views: HashMap>, #[serde(default)] @@ -269,6 +271,7 @@ enum Action { #[derive(Debug, Clone, Deserialize, PartialEq)] #[serde(deny_unknown_fields)] struct Outline { + /// FIXME: replace with Size bounds: Bounds, } @@ -303,6 +306,20 @@ impl From for Error { } } +pub fn add_offsets<'a, I: 'a, T, F: 'a>(iterator: I, get_size: F) + -> impl Iterator + 'a + where I: Iterator, + F: Fn(&T) -> f64, +{ + let mut offset = 0.0; + iterator.map(move |item| { + let size = get_size(&item); + let value = (offset, item); + offset += size; + value + }) +} + impl Layout { pub fn from_resource(name: &str) -> Result { let data = resources::get_keyboard(name) @@ -403,34 +420,35 @@ impl Layout { ); let views = HashMap::from_iter( - self.views.iter().map(|(name, view)| {( - name.clone(), - ::layout::View { - bounds: ::layout::c::Bounds { - x: self.bounds.x, - y: self.bounds.y, - width: self.bounds.width, - height: self.bounds.height, - }, - rows: view.iter().map(|row| { - ::layout::Row { - angle: 0, - bounds: None, - buttons: row.split_ascii_whitespace().map(|name| { - Box::new(create_button( - &self.buttons, - &self.outlines, - name, - button_states_cache.get(name.into()) - .expect("Button state not created") - .clone(), - &mut warning_handler, - )) - }).collect(), - } - }).collect(), - } - )}) + self.views.iter().map(|(name, view)| { + let rows = view.iter().map(|row| { + let buttons = row.split_ascii_whitespace() + .map(|name| { + Box::new(create_button( + &self.buttons, + &self.outlines, + name, + button_states_cache.get(name.into()) + .expect("Button state not created") + .clone(), + &mut warning_handler, + )) + }); + ::layout::Row { + angle: 0, + buttons: add_offsets( + buttons, + |button| button.size.width, + ).collect() + } + }); + let rows = add_offsets(rows, |row| row.get_height()) + .collect(); + ( + name.clone(), + layout::View::new(rows) + ) + }) ); ( @@ -440,6 +458,13 @@ impl Layout { CString::new(keymap_str) .expect("Invalid keymap string generated") }, + // FIXME: use a dedicated field + margins: layout::Margins { + top: self.bounds.x, + left: self.bounds.y, + bottom: 0.0, + right: self.bounds.y, + }, }), warning_handler, ) @@ -629,13 +654,11 @@ fn create_button( } }); - ::layout::Button { + layout::Button { name: cname, outline_name: CString::new(outline_name).expect("Bad outline"), // TODO: do layout before creating buttons - bounds: ::layout::c::Bounds { - x: outline.bounds.x, - y: outline.bounds.y, + size: layout::Size { width: outline.bounds.width, height: outline.bounds.height, }, @@ -734,8 +757,8 @@ mod tests { .unwrap(); assert_eq!( out.views["base"] - .rows[0] - .buttons[0] + .get_rows()[0].1 + .buttons[0].1 .label, ::layout::Label::Text(CString::new("test").unwrap()) ); @@ -749,8 +772,8 @@ mod tests { .unwrap(); assert_eq!( out.views["base"] - .rows[0] - .buttons[0] + .get_rows()[0].1 + .buttons[0].1 .label, ::layout::Label::Text(CString::new("test").unwrap()) ); @@ -765,8 +788,8 @@ mod tests { .unwrap(); assert_eq!( out.views["base"] - .rows[0] - .buttons[0] + .get_rows()[0].1 + .buttons[0].1 .state.borrow() .keycodes.len(), 2 diff --git a/src/drawing.rs b/src/drawing.rs index dfe19702..ead516a7 100644 --- a/src/drawing.rs +++ b/src/drawing.rs @@ -48,17 +48,14 @@ mod c { let cr = unsafe { cairo::Context::from_raw_none(cr) }; let view = layout.get_current_view(); - let view_position = view.bounds.get_position(); - for row in &view.rows { - for button in &row.buttons { + 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 { - let position = &view_position - + row.bounds.clone().unwrap().get_position() - + button.bounds.get_position(); render_button_at_position( renderer, &cr, - position, button.as_ref(), + row_offset + Point { x: *x_offset, y: 0.0 }, + button.as_ref(), state.pressed, state.locked, ); } @@ -76,15 +73,12 @@ mod c { let layout = unsafe { &mut *layout }; let cr = unsafe { cairo::Context::from_raw_none(cr) }; let view = layout.get_current_view(); - let view_position = view.bounds.get_position(); - for row in &view.rows { - for button in &row.buttons { - let position = &view_position - + row.bounds.clone().unwrap().get_position() - + button.bounds.get_position(); + for (row_offset, row) in &view.get_rows() { + for (x_offset, button) in &row.buttons { render_button_at_position( renderer, &cr, - position, button.as_ref(), + row_offset + Point { x: *x_offset, y: 0.0 }, + button.as_ref(), keyboard::PressType::Released, false, ); } @@ -105,7 +99,7 @@ pub fn render_button_at_position( cr.translate(position.x, position.y); cr.rectangle( 0.0, 0.0, - button.bounds.width, button.bounds.height + button.size.width, button.size.height ); cr.clip(); unsafe { diff --git a/src/layout.h b/src/layout.h index 45748ecc..6754ef1a 100644 --- a/src/layout.h +++ b/src/layout.h @@ -28,9 +28,6 @@ struct transformation squeek_layout_calculate_transformation( const struct squeek_layout *layout, double allocation_width, double allocation_size); -void -squeek_layout_place_contents(struct squeek_layout*); - struct squeek_layout *squeek_load_layout(const char *name, uint32_t type); const char *squeek_layout_get_keymap(const struct squeek_layout*); enum squeek_arrangement_kind squeek_layout_get_kind(const struct squeek_layout *); diff --git a/src/layout.rs b/src/layout.rs index 80dcb52c..e1cc5570 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -28,6 +28,7 @@ use ::drawing; use ::float_ord::FloatOrd; use ::keyboard::{ KeyState, PressType }; use ::submission::{ Timestamp, VirtualKeyboard }; +use ::util::find_max_double; use std::borrow::Borrow; @@ -40,7 +41,7 @@ pub mod c { use std::os::raw::{ c_char, c_void }; use std::ptr; - use std::ops::Add; + use std::ops::{ Add, Sub }; // The following defined in C #[repr(transparent)] @@ -49,7 +50,7 @@ pub mod c { /// Defined in eek-types.h #[repr(C)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq)] pub struct Point { pub x: f64, pub y: f64, @@ -71,6 +72,16 @@ pub mod c { } } } + + impl Sub<&Point> for Point { + type Output = Point; + fn sub(self, other: &Point) -> Point { + Point { + x: self.x - other.x, + y: self.y - other.y, + } + } + } /// Defined in eek-types.h #[repr(C)] @@ -81,13 +92,11 @@ pub mod c { pub width: f64, pub height: f64 } - + impl Bounds { - pub fn get_position(&self) -> Point { - Point { - x: self.x, - y: self.y, - } + pub fn contains(&self, point: &Point) -> bool { + (point.x > self.x && point.x < self.x + self.width + && point.y > self.y && point.y < self.y + self.height) } } @@ -133,7 +142,10 @@ pub mod c { pub extern "C" fn squeek_button_get_bounds(button: *const ::layout::Button) -> Bounds { let button = unsafe { &*button }; - button.bounds.clone() + Bounds { + x: 0.0, y: 0.0, + width: button.size.width, height: button.size.height + } } #[no_mangle] @@ -193,13 +205,13 @@ pub mod c { allocation_height: f64, ) -> Transformation { let layout = unsafe { &*layout }; - let bounds = &layout.get_current_view().bounds; - let h_scale = allocation_width / bounds.width; - let v_scale = allocation_height / bounds.height; - let scale = if h_scale > v_scale { h_scale } else { v_scale }; + let size = layout.calculate_size(); + let h_scale = allocation_width / size.width; + let v_scale = allocation_height / size.height; + let scale = if h_scale < v_scale { h_scale } else { v_scale }; Transformation { - origin_x: allocation_width - (scale * bounds.width) / 2.0, - origin_y: allocation_height - (scale * bounds.height) / 2.0, + origin_x: (allocation_width - (scale * size.width)) / 2.0, + origin_y: (allocation_height - (scale * size.height)) / 2.0, scale: scale, } } @@ -251,37 +263,6 @@ pub mod c { #[repr(transparent)] pub struct LevelKeyboard(*const c_void); - #[no_mangle] - extern "C" { - /// Checks if point falls within bounds, - /// which are relative to origin and rotated by angle (I think) - pub fn eek_are_bounds_inside (bounds: Bounds, - point: Point, - origin: Point, - angle: i32 - ) -> u32; - } - - /// Places each button in order, starting from 0 on the left, - /// keeping the spacing. - /// Sizes each button according to outline dimensions. - /// Places each row in order, starting from 0 on the top, - /// keeping the spacing. - /// Sets button and row sizes according to their contents. - #[no_mangle] - pub extern "C" - fn squeek_layout_place_contents(layout: *mut Layout) { - let layout = unsafe { &mut *layout }; - for view in layout.views.values_mut() { - let sizes: Vec> = view.rows.iter().map(|row| { - row.buttons.iter() - .map(|button| button.bounds.clone()) - .collect() - }).collect(); - view.place_buttons_with_sizes(sizes); - } - } - /// Release pointer in the specified position #[no_mangle] pub extern "C" @@ -388,9 +369,7 @@ pub mod c { place.map(|place| {( place.button.state.clone(), place.button.clone(), - view.bounds.get_position() - + place.row.bounds.clone().unwrap().get_position() - + place.button.bounds.get_position(), + place.offset, )}) }; @@ -464,9 +443,10 @@ struct ButtonPosition { pub struct ButtonPlace<'a> { button: &'a Button, row: &'a Row, + offset: c::Point, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Size { pub width: f64, pub height: f64, @@ -487,9 +467,7 @@ pub struct Button { pub name: CString, /// Label to display to the user pub label: Label, - /// TODO: position the buttons before they get initial bounds - /// Position relative to some origin (i.e. parent/row) - pub bounds: c::Bounds, + pub size: Size, /// The name of the visual class applied pub outline_name: CString, /// current state, shared with other buttons @@ -498,11 +476,10 @@ pub struct Button { /// The graphical representation of a row of buttons pub struct Row { - pub buttons: Vec>, + /// Buttons together with their offset from the left + pub buttons: Vec<(f64, Box