Merge branch 'drop_key' into 'master'

Simplify renderer

See merge request Librem5/squeekboard!272
This commit is contained in:
Dorota Czaplejewicz
2019-12-15 16:38:31 +00:00
16 changed files with 346 additions and 849 deletions

3
Cargo.lock generated
View File

@ -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)",

View File

@ -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"]

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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 */

View File

@ -24,7 +24,6 @@
#include "config.h"
#include "eek-keyboard.h"
#include "src/keyboard.h"
#include "src/layout.h"
#include "eek-xml-layout.h"

View File

@ -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
View 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();
}

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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);
@ -55,10 +54,27 @@ pub mod c {
pub x: f64,
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,16 +184,26 @@ 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]
pub extern "C"
fn squeek_layout_get_keymap(layout: *const Layout) -> *const c_char {
@ -222,7 +229,7 @@ pub mod c {
use super::*;
use ::submission::c::ZwpVirtualKeyboardV1;
#[repr(C)]
#[derive(PartialEq, Debug)]
pub struct CButtonPlace {
@ -238,42 +245,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)]
@ -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
@ -403,27 +347,16 @@ pub mod c {
let point = widget_to_layout.forward(
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>(
@ -917,24 +846,6 @@ mod procedures {
c::procedures::eek_are_bounds_inside(bounds, point, origin, angle)
}) == 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 {
@ -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);
}
}

View File

@ -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;