view: Move button finding to Rust

This commit is contained in:
Dorota Czaplejewicz
2019-08-16 18:07:13 +00:00
parent e1c57fa9f0
commit 79b66f81ec
5 changed files with 120 additions and 59 deletions

View File

@ -114,7 +114,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
/* redraw pressed key */
const GList *list = priv->keyboard->pressed_buttons;
for (const GList *head = list; head; head = g_list_next (head)) {
struct button_place place = eek_keyboard_get_button_by_state(
struct button_place place = squeek_view_find_key(
view, squeek_button_get_key(head->data)
);
render_pressed_button (self, &place);
@ -123,7 +123,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
/* redraw locked key */
list = priv->keyboard->locked_buttons;
for (const GList *head = list; head; head = g_list_next (head)) {
struct button_place place = eek_keyboard_get_button_by_state(
struct button_place place = squeek_view_find_key(
view, squeek_button_get_key(
((EekModifierKey *)head->data)->button
)

View File

@ -287,37 +287,3 @@ struct squeek_view *level_keyboard_current(LevelKeyboard *keyboard)
{
return keyboard->views[keyboard->level];
}
struct GetRowData {
struct squeek_button *button;
struct squeek_row *row;
struct squeek_key *needle;
};
void find_key_in_row(struct squeek_row *row, gpointer user_data) {
struct GetRowData *data = user_data;
if (data->button) {
return;
}
data->button = squeek_row_find_key(row, data->needle);
if (data->button) {
data->row = row;
}
}
// TODO: return multiple
struct button_place eek_keyboard_get_button_by_state(struct squeek_view *view,
struct squeek_key *key) {
struct GetRowData data = {
.row = NULL,
.button = NULL,
.needle = key,
};
squeek_view_foreach(view, find_key_in_row, &data);
struct button_place ret = {
.row = data.row,
.button = data.button,
};
return ret;
}

View File

@ -70,9 +70,6 @@ struct button_place {
const struct squeek_button *button;
};
struct button_place eek_keyboard_get_button_by_state(struct squeek_view *view,
struct squeek_key *key);
EekOutline *level_keyboard_get_outline
(LevelKeyboard *keyboard,
guint oref);

View File

@ -23,7 +23,7 @@ void squeek_row_set_bounds(struct squeek_row* row, EekBounds bounds);
uint32_t squeek_row_contains(struct squeek_row*, struct squeek_button *button);
struct squeek_button* squeek_row_find_key(struct squeek_row*, struct squeek_key *state);
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);

View File

@ -310,6 +310,13 @@ pub mod c {
#[repr(transparent)]
pub struct LevelKeyboard(*const c_void);
#[repr(C)]
#[derive(PartialEq, Debug)]
pub struct ButtonPlace {
row: *const Row,
button: *const Button,
}
#[no_mangle]
extern "C" {
fn eek_get_outline_size(
@ -352,25 +359,6 @@ pub mod c {
row.place_buttons_with_sizes(sizes);
}
/// Finds a button sharing this state
#[no_mangle]
pub extern "C"
fn squeek_row_find_key(
row: *mut ::layout::Row,
state: ::keyboard::c::CKeyState,
) -> *mut Button {
let row = unsafe { &mut *row };
let needle = state.unwrap();
let found = row.buttons.iter_mut().find(
|button| Rc::ptr_eq(&button.state, &needle)
);
Rc::into_raw(needle); // Prevent dropping
match found {
Some(button) => button.as_mut() as *mut Button,
None => ptr::null_mut(),
}
}
#[no_mangle]
pub extern "C"
fn squeek_row_find_button_by_position(
@ -424,6 +412,31 @@ pub mod c {
}
}
#[no_mangle]
pub extern "C"
fn squeek_view_find_key(
view: *const View,
needle: ::keyboard::c::CKeyState,
) -> ButtonPlace {
let view = unsafe { &*view };
let state = needle.unwrap();
let paths = ::layout::procedures::find_key_paths(view, &state);
// Iterators used up, can turn the reference back into pointer
Rc::into_raw(state);
// Can only return 1 entry back to C
let (row, button) = match paths.get(0) {
Some((row, button)) => (
row.as_ref() as *const Row,
button.as_ref() as *const Button,
),
None => ( ptr::null(), ptr::null() ),
};
ButtonPlace { row, button }
}
#[cfg(test)]
mod test {
use super::*;
@ -441,6 +454,68 @@ pub mod c {
let row = Row::new(0);
assert_eq!(squeek_row_contains(&row, button), false);
}
#[test]
fn view_has_button() {
let state = Rc::new(RefCell::new(::keyboard::KeyState {
pressed: false,
locked: false,
keycode: 0,
symbol: None,
}));
let state_clone = ::keyboard::c::CKeyState::wrap(state.clone());
let button = Box::new(Button {
oref: OutlineRef(0),
bounds: None,
state: state,
});
let button_ptr = button.as_ref() as *const Button;
let row = Box::new(Row {
buttons: vec!(button),
angle: 0,
bounds: None
});
let row_ptr = row.as_ref() as *const Row;
let view = View {
bounds: Bounds {
x: 0f64, y: 0f64,
width: 0f64, height: 0f64
},
rows: vec!(row),
};
assert_eq!(
squeek_view_find_key(
&view as *const View,
state_clone.clone(),
),
ButtonPlace {
row: row_ptr,
button: button_ptr,
}
);
let view = View {
bounds: Bounds {
x: 0f64, y: 0f64,
width: 0f64, height: 0f64
},
rows: Vec::new(),
};
assert_eq!(
squeek_view_find_key(
&view as *const View,
state_clone.clone()
),
ButtonPlace {
row: ptr::null(),
button: ptr::null(),
}
);
}
}
}
@ -538,3 +613,26 @@ pub struct View {
bounds: c::Bounds,
rows: Vec<Box<Row>>,
}
mod procedures {
use super::*;
type Path<'v> = (&'v Box<Row>, &'v Box<Button>);
/// Finds all `(row, button)` paths that refer to the specified key `state`
pub fn find_key_paths<'v, 's>(
view: &'v View,
state: &'s Rc<RefCell<KeyState>>
) -> Vec<Path<'v>> {
view.rows.iter().flat_map(|row| {
let row_paths: Vec<Path> = row.buttons.iter().filter_map(|button| {
if Rc::ptr_eq(&button.state, state) {
Some((row, button))
} else {
None
}
}).collect(); // collecting not to let row references outlive the function
row_paths.into_iter()
}).collect()
}
}