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