Add XML layout engine (WIP).
This commit is contained in:
343
eek/eek-xml-layout.c
Normal file
343
eek/eek-xml-layout.c
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
/**
|
||||||
|
* SECTION:eek-xml-layout
|
||||||
|
* @short_description: Layout engine which loads layout information from XML
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
#include "eek-xml-layout.h"
|
||||||
|
#include "eek-keyboard.h"
|
||||||
|
#include "eek-section.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP_0,
|
||||||
|
PROP_SOURCE,
|
||||||
|
PROP_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (EekXmlLayout, eek_xml_layout, EEK_TYPE_LAYOUT);
|
||||||
|
|
||||||
|
#define EEK_XML_LAYOUT_GET_PRIVATE(obj) \
|
||||||
|
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_XML_LAYOUT, EekXmlLayoutPrivate))
|
||||||
|
|
||||||
|
struct _EekXmlLayoutPrivate
|
||||||
|
{
|
||||||
|
GInputStream *source;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BUFSIZE 8192
|
||||||
|
|
||||||
|
struct _ParseCallbackData {
|
||||||
|
GSList *element_stack;
|
||||||
|
GString *text;
|
||||||
|
EekLayout *layout;
|
||||||
|
EekKeyboard *keyboard;
|
||||||
|
EekSection *section;
|
||||||
|
EekKey *key;
|
||||||
|
};
|
||||||
|
typedef struct _ParseCallbackData ParseCallbackData;
|
||||||
|
|
||||||
|
static const gchar *valid_path_list[] = {
|
||||||
|
"keyboard",
|
||||||
|
"keyboard/bounds",
|
||||||
|
"keyboard/section",
|
||||||
|
"keyboard/outline",
|
||||||
|
"section/bounds",
|
||||||
|
"section/angle",
|
||||||
|
"section/key",
|
||||||
|
"bounds/key",
|
||||||
|
"outline/key",
|
||||||
|
"keysyms/key",
|
||||||
|
"keycode/key",
|
||||||
|
"index/key",
|
||||||
|
"groups/keysyms",
|
||||||
|
"levels/keysyms",
|
||||||
|
"keysym/keysyms",
|
||||||
|
"point/outline/keyboard"
|
||||||
|
};
|
||||||
|
|
||||||
|
static gchar *
|
||||||
|
join_element_names (GSList *element_names)
|
||||||
|
{
|
||||||
|
GString *string = g_string_sized_new (64);
|
||||||
|
|
||||||
|
if (element_names == NULL)
|
||||||
|
return g_strdup ("");
|
||||||
|
else
|
||||||
|
for (; element_names; element_names = g_slist_next (element_names)) {
|
||||||
|
g_string_append (string, element_names->data);
|
||||||
|
if (g_slist_next (element_names))
|
||||||
|
g_string_append (string, "/");
|
||||||
|
}
|
||||||
|
return g_string_free (string, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
validate (const gchar *element_name,
|
||||||
|
GSList *element_stack,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gint i;
|
||||||
|
gchar *element_path;
|
||||||
|
|
||||||
|
element_stack = g_slist_prepend (element_stack, element_name);
|
||||||
|
element_path = join_element_names (element_stack);
|
||||||
|
for (i = 0; i < G_N_ELEMENTS(valid_path_list); i++) {
|
||||||
|
if (*valid_path_list[i] == '@')
|
||||||
|
continue;
|
||||||
|
if (g_strcmp0 (element_path, valid_path_list[i]) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == G_N_ELEMENTS(valid_path_list)) {
|
||||||
|
g_set_error (error,
|
||||||
|
G_MARKUP_ERROR,
|
||||||
|
G_MARKUP_ERROR_UNKNOWN_ELEMENT,
|
||||||
|
"%s cannot appear under %s",
|
||||||
|
element_name,
|
||||||
|
element_path);
|
||||||
|
g_free (element_path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
g_free (element_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
start_element_callback (GMarkupParseContext *pcontext,
|
||||||
|
const gchar *element_name,
|
||||||
|
const gchar **attribute_names,
|
||||||
|
const gchar **attribute_values,
|
||||||
|
gpointer user_data,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
ParseCallbackData *data = user_data;
|
||||||
|
const gchar **names = attribute_names;
|
||||||
|
const gchar **values = attribute_values;
|
||||||
|
gint column = -1, row = -1;
|
||||||
|
gchar *name = NULL;
|
||||||
|
|
||||||
|
validate (element_name, data->element_stack, error);
|
||||||
|
if (error && *error)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (*names && *values) {
|
||||||
|
if (g_strcmp0 (*names, "column") == 0)
|
||||||
|
column = strtol (*values, NULL, 10);
|
||||||
|
else if (g_strcmp0 (*names, "row") == 0)
|
||||||
|
row = strtol (*values, NULL, 10);
|
||||||
|
else if (g_strcmp0 (*names, "name") == 0)
|
||||||
|
name = g_strdup (*values);
|
||||||
|
names++;
|
||||||
|
values++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_strcmp0 (element_name, "keyboard") == 0) {
|
||||||
|
data->keyboard = g_object_new (EEK_TYPE_KEYBOARD,
|
||||||
|
"layout", data->layout,
|
||||||
|
NULL);
|
||||||
|
if (name)
|
||||||
|
eek_element_set_name (EEK_ELEMENT(data->keyboard), name);
|
||||||
|
} else if (g_strcmp0 (element_name, "section") == 0) {
|
||||||
|
data->section = eek_keyboard_create_section (data->keyboard);
|
||||||
|
if (name)
|
||||||
|
eek_element_set_name (EEK_ELEMENT(data->section), name);
|
||||||
|
} else if (g_strcmp0 (element_name, "key") == 0) {
|
||||||
|
data->key = eek_section_create_key (data->section, column, row);
|
||||||
|
if (name)
|
||||||
|
eek_element_set_name (EEK_ELEMENT(data->key), name);
|
||||||
|
}
|
||||||
|
g_free (name);
|
||||||
|
|
||||||
|
data->element_stack = g_slist_prepend (data->element_stack,
|
||||||
|
g_strdup (element_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
end_element_callback (GMarkupParseContext *pcontext,
|
||||||
|
const gchar *element_name,
|
||||||
|
gpointer user_data,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
ParseCallbackData *data = user_data;
|
||||||
|
|
||||||
|
g_free (data->element_stack->data);
|
||||||
|
data->element_stack = g_slist_remove_link (data->element_stack,
|
||||||
|
data->element_stack);
|
||||||
|
g_slist_free1 (data->element_stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
text_callback (GMarkupParseContext *pcontext,
|
||||||
|
const gchar *text,
|
||||||
|
gsize text_len,
|
||||||
|
gpointer user_data,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static const GMarkupParser parser = {
|
||||||
|
start_element_callback,
|
||||||
|
end_element_callback,
|
||||||
|
text_callback,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
static EekKeyboard *
|
||||||
|
eek_xml_layout_real_create_keyboard (EekLayout *self,
|
||||||
|
gdouble initial_width,
|
||||||
|
gdouble initial_height)
|
||||||
|
{
|
||||||
|
EekXmlLayoutPrivate *priv = EEK_XML_LAYOUT_GET_PRIVATE (self);
|
||||||
|
GMarkupParseContext *pcontext;
|
||||||
|
GError *error;
|
||||||
|
gchar buffer[BUFSIZE];
|
||||||
|
ParseCallbackData data;
|
||||||
|
|
||||||
|
g_return_val_if_fail (priv->source, NULL);
|
||||||
|
|
||||||
|
data.element_stack = NULL;
|
||||||
|
data.text = g_string_sized_new (BUFSIZE);
|
||||||
|
data.keyboard = NULL;
|
||||||
|
pcontext = g_markup_parse_context_new (&parser, 0, &data, NULL);
|
||||||
|
while (1) {
|
||||||
|
gssize nread;
|
||||||
|
|
||||||
|
error = NULL;
|
||||||
|
nread = g_input_stream_read (G_INPUT_STREAM(priv->source),
|
||||||
|
buffer, sizeof buffer, NULL,
|
||||||
|
&error);
|
||||||
|
if (nread <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
error = NULL;
|
||||||
|
if (!g_markup_parse_context_parse (pcontext, buffer, nread, &error))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = NULL;
|
||||||
|
g_markup_parse_context_end_parse (pcontext, &error);
|
||||||
|
g_markup_parse_context_free (pcontext);
|
||||||
|
g_string_free (data.text, TRUE);
|
||||||
|
|
||||||
|
return data.keyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eek_xml_layout_set_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
switch (prop_id) {
|
||||||
|
case PROP_SOURCE:
|
||||||
|
eek_xml_layout_set_source (EEK_XML_LAYOUT(object),
|
||||||
|
g_value_get_object (value));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_object_set_property (object,
|
||||||
|
g_param_spec_get_name (pspec),
|
||||||
|
value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eek_xml_layout_get_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
switch (prop_id) {
|
||||||
|
case PROP_SOURCE:
|
||||||
|
g_value_set_object (value,
|
||||||
|
eek_xml_layout_get_source (EEK_XML_LAYOUT(object)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_object_get_property (object,
|
||||||
|
g_param_spec_get_name (pspec),
|
||||||
|
value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eek_xml_layout_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
EekXmlLayoutPrivate *priv = EEK_XML_LAYOUT_GET_PRIVATE (object);
|
||||||
|
|
||||||
|
if (priv->source) {
|
||||||
|
g_object_unref (priv->source);
|
||||||
|
priv->source = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eek_xml_layout_class_init (EekXmlLayoutClass *klass)
|
||||||
|
{
|
||||||
|
EekLayoutClass *layout_class = EEK_LAYOUT_CLASS (klass);
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||||
|
GParamSpec *pspec;
|
||||||
|
|
||||||
|
g_type_class_add_private (gobject_class, sizeof (EekXmlLayoutPrivate));
|
||||||
|
|
||||||
|
layout_class->create_keyboard = eek_xml_layout_real_create_keyboard;
|
||||||
|
|
||||||
|
gobject_class->set_property = eek_xml_layout_set_property;
|
||||||
|
gobject_class->get_property = eek_xml_layout_get_property;
|
||||||
|
gobject_class->dispose = eek_xml_layout_dispose;
|
||||||
|
|
||||||
|
pspec = g_param_spec_object ("source",
|
||||||
|
"Source",
|
||||||
|
"XML source input stram",
|
||||||
|
G_TYPE_INPUT_STREAM,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
g_object_class_install_property (gobject_class, PROP_SOURCE, pspec);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eek_xml_layout_init (EekXmlLayout *self)
|
||||||
|
{
|
||||||
|
EekXmlLayoutPrivate *priv;
|
||||||
|
|
||||||
|
priv = self->priv = EEK_XML_LAYOUT_GET_PRIVATE (self);
|
||||||
|
priv->source = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EekLayout *
|
||||||
|
eek_xml_layout_new (GInputStream *source)
|
||||||
|
{
|
||||||
|
return g_object_new (EEK_TYPE_XML_LAYOUT, "source", source, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eek_xml_layout_set_source (EekXmlLayout *layout,
|
||||||
|
GInputStream *source)
|
||||||
|
{
|
||||||
|
EekXmlLayoutPrivate *priv;
|
||||||
|
|
||||||
|
g_return_if_fail (EEK_IS_XML_LAYOUT(layout));
|
||||||
|
g_return_if_fail (G_IS_INPUT_STREAM(source));
|
||||||
|
|
||||||
|
priv = EEK_XML_LAYOUT_GET_PRIVATE(layout);
|
||||||
|
if (priv->source)
|
||||||
|
g_object_unref (priv->source);
|
||||||
|
priv->source = g_object_ref (source);
|
||||||
|
}
|
||||||
|
|
||||||
|
GInputStream *
|
||||||
|
eek_xml_layout_get_source (EekXmlLayout *layout)
|
||||||
|
{
|
||||||
|
EekXmlLayoutPrivate *priv;
|
||||||
|
|
||||||
|
g_assert (EEK_IS_XML_LAYOUT(layout));
|
||||||
|
priv = EEK_XML_LAYOUT_GET_PRIVATE(layout);
|
||||||
|
return priv->source;
|
||||||
|
}
|
||||||
47
eek/eek-xml-layout.h
Normal file
47
eek/eek-xml-layout.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#ifndef EEK_XML_LAYOUT_H
|
||||||
|
#define EEK_XML_LAYOUT_H 1
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include "eek-layout.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define EEK_TYPE_XML_LAYOUT (eek_xml_layout_get_type())
|
||||||
|
#define EEK_XML_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_XML_LAYOUT, EekXmlLayout))
|
||||||
|
#define EEK_XML_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_XML_LAYOUT, EekXmlLayoutClass))
|
||||||
|
#define EEK_IS_XML_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_XML_LAYOUT))
|
||||||
|
#define EEK_IS_XML_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_XML_LAYOUT))
|
||||||
|
#define EEK_XML_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_XML_LAYOUT, EekXmlLayoutClass))
|
||||||
|
|
||||||
|
typedef struct _EekXmlLayout EekXmlLayout;
|
||||||
|
typedef struct _EekXmlLayoutClass EekXmlLayoutClass;
|
||||||
|
typedef struct _EekXmlLayoutPrivate EekXmlLayoutPrivate;
|
||||||
|
|
||||||
|
struct _EekXmlLayout
|
||||||
|
{
|
||||||
|
/*< private >*/
|
||||||
|
EekLayout parent;
|
||||||
|
|
||||||
|
EekXmlLayoutPrivate *priv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _EekXmlLayoutClass
|
||||||
|
{
|
||||||
|
/*< private >*/
|
||||||
|
EekLayoutClass parent_class;
|
||||||
|
|
||||||
|
/* padding */
|
||||||
|
gpointer pdummy[24];
|
||||||
|
};
|
||||||
|
|
||||||
|
GType eek_xml_layout_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
|
EekLayout *eek_xml_layout_new (GInputStream *source);
|
||||||
|
|
||||||
|
void eek_xml_layout_set_source (EekXmlLayout *layout,
|
||||||
|
GInputStream *source);
|
||||||
|
|
||||||
|
GInputStream * eek_xml_layout_get_source (EekXmlLayout *layout);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
#endif /* EEK_XML_LAYOUT_H */
|
||||||
207
eek/eek-xml.c
Normal file
207
eek/eek-xml.c
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <glib/gprintf.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
#include "eek-section.h"
|
||||||
|
#include "eek-key.h"
|
||||||
|
#include "eek-xml.h"
|
||||||
|
|
||||||
|
#define g_string_append_indent(string, indent) \
|
||||||
|
{ \
|
||||||
|
gint i; \
|
||||||
|
for (i = 0; i < (indent); i++) { \
|
||||||
|
g_string_append (string, " "); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
G_INLINE_FUNC void
|
||||||
|
g_string_markup_printf (GString *output, const gchar *format, ...)
|
||||||
|
{
|
||||||
|
gchar *escaped_text;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start (ap, format);
|
||||||
|
escaped_text = g_markup_vprintf_escaped (format, ap);
|
||||||
|
va_end (ap);
|
||||||
|
|
||||||
|
g_string_append (output, escaped_text);
|
||||||
|
g_free (escaped_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct _OutputCallbackData {
|
||||||
|
GString *output;
|
||||||
|
gint indent;
|
||||||
|
GArray *outline_array;
|
||||||
|
};
|
||||||
|
typedef struct _OutputCallbackData OutputCallbackData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
output_bounds (GString *output, EekBounds *bounds)
|
||||||
|
{
|
||||||
|
g_string_markup_printf (output,
|
||||||
|
"<bounds>%lf,%lf,%lf,%lf</bounds>\n",
|
||||||
|
bounds->x,
|
||||||
|
bounds->y,
|
||||||
|
bounds->width,
|
||||||
|
bounds->height);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
output_key_callback (EekElement *element, gpointer user_data)
|
||||||
|
{
|
||||||
|
OutputCallbackData *data = user_data;
|
||||||
|
EekBounds bounds;
|
||||||
|
EekOutline *outline;
|
||||||
|
gint i, num_groups, num_levels;
|
||||||
|
guint *keysyms;
|
||||||
|
gint column, row;
|
||||||
|
|
||||||
|
eek_key_get_index (EEK_KEY(element), &column, &row);
|
||||||
|
g_string_append_indent (data->output, data->indent);
|
||||||
|
if (eek_element_get_name (element))
|
||||||
|
g_string_markup_printf (data->output,
|
||||||
|
"<key column=\"%d\" row=\"%d\" name=\"%s\">\n",
|
||||||
|
column, row, eek_element_get_name (element));
|
||||||
|
else
|
||||||
|
g_string_markup_printf (data->output,
|
||||||
|
"<key column=\"%d\" row=\"%d\">\n",
|
||||||
|
column, row);
|
||||||
|
|
||||||
|
eek_element_get_bounds (element, &bounds);
|
||||||
|
g_string_append_indent (data->output, data->indent + 1);
|
||||||
|
output_bounds (data->output, &bounds);
|
||||||
|
|
||||||
|
outline = eek_key_get_outline (EEK_KEY(element));
|
||||||
|
if (outline) {
|
||||||
|
for (i = 0;
|
||||||
|
i < data->outline_array->len &&
|
||||||
|
g_array_index (data->outline_array, gpointer, i) == outline;
|
||||||
|
i++)
|
||||||
|
;
|
||||||
|
if (i == data->outline_array->len)
|
||||||
|
g_array_append_val (data->outline_array, outline);
|
||||||
|
g_string_append_indent (data->output, data->indent + 1);
|
||||||
|
g_string_markup_printf (data->output,
|
||||||
|
"<outline>outline%d</outline>\n",
|
||||||
|
i);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_append_indent (data->output, data->indent + 1);
|
||||||
|
g_string_markup_printf (data->output, "<keycode>%u</keycode>\n",
|
||||||
|
eek_key_get_keycode (EEK_KEY(element)));
|
||||||
|
|
||||||
|
keysyms = NULL;
|
||||||
|
eek_key_get_keysyms (EEK_KEY(element), &keysyms, &num_groups, &num_levels);
|
||||||
|
if (keysyms) {
|
||||||
|
g_string_append_indent (data->output, data->indent + 1);
|
||||||
|
g_string_markup_printf (data->output,
|
||||||
|
"<keysyms groups=\"%d\" levels=\"%d\">\n",
|
||||||
|
num_groups, num_levels);
|
||||||
|
|
||||||
|
for (i = 0; i < num_groups * num_levels; i++) {
|
||||||
|
g_string_append_indent (data->output, data->indent + 2);
|
||||||
|
if (keysyms[i] != EEK_INVALID_KEYSYM) {
|
||||||
|
gchar *name = eek_keysym_to_string (keysyms[i]);
|
||||||
|
|
||||||
|
g_string_markup_printf (data->output,
|
||||||
|
"<keysym name=\"%s\">%u</keysym>\n",
|
||||||
|
name, keysyms[i]);
|
||||||
|
g_free (name);
|
||||||
|
} else
|
||||||
|
g_string_markup_printf (data->output,
|
||||||
|
"<keysym>%u</keysym>\n",
|
||||||
|
keysyms[i]);
|
||||||
|
}
|
||||||
|
g_string_append_indent (data->output, data->indent + 1);
|
||||||
|
g_string_markup_printf (data->output, "</keysyms>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_append_indent (data->output, data->indent);
|
||||||
|
g_string_markup_printf (data->output, "</key>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
output_section_callback (EekElement *element, gpointer user_data)
|
||||||
|
{
|
||||||
|
OutputCallbackData *data = user_data;
|
||||||
|
EekBounds bounds;
|
||||||
|
gint angle;
|
||||||
|
|
||||||
|
g_string_append_indent (data->output, data->indent);
|
||||||
|
if (eek_element_get_name (element))
|
||||||
|
g_string_markup_printf (data->output, "<section name=\"%s\">\n",
|
||||||
|
eek_element_get_name (element));
|
||||||
|
else
|
||||||
|
g_string_markup_printf (data->output, "<section>\n");
|
||||||
|
|
||||||
|
eek_element_get_bounds (element, &bounds);
|
||||||
|
g_string_append_indent (data->output, data->indent + 1);
|
||||||
|
output_bounds (data->output, &bounds);
|
||||||
|
|
||||||
|
angle = eek_section_get_angle (EEK_SECTION(element));
|
||||||
|
g_string_append_indent (data->output, data->indent + 1);
|
||||||
|
g_string_markup_printf (data->output, "<angle>%d</angle>\n", angle);
|
||||||
|
|
||||||
|
data->indent++;
|
||||||
|
eek_container_foreach_child (EEK_CONTAINER(element),
|
||||||
|
output_key_callback,
|
||||||
|
data);
|
||||||
|
data->indent--;
|
||||||
|
|
||||||
|
g_string_append_indent (data->output, data->indent);
|
||||||
|
g_string_markup_printf (data->output, "</section>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eek_keyboard_output (EekKeyboard *keyboard, GString *output, gint indent)
|
||||||
|
{
|
||||||
|
OutputCallbackData data;
|
||||||
|
EekBounds bounds;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
g_assert (EEK_IS_KEYBOARD(keyboard));
|
||||||
|
|
||||||
|
g_string_append_indent (output, indent);
|
||||||
|
g_string_markup_printf (output, "<?xml version=\"1.0\"?>\n<keyboard>\n");
|
||||||
|
|
||||||
|
eek_element_get_bounds (EEK_ELEMENT(keyboard), &bounds);
|
||||||
|
g_string_append_indent (output, indent + 1);
|
||||||
|
output_bounds (output, &bounds);
|
||||||
|
|
||||||
|
data.output = output;
|
||||||
|
data.indent = indent;
|
||||||
|
data.outline_array = g_array_new (FALSE, FALSE, sizeof (gpointer));
|
||||||
|
|
||||||
|
data.indent++;
|
||||||
|
eek_container_foreach_child (EEK_CONTAINER(keyboard),
|
||||||
|
output_section_callback,
|
||||||
|
&data);
|
||||||
|
data.indent--;
|
||||||
|
|
||||||
|
for (i = 0; i < data.outline_array->len; i++) {
|
||||||
|
EekOutline *outline;
|
||||||
|
gint j;
|
||||||
|
|
||||||
|
g_string_append_indent (output, indent + 1);
|
||||||
|
g_string_markup_printf (output, "<outline id=\"outline%d\">\n", i);
|
||||||
|
|
||||||
|
outline = g_array_index (data.outline_array, gpointer, i);
|
||||||
|
for (j = 0; j < outline->num_points; j++) {
|
||||||
|
g_string_append_indent (output, indent + 2);
|
||||||
|
g_string_markup_printf (output, "<point>%lf,%lf</point>\n",
|
||||||
|
outline->points[j].x,
|
||||||
|
outline->points[j].y);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_append_indent (output, indent + 1);
|
||||||
|
g_string_markup_printf (output, "</outline>\n");
|
||||||
|
}
|
||||||
|
g_array_free (data.outline_array, FALSE);
|
||||||
|
|
||||||
|
g_string_append_indent (output, indent);
|
||||||
|
g_string_markup_printf (output, "</keyboard>\n");
|
||||||
|
}
|
||||||
13
eek/eek-xml.h
Normal file
13
eek/eek-xml.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef EEK_XML_H
|
||||||
|
#define EEK_XML_H 1
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include "eek-keyboard.h"
|
||||||
|
#include "eek-xml-layout.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
void eek_keyboard_print (EekKeyboard *keyboard, gint indent);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
#endif /* EEK_XML_H */
|
||||||
Reference in New Issue
Block a user