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