Merge branch 'drop_key' into 'master'
Simplify renderer See merge request Librem5/squeekboard!272
This commit is contained in:
		
							
								
								
									
										3
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -324,6 +324,9 @@ name = "rs"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "cairo-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "cairo-sys-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "gdk 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "gio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "glib 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								Cargo.toml
									
									
									
									
									
								
							@ -11,6 +11,15 @@ serde = { version = "1.0.*", features = ["derive"] }
 | 
			
		||||
serde_yaml = "0.8.*"
 | 
			
		||||
xkbcommon = { version = "0.4.*", features = ["wayland"] }
 | 
			
		||||
 | 
			
		||||
[dependencies.cairo-rs]
 | 
			
		||||
version = "0.5.*"
 | 
			
		||||
 | 
			
		||||
[dependencies.cairo-sys-rs]
 | 
			
		||||
version = ""
 | 
			
		||||
 | 
			
		||||
[dependencies.gdk]
 | 
			
		||||
version = ""
 | 
			
		||||
 | 
			
		||||
[dependencies.gio]
 | 
			
		||||
version = ""
 | 
			
		||||
features = ["v2_44"]
 | 
			
		||||
@ -23,7 +32,6 @@ features = ["v2_44"]
 | 
			
		||||
version = ""
 | 
			
		||||
features = ["v2_44"]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[dependencies.gtk]
 | 
			
		||||
version = "0.5.*"
 | 
			
		||||
features = ["v3_22"]
 | 
			
		||||
 | 
			
		||||
@ -61,10 +61,6 @@ typedef struct _EekGtkKeyboardPrivate
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE_WITH_PRIVATE (EekGtkKeyboard, eek_gtk_keyboard, GTK_TYPE_DRAWING_AREA)
 | 
			
		||||
 | 
			
		||||
static void       render_pressed_button      (GtkWidget *widget, struct button_place *place);
 | 
			
		||||
static void       render_released_button     (GtkWidget *widget,
 | 
			
		||||
                                              const struct squeek_button *button);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_gtk_keyboard_real_realize (GtkWidget      *self)
 | 
			
		||||
{
 | 
			
		||||
@ -85,7 +81,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
 | 
			
		||||
                            cairo_t   *cr)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboardPrivate *priv =
 | 
			
		||||
	    eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
 | 
			
		||||
        eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
 | 
			
		||||
    GtkAllocation allocation;
 | 
			
		||||
    gtk_widget_get_allocation (self, &allocation);
 | 
			
		||||
 | 
			
		||||
@ -101,10 +97,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
 | 
			
		||||
                                       gtk_widget_get_scale_factor (self));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // render the keyboard without any key activity (TODO: from a cached buffer)
 | 
			
		||||
    eek_renderer_render_keyboard (priv->renderer, cr);
 | 
			
		||||
    // render only a few remaining changes
 | 
			
		||||
    squeek_layout_draw_all_changed(priv->keyboard->layout, EEK_GTK_KEYBOARD(self));
 | 
			
		||||
    return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -113,7 +106,7 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget     *self,
 | 
			
		||||
                                     GtkAllocation *allocation)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboardPrivate *priv =
 | 
			
		||||
	    eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
 | 
			
		||||
        eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
 | 
			
		||||
 | 
			
		||||
    if (priv->renderer)
 | 
			
		||||
        eek_renderer_set_allocation_size (priv->renderer,
 | 
			
		||||
@ -158,8 +151,6 @@ eek_gtk_keyboard_real_button_press_event (GtkWidget      *self,
 | 
			
		||||
    return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// TODO: this belongs more in gtk_keyboard, with a way to find out which key to re-render
 | 
			
		||||
static gboolean
 | 
			
		||||
eek_gtk_keyboard_real_button_release_event (GtkWidget      *self,
 | 
			
		||||
@ -231,7 +222,7 @@ static void
 | 
			
		||||
eek_gtk_keyboard_real_unmap (GtkWidget *self)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboardPrivate *priv =
 | 
			
		||||
	    eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
 | 
			
		||||
        eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
 | 
			
		||||
 | 
			
		||||
    if (priv->keyboard) {
 | 
			
		||||
        squeek_layout_release_all_only(
 | 
			
		||||
@ -248,6 +239,7 @@ eek_gtk_keyboard_set_property (GObject      *object,
 | 
			
		||||
                               const GValue *value,
 | 
			
		||||
                               GParamSpec   *pspec)
 | 
			
		||||
{
 | 
			
		||||
    (void)value;
 | 
			
		||||
    switch (prop_id) {
 | 
			
		||||
    default:
 | 
			
		||||
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
@ -304,7 +296,9 @@ eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass)
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_gtk_keyboard_init (EekGtkKeyboard *self)
 | 
			
		||||
{}
 | 
			
		||||
{
 | 
			
		||||
    (void)self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * eek_gtk_keyboard_new:
 | 
			
		||||
@ -322,110 +316,7 @@ eek_gtk_keyboard_new (LevelKeyboard *keyboard)
 | 
			
		||||
    return GTK_WIDGET(ret);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
render_pressed_button (GtkWidget *widget,
 | 
			
		||||
                       struct button_place *place)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboard        *self = EEK_GTK_KEYBOARD (widget);
 | 
			
		||||
EekRenderer *eek_gtk_keyboard_get_renderer(EekGtkKeyboard *self) {
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
    GdkWindow         *window  = gtk_widget_get_window (widget);
 | 
			
		||||
    cairo_region_t    *region  = gdk_window_get_clip_region (window);
 | 
			
		||||
    GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region);
 | 
			
		||||
    cairo_t           *cr      = gdk_drawing_context_get_cairo_context (context);
 | 
			
		||||
 | 
			
		||||
    eek_renderer_render_button (priv->renderer, cr, place, 1.0, TRUE);
 | 
			
		||||
/*
 | 
			
		||||
    eek_renderer_render_key (priv->renderer, cr, key, 1.5, TRUE);
 | 
			
		||||
*/
 | 
			
		||||
    gdk_window_end_draw_frame (window, context);
 | 
			
		||||
 | 
			
		||||
    cairo_region_destroy (region);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eek_gtk_render_locked_button (EekGtkKeyboard *self, struct button_place place)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
    GdkWindow         *window  = gtk_widget_get_window (GTK_WIDGET(self));
 | 
			
		||||
    cairo_region_t    *region  = gdk_window_get_clip_region (window);
 | 
			
		||||
    GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region);
 | 
			
		||||
    cairo_t           *cr      = gdk_drawing_context_get_cairo_context (context);
 | 
			
		||||
 | 
			
		||||
    eek_renderer_render_button (priv->renderer, cr, &place, 1.0, TRUE);
 | 
			
		||||
 | 
			
		||||
    gdk_window_end_draw_frame (window, context);
 | 
			
		||||
 | 
			
		||||
    cairo_region_destroy (region);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: does it really redraw the entire keyboard?
 | 
			
		||||
static void
 | 
			
		||||
render_released_button (GtkWidget *widget,
 | 
			
		||||
                        const struct squeek_button *button)
 | 
			
		||||
{
 | 
			
		||||
    (void)button;
 | 
			
		||||
    EekGtkKeyboard        *self = EEK_GTK_KEYBOARD (widget);
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
    GdkWindow         *window  = gtk_widget_get_window (widget);
 | 
			
		||||
    cairo_region_t    *region  = gdk_window_get_clip_region (window);
 | 
			
		||||
    GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region);
 | 
			
		||||
    cairo_t           *cr      = gdk_drawing_context_get_cairo_context (context);
 | 
			
		||||
 | 
			
		||||
    eek_renderer_render_keyboard (priv->renderer, cr);
 | 
			
		||||
 | 
			
		||||
    gdk_window_end_draw_frame (window, context);
 | 
			
		||||
 | 
			
		||||
    cairo_region_destroy (region);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eek_gtk_on_button_pressed (struct button_place place,
 | 
			
		||||
                   EekGtkKeyboard *self)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
    /* renderer may have not been set yet if the widget is a popup */
 | 
			
		||||
    if (!priv->renderer)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (!place.row) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    render_pressed_button (GTK_WIDGET(self), &place);
 | 
			
		||||
    gtk_widget_queue_draw (GTK_WIDGET(self));
 | 
			
		||||
 | 
			
		||||
#if HAVE_LIBCANBERRA
 | 
			
		||||
    ca_gtk_play_for_widget (widget, 0,
 | 
			
		||||
                            CA_PROP_EVENT_ID, "button-pressed",
 | 
			
		||||
                            CA_PROP_EVENT_DESCRIPTION, "virtual key pressed",
 | 
			
		||||
                            CA_PROP_APPLICATION_ID, "org.fedorahosted.Eekboard",
 | 
			
		||||
                            NULL);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eek_gtk_on_button_released (const struct squeek_button *button,
 | 
			
		||||
                    struct squeek_view *view,
 | 
			
		||||
                    EekGtkKeyboard *self)
 | 
			
		||||
{
 | 
			
		||||
    (void)view;
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
    /* renderer may have not been set yet if the widget is a popup */
 | 
			
		||||
    if (!priv->renderer)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    render_released_button (GTK_WIDGET(self), button);
 | 
			
		||||
    gtk_widget_queue_draw (GTK_WIDGET(self));
 | 
			
		||||
 | 
			
		||||
#if HAVE_LIBCANBERRA
 | 
			
		||||
    ca_gtk_play_for_widget (widget, 0,
 | 
			
		||||
                            CA_PROP_EVENT_ID, "button-released",
 | 
			
		||||
                            CA_PROP_EVENT_DESCRIPTION, "virtual key pressed",
 | 
			
		||||
                            CA_PROP_APPLICATION_ID, "org.fedorahosted.Eekboard",
 | 
			
		||||
                            NULL);
 | 
			
		||||
#endif
 | 
			
		||||
    return priv->renderer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -34,8 +34,6 @@
 | 
			
		||||
#include "eekboard/eekboard-context-service.h"
 | 
			
		||||
#include "eekboard/key-emitter.h"
 | 
			
		||||
#include "keymap.h"
 | 
			
		||||
#include "src/keyboard.h"
 | 
			
		||||
 | 
			
		||||
#include "eek-keyboard.h"
 | 
			
		||||
 | 
			
		||||
void level_keyboard_deinit(LevelKeyboard *self) {
 | 
			
		||||
@ -59,8 +57,3 @@ LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek
 | 
			
		||||
    keyboard->manager = manager;
 | 
			
		||||
    return keyboard;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct squeek_view *level_keyboard_current(LevelKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
    return squeek_layout_get_current_view(keyboard->layout);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -49,7 +49,6 @@ typedef struct _LevelKeyboard LevelKeyboard;
 | 
			
		||||
gchar *             eek_keyboard_get_keymap
 | 
			
		||||
                                     (LevelKeyboard *keyboard);
 | 
			
		||||
 | 
			
		||||
struct squeek_view *level_keyboard_current(LevelKeyboard *keyboard);
 | 
			
		||||
LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_layout *layout);
 | 
			
		||||
void level_keyboard_deinit(LevelKeyboard *self);
 | 
			
		||||
void level_keyboard_free(LevelKeyboard *self);
 | 
			
		||||
 | 
			
		||||
@ -42,17 +42,14 @@ typedef struct _EekRendererPrivate
 | 
			
		||||
    GtkStyleContext *view_context; // owned
 | 
			
		||||
    GtkStyleContext *button_context; // TODO: maybe move a copy to each button
 | 
			
		||||
 | 
			
		||||
    gdouble border_width;
 | 
			
		||||
    gdouble border_width; // FIXME: border of what?
 | 
			
		||||
 | 
			
		||||
    gdouble allocation_width;
 | 
			
		||||
    gdouble allocation_height;
 | 
			
		||||
    gdouble scale;
 | 
			
		||||
    gint scale_factor; /* the outputs scale factor */
 | 
			
		||||
    gint origin_x;
 | 
			
		||||
    gint origin_y;
 | 
			
		||||
    struct transformation widget_to_layout;
 | 
			
		||||
 | 
			
		||||
    PangoFontDescription *font; // owned reference
 | 
			
		||||
    cairo_surface_t *keyboard_surface;
 | 
			
		||||
 | 
			
		||||
} EekRendererPrivate;
 | 
			
		||||
 | 
			
		||||
@ -62,110 +59,10 @@ G_DEFINE_TYPE_WITH_PRIVATE (EekRenderer, eek_renderer, G_TYPE_OBJECT)
 | 
			
		||||
static void eek_renderer_render_button_label (EekRenderer *self, cairo_t *cr, GtkStyleContext *ctx,
 | 
			
		||||
                                                const struct squeek_button *button);
 | 
			
		||||
 | 
			
		||||
static void invalidate                         (EekRenderer *renderer);
 | 
			
		||||
static void render_button                         (EekRenderer *self,
 | 
			
		||||
                                                cairo_t     *cr, EekBounds view_bounds, struct button_place *place,
 | 
			
		||||
void eek_render_button                         (EekRenderer *self,
 | 
			
		||||
                                                cairo_t     *cr, const struct squeek_button *button,
 | 
			
		||||
                                                gboolean     pressed, gboolean locked);
 | 
			
		||||
 | 
			
		||||
struct _CreateKeyboardSurfaceCallbackData {
 | 
			
		||||
    cairo_t *cr;
 | 
			
		||||
    EekRenderer *renderer;
 | 
			
		||||
    struct squeek_view *view;
 | 
			
		||||
    struct squeek_row *row;
 | 
			
		||||
};
 | 
			
		||||
typedef struct _CreateKeyboardSurfaceCallbackData CreateKeyboardSurfaceCallbackData;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
create_keyboard_surface_button_callback (struct squeek_button *button,
 | 
			
		||||
                                      gpointer    user_data)
 | 
			
		||||
{
 | 
			
		||||
    CreateKeyboardSurfaceCallbackData *data = user_data;
 | 
			
		||||
    EekBounds bounds = squeek_button_get_bounds(button);
 | 
			
		||||
 | 
			
		||||
    cairo_save (data->cr);
 | 
			
		||||
 | 
			
		||||
    cairo_translate (data->cr, bounds.x, bounds.y);
 | 
			
		||||
    cairo_rectangle (data->cr,
 | 
			
		||||
                     0.0,
 | 
			
		||||
                     0.0,
 | 
			
		||||
                     bounds.width + 100,
 | 
			
		||||
                     bounds.height + 100);
 | 
			
		||||
    cairo_clip (data->cr);
 | 
			
		||||
    struct button_place place = {
 | 
			
		||||
        .row = data->row,
 | 
			
		||||
        .button = button,
 | 
			
		||||
    };
 | 
			
		||||
    render_button (data->renderer, data->cr, squeek_view_get_bounds(data->view), &place, FALSE, FALSE);
 | 
			
		||||
 | 
			
		||||
    cairo_restore (data->cr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
create_keyboard_surface_row_callback (struct squeek_row *row,
 | 
			
		||||
                                          gpointer    user_data)
 | 
			
		||||
{
 | 
			
		||||
    CreateKeyboardSurfaceCallbackData *data = user_data;
 | 
			
		||||
 | 
			
		||||
    EekBounds bounds = squeek_row_get_bounds(row);
 | 
			
		||||
 | 
			
		||||
    cairo_save (data->cr);
 | 
			
		||||
    cairo_translate (data->cr, bounds.x, bounds.y);
 | 
			
		||||
 | 
			
		||||
    gint angle = squeek_row_get_angle (row);
 | 
			
		||||
    cairo_rotate (data->cr, angle * G_PI / 180);
 | 
			
		||||
 | 
			
		||||
    data->row = row;
 | 
			
		||||
    squeek_row_foreach(row, create_keyboard_surface_button_callback, data);
 | 
			
		||||
 | 
			
		||||
    cairo_restore (data->cr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
render_keyboard_surface (EekRenderer *renderer, struct squeek_view *view)
 | 
			
		||||
{
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
 | 
			
		||||
 | 
			
		||||
    GdkRGBA color = {0};
 | 
			
		||||
    gtk_style_context_get_color (priv->view_context, GTK_STATE_FLAG_NORMAL, &color);
 | 
			
		||||
 | 
			
		||||
    EekBounds bounds = squeek_view_get_bounds (level_keyboard_current(priv->keyboard));
 | 
			
		||||
 | 
			
		||||
    CreateKeyboardSurfaceCallbackData data = {
 | 
			
		||||
        .cr = cairo_create (priv->keyboard_surface),
 | 
			
		||||
        .renderer = renderer,
 | 
			
		||||
        .view = view,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /* Paint the background covering the entire widget area */
 | 
			
		||||
    gtk_render_background (priv->view_context,
 | 
			
		||||
                           data.cr,
 | 
			
		||||
                           0, 0,
 | 
			
		||||
                           priv->allocation_width, priv->allocation_height);
 | 
			
		||||
    gtk_render_frame (priv->view_context,
 | 
			
		||||
                      data.cr,
 | 
			
		||||
                      0, 0,
 | 
			
		||||
                      priv->allocation_width, priv->allocation_height);
 | 
			
		||||
 | 
			
		||||
    cairo_save (data.cr);
 | 
			
		||||
    cairo_scale (data.cr, priv->scale, priv->scale);
 | 
			
		||||
    cairo_translate (data.cr, bounds.x, bounds.y);
 | 
			
		||||
 | 
			
		||||
    cairo_set_source_rgba (data.cr,
 | 
			
		||||
                           color.red,
 | 
			
		||||
                           color.green,
 | 
			
		||||
                           color.blue,
 | 
			
		||||
                           color.alpha);
 | 
			
		||||
 | 
			
		||||
    /* draw rows */
 | 
			
		||||
    squeek_view_foreach(level_keyboard_current(priv->keyboard),
 | 
			
		||||
                        create_keyboard_surface_row_callback,
 | 
			
		||||
                        &data);
 | 
			
		||||
 | 
			
		||||
    cairo_restore (data.cr);
 | 
			
		||||
 | 
			
		||||
    cairo_destroy (data.cr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
render_outline (cairo_t     *cr,
 | 
			
		||||
                GtkStyleContext *ctx,
 | 
			
		||||
@ -190,46 +87,20 @@ render_outline (cairo_t     *cr,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void render_button_in_context(EekRenderer *self,
 | 
			
		||||
                                     gdouble scale,
 | 
			
		||||
                                     gint scale_factor,
 | 
			
		||||
                                     cairo_t     *cr,
 | 
			
		||||
                                     GtkStyleContext *ctx,
 | 
			
		||||
                                     EekBounds view_bounds,
 | 
			
		||||
                                     struct button_place *place,
 | 
			
		||||
                                     gboolean active) {
 | 
			
		||||
    cairo_surface_t *outline_surface = NULL;
 | 
			
		||||
                                     const struct squeek_button *button) {
 | 
			
		||||
    /* blank background */
 | 
			
		||||
    cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
 | 
			
		||||
    cairo_paint (cr);
 | 
			
		||||
 | 
			
		||||
    /* render outline */
 | 
			
		||||
    EekBounds bounds = squeek_button_get_bounds(place->button);
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        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,
 | 
			
		||||
                                        (int)ceil(bounds.width) + 10,
 | 
			
		||||
                                        (int)ceil(bounds.height) + 10);
 | 
			
		||||
        cr = cairo_create (outline_surface);
 | 
			
		||||
 | 
			
		||||
        /* blank background */
 | 
			
		||||
        cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
 | 
			
		||||
        cairo_paint (cr);
 | 
			
		||||
 | 
			
		||||
        cairo_save (cr);
 | 
			
		||||
        eek_renderer_apply_transformation_for_button (cr, view_bounds, place, 1.0, FALSE);
 | 
			
		||||
        render_outline (cr, ctx, bounds);
 | 
			
		||||
        cairo_restore (cr);
 | 
			
		||||
 | 
			
		||||
        cairo_destroy (cr);
 | 
			
		||||
    }
 | 
			
		||||
    cairo_set_source_surface (cr, outline_surface, 0.0, 0.0);
 | 
			
		||||
    cairo_surface_destroy(outline_surface);
 | 
			
		||||
    EekBounds bounds = squeek_button_get_bounds(button);
 | 
			
		||||
    render_outline (cr, ctx, bounds);
 | 
			
		||||
    cairo_paint (cr);
 | 
			
		||||
 | 
			
		||||
    /* render icon (if any) */
 | 
			
		||||
    const char *icon_name = squeek_button_get_icon_name(place->button);
 | 
			
		||||
    const char *icon_name = squeek_button_get_icon_name(button);
 | 
			
		||||
 | 
			
		||||
    if (icon_name) {
 | 
			
		||||
        cairo_surface_t *icon_surface =
 | 
			
		||||
@ -259,14 +130,13 @@ static void render_button_in_context(EekRenderer *self,
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    eek_renderer_render_button_label (self, cr, ctx, place->button);
 | 
			
		||||
    eek_renderer_render_button_label (self, cr, ctx, button);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
render_button (EekRenderer *self,
 | 
			
		||||
void
 | 
			
		||||
eek_render_button (EekRenderer *self,
 | 
			
		||||
            cairo_t     *cr,
 | 
			
		||||
               EekBounds view_bounds,
 | 
			
		||||
            struct button_place *place,
 | 
			
		||||
            const struct squeek_button *button,
 | 
			
		||||
               gboolean     pressed,
 | 
			
		||||
               gboolean     locked)
 | 
			
		||||
{
 | 
			
		||||
@ -277,7 +147,7 @@ render_button (EekRenderer *self,
 | 
			
		||||
       from the button's symbol. */
 | 
			
		||||
    g_autoptr (GtkWidgetPath) path = NULL;
 | 
			
		||||
    path = gtk_widget_path_copy (gtk_style_context_get_path (ctx));
 | 
			
		||||
    const char *name = squeek_button_get_name(place->button);
 | 
			
		||||
    const char *name = squeek_button_get_name(button);
 | 
			
		||||
    gtk_widget_path_iter_set_name (path, -1, name);
 | 
			
		||||
 | 
			
		||||
    /* Update the style context with the updated widget path. */
 | 
			
		||||
@ -286,13 +156,13 @@ render_button (EekRenderer *self,
 | 
			
		||||
       (pressed) or normal. */
 | 
			
		||||
    gtk_style_context_set_state(ctx,
 | 
			
		||||
        pressed ? GTK_STATE_FLAG_ACTIVE : GTK_STATE_FLAG_NORMAL);
 | 
			
		||||
    const char *outline_name = squeek_button_get_outline_name(place->button);
 | 
			
		||||
    const char *outline_name = squeek_button_get_outline_name(button);
 | 
			
		||||
    if (locked) {
 | 
			
		||||
        gtk_style_context_add_class(ctx, "locked");
 | 
			
		||||
    }
 | 
			
		||||
    gtk_style_context_add_class(ctx, outline_name);
 | 
			
		||||
 | 
			
		||||
    render_button_in_context(self, priv->scale, priv->scale_factor, cr, ctx, view_bounds, place, pressed);
 | 
			
		||||
    render_button_in_context(self, priv->scale_factor, cr, ctx, button);
 | 
			
		||||
 | 
			
		||||
    // Save and restore functions don't work if gtk_render_* was used in between
 | 
			
		||||
    gtk_style_context_set_state(ctx, GTK_STATE_FLAG_NORMAL);
 | 
			
		||||
@ -302,47 +172,6 @@ render_button (EekRenderer *self,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * eek_renderer_apply_transformation_for_key:
 | 
			
		||||
 * @self: The renderer used to render the key
 | 
			
		||||
 * @cr: The Cairo rendering context used for rendering
 | 
			
		||||
 * @key: The key to be transformed
 | 
			
		||||
 * @scale: The factor used to scale the key bounds before rendering
 | 
			
		||||
 * @rotate: Whether to rotate the key by the angle defined for the key's
 | 
			
		||||
 *   in its section definition
 | 
			
		||||
 *
 | 
			
		||||
 *  Applies a transformation, consisting of scaling and rotation, to the
 | 
			
		||||
 *  current rendering context using the bounds for the given key. The scale
 | 
			
		||||
 *  factor is separate to the normal scale factor for the keyboard as a whole
 | 
			
		||||
 *  and is applied cumulatively. It is typically used to render larger than
 | 
			
		||||
 *  normal keys for popups.
 | 
			
		||||
*/
 | 
			
		||||
void
 | 
			
		||||
eek_renderer_apply_transformation_for_button (cairo_t     *cr,
 | 
			
		||||
                                              EekBounds view_bounds,
 | 
			
		||||
                                           struct button_place *place,
 | 
			
		||||
                                           gdouble      scale,
 | 
			
		||||
                                           gboolean     rotate)
 | 
			
		||||
{
 | 
			
		||||
    EekBounds bounds, rotated_bounds;
 | 
			
		||||
    gdouble s;
 | 
			
		||||
 | 
			
		||||
    eek_renderer_get_button_bounds (view_bounds, place, &bounds, FALSE);
 | 
			
		||||
    eek_renderer_get_button_bounds (view_bounds, place, &rotated_bounds, TRUE);
 | 
			
		||||
 | 
			
		||||
    gint angle = squeek_row_get_angle (place->row);
 | 
			
		||||
 | 
			
		||||
    cairo_scale (cr, scale, scale);
 | 
			
		||||
    if (rotate) {
 | 
			
		||||
        s = sin (angle * G_PI / 180);
 | 
			
		||||
        if (s < 0)
 | 
			
		||||
            cairo_translate (cr, 0, - bounds.width * s);
 | 
			
		||||
        else
 | 
			
		||||
            cairo_translate (cr, bounds.height * s, 0);
 | 
			
		||||
        cairo_rotate (cr, angle * G_PI / 180);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_renderer_render_button_label (EekRenderer *self,
 | 
			
		||||
                                  cairo_t     *cr,
 | 
			
		||||
@ -415,76 +244,28 @@ eek_renderer_render_button_label (EekRenderer *self,
 | 
			
		||||
    g_object_unref (layout);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * eek_renderer_real_render_key:
 | 
			
		||||
 * @self: The renderer used to render the key
 | 
			
		||||
 * @cr: The Cairo rendering context used for rendering
 | 
			
		||||
 * @key: The key to be transformed
 | 
			
		||||
 * @scale: The factor used to scale the key bounds before rendering
 | 
			
		||||
 * @rotate: Whether to rotate the key by the angle defined for the key's
 | 
			
		||||
 *   in its section definition
 | 
			
		||||
 *
 | 
			
		||||
 *   Renders a key separately from the normal keyboard rendering.
 | 
			
		||||
*/
 | 
			
		||||
static void
 | 
			
		||||
eek_renderer_real_render_button (EekRenderer *self,
 | 
			
		||||
                              cairo_t     *cr,
 | 
			
		||||
                              struct button_place *place,
 | 
			
		||||
                              gdouble      scale,
 | 
			
		||||
                              gboolean     rotate)
 | 
			
		||||
{
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
 | 
			
		||||
    EekBounds bounds;
 | 
			
		||||
 | 
			
		||||
    EekBounds view_bounds = squeek_view_get_bounds (level_keyboard_current(priv->keyboard));
 | 
			
		||||
    eek_renderer_get_button_bounds (view_bounds, place, &bounds, rotate);
 | 
			
		||||
 | 
			
		||||
    cairo_save (cr);
 | 
			
		||||
    /* Because this function is called separately from the keyboard rendering
 | 
			
		||||
       function, the transformation for the context needs to be set up */
 | 
			
		||||
    cairo_translate (cr, priv->origin_x, priv->origin_y);
 | 
			
		||||
    cairo_scale (cr, priv->scale, priv->scale);
 | 
			
		||||
    cairo_translate (cr, bounds.x, bounds.y);
 | 
			
		||||
 | 
			
		||||
    eek_renderer_apply_transformation_for_button (cr, view_bounds, place, scale, rotate);
 | 
			
		||||
    struct squeek_key *key = squeek_button_get_key(place->button);
 | 
			
		||||
    render_button (
 | 
			
		||||
                self, cr, view_bounds, place,
 | 
			
		||||
                squeek_key_is_pressed(key) != 0,
 | 
			
		||||
                squeek_key_is_locked (key) != 0
 | 
			
		||||
    );
 | 
			
		||||
    cairo_restore (cr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_renderer_real_render_keyboard (EekRenderer *self,
 | 
			
		||||
void
 | 
			
		||||
eek_renderer_render_keyboard (EekRenderer *self,
 | 
			
		||||
                                   cairo_t     *cr)
 | 
			
		||||
{
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
 | 
			
		||||
    cairo_pattern_t *source;
 | 
			
		||||
 | 
			
		||||
    g_return_if_fail (priv->keyboard);
 | 
			
		||||
    g_return_if_fail (priv->allocation_width > 0.0);
 | 
			
		||||
    g_return_if_fail (priv->allocation_height > 0.0);
 | 
			
		||||
 | 
			
		||||
    cairo_save (cr);
 | 
			
		||||
    /* Paint the background covering the entire widget area */
 | 
			
		||||
    gtk_render_background (priv->view_context,
 | 
			
		||||
                           cr,
 | 
			
		||||
                           0, 0,
 | 
			
		||||
                           priv->allocation_width, priv->allocation_height);
 | 
			
		||||
 | 
			
		||||
    cairo_translate (cr, priv->origin_x, priv->origin_y);
 | 
			
		||||
 | 
			
		||||
    if (priv->keyboard_surface)
 | 
			
		||||
        cairo_surface_destroy (priv->keyboard_surface);
 | 
			
		||||
 | 
			
		||||
    priv->keyboard_surface = cairo_surface_create_for_rectangle (
 | 
			
		||||
        cairo_get_target (cr), 0, 0,
 | 
			
		||||
        priv->allocation_width, priv->allocation_height);
 | 
			
		||||
 | 
			
		||||
    render_keyboard_surface (self, squeek_layout_get_current_view(priv->keyboard->layout));
 | 
			
		||||
 | 
			
		||||
    cairo_set_source_surface (cr, priv->keyboard_surface, 0.0, 0.0);
 | 
			
		||||
    source = cairo_get_source (cr);
 | 
			
		||||
    cairo_pattern_set_extend (source, CAIRO_EXTEND_PAD);
 | 
			
		||||
    cairo_paint (cr);
 | 
			
		||||
    cairo_save(cr);
 | 
			
		||||
    cairo_translate (cr, priv->widget_to_layout.origin_x, priv->widget_to_layout.origin_y);
 | 
			
		||||
    cairo_scale (cr, priv->widget_to_layout.scale, priv->widget_to_layout.scale);
 | 
			
		||||
 | 
			
		||||
    squeek_draw_layout_base_view(priv->keyboard->layout, self, cr);
 | 
			
		||||
    squeek_layout_draw_all_changed(priv->keyboard->layout, self, cr);
 | 
			
		||||
    cairo_restore (cr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -514,6 +295,7 @@ eek_renderer_get_property (GObject    *object,
 | 
			
		||||
                           GValue     *value,
 | 
			
		||||
                           GParamSpec *pspec)
 | 
			
		||||
{
 | 
			
		||||
    (void)value;
 | 
			
		||||
    switch (prop_id) {
 | 
			
		||||
    default:
 | 
			
		||||
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
@ -535,8 +317,7 @@ eek_renderer_dispose (GObject *object)
 | 
			
		||||
        priv->pcontext = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* this will release all allocated surfaces and font if any */
 | 
			
		||||
    invalidate (EEK_RENDERER(object));
 | 
			
		||||
    // this is where renderer-specific surfaces would be released
 | 
			
		||||
 | 
			
		||||
    G_OBJECT_CLASS (eek_renderer_parent_class)->dispose (object);
 | 
			
		||||
}
 | 
			
		||||
@ -560,9 +341,6 @@ eek_renderer_class_init (EekRendererClass *klass)
 | 
			
		||||
    GObjectClass      *gobject_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
    GParamSpec        *pspec;
 | 
			
		||||
 | 
			
		||||
    klass->render_button = eek_renderer_real_render_button;
 | 
			
		||||
    klass->render_keyboard = eek_renderer_real_render_keyboard;
 | 
			
		||||
 | 
			
		||||
    gobject_class->set_property = eek_renderer_set_property;
 | 
			
		||||
    gobject_class->get_property = eek_renderer_get_property;
 | 
			
		||||
    gobject_class->dispose = eek_renderer_dispose;
 | 
			
		||||
@ -615,10 +393,8 @@ eek_renderer_init (EekRenderer *self)
 | 
			
		||||
    priv->border_width = 1.0;
 | 
			
		||||
    priv->allocation_width = 0.0;
 | 
			
		||||
    priv->allocation_height = 0.0;
 | 
			
		||||
    priv->scale = 1.0;
 | 
			
		||||
    priv->scale_factor = 1;
 | 
			
		||||
    priv->font = NULL;
 | 
			
		||||
    priv->keyboard_surface = NULL;
 | 
			
		||||
 | 
			
		||||
    GtkIconTheme *theme = gtk_icon_theme_get_default ();
 | 
			
		||||
 | 
			
		||||
@ -627,17 +403,6 @@ eek_renderer_init (EekRenderer *self)
 | 
			
		||||
    priv->css_provider = squeek_load_style();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
invalidate (EekRenderer *renderer)
 | 
			
		||||
{
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
 | 
			
		||||
 | 
			
		||||
    if (priv->keyboard_surface) {
 | 
			
		||||
        cairo_surface_destroy (priv->keyboard_surface);
 | 
			
		||||
        priv->keyboard_surface = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
EekRenderer *
 | 
			
		||||
eek_renderer_new (LevelKeyboard  *keyboard,
 | 
			
		||||
                  PangoContext *pcontext)
 | 
			
		||||
@ -685,8 +450,6 @@ eek_renderer_set_allocation_size (EekRenderer *renderer,
 | 
			
		||||
                                  gdouble      width,
 | 
			
		||||
                                  gdouble      height)
 | 
			
		||||
{
 | 
			
		||||
    gdouble scale;
 | 
			
		||||
 | 
			
		||||
    g_return_if_fail (EEK_IS_RENDERER(renderer));
 | 
			
		||||
    g_return_if_fail (width > 0.0 && height > 0.0);
 | 
			
		||||
 | 
			
		||||
@ -695,99 +458,11 @@ eek_renderer_set_allocation_size (EekRenderer *renderer,
 | 
			
		||||
    priv->allocation_width = width;
 | 
			
		||||
    priv->allocation_height = height;
 | 
			
		||||
 | 
			
		||||
    /* Calculate a scale factor to use when rendering the keyboard into the
 | 
			
		||||
       available space. */
 | 
			
		||||
    EekBounds bounds = squeek_view_get_bounds (level_keyboard_current(priv->keyboard));
 | 
			
		||||
    priv->widget_to_layout = squeek_layout_calculate_transformation(
 | 
			
		||||
                priv->keyboard->layout,
 | 
			
		||||
                priv->allocation_width, priv->allocation_height);
 | 
			
		||||
 | 
			
		||||
    gdouble w = (bounds.x * 2) + bounds.width;
 | 
			
		||||
    gdouble h = (bounds.y * 2) + bounds.height;
 | 
			
		||||
 | 
			
		||||
    scale = MIN(width / w, height / h);
 | 
			
		||||
 | 
			
		||||
    priv->scale = scale;
 | 
			
		||||
    /* Set the rendering offset in widget coordinates to center the keyboard */
 | 
			
		||||
    priv->origin_x = (gint)floor((width - (scale * w)) / 2);
 | 
			
		||||
    priv->origin_y = (gint)floor((height - (scale * h)) / 2);
 | 
			
		||||
    invalidate (renderer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eek_renderer_get_size (EekRenderer *renderer,
 | 
			
		||||
                       gdouble     *width,
 | 
			
		||||
                       gdouble     *height)
 | 
			
		||||
{
 | 
			
		||||
    g_return_if_fail (EEK_IS_RENDERER(renderer));
 | 
			
		||||
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
 | 
			
		||||
 | 
			
		||||
    EekBounds bounds = squeek_view_get_bounds (level_keyboard_current(priv->keyboard));
 | 
			
		||||
    if (width)
 | 
			
		||||
        *width = bounds.width;
 | 
			
		||||
    if (height)
 | 
			
		||||
        *height = bounds.height;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eek_renderer_get_button_bounds (EekBounds view_bounds,
 | 
			
		||||
                                struct button_place *place,
 | 
			
		||||
                             EekBounds   *bounds,
 | 
			
		||||
                             gboolean     rotate)
 | 
			
		||||
{
 | 
			
		||||
    gint angle = 0;
 | 
			
		||||
    EekPoint points[4], min, max;
 | 
			
		||||
 | 
			
		||||
    g_return_if_fail (place);
 | 
			
		||||
    g_return_if_fail (bounds != NULL);
 | 
			
		||||
 | 
			
		||||
    EekBounds button_bounds = squeek_button_get_bounds(place->button);
 | 
			
		||||
    EekBounds row_bounds = squeek_row_get_bounds (place->row);
 | 
			
		||||
 | 
			
		||||
    if (!rotate) {
 | 
			
		||||
        button_bounds.x += view_bounds.x + row_bounds.x;
 | 
			
		||||
        button_bounds.y += view_bounds.y + row_bounds.y;
 | 
			
		||||
        *bounds = button_bounds;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    points[0].x = button_bounds.x;
 | 
			
		||||
    points[0].y = button_bounds.y;
 | 
			
		||||
    points[1].x = points[0].x + button_bounds.width;
 | 
			
		||||
    points[1].y = points[0].y;
 | 
			
		||||
    points[2].x = points[1].x;
 | 
			
		||||
    points[2].y = points[1].y + button_bounds.height;
 | 
			
		||||
    points[3].x = points[0].x;
 | 
			
		||||
    points[3].y = points[2].y;
 | 
			
		||||
 | 
			
		||||
    if (rotate) {
 | 
			
		||||
        angle = squeek_row_get_angle (place->row);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    min = points[2];
 | 
			
		||||
    max = points[0];
 | 
			
		||||
    for (unsigned i = 0; i < G_N_ELEMENTS(points); i++) {
 | 
			
		||||
        eek_point_rotate (&points[i], angle);
 | 
			
		||||
        if (points[i].x < min.x)
 | 
			
		||||
            min.x = points[i].x;
 | 
			
		||||
        if (points[i].x > max.x)
 | 
			
		||||
            max.x = points[i].x;
 | 
			
		||||
        if (points[i].y < min.y)
 | 
			
		||||
            min.y = points[i].y;
 | 
			
		||||
        if (points[i].y > max.y)
 | 
			
		||||
            max.y = points[i].y;
 | 
			
		||||
    }
 | 
			
		||||
    bounds->x = view_bounds.x + row_bounds.x + min.x;
 | 
			
		||||
    bounds->y = view_bounds.y + row_bounds.y + min.y;
 | 
			
		||||
    bounds->width = (max.x - min.x);
 | 
			
		||||
    bounds->height = (max.y - min.y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gdouble
 | 
			
		||||
eek_renderer_get_scale (EekRenderer *renderer)
 | 
			
		||||
{
 | 
			
		||||
    g_return_val_if_fail (EEK_IS_RENDERER(renderer), 0);
 | 
			
		||||
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
 | 
			
		||||
 | 
			
		||||
    return priv->scale;
 | 
			
		||||
    // This is where size-dependent surfaces would be released
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@ -823,29 +498,6 @@ eek_renderer_get_icon_surface (const gchar *icon_name,
 | 
			
		||||
    return surface;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eek_renderer_render_button (EekRenderer *renderer,
 | 
			
		||||
                         cairo_t     *cr,
 | 
			
		||||
                         struct button_place *place,
 | 
			
		||||
                         gdouble      scale,
 | 
			
		||||
                         gboolean     rotate)
 | 
			
		||||
{
 | 
			
		||||
    g_return_if_fail (EEK_IS_RENDERER(renderer));
 | 
			
		||||
    g_return_if_fail (place);
 | 
			
		||||
    g_return_if_fail (scale >= 0.0);
 | 
			
		||||
 | 
			
		||||
    EEK_RENDERER_GET_CLASS(renderer)->
 | 
			
		||||
        render_button (renderer, cr, place, scale, rotate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eek_renderer_render_keyboard (EekRenderer *renderer,
 | 
			
		||||
                              cairo_t     *cr)
 | 
			
		||||
{
 | 
			
		||||
    g_return_if_fail (EEK_IS_RENDERER(renderer));
 | 
			
		||||
    EEK_RENDERER_GET_CLASS(renderer)->render_keyboard (renderer, cr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
sign (EekPoint *p1, EekPoint *p2, EekPoint *p3)
 | 
			
		||||
{
 | 
			
		||||
@ -899,10 +551,5 @@ eek_renderer_get_transformation (EekRenderer *renderer) {
 | 
			
		||||
    g_return_val_if_fail (EEK_IS_RENDERER(renderer), failed);
 | 
			
		||||
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
 | 
			
		||||
    struct transformation ret = {
 | 
			
		||||
        .origin_x = priv->origin_x,
 | 
			
		||||
        .origin_y = priv->origin_y,
 | 
			
		||||
        .scale = priv->scale,
 | 
			
		||||
    };
 | 
			
		||||
    return ret;
 | 
			
		||||
    return priv->widget_to_layout;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,6 @@
 | 
			
		||||
#include <pango/pangocairo.h>
 | 
			
		||||
 | 
			
		||||
#include "eek-types.h"
 | 
			
		||||
#include "src/layout.h"
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
@ -36,15 +35,6 @@ struct _EekRendererClass
 | 
			
		||||
{
 | 
			
		||||
    GObjectClass parent_class;
 | 
			
		||||
 | 
			
		||||
    void             (* render_button)         (EekRenderer *self,
 | 
			
		||||
                                             cairo_t     *cr,
 | 
			
		||||
                                             struct button_place *place,
 | 
			
		||||
                                             gdouble      scale,
 | 
			
		||||
                                             gboolean     rotate);
 | 
			
		||||
 | 
			
		||||
    void             (* render_keyboard)    (EekRenderer *self,
 | 
			
		||||
                                             cairo_t     *cr);
 | 
			
		||||
 | 
			
		||||
    cairo_surface_t *(* get_icon_surface)   (EekRenderer *self,
 | 
			
		||||
                                             const gchar *icon_name,
 | 
			
		||||
                                             gint         size,
 | 
			
		||||
@ -62,38 +52,15 @@ void             eek_renderer_set_allocation_size
 | 
			
		||||
                                               (EekRenderer     *renderer,
 | 
			
		||||
                                                gdouble          width,
 | 
			
		||||
                                                gdouble          height);
 | 
			
		||||
void             eek_renderer_get_size         (EekRenderer     *renderer,
 | 
			
		||||
                                                gdouble         *width,
 | 
			
		||||
                                                gdouble         *height);
 | 
			
		||||
void             eek_renderer_get_button_bounds   (EekBounds view_bounds,
 | 
			
		||||
                                                struct button_place *button,
 | 
			
		||||
                                                EekBounds       *bounds,
 | 
			
		||||
                                                gboolean         rotate);
 | 
			
		||||
 | 
			
		||||
gdouble          eek_renderer_get_scale        (EekRenderer     *renderer);
 | 
			
		||||
void             eek_renderer_set_scale_factor (EekRenderer     *renderer,
 | 
			
		||||
                                                gint             scale);
 | 
			
		||||
 | 
			
		||||
void             eek_renderer_render_button       (EekRenderer     *renderer,
 | 
			
		||||
                                                cairo_t         *cr,
 | 
			
		||||
                                                struct button_place *place,
 | 
			
		||||
                                                gdouble          scale,
 | 
			
		||||
                                                gboolean         rotate);
 | 
			
		||||
 | 
			
		||||
cairo_surface_t *eek_renderer_get_icon_surface(const gchar     *icon_name,
 | 
			
		||||
                                                gint             size,
 | 
			
		||||
                                                gint             scale);
 | 
			
		||||
 | 
			
		||||
void             eek_renderer_render_keyboard  (EekRenderer     *renderer,
 | 
			
		||||
                                                cairo_t         *cr);
 | 
			
		||||
void             eek_renderer_set_border_width (EekRenderer     *renderer,
 | 
			
		||||
                                                gdouble          border_width);
 | 
			
		||||
void             eek_renderer_apply_transformation_for_button
 | 
			
		||||
                                               (cairo_t         *cr,
 | 
			
		||||
                                                EekBounds view_bounds,
 | 
			
		||||
                                                struct button_place *place,
 | 
			
		||||
                                                gdouble          scale,
 | 
			
		||||
                                                gboolean         rotate);
 | 
			
		||||
 | 
			
		||||
struct transformation
 | 
			
		||||
eek_renderer_get_transformation (EekRenderer *renderer);
 | 
			
		||||
 | 
			
		||||
@ -88,5 +88,14 @@ struct transformation {
 | 
			
		||||
    gdouble origin_y;
 | 
			
		||||
    gdouble scale;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct squeek_button;
 | 
			
		||||
struct squeek_row;
 | 
			
		||||
 | 
			
		||||
/// Represents the path to the button within a view
 | 
			
		||||
struct button_place {
 | 
			
		||||
    const struct squeek_row *row;
 | 
			
		||||
    const struct squeek_button *button;
 | 
			
		||||
};
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
#endif  /* EEK_TYPES_H */
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,6 @@
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include "eek-keyboard.h"
 | 
			
		||||
#include "src/keyboard.h"
 | 
			
		||||
#include "src/layout.h"
 | 
			
		||||
 | 
			
		||||
#include "eek-xml-layout.h"
 | 
			
		||||
 | 
			
		||||
@ -405,7 +405,7 @@ impl Layout {
 | 
			
		||||
        let views = HashMap::from_iter(
 | 
			
		||||
            self.views.iter().map(|(name, view)| {(
 | 
			
		||||
                name.clone(),
 | 
			
		||||
                Box::new(::layout::View {
 | 
			
		||||
                ::layout::View {
 | 
			
		||||
                    bounds: ::layout::c::Bounds {
 | 
			
		||||
                        x: self.bounds.x,
 | 
			
		||||
                        y: self.bounds.y,
 | 
			
		||||
@ -413,7 +413,7 @@ impl Layout {
 | 
			
		||||
                        height: self.bounds.height,
 | 
			
		||||
                    },
 | 
			
		||||
                    rows: view.iter().map(|row| {
 | 
			
		||||
                        Box::new(::layout::Row {
 | 
			
		||||
                        ::layout::Row {
 | 
			
		||||
                            angle: 0,
 | 
			
		||||
                            bounds: None,
 | 
			
		||||
                            buttons: row.split_ascii_whitespace().map(|name| {
 | 
			
		||||
@ -427,9 +427,9 @@ impl Layout {
 | 
			
		||||
                                    &mut warning_handler,
 | 
			
		||||
                                ))
 | 
			
		||||
                            }).collect(),
 | 
			
		||||
                        })
 | 
			
		||||
                        }
 | 
			
		||||
                    }).collect(),
 | 
			
		||||
                })
 | 
			
		||||
                }
 | 
			
		||||
            )})
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										126
									
								
								src/drawing.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								src/drawing.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,126 @@
 | 
			
		||||
/*! Drawing the UI */
 | 
			
		||||
 | 
			
		||||
use cairo;
 | 
			
		||||
use std::cell::RefCell;
 | 
			
		||||
 | 
			
		||||
use ::keyboard;
 | 
			
		||||
use ::layout::{ Button, Layout };
 | 
			
		||||
use ::layout::c::{ EekGtkKeyboard, Point };
 | 
			
		||||
 | 
			
		||||
use glib::translate::FromGlibPtrNone;
 | 
			
		||||
use gtk::WidgetExt;
 | 
			
		||||
 | 
			
		||||
mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    use cairo_sys;
 | 
			
		||||
    use std::os::raw::c_void;
 | 
			
		||||
    
 | 
			
		||||
    // This is constructed only in C, no need for warnings
 | 
			
		||||
    #[allow(dead_code)]
 | 
			
		||||
    #[repr(transparent)]
 | 
			
		||||
    #[derive(Clone, Copy)]
 | 
			
		||||
    pub struct EekRenderer(*const c_void);
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    extern "C" {
 | 
			
		||||
        // Button and View inside CButtonPlace are safe to pass to C
 | 
			
		||||
        // as long as they don't outlive the call
 | 
			
		||||
        // and nothing dereferences them
 | 
			
		||||
        #[allow(improper_ctypes)]
 | 
			
		||||
        pub fn eek_render_button(
 | 
			
		||||
            renderer: EekRenderer,
 | 
			
		||||
            cr: *mut cairo_sys::cairo_t,
 | 
			
		||||
            button: *const Button,
 | 
			
		||||
            pressed: u64,
 | 
			
		||||
            locked: u64,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_layout_draw_all_changed(
 | 
			
		||||
        layout: *mut Layout,
 | 
			
		||||
        renderer: EekRenderer,
 | 
			
		||||
        cr: *mut cairo_sys::cairo_t,
 | 
			
		||||
    ) {
 | 
			
		||||
        let layout = unsafe { &mut *layout };
 | 
			
		||||
        let cr = unsafe { cairo::Context::from_raw_none(cr) };
 | 
			
		||||
 | 
			
		||||
        let view = layout.get_current_view();
 | 
			
		||||
        let view_position = view.bounds.get_position();
 | 
			
		||||
        for row in &view.rows {
 | 
			
		||||
            for button in &row.buttons {
 | 
			
		||||
                let state = RefCell::borrow(&button.state).clone();
 | 
			
		||||
                if state.pressed == keyboard::PressType::Pressed || state.locked {
 | 
			
		||||
                    let position = &view_position
 | 
			
		||||
                        + row.bounds.clone().unwrap().get_position()
 | 
			
		||||
                        + button.bounds.get_position();
 | 
			
		||||
                    render_button_at_position(
 | 
			
		||||
                        renderer, &cr,
 | 
			
		||||
                        position, button.as_ref(),
 | 
			
		||||
                        state.pressed, state.locked,
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_draw_layout_base_view(
 | 
			
		||||
        layout: *mut Layout,
 | 
			
		||||
        renderer: EekRenderer,
 | 
			
		||||
        cr: *mut cairo_sys::cairo_t,
 | 
			
		||||
    ) {
 | 
			
		||||
        let layout = unsafe { &mut *layout };
 | 
			
		||||
        let cr = unsafe { cairo::Context::from_raw_none(cr) };
 | 
			
		||||
        let view = layout.get_current_view();
 | 
			
		||||
        let view_position = view.bounds.get_position();
 | 
			
		||||
        for row in &view.rows {
 | 
			
		||||
            for button in &row.buttons {
 | 
			
		||||
                let position = &view_position
 | 
			
		||||
                    + row.bounds.clone().unwrap().get_position()
 | 
			
		||||
                    + button.bounds.get_position();
 | 
			
		||||
                render_button_at_position(
 | 
			
		||||
                    renderer, &cr,
 | 
			
		||||
                    position, button.as_ref(),
 | 
			
		||||
                    keyboard::PressType::Released, false,
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Renders a button at a position (button's own bounds ignored)
 | 
			
		||||
pub fn render_button_at_position(
 | 
			
		||||
    renderer: c::EekRenderer,
 | 
			
		||||
    cr: &cairo::Context,
 | 
			
		||||
    position: Point,
 | 
			
		||||
    button: &Button,
 | 
			
		||||
    pressed: keyboard::PressType,
 | 
			
		||||
    locked: bool,
 | 
			
		||||
) {
 | 
			
		||||
    cr.save();
 | 
			
		||||
    cr.translate(position.x, position.y);
 | 
			
		||||
    cr.rectangle(
 | 
			
		||||
        0.0, 0.0,
 | 
			
		||||
        button.bounds.width, button.bounds.height
 | 
			
		||||
    );
 | 
			
		||||
    cr.clip();
 | 
			
		||||
    unsafe {
 | 
			
		||||
        c::eek_render_button(
 | 
			
		||||
            renderer,
 | 
			
		||||
            cairo::Context::to_raw_none(&cr),
 | 
			
		||||
            button as *const Button,
 | 
			
		||||
            pressed as u64,
 | 
			
		||||
            locked as u64,
 | 
			
		||||
        )
 | 
			
		||||
    };
 | 
			
		||||
    cr.restore();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn queue_redraw(keyboard: EekGtkKeyboard) {
 | 
			
		||||
    let widget = unsafe { gtk::Widget::from_glib_none(keyboard.0) };
 | 
			
		||||
    widget.queue_draw();
 | 
			
		||||
}
 | 
			
		||||
@ -1,12 +0,0 @@
 | 
			
		||||
#ifndef __KEYBOARD_H
 | 
			
		||||
#define __KEYBOARD_H
 | 
			
		||||
 | 
			
		||||
#include "inttypes.h"
 | 
			
		||||
#include "stdbool.h"
 | 
			
		||||
#include "virtual-keyboard-unstable-v1-client-protocol.h"
 | 
			
		||||
 | 
			
		||||
struct squeek_key;
 | 
			
		||||
 | 
			
		||||
uint32_t squeek_key_is_pressed(struct squeek_key *key);
 | 
			
		||||
uint32_t squeek_key_is_locked(struct squeek_key *key);
 | 
			
		||||
#endif
 | 
			
		||||
@ -10,32 +10,8 @@ use ::action::Action;
 | 
			
		||||
 | 
			
		||||
use std::io::Write;
 | 
			
		||||
use std::iter::{ FromIterator, IntoIterator };
 | 
			
		||||
use ::util::CloneOwned;
 | 
			
		||||
 | 
			
		||||
/// Gathers stuff defined in C or called by C
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use ::util::c;
 | 
			
		||||
 | 
			
		||||
    pub type CKeyState = c::Wrapped<KeyState>;
 | 
			
		||||
 | 
			
		||||
    // 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_key_is_pressed(key: CKeyState) -> u32 {
 | 
			
		||||
        //let key = unsafe { Rc::from_raw(key.0) };
 | 
			
		||||
        return key.clone_owned().pressed as u32;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_is_locked(key: CKeyState) -> u32 {
 | 
			
		||||
        return key.clone_owned().locked as u32;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy)]
 | 
			
		||||
#[derive(Debug, Clone, Copy, PartialEq)]
 | 
			
		||||
pub enum PressType {
 | 
			
		||||
    Released = 0,
 | 
			
		||||
    Pressed = 1,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										37
									
								
								src/layout.h
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								src/layout.h
									
									
									
									
									
								
							@ -5,8 +5,8 @@
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
#include "eek/eek-element.h"
 | 
			
		||||
#include "eek/eek-gtk-keyboard.h"
 | 
			
		||||
#include "eek/eek-renderer.h"
 | 
			
		||||
#include "eek/eek-types.h"
 | 
			
		||||
#include "src/keyboard.h"
 | 
			
		||||
#include "virtual-keyboard-unstable-v1-client-protocol.h"
 | 
			
		||||
 | 
			
		||||
enum squeek_arrangement_kind {
 | 
			
		||||
@ -14,48 +14,22 @@ enum squeek_arrangement_kind {
 | 
			
		||||
    ARRANGEMENT_KIND_WIDE = 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct squeek_button;
 | 
			
		||||
struct squeek_row;
 | 
			
		||||
struct squeek_view;
 | 
			
		||||
struct squeek_layout;
 | 
			
		||||
 | 
			
		||||
/// Represents the path to the button within a view
 | 
			
		||||
struct button_place {
 | 
			
		||||
    const struct squeek_row *row;
 | 
			
		||||
    const struct squeek_button *button;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int32_t squeek_row_get_angle(const struct squeek_row*);
 | 
			
		||||
 | 
			
		||||
EekBounds squeek_row_get_bounds(const struct squeek_row*);
 | 
			
		||||
 | 
			
		||||
typedef void (*ButtonCallback) (struct squeek_button *button, gpointer user_data);
 | 
			
		||||
void squeek_row_foreach(struct squeek_row*,
 | 
			
		||||
                            ButtonCallback   callback,
 | 
			
		||||
                            gpointer      user_data);
 | 
			
		||||
 | 
			
		||||
EekBounds squeek_button_get_bounds(const struct squeek_button*);
 | 
			
		||||
const char *squeek_button_get_label(const struct squeek_button*);
 | 
			
		||||
const char *squeek_button_get_icon_name(const struct squeek_button*);
 | 
			
		||||
const char *squeek_button_get_name(const struct squeek_button*);
 | 
			
		||||
const char *squeek_button_get_outline_name(const struct squeek_button*);
 | 
			
		||||
 | 
			
		||||
struct squeek_key *squeek_button_get_key(const struct squeek_button*);
 | 
			
		||||
uint32_t *squeek_button_has_key(const struct squeek_button* button,
 | 
			
		||||
                                const struct squeek_key *key);
 | 
			
		||||
void squeek_button_print(const struct squeek_button* button);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
EekBounds squeek_view_get_bounds(const struct squeek_view*);
 | 
			
		||||
 | 
			
		||||
typedef void (*RowCallback) (struct squeek_row *row, gpointer user_data);
 | 
			
		||||
void squeek_view_foreach(struct squeek_view*,
 | 
			
		||||
                            RowCallback   callback,
 | 
			
		||||
                            gpointer      user_data);
 | 
			
		||||
struct transformation squeek_layout_calculate_transformation(
 | 
			
		||||
        const struct squeek_layout *layout,
 | 
			
		||||
        double allocation_width, double allocation_size);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
squeek_layout_place_contents(struct squeek_layout*);
 | 
			
		||||
struct squeek_view *squeek_layout_get_current_view(struct squeek_layout*);
 | 
			
		||||
 | 
			
		||||
struct squeek_layout *squeek_load_layout(const char *name, uint32_t type);
 | 
			
		||||
const char *squeek_layout_get_keymap(const struct squeek_layout*);
 | 
			
		||||
@ -75,5 +49,6 @@ void squeek_layout_drag(struct squeek_layout *layout, struct zwp_virtual_keyboar
 | 
			
		||||
                        double x_widget, double y_widget,
 | 
			
		||||
                        struct transformation widget_to_layout,
 | 
			
		||||
                        uint32_t timestamp, EekGtkKeyboard *ui_keyboard);
 | 
			
		||||
void squeek_layout_draw_all_changed(struct squeek_layout *layout, EekGtkKeyboard *ui_keyboard);
 | 
			
		||||
void squeek_layout_draw_all_changed(struct squeek_layout *layout, EekRenderer* renderer, cairo_t     *cr);
 | 
			
		||||
void squeek_draw_layout_base_view(struct squeek_layout *layout, EekRenderer* renderer, cairo_t     *cr);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										358
									
								
								src/layout.rs
									
									
									
									
									
								
							
							
						
						
									
										358
									
								
								src/layout.rs
									
									
									
									
									
								
							@ -24,6 +24,7 @@ use std::rc::Rc;
 | 
			
		||||
use std::vec::Vec;
 | 
			
		||||
 | 
			
		||||
use ::action::Action;
 | 
			
		||||
use ::drawing;
 | 
			
		||||
use ::float_ord::FloatOrd;
 | 
			
		||||
use ::keyboard::{ KeyState, PressType };
 | 
			
		||||
use ::submission::{ Timestamp, VirtualKeyboard };
 | 
			
		||||
@ -34,16 +35,14 @@ use std::borrow::Borrow;
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    use gtk_sys;
 | 
			
		||||
    use std::ffi::CStr;
 | 
			
		||||
    use std::os::raw::{ c_char, c_void };
 | 
			
		||||
    use std::ptr;
 | 
			
		||||
    use gtk_sys;
 | 
			
		||||
 | 
			
		||||
    use std::ops::Add;
 | 
			
		||||
 | 
			
		||||
    // The following defined in C
 | 
			
		||||
 | 
			
		||||
    #[repr(transparent)]
 | 
			
		||||
    pub struct UserData(*const c_void);
 | 
			
		||||
 | 
			
		||||
    #[repr(transparent)]
 | 
			
		||||
    #[derive(Copy, Clone)]
 | 
			
		||||
    pub struct EekGtkKeyboard(pub *const gtk_sys::GtkWidget);
 | 
			
		||||
@ -56,9 +55,26 @@ pub mod c {
 | 
			
		||||
        pub y: f64,
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    impl Add for Point {
 | 
			
		||||
        type Output = Self;
 | 
			
		||||
        fn add(self, other: Self) -> Self {
 | 
			
		||||
            &self + other
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Add<Point> for &Point {
 | 
			
		||||
        type Output = Point;
 | 
			
		||||
        fn add(self, other: Point) -> Point {
 | 
			
		||||
            Point {
 | 
			
		||||
                x: self.x + other.x,
 | 
			
		||||
                y: self.y + other.y,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Defined in eek-types.h
 | 
			
		||||
    #[repr(C)]
 | 
			
		||||
    #[derive(Clone, Debug)]
 | 
			
		||||
    #[derive(Clone, Debug, PartialEq)]
 | 
			
		||||
    pub struct Bounds {
 | 
			
		||||
        pub x: f64,
 | 
			
		||||
        pub y: f64,
 | 
			
		||||
@ -66,62 +82,53 @@ pub mod c {
 | 
			
		||||
        pub height: f64
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    type ButtonCallback = unsafe extern "C" fn(button: *mut ::layout::Button, data: *mut UserData);
 | 
			
		||||
    type RowCallback = unsafe extern "C" fn(row: *mut ::layout::Row, data: *mut UserData);
 | 
			
		||||
    impl Bounds {
 | 
			
		||||
        pub fn get_position(&self) -> Point {
 | 
			
		||||
            Point {
 | 
			
		||||
                x: self.x,
 | 
			
		||||
                y: self.y,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Scale + translate
 | 
			
		||||
    #[repr(C)]
 | 
			
		||||
    pub struct Transformation {
 | 
			
		||||
        pub origin_x: f64,
 | 
			
		||||
        pub origin_y: f64,
 | 
			
		||||
        pub scale: f64,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Transformation {
 | 
			
		||||
        fn forward(&self, p: Point) -> Point {
 | 
			
		||||
            Point {
 | 
			
		||||
                x: (p.x - self.origin_x) / self.scale,
 | 
			
		||||
                y: (p.y - self.origin_y) / self.scale,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        fn reverse(&self, p: Point) -> Point {
 | 
			
		||||
            Point {
 | 
			
		||||
                x: p.x * self.scale + self.origin_x,
 | 
			
		||||
                y: p.y * self.scale + self.origin_y,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        pub fn reverse_bounds(&self, b: Bounds) -> Bounds {
 | 
			
		||||
            let start = self.reverse(Point { x: b.x, y: b.y });
 | 
			
		||||
            let end = self.reverse(Point {
 | 
			
		||||
                x: b.x + b.width,
 | 
			
		||||
                y: b.y + b.height,
 | 
			
		||||
            });
 | 
			
		||||
            Bounds {
 | 
			
		||||
                x: start.x,
 | 
			
		||||
                y: start.y,
 | 
			
		||||
                width: end.x - start.x,
 | 
			
		||||
                height: end.y - start.y,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 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_view_get_bounds(view: *const ::layout::View) -> Bounds {
 | 
			
		||||
        unsafe { &*view }.bounds.clone()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_view_foreach(
 | 
			
		||||
        view: *mut ::layout::View,
 | 
			
		||||
        callback: RowCallback,
 | 
			
		||||
        data: *mut UserData,
 | 
			
		||||
    ) {
 | 
			
		||||
        let view = unsafe { &mut *view };
 | 
			
		||||
        for row in view.rows.iter_mut() {
 | 
			
		||||
            let row = row.as_mut() as *mut ::layout::Row;
 | 
			
		||||
            unsafe { callback(row, data) };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[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_get_bounds(row: *const ::layout::Row) -> Bounds {
 | 
			
		||||
        let row = unsafe { &*row };
 | 
			
		||||
        match &row.bounds {
 | 
			
		||||
            Some(bounds) => bounds.clone(),
 | 
			
		||||
            None => panic!("Row doesn't have any bounds yet"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[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_button_get_bounds(button: *const ::layout::Button) -> Bounds {
 | 
			
		||||
@ -129,16 +136,6 @@ pub mod c {
 | 
			
		||||
        button.bounds.clone()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Borrow a new reference to key state. Doesn't need freeing
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_button_get_key(
 | 
			
		||||
        button: *const ::layout::Button
 | 
			
		||||
    ) -> ::keyboard::c::CKeyState {
 | 
			
		||||
        let button = unsafe { &*button };
 | 
			
		||||
        ::keyboard::c::CKeyState::wrap(button.state.clone())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_button_get_label(
 | 
			
		||||
@ -187,14 +184,24 @@ pub mod c {
 | 
			
		||||
        println!("{:?}", button);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Positions the layout within the available space
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_layout_get_current_view(layout: *const Layout) -> *const View {
 | 
			
		||||
    fn squeek_layout_calculate_transformation(
 | 
			
		||||
        layout: *const Layout,
 | 
			
		||||
        allocation_width: f64,
 | 
			
		||||
        allocation_height: f64,
 | 
			
		||||
    ) -> Transformation {
 | 
			
		||||
        let layout = unsafe { &*layout };
 | 
			
		||||
        let view_name = layout.current_view.clone();
 | 
			
		||||
        layout.views.get(&view_name)
 | 
			
		||||
            .expect("Current view doesn't exist")
 | 
			
		||||
            .as_ref() as *const View
 | 
			
		||||
        let bounds = &layout.get_current_view().bounds;
 | 
			
		||||
        let h_scale = allocation_width / bounds.width;
 | 
			
		||||
        let v_scale = allocation_height / bounds.height;
 | 
			
		||||
        let scale = if h_scale > v_scale { h_scale } else { v_scale };
 | 
			
		||||
        Transformation {
 | 
			
		||||
            origin_x: allocation_width - (scale * bounds.width) / 2.0,
 | 
			
		||||
            origin_y: allocation_height - (scale * bounds.height) / 2.0,
 | 
			
		||||
            scale: scale,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
@ -239,42 +246,6 @@ pub mod c {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// Scale + translate
 | 
			
		||||
        #[repr(C)]
 | 
			
		||||
        pub struct Transformation {
 | 
			
		||||
            origin_x: f64,
 | 
			
		||||
            origin_y: f64,
 | 
			
		||||
            scale: f64,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        impl Transformation {
 | 
			
		||||
            fn forward(&self, p: Point) -> Point {
 | 
			
		||||
                Point {
 | 
			
		||||
                    x: (p.x - self.origin_x) / self.scale,
 | 
			
		||||
                    y: (p.y - self.origin_y) / self.scale,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            fn reverse(&self, p: Point) -> Point {
 | 
			
		||||
                Point {
 | 
			
		||||
                    x: p.x * self.scale + self.origin_x,
 | 
			
		||||
                    y: p.y * self.scale + self.origin_y,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            pub fn reverse_bounds(&self, b: Bounds) -> Bounds {
 | 
			
		||||
                let start = self.reverse(Point { x: b.x, y: b.y });
 | 
			
		||||
                let end = self.reverse(Point {
 | 
			
		||||
                    x: b.x + b.width,
 | 
			
		||||
                    y: b.y + b.height,
 | 
			
		||||
                });
 | 
			
		||||
                Bounds {
 | 
			
		||||
                    x: start.x,
 | 
			
		||||
                    y: start.y,
 | 
			
		||||
                    width: end.x - start.x,
 | 
			
		||||
                    height: end.y - start.y,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // This is constructed only in C, no need for warnings
 | 
			
		||||
        #[allow(dead_code)]
 | 
			
		||||
        #[repr(transparent)]
 | 
			
		||||
@ -289,34 +260,6 @@ pub mod c {
 | 
			
		||||
                origin: Point,
 | 
			
		||||
                angle: i32
 | 
			
		||||
            ) -> u32;
 | 
			
		||||
 | 
			
		||||
            // Button and View are safe to pass to C
 | 
			
		||||
            // as long as they don't outlive the call
 | 
			
		||||
            // and nothing dereferences them
 | 
			
		||||
            #[allow(improper_ctypes)]
 | 
			
		||||
            pub fn eek_gtk_on_button_released(
 | 
			
		||||
                button: *const Button,
 | 
			
		||||
                view: *const View,
 | 
			
		||||
                keyboard: EekGtkKeyboard,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Button and View inside CButtonPlace are safe to pass to C
 | 
			
		||||
            // as long as they don't outlive the call
 | 
			
		||||
            // and nothing dereferences them
 | 
			
		||||
            #[allow(improper_ctypes)]
 | 
			
		||||
            pub fn eek_gtk_on_button_pressed(
 | 
			
		||||
                place: CButtonPlace,
 | 
			
		||||
                keyboard: EekGtkKeyboard,
 | 
			
		||||
            );
 | 
			
		||||
            
 | 
			
		||||
            // Button and View inside CButtonPlace are safe to pass to C
 | 
			
		||||
            // as long as they don't outlive the call
 | 
			
		||||
            // and nothing dereferences them
 | 
			
		||||
            #[allow(improper_ctypes)]
 | 
			
		||||
            pub fn eek_gtk_render_locked_button(
 | 
			
		||||
                keyboard: EekGtkKeyboard,
 | 
			
		||||
                place: CButtonPlace,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// Places each button in order, starting from 0 on the left,
 | 
			
		||||
@ -356,15 +299,16 @@ pub mod c {
 | 
			
		||||
            // because it will be mutated in the loop
 | 
			
		||||
            for key in layout.pressed_keys.clone() {
 | 
			
		||||
                let key: &Rc<RefCell<KeyState>> = key.borrow();
 | 
			
		||||
                ui::release_key(
 | 
			
		||||
                seat::handle_release_key(
 | 
			
		||||
                    layout,
 | 
			
		||||
                    &virtual_keyboard,
 | 
			
		||||
                    &widget_to_layout,
 | 
			
		||||
                    time,
 | 
			
		||||
                    ui_keyboard,
 | 
			
		||||
                    key
 | 
			
		||||
                    key,
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
            drawing::queue_redraw(ui_keyboard);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// Release all buittons but don't redraw
 | 
			
		||||
@ -404,26 +348,15 @@ pub mod c {
 | 
			
		||||
                Point { x: x_widget, y: y_widget }
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // the immutable reference to `layout` through `view`
 | 
			
		||||
            // must be dropped
 | 
			
		||||
            // before `layout.press_key` borrows it mutably again
 | 
			
		||||
            let state_place = {
 | 
			
		||||
                let view = layout.get_current_view();
 | 
			
		||||
                let place = view.find_button_by_position(point);
 | 
			
		||||
                place.map(|place| {(
 | 
			
		||||
                    place.button.state.clone(),
 | 
			
		||||
                    place.into(),
 | 
			
		||||
                )})
 | 
			
		||||
            };
 | 
			
		||||
            
 | 
			
		||||
            if let Some((mut state, c_place)) = state_place {
 | 
			
		||||
            if let Some(position) = layout.get_button_at_point(point) {
 | 
			
		||||
                let mut state = position.button.state.clone();
 | 
			
		||||
                layout.press_key(
 | 
			
		||||
                    &VirtualKeyboard(virtual_keyboard),
 | 
			
		||||
                    &mut state,
 | 
			
		||||
                    Timestamp(time),
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                unsafe { eek_gtk_on_button_pressed(c_place, ui_keyboard) };
 | 
			
		||||
                // maybe TODO: draw on the display buffer here
 | 
			
		||||
                drawing::queue_redraw(ui_keyboard);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -449,23 +382,26 @@ pub mod c {
 | 
			
		||||
            );
 | 
			
		||||
            
 | 
			
		||||
            let pressed = layout.pressed_keys.clone();
 | 
			
		||||
            let state_place = {
 | 
			
		||||
            let button_info = {
 | 
			
		||||
                let view = layout.get_current_view();
 | 
			
		||||
                let place = view.find_button_by_position(point);
 | 
			
		||||
                place.map(|place| {(
 | 
			
		||||
                    place.button.state.clone(),
 | 
			
		||||
                    place.into(),
 | 
			
		||||
                    place.button.clone(),
 | 
			
		||||
                    view.bounds.get_position()
 | 
			
		||||
                        + place.row.bounds.clone().unwrap().get_position()
 | 
			
		||||
                        + place.button.bounds.get_position(),
 | 
			
		||||
                )})
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            if let Some((mut state, c_place)) = state_place {
 | 
			
		||||
            if let Some((mut state, _button, _view_position)) = button_info {
 | 
			
		||||
                let mut found = false;
 | 
			
		||||
                for wrapped_key in pressed {
 | 
			
		||||
                    let key: &Rc<RefCell<KeyState>> = wrapped_key.borrow();
 | 
			
		||||
                    if Rc::ptr_eq(&state, &wrapped_key.0) {
 | 
			
		||||
                        found = true;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        ui::release_key(
 | 
			
		||||
                        seat::handle_release_key(
 | 
			
		||||
                            layout,
 | 
			
		||||
                            &virtual_keyboard,
 | 
			
		||||
                            &widget_to_layout,
 | 
			
		||||
@ -477,12 +413,12 @@ pub mod c {
 | 
			
		||||
                }
 | 
			
		||||
                if !found {
 | 
			
		||||
                    layout.press_key(&virtual_keyboard, &mut state, time);
 | 
			
		||||
                    unsafe { eek_gtk_on_button_pressed(c_place, ui_keyboard) };
 | 
			
		||||
                    // maybe TODO: draw on the display buffer here
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                for wrapped_key in pressed {
 | 
			
		||||
                    let key: &Rc<RefCell<KeyState>> = wrapped_key.borrow();
 | 
			
		||||
                    ui::release_key(
 | 
			
		||||
                    seat::handle_release_key(
 | 
			
		||||
                        layout,
 | 
			
		||||
                        &virtual_keyboard,
 | 
			
		||||
                        &widget_to_layout,
 | 
			
		||||
@ -492,33 +428,7 @@ pub mod c {
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #[no_mangle]
 | 
			
		||||
        pub extern "C"
 | 
			
		||||
        fn squeek_layout_draw_all_changed(
 | 
			
		||||
            layout: *mut Layout,
 | 
			
		||||
            ui_keyboard: EekGtkKeyboard,
 | 
			
		||||
        ) {
 | 
			
		||||
            let layout = unsafe { &mut *layout };
 | 
			
		||||
            
 | 
			
		||||
            for row in &layout.get_current_view().rows {
 | 
			
		||||
                for button in &row.buttons {
 | 
			
		||||
                    let c_place = CButtonPlace::from(
 | 
			
		||||
                        ButtonPlace { row, button }
 | 
			
		||||
                    );
 | 
			
		||||
                    let state = RefCell::borrow(&button.state);
 | 
			
		||||
                    match (state.pressed, state.locked) {
 | 
			
		||||
                        (PressType::Released, false) => {}
 | 
			
		||||
                        (PressType::Pressed, _) => unsafe {
 | 
			
		||||
                            eek_gtk_on_button_pressed(c_place, ui_keyboard)
 | 
			
		||||
                        },
 | 
			
		||||
                        (_, true) => unsafe {
 | 
			
		||||
                            eek_gtk_render_locked_button(ui_keyboard, c_place)
 | 
			
		||||
                        },
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            drawing::queue_redraw(ui_keyboard);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #[cfg(test)]
 | 
			
		||||
@ -545,6 +455,12 @@ pub mod c {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Relative to `View`
 | 
			
		||||
struct ButtonPosition {
 | 
			
		||||
    view_position: c::Point,
 | 
			
		||||
    button: Button,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct ButtonPlace<'a> {
 | 
			
		||||
    button: &'a Button,
 | 
			
		||||
    row: &'a Row,
 | 
			
		||||
@ -654,7 +570,7 @@ pub struct Spacing {
 | 
			
		||||
pub struct View {
 | 
			
		||||
    /// Position relative to keyboard origin
 | 
			
		||||
    pub bounds: c::Bounds,
 | 
			
		||||
    pub rows: Vec<Box<Row>>,
 | 
			
		||||
    pub rows: Vec<Row>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl View {
 | 
			
		||||
@ -749,7 +665,7 @@ pub struct Layout {
 | 
			
		||||
    // Views own the actual buttons which have state
 | 
			
		||||
    // Maybe they should own UI only,
 | 
			
		||||
    // and keys should be owned by a dedicated non-UI-State?
 | 
			
		||||
    pub views: HashMap<String, Box<View>>,
 | 
			
		||||
    pub views: HashMap<String, View>,
 | 
			
		||||
 | 
			
		||||
    // Non-UI stuff
 | 
			
		||||
    /// xkb keymap applicable to the contained keys. Unchangeable
 | 
			
		||||
@ -768,7 +684,7 @@ pub struct Layout {
 | 
			
		||||
 | 
			
		||||
/// A builder structure for picking up layout data from storage
 | 
			
		||||
pub struct LayoutData {
 | 
			
		||||
    pub views: HashMap<String, Box<View>>,
 | 
			
		||||
    pub views: HashMap<String, View>,
 | 
			
		||||
    pub keymap_str: CString,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -789,7 +705,8 @@ impl Layout {
 | 
			
		||||
            locked_keys: HashSet::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn get_current_view(&self) -> &Box<View> {
 | 
			
		||||
 | 
			
		||||
    pub fn get_current_view(&self) -> &View {
 | 
			
		||||
        self.views.get(&self.current_view).expect("Selected nonexistent view")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -881,12 +798,24 @@ impl Layout {
 | 
			
		||||
            };
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_button_at_point(&self, point: c::Point) -> Option<ButtonPosition> {
 | 
			
		||||
        let view = self.get_current_view();
 | 
			
		||||
        let place = view.find_button_by_position(point);
 | 
			
		||||
        place.map(|place| ButtonPosition {
 | 
			
		||||
            button: place.button.clone(),
 | 
			
		||||
            // Rows have no business being inside a view
 | 
			
		||||
            // if they have no valid bounds.
 | 
			
		||||
            view_position: place.row.bounds.clone().unwrap().get_position()
 | 
			
		||||
                + place.button.bounds.get_position(),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mod procedures {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    type Path<'v> = (&'v Box<Row>, &'v Box<Button>);
 | 
			
		||||
    type Path<'v> = (&'v Row, &'v Box<Button>);
 | 
			
		||||
 | 
			
		||||
    /// Finds all `(row, button)` paths that refer to the specified key `state`
 | 
			
		||||
    pub fn find_key_paths<'v, 's>(
 | 
			
		||||
@ -918,24 +847,6 @@ mod procedures {
 | 
			
		||||
        }) == 1
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Switch off all UI buttons associated with the (state) key
 | 
			
		||||
    pub fn release_ui_buttons(
 | 
			
		||||
        view: &Box<View>,
 | 
			
		||||
        key: &Rc<RefCell<KeyState>>,
 | 
			
		||||
        ui_keyboard: c::EekGtkKeyboard,
 | 
			
		||||
    ) {
 | 
			
		||||
        let paths = ::layout::procedures::find_key_paths(&view, key);
 | 
			
		||||
        for (_row, button) in paths {
 | 
			
		||||
            unsafe {
 | 
			
		||||
                c::procedures::eek_gtk_on_button_released(
 | 
			
		||||
                    button.as_ref() as *const Button,
 | 
			
		||||
                    view.as_ref() as *const View,
 | 
			
		||||
                    ui_keyboard,
 | 
			
		||||
                );
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[cfg(test)]
 | 
			
		||||
    mod test {
 | 
			
		||||
        use super::*;
 | 
			
		||||
@ -957,12 +868,15 @@ mod procedures {
 | 
			
		||||
            let button = make_button_with_state("1".into(), state);
 | 
			
		||||
            let button_ptr = as_ptr(&button);
 | 
			
		||||
            
 | 
			
		||||
            let row = Box::new(Row {
 | 
			
		||||
            let row_bounds = Some(c::Bounds {
 | 
			
		||||
                x: 0.1, y: 2.3,
 | 
			
		||||
                width: 4.5, height: 6.7,
 | 
			
		||||
            });
 | 
			
		||||
            let row = Row {
 | 
			
		||||
                buttons: vec!(button),
 | 
			
		||||
                angle: 0,
 | 
			
		||||
                bounds: None
 | 
			
		||||
            });
 | 
			
		||||
            let row_ptr = as_ptr(&row);
 | 
			
		||||
                bounds: row_bounds.clone(),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            let view = View {
 | 
			
		||||
                bounds: c::Bounds {
 | 
			
		||||
@ -974,10 +888,10 @@ mod procedures {
 | 
			
		||||
 | 
			
		||||
            assert_eq!(
 | 
			
		||||
                find_key_paths(&view, &state_clone.clone()).iter()
 | 
			
		||||
                    .map(|(row, button)| { (as_ptr(row), as_ptr(button)) })
 | 
			
		||||
                    .map(|(row, button)| { (row.bounds.clone(), as_ptr(button)) })
 | 
			
		||||
                    .collect::<Vec<_>>(),
 | 
			
		||||
                vec!(
 | 
			
		||||
                    (row_ptr, button_ptr)
 | 
			
		||||
                    (row_bounds, button_ptr)
 | 
			
		||||
                )
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
@ -1012,15 +926,15 @@ mod procedures {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Top level UI procedures
 | 
			
		||||
mod ui {
 | 
			
		||||
/// Top level procedures, dispatching to everything
 | 
			
		||||
mod seat {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    // TODO: turn into release_button
 | 
			
		||||
    pub fn release_key(
 | 
			
		||||
    pub fn handle_release_key(
 | 
			
		||||
        layout: &mut Layout,
 | 
			
		||||
        virtual_keyboard: &VirtualKeyboard,
 | 
			
		||||
        widget_to_layout: &c::procedures::Transformation,
 | 
			
		||||
        widget_to_layout: &c::Transformation,
 | 
			
		||||
        time: Timestamp,
 | 
			
		||||
        ui_keyboard: c::EekGtkKeyboard,
 | 
			
		||||
        key: &Rc<RefCell<KeyState>>,
 | 
			
		||||
@ -1049,8 +963,6 @@ mod ui {
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        procedures::release_ui_buttons(view, key, ui_keyboard);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,8 @@
 | 
			
		||||
#[macro_use]
 | 
			
		||||
extern crate bitflags;
 | 
			
		||||
extern crate cairo;
 | 
			
		||||
extern crate cairo_sys;
 | 
			
		||||
extern crate gdk;
 | 
			
		||||
extern crate gio;
 | 
			
		||||
extern crate glib;
 | 
			
		||||
extern crate glib_sys;
 | 
			
		||||
@ -14,6 +17,7 @@ extern crate xkbcommon;
 | 
			
		||||
 | 
			
		||||
mod action;
 | 
			
		||||
pub mod data;
 | 
			
		||||
mod drawing;
 | 
			
		||||
pub mod float_ord;
 | 
			
		||||
pub mod imservice;
 | 
			
		||||
mod keyboard;
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user