diff --git a/data/keyboards/geometry/compact.xml b/data/keyboards/geometry/compact.xml index a468adde..e4a9ec5c 100644 --- a/data/keyboards/geometry/compact.xml +++ b/data/keyboards/geometry/compact.xml @@ -1,102 +1,11 @@ - +
- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -125,20 +34,11 @@ - - - - - - - - - +
+
+ - - - @@ -166,18 +66,12 @@ - - - - - - - - - +
+
+ - + @@ -201,113 +95,95 @@ - - - - - - - - - - - + + +
+
+ - - - - + - + - + - - + + - - - - - - - - - - - + +
- - + + - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - - - + + +
diff --git a/data/themes/default.css b/data/themes/default.css index 2a106bb2..15875d54 100644 --- a/data/themes/default.css +++ b/data/themes/default.css @@ -5,18 +5,14 @@ } .key { - color: #ffffff; - background-gradient-direction: vertical; - background-gradient-start: rgba(0, 0, 0, 255); - background-gradient-end: rgba(64, 64, 64, 255); - border-width: 2px; - border-color: rgba(128, 128, 128, 255); - border-radius: 3px; + color: #deddda; + background: #464448; + border-width: 0.5px; + border-color: #5e5c64; + border-radius: 2px; } .key:active { - background-gradient-direction: vertical; - background-gradient-start: rgba(0, 0, 255, 255); - background-gradient-end: rgba(64, 64, 255, 255); - border-color: rgba(160, 160, 255, 255); + background: #1c71d8; + border-color: #3584e4; } diff --git a/eek/eek-key.c b/eek/eek-key.c index f58da112..a3cada98 100644 --- a/eek/eek-key.c +++ b/eek/eek-key.c @@ -66,7 +66,7 @@ struct _EekKeyPrivate EekSymbolMatrix *symbol_matrix; gint column; gint row; - gulong oref; + gulong oref; // UI outline reference gboolean is_pressed; gboolean is_locked; }; diff --git a/eek/eek-keyboard-drawing.c b/eek/eek-keyboard-drawing.c index bc01d607..1ead5de2 100644 --- a/eek/eek-keyboard-drawing.c +++ b/eek/eek-keyboard-drawing.c @@ -199,32 +199,21 @@ void _eek_rounded_polygon (cairo_t *cr, gdouble radius, EekPoint *points, - gint num_points) + guint num_points) { - gint i, j; - cairo_move_to (cr, (gdouble) (points[num_points - 1].x + points[0].x) / 2, (gdouble) (points[num_points - 1].y + points[0].y) / 2); - -#ifdef KBDRAW_DEBUG - printf (" rounded polygon of radius %f:\n", radius); -#endif - for (i = 0; i < num_points; i++) { - j = (i + 1) % num_points; + for (guint i = 0; i < num_points; i++) { + guint j = (i + 1) % num_points; rounded_corner (cr, (gdouble) points[i].x, (gdouble) points[i].y, (gdouble) (points[i].x + points[j].x) / 2, (gdouble) (points[i].y + points[j].y) / 2, radius); -#ifdef KBDRAW_DEBUG - printf (" corner (%d, %d) -> (%d, %d):\n", - points[i].x, points[i].y, points[j].x, - points[j].y); -#endif - }; + } cairo_close_path (cr); } diff --git a/eek/eek-keyboard.h b/eek/eek-keyboard.h index 8759f077..afe72c27 100644 --- a/eek/eek-keyboard.h +++ b/eek/eek-keyboard.h @@ -48,6 +48,8 @@ typedef struct _EekKeyboardPrivate EekKeyboardPrivate; * * Contains the state of the physical keyboard. * + * Is also a graphical element... + * * The #EekKeyboard structure contains only private data and should * only be accessed using the provided API. */ diff --git a/eek/eek-renderer.c b/eek/eek-renderer.c index 546cc006..9a925b7e 100644 --- a/eek/eek-renderer.c +++ b/eek/eek-renderer.c @@ -79,7 +79,7 @@ typedef struct _TextProperty TextProperty; extern void _eek_rounded_polygon (cairo_t *cr, gdouble radius, EekPoint *points, - gint num_points); + guint num_points); static void eek_renderer_real_render_key_label (EekRenderer *self, PangoLayout *layout, @@ -116,8 +116,8 @@ create_keyboard_surface_key_callback (EekElement *element, cairo_rectangle (data->cr, 0.0, 0.0, - bounds.width * priv->scale, - bounds.height * priv->scale); + bounds.width * priv->scale + 100, + bounds.height * priv->scale + 100); cairo_clip (data->cr); render_key (data->renderer, data->cr, EEK_KEY(element), FALSE); @@ -205,8 +205,6 @@ render_key_outline (EekRenderer *renderer, EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(renderer); EekOutline *outline; EekBounds bounds; - gdouble scale; - gint i; guint oref; EekThemeNode *theme_node; EekColor foreground, background, gradient_start, gradient_end, border_color; @@ -233,14 +231,14 @@ render_key_outline (EekRenderer *renderer, border_width = eek_theme_node_get_border_width (theme_node, EEK_SIDE_TOP); border_radius = eek_theme_node_get_border_radius (theme_node, - EEK_SIDE_TOP); + EEK_CORNER_TOPLEFT); eek_theme_node_get_border_color (theme_node, EEK_SIDE_TOP, &border_color); } else { foreground = priv->default_foreground_color; background = priv->default_background_color; gradient_type = EEK_GRADIENT_NONE; - border_width = priv->border_width; + border_width = (gint)round(priv->border_width); border_radius = -1; border_color.red = ABS(background.red - foreground.red) * 0.7; border_color.green = ABS(background.green - foreground.green) * 0.7; @@ -248,21 +246,15 @@ render_key_outline (EekRenderer *renderer, border_color.alpha = foreground.alpha; } - /* need to rescale so that the border fit inside the clipping - region */ - eek_element_get_bounds (EEK_ELEMENT(key), &bounds); - scale = MIN((bounds.width - border_width * 2) / bounds.width, - (bounds.height - border_width * 2) / bounds.height); - outline = eek_outline_copy (outline); - for (i = 0; i < outline->num_points; i++) { - outline->points[i].x *= priv->scale * scale; - outline->points[i].y *= priv->scale * scale; + for (guint i = 0; i < outline->num_points; i++) { + outline->points[i].x *= priv->scale; + outline->points[i].y *= priv->scale; } cairo_translate (cr, - border_width * priv->scale * scale, - border_width * priv->scale * scale); + border_width * priv->scale, + border_width * priv->scale); if (gradient_type != EEK_GRADIENT_NONE) { cairo_pattern_t *pat; @@ -340,6 +332,10 @@ render_key_outline (EekRenderer *renderer, outline->num_points); cairo_stroke (cr); + cairo_translate (cr, + -border_width * priv->scale, + -border_width * priv->scale); + eek_outline_free (outline); } @@ -464,10 +460,11 @@ render_key (EekRenderer *self, if (!outline_surface) { cairo_t *cr; + // Outline will be drawn on the outside of the button, so the surface needs to be bigger than the button outline_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - bounds.width, - bounds.height); + (int)ceil(bounds.width) + 10, + (int)ceil(bounds.height) + 10); cr = cairo_create (outline_surface); /* blank background */ diff --git a/eek/eek-section.c b/eek/eek-section.c index cec1fd99..9c6a2f5a 100644 --- a/eek/eek-section.c +++ b/eek/eek-section.c @@ -129,7 +129,7 @@ static EekKey * eek_section_real_create_key (EekSection *self, guint keycode, gint column_index, - gint row_index) + guint row_index) { EekKey *key; gint num_rows; @@ -479,3 +479,80 @@ eek_section_create_key (EekSection *section, column, row); } + +static void keysizer(EekElement *element, gpointer user_data) { + EekKey *key = EEK_KEY(element); + EekKeyboard *keyboard = EEK_KEYBOARD(user_data); + uint oref = eek_key_get_oref (key); + EekOutline *outline = eek_keyboard_get_outline (keyboard, oref); + if (outline && outline->num_points > 0) { + double minx = outline->points[0].x; + double maxx = minx; + double miny = outline->points[0].y; + double maxy = miny; + for (uint i = 1; i < outline->num_points; i++) { + EekPoint p = outline->points[i]; + if (p.x < minx) { + minx = p.x; + } else if (p.x > maxx) { + maxx = p.x; + } + + if (p.y < miny) { + miny = p.y; + } else if (p.y > maxy) { + maxy = p.y; + } + } + EekBounds key_bounds = {0}; + eek_element_get_bounds(element, &key_bounds); + key_bounds.height = maxy - miny; + key_bounds.width = maxx - minx; + eek_element_set_bounds(element, &key_bounds); + } +} + +struct keys_info { + uint count; + double total_width; + double biggest_height; +}; + +static void keycounter (EekElement *element, gpointer user_data) { + struct keys_info *data = user_data; + data->count++; + EekBounds key_bounds = {0}; + eek_element_get_bounds(element, &key_bounds); + data->total_width += key_bounds.width; + if (key_bounds.height > data->biggest_height) { + data->biggest_height = key_bounds.height; + } +} + +const double keyspacing = 3.0; + +static void keyplacer(EekElement *element, gpointer user_data) { + double *current_offset = user_data; + EekBounds key_bounds = {0}; + eek_element_get_bounds(element, &key_bounds); + key_bounds.x = *current_offset; + key_bounds.y = 0; + eek_element_set_bounds(element, &key_bounds); + *current_offset += key_bounds.width + keyspacing; +} + +void eek_section_place_keys(EekSection *section, EekKeyboard *keyboard) +{ + eek_container_foreach_child(EEK_CONTAINER(section), keysizer, keyboard); + + struct keys_info keyinfo = {0}; + eek_container_foreach_child(EEK_CONTAINER(section), keycounter, &keyinfo); + EekBounds section_bounds = {0}; + eek_element_get_bounds(EEK_ELEMENT(section), §ion_bounds); + + double key_offset = (section_bounds.width - (keyinfo.total_width + (keyinfo.count - 1) * keyspacing)) / 2; + eek_container_foreach_child(EEK_CONTAINER(section), keyplacer, &key_offset); + + section_bounds.height = keyinfo.biggest_height; + eek_element_set_bounds(EEK_ELEMENT(section), §ion_bounds); +} diff --git a/eek/eek-section.h b/eek/eek-section.h index 6392cdb2..77694a49 100644 --- a/eek/eek-section.h +++ b/eek/eek-section.h @@ -127,5 +127,7 @@ EekKey *eek_section_create_key (EekSection *section, EekKey *eek_section_find_key_by_keycode (EekSection *section, guint keycode); +void eek_section_place_keys (EekSection *section, EekKeyboard *keyboard); + G_END_DECLS #endif /* EEK_SECTION_H */ diff --git a/eek/eek-types.h b/eek/eek-types.h index 5bf73aec..015b9a90 100644 --- a/eek/eek-types.h +++ b/eek/eek-types.h @@ -214,7 +214,7 @@ struct _EekOutline /*< public >*/ gdouble corner_radius; EekPoint *points; - gint num_points; + guint num_points; }; GType eek_outline_get_type (void) G_GNUC_CONST; diff --git a/eek/eek-xml-layout.c b/eek/eek-xml-layout.c index ccee00be..1dc59783 100644 --- a/eek/eek-xml-layout.c +++ b/eek/eek-xml-layout.c @@ -362,9 +362,6 @@ geometry_start_element_callback (GMarkupParseContext *pcontext, eek_element_set_bounds (EEK_ELEMENT(data->keyboard), &bounds); else if (g_strcmp0 (data->element_stack->data, "section") == 0) eek_element_set_bounds (EEK_ELEMENT(data->section), &bounds); - else if (g_strcmp0 (data->element_stack->data, "key") == 0) - eek_element_set_bounds (EEK_ELEMENT(data->key), &bounds); - goto out; } @@ -504,7 +501,6 @@ geometry_end_element_callback (GMarkupParseContext *pcontext, { GeometryParseData *data = user_data; GSList *head = data->element_stack; - gint i; g_free (head->data); data->element_stack = g_slist_next (data->element_stack); @@ -536,7 +532,8 @@ geometry_end_element_callback (GMarkupParseContext *pcontext, outline->num_points = g_slist_length (data->points); outline->points = g_slice_alloc0 (sizeof (EekPoint) * outline->num_points); - for (head = data->points = g_slist_reverse (data->points), i = 0; + guint i; + for (i = 0, head = data->points = g_slist_reverse (data->points); head && i < outline->num_points; head = g_slist_next (head), i++) { memcpy (&outline->points[i], head->data, sizeof (EekPoint)); @@ -640,13 +637,13 @@ symbols_start_element_callback (GMarkupParseContext *pcontext, data->key = eek_keyboard_find_key_by_keycode (data->keyboard, keycode); - if (data->key == NULL) { + /*if (data->key == NULL) { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "no such keycode %u", keycode); return; - } + }*/ attribute = get_attribute (attribute_names, attribute_values, "groups"); @@ -721,6 +718,10 @@ symbols_end_element_callback (GMarkupParseContext *pcontext, text = g_strndup (data->text->str, data->text->len); if (g_strcmp0 (element_name, "key") == 0) { + if (!data->key) { + return; + } + gint num_symbols = g_slist_length (data->symbols); gint levels = num_symbols / data->groups; EekSymbolMatrix *matrix = eek_symbol_matrix_new (data->groups, @@ -1132,6 +1133,38 @@ eek_xml_keyboard_desc_free (EekXmlKeyboardDesc *desc) g_slice_free (EekXmlKeyboardDesc, desc); } +struct place_data { + double desired_width; + double current_offset; + EekKeyboard *keyboard; +}; + +const double section_spacing = 7.0; + +static void section_placer(EekElement *element, gpointer user_data) { + struct place_data *data = (struct place_data*)user_data; + + EekBounds section_bounds = {0}; + eek_element_get_bounds(element, §ion_bounds); + section_bounds.width = data->desired_width; + eek_element_set_bounds(element, §ion_bounds); + + // Sections are rows now. Gather up all the keys and adjust their bounds. + eek_section_place_keys(EEK_SECTION(element), EEK_KEYBOARD(data->keyboard)); + + eek_element_get_bounds(element, §ion_bounds); + section_bounds.y = data->current_offset; + eek_element_set_bounds(element, §ion_bounds); + data->current_offset += section_bounds.height + section_spacing; +} + +static void section_counter(EekElement *element, gpointer user_data) { + double *total_height = user_data; + EekBounds section_bounds = {0}; + eek_element_get_bounds(element, §ion_bounds); + *total_height += section_bounds.height + section_spacing; +} + static gboolean parse_geometry (const gchar *path, EekKeyboard *keyboard, GError **error) { @@ -1184,6 +1217,27 @@ parse_geometry (const gchar *path, EekKeyboard *keyboard, GError **error) } g_hash_table_destroy (oref_hash); + /* Order rows */ + // This needs to be done after outlines, because outlines define key sizes + // TODO: do this only for rows without bounds + + // The keyboard width is given by the user via screen size. The height will be given dynamically. + // TODO: calculate max line width beforehand for button centering. Leave keyboard centering to the renderer later + EekBounds keyboard_bounds = {0}; + eek_element_get_bounds(EEK_ELEMENT(keyboard), &keyboard_bounds); + + struct place_data placer_data = { + .desired_width = keyboard_bounds.width, + .current_offset = 0, + .keyboard = keyboard, + }; + eek_container_foreach_child(EEK_CONTAINER(keyboard), section_placer, &placer_data); + + double total_height = 0; + eek_container_foreach_child(EEK_CONTAINER(keyboard), section_counter, &total_height); + keyboard_bounds.height = total_height; + eek_element_set_bounds(EEK_ELEMENT(keyboard), &keyboard_bounds); + geometry_parse_data_free (data); return TRUE; } diff --git a/eekboard/eekboard-context-service.c b/eekboard/eekboard-context-service.c index 18a9e162..16336818 100644 --- a/eekboard/eekboard-context-service.c +++ b/eekboard/eekboard-context-service.c @@ -136,6 +136,9 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self, } } keyboard = eek_keyboard_new (self, layout, CSW, CSH); + if (!keyboard) { + g_error("Failed to create a keyboard"); + } g_object_unref (layout); struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);