section: Move properties into Row
This commit is contained in:
		@ -432,9 +432,9 @@ EekKeyboard *level_keyboard_current(LevelKeyboard *keyboard)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct GetSectionData {
 | 
					struct GetSectionData {
 | 
				
			||||||
    const struct squeek_button *button;
 | 
					    struct squeek_button *button;
 | 
				
			||||||
    EekSection *section;
 | 
					    EekSection *section;
 | 
				
			||||||
    const struct squeek_key *needle;
 | 
					    struct squeek_key *needle;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void find_button_in_section(EekElement *element, gpointer user_data) {
 | 
					void find_button_in_section(EekElement *element, gpointer user_data) {
 | 
				
			||||||
@ -449,7 +449,7 @@ void find_button_in_section(EekElement *element, gpointer user_data) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EekSection *eek_keyboard_get_section(EekKeyboard *keyboard,
 | 
					EekSection *eek_keyboard_get_section(EekKeyboard *keyboard,
 | 
				
			||||||
                                     const struct squeek_button *button) {
 | 
					                                     struct squeek_button *button) {
 | 
				
			||||||
    struct GetSectionData data = {
 | 
					    struct GetSectionData data = {
 | 
				
			||||||
        .button = button,
 | 
					        .button = button,
 | 
				
			||||||
        .section = NULL,
 | 
					        .section = NULL,
 | 
				
			||||||
@ -473,7 +473,7 @@ void find_key_in_section(EekElement *element, gpointer user_data) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// TODO: return multiple
 | 
					// TODO: return multiple
 | 
				
			||||||
struct button_place eek_keyboard_get_button_by_state(EekKeyboard *keyboard,
 | 
					struct button_place eek_keyboard_get_button_by_state(EekKeyboard *keyboard,
 | 
				
			||||||
                                             const struct squeek_key *key) {
 | 
					                                             struct squeek_key *key) {
 | 
				
			||||||
    struct GetSectionData data = {
 | 
					    struct GetSectionData data = {
 | 
				
			||||||
        .section = NULL,
 | 
					        .section = NULL,
 | 
				
			||||||
        .button = NULL,
 | 
					        .button = NULL,
 | 
				
			||||||
@ -482,7 +482,7 @@ struct button_place eek_keyboard_get_button_by_state(EekKeyboard *keyboard,
 | 
				
			|||||||
    eek_container_foreach_child(EEK_CONTAINER(keyboard), find_key_in_section, &data);
 | 
					    eek_container_foreach_child(EEK_CONTAINER(keyboard), find_key_in_section, &data);
 | 
				
			||||||
    struct button_place ret = {
 | 
					    struct button_place ret = {
 | 
				
			||||||
        .section = data.section,
 | 
					        .section = data.section,
 | 
				
			||||||
        .button = (struct squeek_button*)data.button,
 | 
					        .button = data.button,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -158,7 +158,7 @@ EekSection         *eek_keyboard_create_section
 | 
				
			|||||||
                                     (EekKeyboard        *keyboard);
 | 
					                                     (EekKeyboard        *keyboard);
 | 
				
			||||||
EekSection         *eek_keyboard_get_section
 | 
					EekSection         *eek_keyboard_get_section
 | 
				
			||||||
                                     (EekKeyboard *keyboard,
 | 
					                                     (EekKeyboard *keyboard,
 | 
				
			||||||
                                      const struct squeek_button *button);
 | 
					                                      struct squeek_button *button);
 | 
				
			||||||
struct squeek_button *eek_keyboard_find_button_by_name(LevelKeyboard *keyboard,
 | 
					struct squeek_button *eek_keyboard_find_button_by_name(LevelKeyboard *keyboard,
 | 
				
			||||||
                                      const gchar        *name);
 | 
					                                      const gchar        *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -169,7 +169,7 @@ struct button_place {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct button_place eek_keyboard_get_button_by_state(EekKeyboard *keyboard,
 | 
					struct button_place eek_keyboard_get_button_by_state(EekKeyboard *keyboard,
 | 
				
			||||||
                                             const struct squeek_key *key);
 | 
					                                             struct squeek_key *key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EekOutline         *level_keyboard_get_outline
 | 
					EekOutline         *level_keyboard_get_outline
 | 
				
			||||||
                                     (LevelKeyboard        *keyboard,
 | 
					                                     (LevelKeyboard        *keyboard,
 | 
				
			||||||
@ -196,5 +196,9 @@ void level_keyboard_free(LevelKeyboard *self);
 | 
				
			|||||||
EekSection *
 | 
					EekSection *
 | 
				
			||||||
eek_keyboard_real_create_section (EekKeyboard *self);
 | 
					eek_keyboard_real_create_section (EekKeyboard *self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct squeek_row *
 | 
				
			||||||
 | 
					eek_keyboard_real_create_row (EekKeyboard *self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
G_END_DECLS
 | 
					G_END_DECLS
 | 
				
			||||||
#endif  /* EEK_KEYBOARD_H */
 | 
					#endif  /* EEK_KEYBOARD_H */
 | 
				
			||||||
 | 
				
			|||||||
@ -93,10 +93,9 @@ struct _CreateKeyboardSurfaceCallbackData {
 | 
				
			|||||||
typedef struct _CreateKeyboardSurfaceCallbackData CreateKeyboardSurfaceCallbackData;
 | 
					typedef struct _CreateKeyboardSurfaceCallbackData CreateKeyboardSurfaceCallbackData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
create_keyboard_surface_button_callback (gpointer item,
 | 
					create_keyboard_surface_button_callback (struct squeek_button *button,
 | 
				
			||||||
                                      gpointer    user_data)
 | 
					                                      gpointer    user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct squeek_button *button = item;
 | 
					 | 
				
			||||||
    CreateKeyboardSurfaceCallbackData *data = user_data;
 | 
					    CreateKeyboardSurfaceCallbackData *data = user_data;
 | 
				
			||||||
    EekBounds bounds = squeek_button_get_bounds(button);
 | 
					    EekBounds bounds = squeek_button_get_bounds(button);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -978,10 +977,9 @@ sign (EekPoint *p1, EekPoint *p2, EekPoint *p3)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
find_button_by_position_key_callback (gpointer item,
 | 
					find_button_by_position_key_callback (struct squeek_button *button,
 | 
				
			||||||
                                   gpointer user_data)
 | 
					                                   gpointer user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct squeek_button *button = item;
 | 
					 | 
				
			||||||
    FindKeyByPositionCallbackData *data = user_data;
 | 
					    FindKeyByPositionCallbackData *data = user_data;
 | 
				
			||||||
    if (data->button) {
 | 
					    if (data->button) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
 | 
				
			|||||||
@ -44,36 +44,11 @@ enum {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
typedef struct _EekSectionPrivate
 | 
					typedef struct _EekSectionPrivate
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    gint angle;
 | 
					    struct squeek_row *row;
 | 
				
			||||||
    EekModifierType modifiers;
 | 
					 | 
				
			||||||
    GPtrArray *buttons; // struct squeek_button*
 | 
					 | 
				
			||||||
} EekSectionPrivate;
 | 
					} EekSectionPrivate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
G_DEFINE_TYPE_WITH_PRIVATE (EekSection, eek_section, EEK_TYPE_ELEMENT)
 | 
					G_DEFINE_TYPE_WITH_PRIVATE (EekSection, eek_section, EEK_TYPE_ELEMENT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct squeek_button*
 | 
					 | 
				
			||||||
eek_section_create_button (EekSection *self,
 | 
					 | 
				
			||||||
                             const gchar *name,
 | 
					 | 
				
			||||||
                             guint        keycode,
 | 
					 | 
				
			||||||
                             guint oref)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    struct squeek_button *button = squeek_button_new(keycode, oref);
 | 
					 | 
				
			||||||
    g_return_val_if_fail (button, NULL);
 | 
					 | 
				
			||||||
    EekSectionPrivate *priv = eek_section_get_instance_private (self);
 | 
					 | 
				
			||||||
    g_ptr_array_add(priv->buttons, button);
 | 
					 | 
				
			||||||
    return button;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct squeek_button *eek_section_create_button_with_state(EekSection *self,
 | 
					 | 
				
			||||||
                                  const gchar *name,
 | 
					 | 
				
			||||||
                                    struct squeek_button *source) {
 | 
					 | 
				
			||||||
    struct squeek_button *button = squeek_button_new_with_state(source);
 | 
					 | 
				
			||||||
    g_return_val_if_fail (button, NULL);
 | 
					 | 
				
			||||||
    EekSectionPrivate *priv = eek_section_get_instance_private (self);
 | 
					 | 
				
			||||||
    g_ptr_array_add(priv->buttons, button);
 | 
					 | 
				
			||||||
    return button;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
eek_section_finalize (GObject *object)
 | 
					eek_section_finalize (GObject *object)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -143,7 +118,7 @@ static void
 | 
				
			|||||||
eek_section_init (EekSection *self)
 | 
					eek_section_init (EekSection *self)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    EekSectionPrivate *priv = eek_section_get_instance_private (self);
 | 
					    EekSectionPrivate *priv = eek_section_get_instance_private (self);
 | 
				
			||||||
    priv->buttons = g_ptr_array_new();
 | 
					    priv->row = squeek_row_new(0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -161,10 +136,7 @@ eek_section_set_angle (EekSection  *section,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    EekSectionPrivate *priv = eek_section_get_instance_private (section);
 | 
					    EekSectionPrivate *priv = eek_section_get_instance_private (section);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (priv->angle != angle) {
 | 
					    squeek_row_set_angle(priv->row, angle);
 | 
				
			||||||
        priv->angle = angle;
 | 
					 | 
				
			||||||
        g_object_notify (G_OBJECT(section), "angle");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -180,7 +152,16 @@ eek_section_get_angle (EekSection *section)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    EekSectionPrivate *priv = eek_section_get_instance_private (section);
 | 
					    EekSectionPrivate *priv = eek_section_get_instance_private (section);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return priv->angle;
 | 
					    return squeek_row_get_angle(priv->row);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct squeek_row *
 | 
				
			||||||
 | 
					eek_section_get_row (EekSection *section)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    g_return_val_if_fail (EEK_IS_SECTION(section), NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    EekSectionPrivate *priv = eek_section_get_instance_private (section);
 | 
				
			||||||
 | 
					    return priv->row;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const double keyspacing = 4.0;
 | 
					const double keyspacing = 4.0;
 | 
				
			||||||
@ -191,14 +172,7 @@ struct keys_info {
 | 
				
			|||||||
    double biggest_height;
 | 
					    double biggest_height;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Set button size to match the outline. Reset position
 | 
					EekBounds eek_get_outline_size(LevelKeyboard *keyboard, uint32_t oref) {
 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
buttonsizer(gpointer item, gpointer user_data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    struct squeek_button *button = item;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    LevelKeyboard *keyboard = user_data;
 | 
					 | 
				
			||||||
    uint oref = squeek_button_get_oref(button);
 | 
					 | 
				
			||||||
    EekOutline *outline = level_keyboard_get_outline (keyboard, oref);
 | 
					    EekOutline *outline = level_keyboard_get_outline (keyboard, oref);
 | 
				
			||||||
    if (outline && outline->num_points > 0) {
 | 
					    if (outline && outline->num_points > 0) {
 | 
				
			||||||
        double minx = outline->points[0].x;
 | 
					        double minx = outline->points[0].x;
 | 
				
			||||||
@ -225,81 +199,47 @@ buttonsizer(gpointer item, gpointer user_data)
 | 
				
			|||||||
            .x = 0,
 | 
					            .x = 0,
 | 
				
			||||||
            .y = 0,
 | 
					            .y = 0,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        squeek_button_set_bounds(button, key_bounds);
 | 
					        return key_bounds;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    EekBounds bounds = {0, 0, 0, 0};
 | 
				
			||||||
 | 
					    return bounds;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					void eek_section_set_bounds(EekSection *section, EekBounds bounds) {
 | 
				
			||||||
buttoncounter (gpointer item, gpointer user_data)
 | 
					    eek_element_set_bounds(EEK_ELEMENT(section), &bounds);
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    struct squeek_button *button = item;
 | 
					 | 
				
			||||||
    struct keys_info *data = user_data;
 | 
					 | 
				
			||||||
    data->count++;
 | 
					 | 
				
			||||||
    EekBounds key_bounds = squeek_button_get_bounds(button);
 | 
					 | 
				
			||||||
    data->total_width += key_bounds.width;
 | 
					 | 
				
			||||||
    if (key_bounds.height > data->biggest_height) {
 | 
					 | 
				
			||||||
        data->biggest_height = key_bounds.height;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
buttonplacer(gpointer item, gpointer user_data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    struct squeek_button *button = item;
 | 
					 | 
				
			||||||
    double *current_offset = user_data;
 | 
					 | 
				
			||||||
    EekBounds key_bounds = squeek_button_get_bounds(button);
 | 
					 | 
				
			||||||
    key_bounds.x = *current_offset;
 | 
					 | 
				
			||||||
    key_bounds.y = 0;
 | 
					 | 
				
			||||||
    squeek_button_set_bounds(button, key_bounds);
 | 
					 | 
				
			||||||
    *current_offset += key_bounds.width + keyspacing;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
eek_section_place_keys(EekSection *section, LevelKeyboard *keyboard)
 | 
					eek_section_place_keys(EekSection *section, LevelKeyboard *keyboard)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    EekSectionPrivate *priv = eek_section_get_instance_private (section);
 | 
					    EekSectionPrivate *priv = eek_section_get_instance_private (section);
 | 
				
			||||||
 | 
					    EekBounds section_size = squeek_row_place_keys(priv->row, keyboard);
 | 
				
			||||||
    g_ptr_array_foreach(priv->buttons, buttonsizer, keyboard);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    struct keys_info keyinfo = {0};
 | 
					 | 
				
			||||||
    g_ptr_array_foreach(priv->buttons, buttoncounter, &keyinfo);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    EekBounds section_bounds = {0};
 | 
					    EekBounds section_bounds = {0};
 | 
				
			||||||
    eek_element_get_bounds(EEK_ELEMENT(section), §ion_bounds);
 | 
					    eek_element_get_bounds(EEK_ELEMENT(section), §ion_bounds);
 | 
				
			||||||
 | 
					    // FIXME: do centering of each section based on keyboard dimensions,
 | 
				
			||||||
    double key_offset = (section_bounds.width - (keyinfo.total_width + (keyinfo.count - 1) * keyspacing)) / 2;
 | 
					    // one level up the iterators
 | 
				
			||||||
    g_ptr_array_foreach(priv->buttons, buttonplacer, &key_offset);
 | 
					    // now centering by comparing previous width to the new, calculated one
 | 
				
			||||||
 | 
					    section_bounds.x = (section_bounds.width - section_size.width) / 2;
 | 
				
			||||||
    section_bounds.height = keyinfo.biggest_height;
 | 
					    section_bounds.width = section_size.width;
 | 
				
			||||||
 | 
					    section_bounds.height = section_size.height;
 | 
				
			||||||
    eek_element_set_bounds(EEK_ELEMENT(section), §ion_bounds);
 | 
					    eek_element_set_bounds(EEK_ELEMENT(section), §ion_bounds);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void eek_section_foreach (EekSection *section,
 | 
					void eek_section_foreach (EekSection *section,
 | 
				
			||||||
                     GFunc      func,
 | 
					                          ButtonCallback func,
 | 
				
			||||||
                          gpointer   user_data) {
 | 
					                          gpointer   user_data) {
 | 
				
			||||||
    EekSectionPrivate *priv = eek_section_get_instance_private (section);
 | 
					    EekSectionPrivate *priv = eek_section_get_instance_private (section);
 | 
				
			||||||
    g_ptr_array_foreach(priv->buttons, func, user_data);
 | 
					    squeek_row_foreach(priv->row, func, user_data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
gboolean eek_section_find(EekSection *section,
 | 
					gboolean eek_section_find(EekSection *section,
 | 
				
			||||||
                          const struct squeek_button *button) {
 | 
					                          struct squeek_button *button) {
 | 
				
			||||||
    EekSectionPrivate *priv = eek_section_get_instance_private (section);
 | 
					    EekSectionPrivate *priv = eek_section_get_instance_private (section);
 | 
				
			||||||
    return g_ptr_array_find(priv->buttons, button, NULL);
 | 
					    return squeek_row_contains(priv->row, button) != 0;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean button_has_key(gconstpointer buttonptr, gconstpointer keyptr) {
 | 
					 | 
				
			||||||
    const struct squeek_button *button = buttonptr;
 | 
					 | 
				
			||||||
    const struct squeek_key *key = keyptr;
 | 
					 | 
				
			||||||
    return squeek_button_has_key((struct squeek_button*)button, key) != 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct squeek_button *eek_section_find_key(EekSection *section,
 | 
					struct squeek_button *eek_section_find_key(EekSection *section,
 | 
				
			||||||
                                           const struct squeek_key *key) {
 | 
					                                           struct squeek_key *key) {
 | 
				
			||||||
    EekSectionPrivate *priv = eek_section_get_instance_private (section);
 | 
					    EekSectionPrivate *priv = eek_section_get_instance_private (section);
 | 
				
			||||||
    guint index;
 | 
					    return squeek_row_find_key(priv->row, key);
 | 
				
			||||||
    gboolean ret = g_ptr_array_find_with_equal_func(priv->buttons, key, button_has_key, &index);
 | 
					 | 
				
			||||||
    if (ret) {
 | 
					 | 
				
			||||||
        return g_ptr_array_index(priv->buttons, index);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return NULL;// TODO: store keys in locked_keys, pressed_keys
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -64,6 +64,8 @@ GType   eek_section_get_type             (void) G_GNUC_CONST;
 | 
				
			|||||||
void    eek_section_set_angle            (EekSection     *section,
 | 
					void    eek_section_set_angle            (EekSection     *section,
 | 
				
			||||||
                                          gint            angle);
 | 
					                                          gint            angle);
 | 
				
			||||||
gint    eek_section_get_angle            (EekSection     *section);
 | 
					gint    eek_section_get_angle            (EekSection     *section);
 | 
				
			||||||
 | 
					struct squeek_row *
 | 
				
			||||||
 | 
					eek_section_get_row (EekSection *section);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct squeek_button *eek_section_create_button (EekSection     *section,
 | 
					struct squeek_button *eek_section_create_button (EekSection     *section,
 | 
				
			||||||
                                          const gchar    *name,
 | 
					                                          const gchar    *name,
 | 
				
			||||||
@ -73,13 +75,13 @@ struct squeek_button *eek_section_create_button_with_state(EekSection *self,
 | 
				
			|||||||
                                    struct squeek_button *source);
 | 
					                                    struct squeek_button *source);
 | 
				
			||||||
void eek_section_place_keys              (EekSection     *section, LevelKeyboard *keyboard);
 | 
					void eek_section_place_keys              (EekSection     *section, LevelKeyboard *keyboard);
 | 
				
			||||||
void eek_section_foreach (EekSection *section,
 | 
					void eek_section_foreach (EekSection *section,
 | 
				
			||||||
                     GFunc      func,
 | 
					                     ButtonCallback func,
 | 
				
			||||||
                     gpointer   user_data);
 | 
					                     gpointer   user_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
gboolean eek_section_find(EekSection *section,
 | 
					gboolean eek_section_find(EekSection *section,
 | 
				
			||||||
                     const struct squeek_button *button);
 | 
					                     struct squeek_button *button);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct squeek_button *eek_section_find_key(EekSection *section,
 | 
					struct squeek_button *eek_section_find_key(EekSection *section,
 | 
				
			||||||
                                           const struct squeek_key *key);
 | 
					                                           struct squeek_key *key);
 | 
				
			||||||
G_END_DECLS
 | 
					G_END_DECLS
 | 
				
			||||||
#endif  /* EEK_SECTION_H */
 | 
					#endif  /* EEK_SECTION_H */
 | 
				
			||||||
 | 
				
			|||||||
@ -235,6 +235,7 @@ struct _GeometryParseData {
 | 
				
			|||||||
    EekKeyboard **views;
 | 
					    EekKeyboard **views;
 | 
				
			||||||
    guint view_idx;
 | 
					    guint view_idx;
 | 
				
			||||||
    EekSection *section;
 | 
					    EekSection *section;
 | 
				
			||||||
 | 
					    struct squeek_row *row;
 | 
				
			||||||
    gint num_rows;
 | 
					    gint num_rows;
 | 
				
			||||||
    EekOrientation orientation;
 | 
					    EekOrientation orientation;
 | 
				
			||||||
    gdouble corner_radius;
 | 
					    gdouble corner_radius;
 | 
				
			||||||
@ -375,6 +376,7 @@ geometry_start_element_callback (GMarkupParseContext *pcontext,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (g_strcmp0 (element_name, "section") == 0) {
 | 
					    if (g_strcmp0 (element_name, "section") == 0) {
 | 
				
			||||||
        data->section = eek_keyboard_real_create_section (data->views[data->view_idx]);
 | 
					        data->section = eek_keyboard_real_create_section (data->views[data->view_idx]);
 | 
				
			||||||
 | 
					        data->row = eek_section_get_row(data->section);
 | 
				
			||||||
        attribute = get_attribute (attribute_names, attribute_values,
 | 
					        attribute = get_attribute (attribute_names, attribute_values,
 | 
				
			||||||
                                   "id");
 | 
					                                   "id");
 | 
				
			||||||
        if (attribute != NULL)
 | 
					        if (attribute != NULL)
 | 
				
			||||||
@ -384,7 +386,7 @@ geometry_start_element_callback (GMarkupParseContext *pcontext,
 | 
				
			|||||||
        if (attribute != NULL) {
 | 
					        if (attribute != NULL) {
 | 
				
			||||||
            gint angle;
 | 
					            gint angle;
 | 
				
			||||||
            angle = strtol (attribute, NULL, 10);
 | 
					            angle = strtol (attribute, NULL, 10);
 | 
				
			||||||
            eek_section_set_angle (data->section, angle);
 | 
					            squeek_row_set_angle (data->row, angle);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        goto out;
 | 
					        goto out;
 | 
				
			||||||
@ -566,15 +568,12 @@ geometry_end_element_callback (GMarkupParseContext *pcontext,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                guint oref = GPOINTER_TO_UINT(g_hash_table_lookup(data->keyname_oref_hash, name));
 | 
					                guint oref = GPOINTER_TO_UINT(g_hash_table_lookup(data->keyname_oref_hash, name));
 | 
				
			||||||
                // default value gives idx 0, which is guaranteed to be occupied
 | 
					                // default value gives idx 0, which is guaranteed to be occupied
 | 
				
			||||||
                button = eek_section_create_button (data->section,
 | 
					                button = squeek_row_create_button (data->row, keycode, oref);
 | 
				
			||||||
                                                    name,
 | 
					 | 
				
			||||||
                                                    keycode,
 | 
					 | 
				
			||||||
                                              oref);
 | 
					 | 
				
			||||||
                g_hash_table_insert (data->name_button_hash,
 | 
					                g_hash_table_insert (data->name_button_hash,
 | 
				
			||||||
                                     g_strdup(name),
 | 
					                                     g_strdup(name),
 | 
				
			||||||
                                     button);
 | 
					                                     button);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                struct squeek_button *new_button = eek_section_create_button_with_state(data->section, name, button);
 | 
					                struct squeek_button *new_button = squeek_row_create_button_with_state(data->row, button);
 | 
				
			||||||
                if (!new_button) {
 | 
					                if (!new_button) {
 | 
				
			||||||
                    g_set_error (error,
 | 
					                    g_set_error (error,
 | 
				
			||||||
                                 G_MARKUP_ERROR,
 | 
					                                 G_MARKUP_ERROR,
 | 
				
			||||||
@ -586,6 +585,7 @@ geometry_end_element_callback (GMarkupParseContext *pcontext,
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data->section = NULL;
 | 
					        data->section = NULL;
 | 
				
			||||||
 | 
					        data->row = NULL;
 | 
				
			||||||
        data->num_rows = 0;
 | 
					        data->num_rows = 0;
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										141
									
								
								src/float_ord.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								src/float_ord.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,141 @@
 | 
				
			|||||||
 | 
					//! Order floating point numbers, into this ordering:
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//!    NaN | -Infinity | x < 0 | -0 | +0 | x > 0 | +Infinity | NaN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Adapted from https://github.com/notriddle/rust-float-ord revision e995165f
 | 
				
			||||||
 | 
					 * maintained by Michael Howell <michael@notriddle.com>
 | 
				
			||||||
 | 
					 * licensed under MIT / Apache-2.0 licenses
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern crate core;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use ::float_ord::core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
 | 
				
			||||||
 | 
					use ::float_ord::core::hash::{Hash, Hasher};
 | 
				
			||||||
 | 
					use ::float_ord::core::mem::transmute;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A wrapper for floats, that implements total equality and ordering
 | 
				
			||||||
 | 
					/// and hashing.
 | 
				
			||||||
 | 
					#[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					pub struct FloatOrd<T>(pub T);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! float_ord_impl {
 | 
				
			||||||
 | 
					    ($f:ident, $i:ident, $n:expr) => {
 | 
				
			||||||
 | 
					        impl FloatOrd<$f> {
 | 
				
			||||||
 | 
					            fn convert(self) -> $i {
 | 
				
			||||||
 | 
					                let u = unsafe { transmute::<$f, $i>(self.0) };
 | 
				
			||||||
 | 
					                let bit = 1 << ($n - 1);
 | 
				
			||||||
 | 
					                if u & bit == 0 {
 | 
				
			||||||
 | 
					                    u | bit
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    !u
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        impl PartialEq for FloatOrd<$f> {
 | 
				
			||||||
 | 
					            fn eq(&self, other: &Self) -> bool {
 | 
				
			||||||
 | 
					                self.convert() == other.convert()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        impl Eq for FloatOrd<$f> {}
 | 
				
			||||||
 | 
					        impl PartialOrd for FloatOrd<$f> {
 | 
				
			||||||
 | 
					            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
 | 
				
			||||||
 | 
					                self.convert().partial_cmp(&other.convert())
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        impl Ord for FloatOrd<$f> {
 | 
				
			||||||
 | 
					            fn cmp(&self, other: &Self) -> Ordering {
 | 
				
			||||||
 | 
					                self.convert().cmp(&other.convert())
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        impl Hash for FloatOrd<$f> {
 | 
				
			||||||
 | 
					            fn hash<H: Hasher>(&self, state: &mut H) {
 | 
				
			||||||
 | 
					                self.convert().hash(state);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float_ord_impl!(f32, u32, 32);
 | 
				
			||||||
 | 
					float_ord_impl!(f64, u64, 64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Sort a slice of floats.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Allocation behavior
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// This routine uses a quicksort implementation that does not heap allocate.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// # Example
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
 | 
					/// let mut v = [-5.0, 4.0, 1.0, -3.0, 2.0];
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// float_ord::sort(&mut v);
 | 
				
			||||||
 | 
					/// assert!(v == [-5.0, -3.0, 1.0, 2.0, 4.0]);
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
 | 
					#[allow(dead_code)]
 | 
				
			||||||
 | 
					pub fn sort<T>(v: &mut [T]) where FloatOrd<T>: Ord {
 | 
				
			||||||
 | 
					    let v_: &mut [FloatOrd<T>] = unsafe { transmute(v) };
 | 
				
			||||||
 | 
					    v_.sort_unstable();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod tests {
 | 
				
			||||||
 | 
					    extern crate std;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    use self::std::collections::hash_map::DefaultHasher;
 | 
				
			||||||
 | 
					    use self::std::hash::{Hash, Hasher};
 | 
				
			||||||
 | 
					    use super::FloatOrd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_ord() {
 | 
				
			||||||
 | 
					        assert!(FloatOrd(1.0f64) < FloatOrd(2.0f64));
 | 
				
			||||||
 | 
					        assert!(FloatOrd(2.0f32) > FloatOrd(1.0f32));
 | 
				
			||||||
 | 
					        assert!(FloatOrd(1.0f64) == FloatOrd(1.0f64));
 | 
				
			||||||
 | 
					        assert!(FloatOrd(1.0f32) == FloatOrd(1.0f32));
 | 
				
			||||||
 | 
					        assert!(FloatOrd(0.0f64) > FloatOrd(-0.0f64));
 | 
				
			||||||
 | 
					        assert!(FloatOrd(0.0f32) > FloatOrd(-0.0f32));
 | 
				
			||||||
 | 
					        assert!(FloatOrd(::float_ord::core::f64::NAN) == FloatOrd(::float_ord::core::f64::NAN));
 | 
				
			||||||
 | 
					        assert!(FloatOrd(::float_ord::core::f32::NAN) == FloatOrd(::float_ord::core::f32::NAN));
 | 
				
			||||||
 | 
					        assert!(FloatOrd(-::float_ord::core::f64::NAN) < FloatOrd(::float_ord::core::f64::NAN));
 | 
				
			||||||
 | 
					        assert!(FloatOrd(-::float_ord::core::f32::NAN) < FloatOrd(::float_ord::core::f32::NAN));
 | 
				
			||||||
 | 
					        assert!(FloatOrd(-::float_ord::core::f64::INFINITY) < FloatOrd(::float_ord::core::f64::INFINITY));
 | 
				
			||||||
 | 
					        assert!(FloatOrd(-::float_ord::core::f32::INFINITY) < FloatOrd(::float_ord::core::f32::INFINITY));
 | 
				
			||||||
 | 
					        assert!(FloatOrd(::float_ord::core::f64::INFINITY) < FloatOrd(::float_ord::core::f64::NAN));
 | 
				
			||||||
 | 
					        assert!(FloatOrd(::float_ord::core::f32::INFINITY) < FloatOrd(::float_ord::core::f32::NAN));
 | 
				
			||||||
 | 
					        assert!(FloatOrd(-::float_ord::core::f64::NAN) < FloatOrd(::float_ord::core::f64::INFINITY));
 | 
				
			||||||
 | 
					        assert!(FloatOrd(-::float_ord::core::f32::NAN) < FloatOrd(::float_ord::core::f32::INFINITY));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn hash<F: Hash>(f: F) -> u64 {
 | 
				
			||||||
 | 
					        let mut hasher = DefaultHasher::new();
 | 
				
			||||||
 | 
					        f.hash(&mut hasher);
 | 
				
			||||||
 | 
					        hasher.finish()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_hash() {
 | 
				
			||||||
 | 
					        assert_ne!(hash(FloatOrd(0.0f64)), hash(FloatOrd(-0.0f64)));
 | 
				
			||||||
 | 
					        assert_ne!(hash(FloatOrd(0.0f32)), hash(FloatOrd(-0.0f32)));
 | 
				
			||||||
 | 
					        assert_eq!(hash(FloatOrd(-0.0f64)), hash(FloatOrd(-0.0f64)));
 | 
				
			||||||
 | 
					        assert_eq!(hash(FloatOrd(0.0f32)), hash(FloatOrd(0.0f32)));
 | 
				
			||||||
 | 
					        assert_ne!(hash(FloatOrd(::float_ord::core::f64::NAN)), hash(FloatOrd(-::float_ord::core::f64::NAN)));
 | 
				
			||||||
 | 
					        assert_ne!(hash(FloatOrd(::float_ord::core::f32::NAN)), hash(FloatOrd(-::float_ord::core::f32::NAN)));
 | 
				
			||||||
 | 
					        assert_eq!(hash(FloatOrd(::float_ord::core::f64::NAN)), hash(FloatOrd(::float_ord::core::f64::NAN)));
 | 
				
			||||||
 | 
					        assert_eq!(hash(FloatOrd(-::float_ord::core::f32::NAN)), hash(FloatOrd(-::float_ord::core::f32::NAN)));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_sort_nan() {
 | 
				
			||||||
 | 
					        let nan = ::float_ord::core::f64::NAN;
 | 
				
			||||||
 | 
					        let mut v = [-1.0, 5.0, 0.0, -0.0, nan, 1.5, nan, 3.7];
 | 
				
			||||||
 | 
					        super::sort(&mut v);
 | 
				
			||||||
 | 
					        assert!(v[0] == -1.0);
 | 
				
			||||||
 | 
					        assert!(v[1] == 0.0 && v[1].is_sign_negative());
 | 
				
			||||||
 | 
					        assert!(v[2] == 0.0 && !v[2].is_sign_negative());
 | 
				
			||||||
 | 
					        assert!(v[3] == 1.5);
 | 
				
			||||||
 | 
					        assert!(v[4] == 3.7);
 | 
				
			||||||
 | 
					        assert!(v[5] == 5.0);
 | 
				
			||||||
 | 
					        assert!(v[6].is_nan());
 | 
				
			||||||
 | 
					        assert!(v[7].is_nan());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										28
									
								
								src/layout.h
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								src/layout.h
									
									
									
									
									
								
							@ -7,17 +7,28 @@
 | 
				
			|||||||
#include "src/keyboard.h"
 | 
					#include "src/keyboard.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct squeek_button;
 | 
					struct squeek_button;
 | 
				
			||||||
 | 
					struct squeek_row;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					struct squeek_row *squeek_row_new(int32_t angle);
 | 
				
			||||||
struct squeek_buttons;
 | 
					struct squeek_button *squeek_row_create_button (struct squeek_row *row,
 | 
				
			||||||
 | 
					                                          guint keycode, guint oref);
 | 
				
			||||||
 | 
					struct squeek_button *squeek_row_create_button_with_state(struct squeek_row *row,
 | 
				
			||||||
 | 
					                                    struct squeek_button *source);
 | 
				
			||||||
 | 
					void squeek_row_set_angle(struct squeek_row *row, int32_t angle);
 | 
				
			||||||
 | 
					int32_t squeek_row_get_angle(struct squeek_row*);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void (*ButtonCallback) (struct squeek_button *button, gpointer user_data);
 | 
					typedef void (*ButtonCallback) (struct squeek_button *button, gpointer user_data);
 | 
				
			||||||
 | 
					void squeek_row_foreach(struct squeek_row*,
 | 
				
			||||||
struct squeek_buttons *squeek_buttons_new();
 | 
					 | 
				
			||||||
void squeek_buttons_free(struct squeek_buttons*);
 | 
					 | 
				
			||||||
void squeek_buttons_foreach(const struct squeek_buttons*,
 | 
					 | 
				
			||||||
                            ButtonCallback   callback,
 | 
					                            ButtonCallback   callback,
 | 
				
			||||||
                            gpointer      user_data);
 | 
					                            gpointer      user_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void squeek_row_free(struct squeek_row*);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
struct squeek_button *squeek_buttons_find_by_position(
 | 
					struct squeek_button *squeek_buttons_find_by_position(
 | 
				
			||||||
    const struct squeek_buttons *buttons,
 | 
					    const struct squeek_buttons *buttons,
 | 
				
			||||||
    double x, double y,
 | 
					    double x, double y,
 | 
				
			||||||
@ -26,6 +37,7 @@ struct squeek_button *squeek_buttons_find_by_position(
 | 
				
			|||||||
void squeek_buttons_add(struct squeek_buttons*, const struct squeek_button* button);
 | 
					void squeek_buttons_add(struct squeek_buttons*, const struct squeek_button* button);
 | 
				
			||||||
void squeek_buttons_remove_key(struct squeek_buttons*, const struct squeek_key* key);
 | 
					void squeek_buttons_remove_key(struct squeek_buttons*, const struct squeek_key* key);
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct squeek_button *squeek_button_new(uint32_t keycode, uint32_t oref);
 | 
					struct squeek_button *squeek_button_new(uint32_t keycode, uint32_t oref);
 | 
				
			||||||
struct squeek_button *squeek_button_new_with_state(const struct squeek_button* source);
 | 
					struct squeek_button *squeek_button_new_with_state(const struct squeek_button* source);
 | 
				
			||||||
uint32_t squeek_button_get_oref(const struct squeek_button*);
 | 
					uint32_t squeek_button_get_oref(const struct squeek_button*);
 | 
				
			||||||
@ -37,4 +49,8 @@ struct squeek_symbol *squeek_button_get_symbol (
 | 
				
			|||||||
struct squeek_key *squeek_button_get_key(struct squeek_button*);
 | 
					struct squeek_key *squeek_button_get_key(struct squeek_button*);
 | 
				
			||||||
uint32_t *squeek_button_has_key(const struct squeek_button* button,
 | 
					uint32_t *squeek_button_has_key(const struct squeek_button* button,
 | 
				
			||||||
                                const struct squeek_key *key);
 | 
					                                const struct squeek_key *key);
 | 
				
			||||||
 | 
					void squeek_button_print(const struct squeek_button* button);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EekBounds squeek_row_place_keys(struct squeek_row *row, LevelKeyboard *keyboard);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										240
									
								
								src/layout.rs
									
									
									
									
									
								
							
							
						
						
									
										240
									
								
								src/layout.rs
									
									
									
									
									
								
							@ -1,25 +1,31 @@
 | 
				
			|||||||
use std::cell::RefCell;
 | 
					use std::cell::RefCell;
 | 
				
			||||||
use std::rc::Rc;
 | 
					use std::rc::Rc;
 | 
				
			||||||
 | 
					use std::vec::Vec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use ::symbol::*;
 | 
					 | 
				
			||||||
use ::keyboard::*;
 | 
					use ::keyboard::*;
 | 
				
			||||||
 | 
					use ::float_ord::FloatOrd;
 | 
				
			||||||
 | 
					use ::symbol::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Gathers stuff defined in C or called by C
 | 
					/// Gathers stuff defined in C or called by C
 | 
				
			||||||
pub mod c {
 | 
					pub mod c {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    use std::os::raw::c_void;
 | 
				
			||||||
    use std::ptr;
 | 
					    use std::ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // The following defined in C
 | 
					    // The following defined in C
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[repr(transparent)]
 | 
				
			||||||
 | 
					    pub struct UserData(*const c_void);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    /// The index in the relevant outline table
 | 
					    /// The index in the relevant outline table
 | 
				
			||||||
    #[repr(C)]
 | 
					    #[repr(C)]
 | 
				
			||||||
    #[derive(Clone)]
 | 
					    #[derive(Clone, Debug)]
 | 
				
			||||||
    pub struct OutlineRef(u32);
 | 
					    pub struct OutlineRef(u32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Defined in eek-types.h
 | 
					    /// Defined in eek-types.h
 | 
				
			||||||
    #[repr(C)]
 | 
					    #[repr(C)]
 | 
				
			||||||
    #[derive(Clone)]
 | 
					    #[derive(Clone, Debug)]
 | 
				
			||||||
    pub struct Bounds {
 | 
					    pub struct Bounds {
 | 
				
			||||||
        x: f64,
 | 
					        x: f64,
 | 
				
			||||||
        y: f64,
 | 
					        y: f64,
 | 
				
			||||||
@ -27,6 +33,114 @@ pub mod c {
 | 
				
			|||||||
        height: f64
 | 
					        height: f64
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    type ButtonCallback = unsafe extern "C" fn(button: *mut ::layout::Button, data: *mut UserData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_row_new(angle: i32) -> *mut ::layout::Row {
 | 
				
			||||||
 | 
					        Box::into_raw(Box::new(::layout::Row {
 | 
				
			||||||
 | 
					            buttons: Vec::new(),
 | 
				
			||||||
 | 
					            angle: angle,
 | 
				
			||||||
 | 
					        }))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /// Places a button into the row and returns a reference to it
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_row_create_button(
 | 
				
			||||||
 | 
					        row: *mut ::layout::Row,
 | 
				
			||||||
 | 
					        keycode: u32, oref: u32
 | 
				
			||||||
 | 
					    ) -> *mut ::layout::Button {
 | 
				
			||||||
 | 
					        let row = unsafe { &mut *row };
 | 
				
			||||||
 | 
					        let state: Rc<RefCell<::keyboard::KeyState>> = Rc::new(RefCell::new(
 | 
				
			||||||
 | 
					            ::keyboard::KeyState {
 | 
				
			||||||
 | 
					                pressed: false,
 | 
				
			||||||
 | 
					                locked: false,
 | 
				
			||||||
 | 
					                keycode: keycode,
 | 
				
			||||||
 | 
					                symbol: None,
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					        row.buttons.push(Box::new(::layout::Button {
 | 
				
			||||||
 | 
					            oref: OutlineRef(oref),
 | 
				
			||||||
 | 
					            bounds: None,
 | 
				
			||||||
 | 
					            state: state,
 | 
				
			||||||
 | 
					        }));
 | 
				
			||||||
 | 
					        // Return the reference directly instead of a Box, it's not on the stack
 | 
				
			||||||
 | 
					        // It will live as long as the Vec
 | 
				
			||||||
 | 
					        let last_idx = row.buttons.len() - 1;
 | 
				
			||||||
 | 
					        // Caution: Box can't be returned directly,
 | 
				
			||||||
 | 
					        // so returning a reference to its innards
 | 
				
			||||||
 | 
					        row.buttons[last_idx].as_mut() as *mut ::layout::Button
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /// Places a button into the row, copying its state,
 | 
				
			||||||
 | 
					    /// and returns a reference to it
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_row_create_button_with_state(
 | 
				
			||||||
 | 
					        row: *mut ::layout::Row,
 | 
				
			||||||
 | 
					        button: *const ::layout::Button,
 | 
				
			||||||
 | 
					    ) -> *mut ::layout::Button {
 | 
				
			||||||
 | 
					        let row = unsafe { &mut *row };
 | 
				
			||||||
 | 
					        let source = unsafe { &*button };
 | 
				
			||||||
 | 
					        row.buttons.push(Box::new(source.clone()));
 | 
				
			||||||
 | 
					        // Return the reference directly instead of a Box, it's not on the stack
 | 
				
			||||||
 | 
					        // It will live as long as the Vec
 | 
				
			||||||
 | 
					        let last_idx = row.buttons.len() - 1;
 | 
				
			||||||
 | 
					        // Caution: Box can't be returned directly,
 | 
				
			||||||
 | 
					        // so returning a reference to its innards directly
 | 
				
			||||||
 | 
					        row.buttons[last_idx].as_mut() as *mut ::layout::Button
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_row_set_angle(row: *mut ::layout::Row, angle: i32) {
 | 
				
			||||||
 | 
					        let row = unsafe { &mut *row };
 | 
				
			||||||
 | 
					        row.angle = angle;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_row_get_angle(row: *const ::layout::Row) -> i32 {
 | 
				
			||||||
 | 
					        let row = unsafe { &*row };
 | 
				
			||||||
 | 
					        row.angle
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_row_contains(
 | 
				
			||||||
 | 
					        row: *mut ::layout::Row,
 | 
				
			||||||
 | 
					        needle: *const ::layout::Button,
 | 
				
			||||||
 | 
					    ) -> u32 {
 | 
				
			||||||
 | 
					        let row = unsafe { &mut *row };
 | 
				
			||||||
 | 
					        row.buttons.iter().position(
 | 
				
			||||||
 | 
					            // TODO: wrap Button properly in Rc; this comparison is unreliable
 | 
				
			||||||
 | 
					            |button| button.as_ref() as *const ::layout::Button == needle
 | 
				
			||||||
 | 
					        ).is_some() as u32
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_row_foreach(
 | 
				
			||||||
 | 
					        row: *mut ::layout::Row,
 | 
				
			||||||
 | 
					        callback: ButtonCallback,
 | 
				
			||||||
 | 
					        data: *mut UserData,
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        let row = unsafe { &mut *row };
 | 
				
			||||||
 | 
					        for button in row.buttons.iter_mut() {
 | 
				
			||||||
 | 
					            let button = button.as_mut() as *mut ::layout::Button;
 | 
				
			||||||
 | 
					            unsafe { callback(button, data) };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_row_free(row: *mut ::layout::Row) {
 | 
				
			||||||
 | 
					        unsafe { Box::from_raw(row) }; // gets dropped
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_button_new(keycode: u32, oref: u32) -> *mut ::layout::Button {
 | 
					    fn squeek_button_new(keycode: u32, oref: u32) -> *mut ::layout::Button {
 | 
				
			||||||
@ -117,6 +231,108 @@ pub mod c {
 | 
				
			|||||||
        equal as u32
 | 
					        equal as u32
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_button_print(button: *const ::layout::Button) {
 | 
				
			||||||
 | 
					        let button = unsafe { &*button };
 | 
				
			||||||
 | 
					        println!("{:?}", button);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /// More complex procedures and algoithms which span multiple modules
 | 
				
			||||||
 | 
					    mod procedures {
 | 
				
			||||||
 | 
					        use super::*;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        use std::convert::TryFrom;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #[repr(transparent)]
 | 
				
			||||||
 | 
					        pub struct LevelKeyboard(*const c_void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #[no_mangle]
 | 
				
			||||||
 | 
					        extern "C" {
 | 
				
			||||||
 | 
					            fn eek_get_outline_size(
 | 
				
			||||||
 | 
					                keyboard: *const LevelKeyboard,
 | 
				
			||||||
 | 
					                outline: u32
 | 
				
			||||||
 | 
					            ) -> Bounds;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        const BUTTON_SPACING: f64 = 4.0;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        /// Places each button in order, starting from 0 on the left,
 | 
				
			||||||
 | 
					        /// keeping the spacing.
 | 
				
			||||||
 | 
					        /// Sizes each button according to outline dimensions.
 | 
				
			||||||
 | 
					        /// Returns the width and height of the resulting row.
 | 
				
			||||||
 | 
					        #[no_mangle]
 | 
				
			||||||
 | 
					        pub extern "C"
 | 
				
			||||||
 | 
					        fn squeek_row_place_keys(
 | 
				
			||||||
 | 
					            row: *mut ::layout::Row,
 | 
				
			||||||
 | 
					            keyboard: *const LevelKeyboard,
 | 
				
			||||||
 | 
					        ) -> Bounds {
 | 
				
			||||||
 | 
					            let row = unsafe { &mut *row };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Size buttons
 | 
				
			||||||
 | 
					            for mut button in &mut row.buttons {
 | 
				
			||||||
 | 
					                button.bounds = Some(
 | 
				
			||||||
 | 
					                    unsafe { eek_get_outline_size(keyboard, button.oref.0) }
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Place buttons
 | 
				
			||||||
 | 
					            let cumulative_width: f64 = row.buttons.iter().map(
 | 
				
			||||||
 | 
					                |button| button.bounds.as_ref().unwrap().width
 | 
				
			||||||
 | 
					            ).sum();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let max_height = row.buttons.iter().map(
 | 
				
			||||||
 | 
					                |button| FloatOrd(
 | 
				
			||||||
 | 
					                    button.bounds.as_ref().unwrap().height
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            ).max()
 | 
				
			||||||
 | 
					                .unwrap_or(FloatOrd(0f64))
 | 
				
			||||||
 | 
					                .0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            row.buttons.iter_mut().fold(0f64, |acc, button| {
 | 
				
			||||||
 | 
					                let mut bounds = button.bounds.as_mut().unwrap();
 | 
				
			||||||
 | 
					                bounds.x = acc;
 | 
				
			||||||
 | 
					                acc + bounds.width + BUTTON_SPACING
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            // Total size
 | 
				
			||||||
 | 
					            let total_width = match row.buttons.is_empty() {
 | 
				
			||||||
 | 
					                true => 0f64,
 | 
				
			||||||
 | 
					                false => {
 | 
				
			||||||
 | 
					                    let last_button = &row.buttons[row.buttons.len() - 1];
 | 
				
			||||||
 | 
					                    let bounds = last_button.bounds.as_ref().unwrap();
 | 
				
			||||||
 | 
					                    bounds.x + bounds.width
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Bounds {
 | 
				
			||||||
 | 
					                x: 0f64,
 | 
				
			||||||
 | 
					                y: 0f64,
 | 
				
			||||||
 | 
					                width: total_width,
 | 
				
			||||||
 | 
					                height: max_height,
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// 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(),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    #[cfg(test)]
 | 
					    #[cfg(test)]
 | 
				
			||||||
    mod test {
 | 
					    mod test {
 | 
				
			||||||
        use super::*;
 | 
					        use super::*;
 | 
				
			||||||
@ -133,11 +349,22 @@ pub mod c {
 | 
				
			|||||||
            let shared_button = squeek_button_new_with_state(button);
 | 
					            let shared_button = squeek_button_new_with_state(button);
 | 
				
			||||||
            assert_eq!(squeek_button_has_key(shared_button, state), 1);
 | 
					            assert_eq!(squeek_button_has_key(shared_button, state), 1);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        #[test]
 | 
				
			||||||
 | 
					        fn row_has_button() {
 | 
				
			||||||
 | 
					            let row = squeek_row_new(0);
 | 
				
			||||||
 | 
					            let button = squeek_row_create_button(row, 0, 0);
 | 
				
			||||||
 | 
					            assert_eq!(squeek_row_contains(row, button), 1);
 | 
				
			||||||
 | 
					            let shared_button = squeek_row_create_button_with_state(row, button);
 | 
				
			||||||
 | 
					            assert_eq!(squeek_row_contains(row, shared_button), 1);
 | 
				
			||||||
 | 
					            let row = squeek_row_new(0);
 | 
				
			||||||
 | 
					            assert_eq!(squeek_row_contains(row, button), 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The graphical representation of a button
 | 
					/// The graphical representation of a button
 | 
				
			||||||
#[derive(Clone)]
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
pub struct Button {
 | 
					pub struct Button {
 | 
				
			||||||
    oref: c::OutlineRef,
 | 
					    oref: c::OutlineRef,
 | 
				
			||||||
    /// TODO: abolish Option, buttons should be created with bounds fully formed
 | 
					    /// TODO: abolish Option, buttons should be created with bounds fully formed
 | 
				
			||||||
@ -145,3 +372,8 @@ pub struct Button {
 | 
				
			|||||||
    /// current state, shared with other buttons
 | 
					    /// current state, shared with other buttons
 | 
				
			||||||
    pub state: Rc<RefCell<KeyState>>,
 | 
					    pub state: Rc<RefCell<KeyState>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct Row {
 | 
				
			||||||
 | 
					    buttons: Vec<Box<Button>>,
 | 
				
			||||||
 | 
					    angle: i32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
#[macro_use]
 | 
					#[macro_use]
 | 
				
			||||||
mod bitflags;
 | 
					mod bitflags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod float_ord;
 | 
				
			||||||
mod imservice;
 | 
					mod imservice;
 | 
				
			||||||
mod keyboard;
 | 
					mod keyboard;
 | 
				
			||||||
mod layout;
 | 
					mod layout;
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ pub mod c {
 | 
				
			|||||||
    use std::os::raw::c_char;
 | 
					    use std::os::raw::c_char;
 | 
				
			||||||
    use std::str::Utf8Error;
 | 
					    use std::str::Utf8Error;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    #[allow(dead_code)]
 | 
				
			||||||
    pub fn as_str(s: &*const c_char) -> Result<Option<&str>, Utf8Error> {
 | 
					    pub fn as_str(s: &*const c_char) -> Result<Option<&str>, Utf8Error> {
 | 
				
			||||||
        if s.is_null() {
 | 
					        if s.is_null() {
 | 
				
			||||||
            Ok(None)
 | 
					            Ok(None)
 | 
				
			||||||
 | 
				
			|||||||
@ -31,9 +31,11 @@ test_create (void)
 | 
				
			|||||||
    keyboard = g_object_new (EEK_TYPE_KEYBOARD, NULL);
 | 
					    keyboard = g_object_new (EEK_TYPE_KEYBOARD, NULL);
 | 
				
			||||||
    section = eek_keyboard_real_create_section (keyboard);
 | 
					    section = eek_keyboard_real_create_section (keyboard);
 | 
				
			||||||
    g_assert (EEK_IS_SECTION(section));
 | 
					    g_assert (EEK_IS_SECTION(section));
 | 
				
			||||||
    button0 = eek_section_create_button (section, "key0", 1, 0);
 | 
					    struct squeek_row *row = eek_section_get_row(section);
 | 
				
			||||||
 | 
					    g_assert (row);
 | 
				
			||||||
 | 
					    button0 = squeek_row_create_button (row, 1, 0);
 | 
				
			||||||
    g_assert (button0);
 | 
					    g_assert (button0);
 | 
				
			||||||
    button1 = eek_section_create_button (section, "key1", 2, 0);
 | 
					    button1 = squeek_row_create_button (row, 2, 0);
 | 
				
			||||||
    g_assert (button1);
 | 
					    g_assert (button1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user