view: Move button finding to Rust
This commit is contained in:
@ -114,7 +114,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
|
|||||||
/* redraw pressed key */
|
/* redraw pressed key */
|
||||||
const GList *list = priv->keyboard->pressed_buttons;
|
const GList *list = priv->keyboard->pressed_buttons;
|
||||||
for (const GList *head = list; head; head = g_list_next (head)) {
|
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)
|
view, squeek_button_get_key(head->data)
|
||||||
);
|
);
|
||||||
render_pressed_button (self, &place);
|
render_pressed_button (self, &place);
|
||||||
@ -123,7 +123,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
|
|||||||
/* redraw locked key */
|
/* redraw locked key */
|
||||||
list = priv->keyboard->locked_buttons;
|
list = priv->keyboard->locked_buttons;
|
||||||
for (const GList *head = list; head; head = g_list_next (head)) {
|
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(
|
view, squeek_button_get_key(
|
||||||
((EekModifierKey *)head->data)->button
|
((EekModifierKey *)head->data)->button
|
||||||
)
|
)
|
||||||
|
|||||||
@ -287,37 +287,3 @@ struct squeek_view *level_keyboard_current(LevelKeyboard *keyboard)
|
|||||||
{
|
{
|
||||||
return keyboard->views[keyboard->level];
|
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;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -70,9 +70,6 @@ struct button_place {
|
|||||||
const struct squeek_button *button;
|
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
|
EekOutline *level_keyboard_get_outline
|
||||||
(LevelKeyboard *keyboard,
|
(LevelKeyboard *keyboard,
|
||||||
guint oref);
|
guint oref);
|
||||||
|
|||||||
@ -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);
|
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);
|
struct squeek_button *squeek_row_find_button_by_position(struct squeek_row *row, EekPoint point, EekPoint origin);
|
||||||
|
|
||||||
|
|||||||
136
src/layout.rs
136
src/layout.rs
@ -310,6 +310,13 @@ pub mod c {
|
|||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct LevelKeyboard(*const c_void);
|
pub struct LevelKeyboard(*const c_void);
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
pub struct ButtonPlace {
|
||||||
|
row: *const Row,
|
||||||
|
button: *const Button,
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn eek_get_outline_size(
|
fn eek_get_outline_size(
|
||||||
@ -352,25 +359,6 @@ pub mod c {
|
|||||||
row.place_buttons_with_sizes(sizes);
|
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]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_row_find_button_by_position(
|
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)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -441,6 +454,68 @@ pub mod c {
|
|||||||
let row = Row::new(0);
|
let row = Row::new(0);
|
||||||
assert_eq!(squeek_row_contains(&row, button), false);
|
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,
|
bounds: c::Bounds,
|
||||||
rows: Vec<Box<Row>>,
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user