From 75992ff13ff7d920ed5fa8d670efb4c95828e9dd Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Thu, 29 Aug 2019 12:19:42 +0000 Subject: [PATCH] Check for button position more in Rust The check against fitting inside the Layout was removed: as an optimization it is unneeded, as the actual search must be optimized to be quick. In addition, the view bounds don't correspond to anything physical as long as negative offsets are allowed. --- eek/eek-gtk-keyboard.c | 6 +- eek/eek-renderer.c | 46 ++------------- src/layout.h | 3 +- src/layout.rs | 126 ++++++++++++++++++++++++++++++----------- 4 files changed, 103 insertions(+), 78 deletions(-) diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index d42564b6..0dc3e1f5 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -117,7 +117,8 @@ eek_gtk_keyboard_real_draw (GtkWidget *self, struct button_place place = squeek_view_find_key( view, squeek_button_get_key(head->data) ); - render_pressed_button (self, &place); + if (place.button) + render_pressed_button (self, &place); } /* redraw locked key */ @@ -128,7 +129,8 @@ eek_gtk_keyboard_real_draw (GtkWidget *self, ((EekModifierKey *)head->data)->button ) ); - render_locked_button (self, &place); + if (place.button) + render_locked_button (self, &place); } return FALSE; diff --git a/eek/eek-renderer.c b/eek/eek-renderer.c index 0e96056d..a8a46dca 100644 --- a/eek/eek-renderer.c +++ b/eek/eek-renderer.c @@ -913,14 +913,6 @@ eek_renderer_get_foreground_color (EekRenderer *renderer, color->alpha = gcolor.alpha; } -struct _FindKeyByPositionCallbackData { - EekPoint point; - EekPoint origin; - gint angle; - struct squeek_button *button; -}; -typedef struct _FindKeyByPositionCallbackData FindKeyByPositionCallbackData; - static gboolean sign (EekPoint *p1, EekPoint *p2, EekPoint *p3) { @@ -968,17 +960,6 @@ eek_are_bounds_inside (EekBounds bounds, EekPoint point, EekPoint origin, int32_ return 0; } -static void -find_button_by_position_row_callback (struct squeek_row *row, - gpointer user_data) -{ - FindKeyByPositionCallbackData *data = user_data; - if (data->button) { - return; - } - data->button = squeek_row_find_button_by_position(row, data->point, data->origin); -} - /** * eek_renderer_find_key_by_position: * @renderer: The renderer normally used to render the key @@ -994,30 +975,13 @@ eek_renderer_find_button_by_position (EekRenderer *renderer, gdouble x, gdouble y) { - FindKeyByPositionCallbackData data; - g_return_val_if_fail (EEK_IS_RENDERER(renderer), NULL); EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer); - EekBounds bounds = squeek_view_get_bounds (view); - /* Transform from widget coordinates to keyboard coordinates */ - x = (x - priv->origin_x)/priv->scale - bounds.x; - y = (y - priv->origin_y)/priv->scale - bounds.y; - - if (x < 0 || - y < 0 || - x > bounds.width || - y > bounds.height) - return NULL; - - data.point.x = x; - data.point.y = y; - data.origin.x = 0; - data.origin.y = 0; - data.button = NULL; - - squeek_view_foreach (view, find_button_by_position_row_callback, - &data); - return data.button; + EekPoint point = { + .x = (x - priv->origin_x)/priv->scale, + .y = (y - priv->origin_y)/priv->scale, + }; + return squeek_view_find_button_by_position(view, point); } diff --git a/src/layout.h b/src/layout.h index 91a5a173..d0615154 100644 --- a/src/layout.h +++ b/src/layout.h @@ -25,7 +25,6 @@ uint32_t squeek_row_contains(struct squeek_row*, struct squeek_button *button); struct button_place squeek_view_find_key(struct squeek_view*, struct squeek_key *state); -struct squeek_button *squeek_row_find_button_by_position(struct squeek_row *row, EekPoint point, EekPoint origin); typedef void (*ButtonCallback) (struct squeek_button *button, gpointer user_data); void squeek_row_foreach(struct squeek_row*, @@ -74,4 +73,6 @@ struct squeek_row *squeek_view_get_row(struct squeek_view *view, void squeek_view_place_contents(struct squeek_view *view, LevelKeyboard *keyboard); + +struct squeek_button *squeek_view_find_button_by_position(struct squeek_view *view, EekPoint point); #endif diff --git a/src/layout.rs b/src/layout.rs index 58d635b7..b21d5d23 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -1,3 +1,22 @@ +/** + * Layout-related data. + * + * The `View` contains `Row`s and each `Row` contains `Button`s. + * They carry data relevant to their positioning only, + * except the Button, which also carries some data + * about its appearance and function. + * + * The layout is determined bottom-up, by measuring `Button` sizes, + * deriving `Row` sizes from them, and then centering them within the `View`. + * + * That makes the `View` position immutable, + * and therefore different than the other positions. + * + * Note that it might be a better idea + * to make `View` position depend on its contents, + * and let the renderer scale and center it within the widget. + */ + use std::cell::RefCell; use std::rc::Rc; use std::vec::Vec; @@ -310,7 +329,7 @@ pub mod c { } /// Entry points for more complex procedures and algoithms which span multiple modules - mod procedures { + pub mod procedures { use super::*; #[repr(transparent)] @@ -332,7 +351,7 @@ pub mod c { /// Checks if point falls within bounds, /// which are relative to origin and rotated by angle (I think) - fn eek_are_bounds_inside (bounds: Bounds, + pub fn eek_are_bounds_inside (bounds: Bounds, point: Point, origin: Point, angle: i32 @@ -369,36 +388,6 @@ pub mod c { view.place_buttons_with_sizes(sizes); } - #[no_mangle] - pub extern "C" - fn squeek_row_find_button_by_position( - row: *mut Row, point: Point, origin: Point - ) -> *mut Button { - let row = unsafe { &mut *row }; - let row_bounds = row.bounds - .as_ref().expect("Missing bounds on row"); - let origin = Point { - x: origin.x + row_bounds.x, - y: origin.y + row_bounds.y, - }; - let angle = row.angle; - let result = row.buttons.iter_mut().find(|button| { - let bounds = button.bounds - .as_ref().expect("Missing bounds on button") - .clone(); - let point = point.clone(); - let origin = origin.clone(); - unsafe { - eek_are_bounds_inside(bounds, point, origin, angle) == 1 - } - }); - - match result { - Some(button) => button.as_mut() as *mut Button, - None => ptr::null_mut(), - } - } - fn squeek_row_contains(row: &Row, needle: *const Button) -> bool { row.buttons.iter().position( // TODO: wrap Button properly in Rc; this comparison is unreliable @@ -446,6 +435,20 @@ pub mod c { }; ButtonPlace { row, button } } + + + #[no_mangle] + pub extern "C" + fn squeek_view_find_button_by_position( + view: *mut View, point: Point + ) -> *mut Button { + let view = unsafe { &mut *view }; + let result = view.find_button_by_position(point); + match result { + Some(button) => button.as_mut() as *mut Button, + None => ptr::null_mut(), + } + } #[cfg(test)] mod test { @@ -559,12 +562,13 @@ pub struct Size { pub struct Button { oref: c::OutlineRef, /// TODO: abolish Option, buttons should be created with bounds fully formed + /// Position relative to some origin (i.e. parent/row) bounds: Option, /// current state, shared with other buttons pub state: Rc>, } - +// FIXME: derive from the style/margin/padding const BUTTON_SPACING: f64 = 4.0; const ROW_SPACING: f64 = 7.0; @@ -573,6 +577,7 @@ pub struct Row { buttons: Vec>, /// Angle is not really used anywhere... angle: i32, + /// Position relative to some origin (i.e. parent/view origin) bounds: Option, } @@ -621,6 +626,27 @@ impl Row { }; Size { width: total_width, height: max_height } } + + /// Finds the first button that covers the specified point + /// relative to row's position's origin + fn find_button_by_position(&mut self, point: c::Point) + -> Option<&mut Box