support HTML <form>, <input> for text / password / submit
authoryu.dongliang <18588496441@163.com>
Sun, 20 Oct 2024 13:23:14 +0000 (21:23 +0800)
committeryu.dongliang <18588496441@163.com>
Sun, 20 Oct 2024 13:23:14 +0000 (21:23 +0800)
16 files changed:
examples/form.html [new file with mode: 0644]
html/abc_html.c
html/abc_obj.c
html/abc_obj.h
ui/Makefile
ui/abc.h
ui/abc_layout.c
ui/abc_layout_form.c [new file with mode: 0644]
ui/abc_layout_input.c [new file with mode: 0644]
ui/abc_layout_label.c [new file with mode: 0644]
ui/abc_render.c
ui/abc_render_form.c [new file with mode: 0644]
ui/abc_render_h1.c
ui/abc_render_input.c [new file with mode: 0644]
ui/abc_render_label.c [new file with mode: 0644]
ui/main.c

diff --git a/examples/form.html b/examples/form.html
new file mode 100644 (file)
index 0000000..8350c76
--- /dev/null
@@ -0,0 +1,19 @@
+<html>
+<title>test</title>
+<body>
+
+<form action="/" method="post">
+
+<label for="name">用户:</label>
+<input type="text" id="name" name="name">
+<br>
+
+<label for="password">密码:</label>
+<input type="password" id="password" name="password">
+<br>
+
+<input type="submit" value="提交">
+</form>
+
+</body>
+</html>
index 146b53b5c3a053370b2b4e1b0ef663ed5841900a..d4c4e532257a4bed75976d355bb2f1321a51c48e 100644 (file)
@@ -4,6 +4,7 @@ typedef struct {
        char* name;
        char* value;
        int   type;
+       int   flags;
 } html_attr_t;
 
 typedef struct {
@@ -20,59 +21,87 @@ typedef struct {
 
 static html_attr_t  h1_attrs[] =
 {
-       {"font",        "SimHei",     ABC_HTML_ATTR_FONT},
-       {"font-size",   "40",         ABC_HTML_ATTR_FONT_SIZE},
+       {"font",        "SimHei",     ABC_HTML_ATTR_FONT,      0},
+       {"font-size",   "40",         ABC_HTML_ATTR_FONT_SIZE, 0},
 };
 
 static html_attr_t  h2_attrs[] =
 {
-       {"font",        "SimHei",     ABC_HTML_ATTR_FONT},
-       {"font-size",   "32",         ABC_HTML_ATTR_FONT_SIZE},
+       {"font",        "SimHei",     ABC_HTML_ATTR_FONT,      0},
+       {"font-size",   "32",         ABC_HTML_ATTR_FONT_SIZE, 0},
 };
 
 static html_attr_t  h3_attrs[] =
 {
-       {"font",        "SimHei",     ABC_HTML_ATTR_FONT},
-       {"font-size",   "28",         ABC_HTML_ATTR_FONT_SIZE},
+       {"font",        "SimHei",     ABC_HTML_ATTR_FONT,      0},
+       {"font-size",   "28",         ABC_HTML_ATTR_FONT_SIZE, 0},
 };
 
 static html_attr_t  h4_attrs[] =
 {
-       {"font",        "SimHei",     ABC_HTML_ATTR_FONT},
-       {"font-size",   "24",         ABC_HTML_ATTR_FONT_SIZE},
+       {"font",        "SimHei",     ABC_HTML_ATTR_FONT,      0},
+       {"font-size",   "24",         ABC_HTML_ATTR_FONT_SIZE, 0},
 };
 
 static html_attr_t  h5_attrs[] =
 {
-       {"font",        "SimHei",     ABC_HTML_ATTR_FONT},
-       {"font-size",   "20",         ABC_HTML_ATTR_FONT_SIZE},
+       {"font",        "SimHei",     ABC_HTML_ATTR_FONT,      0},
+       {"font-size",   "20",         ABC_HTML_ATTR_FONT_SIZE, 0},
 };
 
 static html_attr_t  h6_attrs[] =
 {
-       {"font",        "SimHei",     ABC_HTML_ATTR_FONT},
-       {"font-size",   "16",         ABC_HTML_ATTR_FONT_SIZE},
+       {"font",        "SimHei",     ABC_HTML_ATTR_FONT,      0},
+       {"font-size",   "16",         ABC_HTML_ATTR_FONT_SIZE, 0},
 };
 
 static html_attr_t  p_attrs[] =
 {
-       {"font",        "SimSong",    ABC_HTML_ATTR_FONT},
-       {"font-size",   "16",         ABC_HTML_ATTR_FONT_SIZE},
+       {"font",        "SimSong",    ABC_HTML_ATTR_FONT,      0},
+       {"font-size",   "16",         ABC_HTML_ATTR_FONT_SIZE, 0},
 };
 
 static html_attr_t  a_attrs[] =
 {
-       {"href",        "",           ABC_HTML_ATTR_HREF},
-       {"font",        "SimHei",     ABC_HTML_ATTR_FONT},
-       {"font-size",   "24",         ABC_HTML_ATTR_FONT_SIZE},
-       {"font-color",  "blue",       ABC_HTML_ATTR_FONT_COLOR},
+       {"href",        "",           ABC_HTML_ATTR_HREF,       ABC_HTML_FLAG_SHOW},
+       {"font",        "SimHei",     ABC_HTML_ATTR_FONT,       0},
+       {"font-size",   "24",         ABC_HTML_ATTR_FONT_SIZE,  0},
+       {"font-color",  "blue",       ABC_HTML_ATTR_FONT_COLOR, 0},
 };
 
 static html_attr_t  img_attrs[] =
 {
-       {"src",         "",           ABC_HTML_ATTR_SRC},
-       {"width",       "100",        ABC_HTML_ATTR_WIDTH},
-       {"height",      "100",        ABC_HTML_ATTR_HEIGHT},
+       {"src",         "",           ABC_HTML_ATTR_SRC,        ABC_HTML_FLAG_SHOW},
+       {"width",       "100",        ABC_HTML_ATTR_WIDTH,      ABC_HTML_FLAG_SHOW},
+       {"height",      "100",        ABC_HTML_ATTR_HEIGHT,     ABC_HTML_FLAG_SHOW},
+};
+
+static html_attr_t  input_attrs[] =
+{
+       {"type",        "text",       ABC_HTML_ATTR_TYPE,       ABC_HTML_FLAG_SHOW},
+       {"id",          "",           ABC_HTML_ATTR_ID,         ABC_HTML_FLAG_SHOW},
+       {"name",        "",           ABC_HTML_ATTR_NAME,       ABC_HTML_FLAG_SHOW},
+       {"value",       "",           ABC_HTML_ATTR_VALUE,      ABC_HTML_FLAG_SHOW},
+
+       {"font",        "SimSong",    ABC_HTML_ATTR_FONT,       0},
+       {"font-size",   "16",         ABC_HTML_ATTR_FONT_SIZE,  0},
+};
+
+static html_attr_t  label_attrs[] =
+{
+       {"for",         "",           ABC_HTML_ATTR_FOR,        ABC_HTML_FLAG_SHOW},
+
+       {"font",        "SimSong",    ABC_HTML_ATTR_FONT,       0},
+       {"font-size",   "16",         ABC_HTML_ATTR_FONT_SIZE,  0},
+};
+
+static html_attr_t  form_attrs[] =
+{
+       {"action",      "/",          ABC_HTML_ATTR_ACTION,     ABC_HTML_FLAG_SHOW},
+       {"method",      "post",       ABC_HTML_ATTR_METHOD,     ABC_HTML_FLAG_SHOW},
+
+       {"font",        "SimSong",    ABC_HTML_ATTR_FONT,       0},
+       {"font-size",   "16",         ABC_HTML_ATTR_FONT_SIZE,  0},
 };
 
 static html_label_t  html_labels[] =
@@ -84,18 +113,22 @@ static html_label_t  html_labels[] =
 
        {"div",   ABC_HTML_DIV,   0, NULL, ABC_HTML_FLAG_CLOSE},
 
-       {"h1",    ABC_HTML_H1,    abc_number_of(h1_attrs),  h1_attrs,  ABC_HTML_FLAG_CLOSE},
-       {"h2",    ABC_HTML_H2,    abc_number_of(h2_attrs),  h2_attrs,  ABC_HTML_FLAG_CLOSE},
-       {"h3",    ABC_HTML_H3,    abc_number_of(h3_attrs),  h3_attrs,  ABC_HTML_FLAG_CLOSE},
-       {"h4",    ABC_HTML_H4,    abc_number_of(h4_attrs),  h4_attrs,  ABC_HTML_FLAG_CLOSE},
-       {"h5",    ABC_HTML_H5,    abc_number_of(h5_attrs),  h5_attrs,  ABC_HTML_FLAG_CLOSE},
-       {"h6",    ABC_HTML_H6,    abc_number_of(h6_attrs),  h6_attrs,  ABC_HTML_FLAG_CLOSE},
+       {"h1",    ABC_HTML_H1,    abc_number_of(h1_attrs),    h1_attrs,    ABC_HTML_FLAG_CLOSE},
+       {"h2",    ABC_HTML_H2,    abc_number_of(h2_attrs),    h2_attrs,    ABC_HTML_FLAG_CLOSE},
+       {"h3",    ABC_HTML_H3,    abc_number_of(h3_attrs),    h3_attrs,    ABC_HTML_FLAG_CLOSE},
+       {"h4",    ABC_HTML_H4,    abc_number_of(h4_attrs),    h4_attrs,    ABC_HTML_FLAG_CLOSE},
+       {"h5",    ABC_HTML_H5,    abc_number_of(h5_attrs),    h5_attrs,    ABC_HTML_FLAG_CLOSE},
+       {"h6",    ABC_HTML_H6,    abc_number_of(h6_attrs),    h6_attrs,    ABC_HTML_FLAG_CLOSE},
+
+       {"p",     ABC_HTML_P,     abc_number_of(p_attrs),     p_attrs,     ABC_HTML_FLAG_CLOSE},
+       {"br",    ABC_HTML_BR,    0,                          NULL,        ABC_HTML_FLAG_OPEN},
 
-       {"p",     ABC_HTML_P,     abc_number_of(p_attrs),   p_attrs,   ABC_HTML_FLAG_CLOSE},
-       {"br",    ABC_HTML_BR,    0, NULL,                             ABC_HTML_FLAG_OPEN},
+       {"a",     ABC_HTML_A,     abc_number_of(a_attrs),     a_attrs,     ABC_HTML_FLAG_CLOSE},
+       {"img",   ABC_HTML_IMG,   abc_number_of(img_attrs),   img_attrs,   ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SINGLE},
 
-       {"a",     ABC_HTML_A,     abc_number_of(a_attrs),   a_attrs,   ABC_HTML_FLAG_CLOSE},
-       {"img",   ABC_HTML_IMG,   abc_number_of(img_attrs), img_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SINGLE},
+       {"form",  ABC_HTML_FORM,  abc_number_of(form_attrs),  form_attrs,  ABC_HTML_FLAG_CLOSE},
+       {"input", ABC_HTML_INPUT, abc_number_of(input_attrs), input_attrs, ABC_HTML_FLAG_OPEN},
+       {"label", ABC_HTML_LABEL, abc_number_of(label_attrs), label_attrs, ABC_HTML_FLAG_CLOSE},
 };
 
 static int __html_parse_obj(abc_html_t* html, abc_char_t* c);
@@ -116,7 +149,7 @@ static html_label_t* __html_find_label(const char* name)
        return NULL;
 }
 
-static int __html_add_attr(abc_obj_t* obj, int type, const char* name, const char* value)
+static int __html_add_attr(abc_obj_t* obj, int type, const char* name, const char* value, int flags)
 {
        abc_obj_t* attr = abc_obj_alloc(NULL, 0, 0, type);
        if (!attr)
@@ -134,6 +167,8 @@ static int __html_add_attr(abc_obj_t* obj, int type, const char* name, const cha
                return -ENOMEM;
        }
 
+       attr->flags = flags;
+
        scf_list_add_tail(&obj->attrs, &attr->list);
        return 0;
 }
@@ -149,7 +184,7 @@ static int __html_load_attrs(abc_obj_t* obj, html_attr_t* attrs, int n_attrs)
        if (attrs && n_attrs > 0) {
 
                for (i = 0; i < n_attrs; i++) {
-                       ret = __html_add_attr(obj, attrs[i].type, attrs[i].name, attrs[i].value);
+                       ret = __html_add_attr(obj, attrs[i].type, attrs[i].name, attrs[i].value, attrs[i].flags);
                        if (ret < 0)
                                return ret;
                }
@@ -159,7 +194,7 @@ static int __html_load_attrs(abc_obj_t* obj, html_attr_t* attrs, int n_attrs)
                for (l   = scf_list_head(&obj->parent->attrs); l != scf_list_sentinel(&obj->parent->attrs); l = scf_list_next(l)) {
                        attr = scf_list_data(l, abc_obj_t, list);
 
-                       ret = __html_add_attr(obj, attr->type, attr->key->data, attr->value->data);
+                       ret = __html_add_attr(obj, attr->type, attr->key->data, attr->value->data, 0);
                        if (ret < 0)
                                return ret;
                }
@@ -304,11 +339,12 @@ static int __html_parse_text(abc_html_t* html, abc_obj_t* obj)
        text = NULL;
 
 
-       if (ABC_HTML_BR == obj->type) { // single label
+       if (ABC_HTML_FLAG_OPEN == (obj->flags & 0x1)) { // single labels
+
                __html_push_char(html, c);
                c = NULL;
                return 0;
-       }
+       };
 
        html->pos++;
        free(c);
index bc436e752251034d9836c08082ac7044523e7e2b..d7d0fd7e0a23b187bbd16e67f75a72f48d20de35 100644 (file)
@@ -135,18 +135,16 @@ void abc_obj_print(abc_obj_t* obj)
                return;
 
        if (obj->value)
-               printf(" %s=%s", obj->key->data, obj->value->data);
+               printf(" %s=\"%s\"", obj->key->data, obj->value->data);
        else if (obj->key)
                printf("<%s", obj->key->data);
 
 
-       if (ABC_HTML_FLAG_CLOSE & obj->flags) {
-
-               for (l = scf_list_head(&obj->attrs); l != scf_list_sentinel(&obj->attrs); l = scf_list_next(l)) {
-                       attr = scf_list_data(l, abc_obj_t, list);
+       for (l = scf_list_head(&obj->attrs); l != scf_list_sentinel(&obj->attrs); l = scf_list_next(l)) {
+               attr = scf_list_data(l, abc_obj_t, list);
 
+               if (ABC_HTML_FLAG_SHOW & attr->flags)
                        abc_obj_print(attr);
-               }
        }
 
        if (!obj->value) {
index eaad4a6a61a7f52f5e7a5c63dc022f969901d9a6..92a8917a29eb07b426aa5ac10eb2884848eccb37 100644 (file)
@@ -34,12 +34,25 @@ enum abc_objs
        // 15
        ABC_HTML_IMG,
 
+       ABC_HTML_FORM,
+       ABC_HTML_LABEL,
+       ABC_HTML_INPUT,
+
        ABC_HTML_NB, // total HTML objects
 
        ABC_HTML_ATTR_ID,
+       ABC_HTML_ATTR_TYPE,
+       ABC_HTML_ATTR_NAME,
+       ABC_HTML_ATTR_VALUE,
+
        ABC_HTML_ATTR_HREF,
        ABC_HTML_ATTR_SRC,
 
+       ABC_HTML_ATTR_FOR,
+
+       ABC_HTML_ATTR_ACTION,
+       ABC_HTML_ATTR_METHOD,
+
        ABC_HTML_ATTR_FONT,
        ABC_HTML_ATTR_FONT_SIZE,
        ABC_HTML_ATTR_FONT_COLOR,
@@ -64,6 +77,7 @@ struct abc_obj_s
 #define ABC_HTML_FLAG_OPEN   0
 #define ABC_HTML_FLAG_CLOSE  1
 #define ABC_HTML_FLAG_SINGLE 2
+#define ABC_HTML_FLAG_SHOW   4
        uint32_t        flags;
 
        int             x;
@@ -71,6 +85,9 @@ struct abc_obj_s
        int             w;
        int             h;
 
+       int             progress;
+       uint32_t        jiffies; // timeout numbers of sys timer
+
        scf_string_t*   key;
        scf_string_t*   value;
        scf_string_t*   text;
@@ -78,6 +95,8 @@ struct abc_obj_s
        scf_string_t*   file; // file name
        int             line; // line
        int             pos;  // position
+
+       uint32_t        clicked:1;
 };
 
 abc_obj_t*  abc_obj_alloc(scf_string_t* file, int line, int pos, int type);
index 4dc7d040c5db484bfdbec93a23271ae0bea8630e..a83c489154cdc8b12b5fdd9d08daca41f5db941f 100644 (file)
@@ -9,6 +9,9 @@ CFILES += abc_layout_div.c
 CFILES += abc_layout_h1.c
 CFILES += abc_layout_a.c
 CFILES += abc_layout_img.c
+CFILES += abc_layout_form.c
+CFILES += abc_layout_label.c
+CFILES += abc_layout_input.c
 
 CFILES += abc_render.c
 CFILES += abc_render_html.c
@@ -20,6 +23,9 @@ CFILES += abc_render_h1.c
 CFILES += abc_render_a.c
 CFILES += abc_render_a_href.c
 CFILES += abc_render_img.c
+CFILES += abc_render_form.c
+CFILES += abc_render_label.c
+CFILES += abc_render_input.c
 
 CFILES += ../html/abc_html.c
 CFILES += ../html/abc_html_util.c
index 02ac07e89935b4504b0dfa7bfb0c1606926af300..4ed637a4b67d0f27e31e8a557994711efe62acb5 100644 (file)
--- a/ui/abc.h
+++ b/ui/abc.h
@@ -32,16 +32,18 @@ struct abc_render_s
 
 struct abc_ctx_s
 {
-       scf_list_t   html_list;
-       abc_html_t*  current;
+       scf_list_t     html_list;
+       abc_html_t*    current;
 
-       GtkBuilder*  builder;
+       GtkBuilder*    builder;
 
-       GtkGLArea*   gl_area;
+       GtkGLArea*     gl_area;
 
-       GtkButton*   back;
-       GtkButton*   forward;
-       GtkButton*   refresh;
+       GtkButton*     back;
+       GtkButton*     forward;
+       GtkButton*     refresh;
+
+       GtkIMContext*  im;
 };
 
 #define ABC_CTX_INIT(__ctx) {SCF_LIST_INIT((__ctx).html_list), NULL, NULL, NULL, NULL, NULL, NULL}
index 3dde5fb3d0e1a04a37609c1770620dc6a27f8979..7b64e5da65460bede0809ca2b2a871348394846c 100644 (file)
@@ -10,31 +10,34 @@ int abc_layout_h1   (abc_layout_t* layout, abc_obj_t* obj, int width, int height
 int abc_layout_a    (abc_layout_t* layout, abc_obj_t* obj, int width, int height);
 int abc_layout_img  (abc_layout_t* layout, abc_obj_t* obj, int width, int height);
 
+int abc_layout_form (abc_layout_t* layout, abc_obj_t* obj, int width, int height);
+int abc_layout_label(abc_layout_t* layout, abc_obj_t* obj, int width, int height);
+int abc_layout_input(abc_layout_t* layout, abc_obj_t* obj, int width, int height);
+
 static abc_layout_pt abc_layouts[ABC_HTML_NB] =
 {
-       abc_layout_html,
-       abc_layout_title,
-       abc_layout_head,
-       abc_layout_body,
-
-       // 4
-       abc_layout_div,
-
-       // 5
-       abc_layout_h1,
-       abc_layout_h1,
-       abc_layout_h1,
-       abc_layout_h1,
-       abc_layout_h1,
-       abc_layout_h1,
-
-       // 11
-       abc_layout_h1, // <p>
-       abc_layout_h1, // <br>
-       abc_layout_a,
-       NULL,
-
-       abc_layout_img,
+       [ABC_HTML]         = abc_layout_html,
+       [ABC_HTML_TITLE]   = abc_layout_title,
+       [ABC_HTML_HEAD]    = abc_layout_head,
+       [ABC_HTML_BODY]    = abc_layout_body,
+       [ABC_HTML_DIV]     = abc_layout_div,
+
+       [ABC_HTML_H1]      = abc_layout_h1,
+       [ABC_HTML_H2]      = abc_layout_h1,
+       [ABC_HTML_H3]      = abc_layout_h1,
+       [ABC_HTML_H4]      = abc_layout_h1,
+       [ABC_HTML_H5]      = abc_layout_h1,
+       [ABC_HTML_H6]      = abc_layout_h1,
+
+       [ABC_HTML_P]       = abc_layout_h1,
+       [ABC_HTML_BR]      = abc_layout_h1,
+
+       [ABC_HTML_A]       = abc_layout_a,
+       [ABC_HTML_IMG]     = abc_layout_img,
+
+       [ABC_HTML_FORM]    = abc_layout_form,
+       [ABC_HTML_LABEL]   = abc_layout_label,
+       [ABC_HTML_INPUT]   = abc_layout_input,
 };
 
 int abc_layout_obj(abc_layout_t* layout, abc_obj_t* obj, int width, int height)
@@ -114,7 +117,7 @@ int abc_layout_root(abc_ctx_t* abc, abc_obj_t* root, int width, int height)
                };
 
                if (child->key)
-                       scf_logi("key: %s, x: %d, y: %d, w: %d, h: %d\n\n", child->key->data, child->x, child->y, child->w, child->h);
+                       scf_logd("key: %s, x: %d, y: %d, w: %d, h: %d\n\n", child->key->data, child->x, child->y, child->w, child->h);
 
                if (__w < child->x + child->w)
                        __w = child->x + child->w;
@@ -134,7 +137,7 @@ int abc_layout_root(abc_ctx_t* abc, abc_obj_t* root, int width, int height)
                root->h = __h;
 
        if (root->key)
-               scf_logi("key: %s, x: %d, y: %d, w: %d, h: %d\n", root->key->data, root->x, root->y, root->w, root->h);
+               scf_logd("key: %s, x: %d, y: %d, w: %d, h: %d\n", root->key->data, root->x, root->y, root->w, root->h);
 
        return 0;
 }
diff --git a/ui/abc_layout_form.c b/ui/abc_layout_form.c
new file mode 100644 (file)
index 0000000..9b7d25f
--- /dev/null
@@ -0,0 +1,43 @@
+#include"abc.h"
+
+int abc_layout_form(abc_layout_t* layout, abc_obj_t* obj, int width, int height)
+{
+       abc_obj_t*            attr;
+       cairo_text_extents_t  extents;
+       cairo_surface_t*      surface;
+       cairo_t*              cr;
+
+       if (!obj->text)
+               return 0;
+
+       surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+       cr      = cairo_create(surface);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT);
+       if (attr)
+               cairo_select_font_face(cr, attr->value->data, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_SIZE);
+       if (attr)
+               cairo_set_font_size(cr, atoi(attr->value->data));
+
+       cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
+       cairo_text_extents(cr, obj->text->data, &extents);
+
+       obj->x = 4;
+       obj->y = 4;
+       obj->w = extents.width  + extents.x_bearing;
+       obj->h = extents.height + extents.height / 2;
+
+       obj->w = (obj->w + 3) & ~0x3;
+       obj->h = (obj->h + 3) & ~0x3;
+
+       scf_logi("%s, w: %d, h: %d, x_bearing: %lg, y_bearing: %lg, width: %lg, height: %lg, x_advance: %lg, y_advance: %lg\n",
+                       obj->text->data, obj->w, obj->h,
+                       extents.x_bearing, extents.y_bearing, extents.width, extents.height,
+                       extents.x_advance, extents.y_advance);
+
+       cairo_destroy(cr);
+       cairo_surface_destroy(surface);
+       return 0;
+}
diff --git a/ui/abc_layout_input.c b/ui/abc_layout_input.c
new file mode 100644 (file)
index 0000000..b08bdfe
--- /dev/null
@@ -0,0 +1,54 @@
+#include"abc.h"
+
+int abc_layout_input(abc_layout_t* layout, abc_obj_t* obj, int width, int height)
+{
+       abc_obj_t*            attr;
+       cairo_text_extents_t  extents;
+       cairo_surface_t*      surface;
+       cairo_t*              cr;
+
+       char* text = "Hello HTML INPUT";
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_TYPE);
+
+       if (!strcmp(attr->value->data, "submit")) {
+
+               attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_VALUE);
+
+               if (attr && attr->value && attr->value->len > 0)
+                       text = attr->value->data;
+               else
+                       text = "submit";
+       }
+
+       surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+       cr      = cairo_create(surface);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT);
+       if (attr)
+               cairo_select_font_face(cr, attr->value->data, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_SIZE);
+       if (attr)
+               cairo_set_font_size(cr, atoi(attr->value->data));
+
+       cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
+       cairo_text_extents(cr, text, &extents);
+
+       obj->x = 4;
+       obj->y = 4;
+       obj->w = extents.width  + extents.x_bearing;
+       obj->h = extents.height;
+
+       obj->w = ((obj->w + 3) & ~0x3) + 8;
+       obj->h = ((obj->h + 3) & ~0x3) + 8;
+
+       scf_logd("%s, w: %d, h: %d, x_bearing: %lg, y_bearing: %lg, width: %lg, height: %lg, x_advance: %lg, y_advance: %lg\n",
+                       text, obj->w, obj->h,
+                       extents.x_bearing, extents.y_bearing, extents.width, extents.height,
+                       extents.x_advance, extents.y_advance);
+
+       cairo_destroy(cr);
+       cairo_surface_destroy(surface);
+       return 0;
+}
diff --git a/ui/abc_layout_label.c b/ui/abc_layout_label.c
new file mode 100644 (file)
index 0000000..7a7aa83
--- /dev/null
@@ -0,0 +1,43 @@
+#include"abc.h"
+
+int abc_layout_label(abc_layout_t* layout, abc_obj_t* obj, int width, int height)
+{
+       abc_obj_t*            attr;
+       cairo_text_extents_t  extents;
+       cairo_surface_t*      surface;
+       cairo_t*              cr;
+
+       if (!obj->text)
+               return 0;
+
+       surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+       cr      = cairo_create(surface);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT);
+       if (attr)
+               cairo_select_font_face(cr, attr->value->data, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_SIZE);
+       if (attr)
+               cairo_set_font_size(cr, atoi(attr->value->data));
+
+       cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
+       cairo_text_extents(cr, obj->text->data, &extents);
+
+       obj->x = 4;
+       obj->y = 4;
+       obj->w = extents.width  + extents.x_bearing;
+       obj->h = extents.height;
+
+       obj->w = ((obj->w + 3) & ~0x3) + 4;
+       obj->h = ((obj->h + 3) & ~0x3) + 4;
+
+       scf_logd("%s, w: %d, h: %d, x_bearing: %lg, y_bearing: %lg, width: %lg, height: %lg, x_advance: %lg, y_advance: %lg\n",
+                       obj->text->data, obj->w, obj->h,
+                       extents.x_bearing, extents.y_bearing, extents.width, extents.height,
+                       extents.x_advance, extents.y_advance);
+
+       cairo_destroy(cr);
+       cairo_surface_destroy(surface);
+       return 0;
+}
index 06c2d27de4e2e17a526ff0ac8b4e5f4d6d687efe..0b7960d4cd30207fe695f01be3b93c8b8f66ed94 100644 (file)
@@ -12,30 +12,35 @@ extern abc_render_t  abc_render_a;
 extern abc_render_t  abc_render_a_href;
 extern abc_render_t  abc_render_img;
 
+extern abc_render_t  abc_render_form;
+extern abc_render_t  abc_render_label;
+extern abc_render_t  abc_render_input;
+
 static abc_render_t* abc_renders[ABC_HTML_NB] =
 {
-       &abc_render_html,
-       &abc_render_title,
-       &abc_render_head,
-       &abc_render_body,
-
-       // 4
-       &abc_render_div,
-
-       &abc_render_h1,
-       &abc_render_h1,
-       &abc_render_h1,
-       &abc_render_h1,
-       &abc_render_h1,
-       &abc_render_h1,
-
-       // 11
-       &abc_render_h1, // <p>
-       &abc_render_h1, // <br>
-       &abc_render_a,
-       &abc_render_a_href,
-
-       &abc_render_img,
+       [ABC_HTML]         = &abc_render_html,
+       [ABC_HTML_TITLE]   = &abc_render_title,
+       [ABC_HTML_HEAD]    = &abc_render_head,
+       [ABC_HTML_BODY]    = &abc_render_body,
+       [ABC_HTML_DIV]     = &abc_render_div,
+
+       [ABC_HTML_H1]      = &abc_render_h1,
+       [ABC_HTML_H2]      = &abc_render_h1,
+       [ABC_HTML_H3]      = &abc_render_h1,
+       [ABC_HTML_H4]      = &abc_render_h1,
+       [ABC_HTML_H5]      = &abc_render_h1,
+       [ABC_HTML_H6]      = &abc_render_h1,
+
+       [ABC_HTML_P]       = &abc_render_h1,
+       [ABC_HTML_BR]      = &abc_render_h1,
+
+       [ABC_HTML_A]       = &abc_render_a,
+       [ABC_HTML_A_HREF]  = &abc_render_a_href,
+       [ABC_HTML_IMG]     = &abc_render_img,
+
+       [ABC_HTML_FORM]    = &abc_render_form,
+       [ABC_HTML_LABEL]   = &abc_render_label,
+       [ABC_HTML_INPUT]   = &abc_render_input,
 };
 
 int abc_renders_fini()
@@ -113,7 +118,7 @@ int abc_render_root(abc_ctx_t* ctx, abc_obj_t* root, int width, int height)
                }
        }
 
-       scf_logi("-----------------\n\n");
+       scf_logd("-----------------\n\n");
        return 0;
 }
 
diff --git a/ui/abc_render_form.c b/ui/abc_render_form.c
new file mode 100644 (file)
index 0000000..34ccda5
--- /dev/null
@@ -0,0 +1,147 @@
+#include"abc.h"
+
+static const char* vert_shader =
+       "#version 330 core\n"
+       "layout(location = 0) in vec4 position; \n"
+       "layout(location = 1) in vec2 a_texCoord; \n"
+       "out vec2 v_texCoord; \n"
+       "uniform mat4 mvp; \n"
+       "void main() { \n"
+               "gl_Position = mvp * position; \n"
+               "v_texCoord  = a_texCoord; \n"
+       "} \n";
+
+static const char* frag_shader =
+       "#version 330 core\n"
+       "in  vec2 v_texCoord; \n"
+       "out vec4 outputColor; \n"
+       "uniform sampler2D tex_rgba; \n"
+       "void main() { \n"
+       "    vec2 xy = v_texCoord; \n"
+       "    vec4 v  = texture2D(tex_rgba, xy).rgba; \n"
+       "    outputColor = vec4(v.b, v.g, v.r, 1.0); \n"
+       "} \n";
+
+
+static GLuint program = 0;
+
+static GLuint vao = 0;
+static GLuint buffers[2]   = {0};
+static GLuint texture_rgba = 0;
+
+static GLuint uniform_mvp;
+static GLuint uniform_rgba;
+
+
+static int _render_fini_form(abc_render_t* render)
+{
+       return 0;
+}
+
+static int _render_draw_form(abc_render_t* render, abc_obj_t* obj, int width, int height)
+{
+       if (!obj->text)
+               return 0;
+
+       if (0 == program)
+               __init_program(&program, vert_shader, frag_shader);
+
+       if (0 == vao)
+               __init_buffers(&vao, buffers);
+
+       if (0 == texture_rgba)
+               __init_texture(&texture_rgba, GL_RGBA, obj->w, obj->h, NULL);
+
+       abc_obj_t*            attr;
+       cairo_text_extents_t  extents;
+       cairo_surface_t*      surface;
+       cairo_t*              cr;
+
+       uint8_t* bgra = calloc(1, obj->w * obj->h * 4);
+       if (!bgra)
+               return -ENOMEM;
+
+       surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4);
+       cr      = cairo_create(surface);
+
+       cairo_set_line_width(cr, 1);
+       cairo_set_source_rgb(cr, 1, 1, 1);
+       cairo_rectangle(cr, 0, 0, obj->w, obj->h);
+       cairo_fill(cr);
+       cairo_stroke(cr);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT);
+       if (attr)
+               cairo_select_font_face(cr, attr->value->data, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_SIZE);
+       if (attr)
+               cairo_set_font_size(cr, atoi(attr->value->data));
+
+       cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
+       cairo_text_extents(cr, obj->text->data, &extents);
+
+       cairo_move_to  (cr, extents.x_bearing, -extents.y_bearing);
+       cairo_show_text(cr, obj->text->data);
+
+//     cairo_surface_write_to_png(surface, "tmp.png");
+
+       cairo_destroy(cr);
+       cairo_surface_destroy(surface);
+       surface = NULL;
+       cr = NULL;
+
+       float mvp[16];
+       __compute_mvp(mvp, 0, 0, 0);
+
+       scf_logi("%s, x: %d, y: %d, w: %d, h: %d\n", obj->text->data, obj->x, obj->y, obj->w, obj->h);
+
+       GLfloat vert_update[] =
+       {
+                2.0 *  obj->x           / (float)width  - 1.0,
+               -2.0 * (obj->y + obj->h) / (float)height + 1.0,
+
+                2.0 * (obj->x + obj->w) / (float)width  - 1.0,
+               -2.0 * (obj->y + obj->h) / (float)height + 1.0,
+
+                2.0 *  obj->x           / (float)width  - 1.0,
+               -2.0 *  obj->y           / (float)height + 1.0,
+
+                2.0 * (obj->x + obj->w) / (float)width  - 1.0,
+               -2.0 *  obj->y           / (float)height + 1.0,
+       };
+
+       glUseProgram(program);
+       uniform_rgba = glGetUniformLocation(program, "tex_rgba");
+       uniform_mvp  = glGetUniformLocation(program, "mvp");
+
+       glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, mvp);
+
+       // board
+       glActiveTexture(GL_TEXTURE0);
+       glBindTexture  (GL_TEXTURE_2D, texture_rgba);
+       glTexImage2D   (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
+       glUniform1i(uniform_rgba, 0);
+
+       // draw
+       glBindBuffer   (GL_ARRAY_BUFFER, buffers[0]);
+       glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vert_update), vert_update);
+
+       glBindVertexArray(vao);
+
+       glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+       glBindVertexArray(0);
+       glUseProgram(0);
+
+       free(bgra);
+       return 0;
+}
+
+abc_render_t  abc_render_form =
+{
+       .type = ABC_HTML_FORM,
+
+       .draw = _render_draw_form,
+       .fini = _render_fini_form,
+};
index f954d887cb5d9c22f26421698d39fab2cb5b03a4..35031373adfa2404003e2dfc48eec8d0bf64c800 100644 (file)
@@ -1,6 +1,6 @@
 #include"abc.h"
 
-const char* vert_shader =
+static const char* vert_shader =
        "#version 330 core\n"
        "layout(location = 0) in vec4 position; \n"
        "layout(location = 1) in vec2 a_texCoord; \n"
@@ -11,7 +11,7 @@ const char* vert_shader =
                "v_texCoord  = a_texCoord; \n"
        "} \n";
 
-const char* frag_shader =
+static const char* frag_shader =
        "#version 330 core\n"
        "in  vec2 v_texCoord; \n"
        "out vec4 outputColor; \n"
diff --git a/ui/abc_render_input.c b/ui/abc_render_input.c
new file mode 100644 (file)
index 0000000..8c7ebe0
--- /dev/null
@@ -0,0 +1,185 @@
+#include"abc.h"
+
+static const char* vert_shader =
+       "#version 330 core\n"
+       "layout(location = 0) in vec4 position; \n"
+       "layout(location = 1) in vec2 a_texCoord; \n"
+       "out vec2 v_texCoord; \n"
+       "uniform mat4 mvp; \n"
+       "void main() { \n"
+               "gl_Position = mvp * position; \n"
+               "v_texCoord  = a_texCoord; \n"
+       "} \n";
+
+static const char* frag_shader =
+       "#version 330 core\n"
+       "in  vec2 v_texCoord; \n"
+       "out vec4 outputColor; \n"
+       "uniform sampler2D tex_rgba; \n"
+       "void main() { \n"
+       "    vec2 xy = v_texCoord; \n"
+       "    vec4 v  = texture2D(tex_rgba, xy).rgba; \n"
+       "    outputColor = vec4(v.b, v.g, v.r, 1.0); \n"
+       "} \n";
+
+
+static GLuint program = 0;
+
+static GLuint vao = 0;
+static GLuint buffers[2]   = {0};
+static GLuint texture_rgba = 0;
+
+static GLuint uniform_mvp;
+static GLuint uniform_rgba;
+
+
+static int _render_fini_input(abc_render_t* render)
+{
+       return 0;
+}
+
+static int _render_draw_input(abc_render_t* render, abc_obj_t* obj, int width, int height)
+{
+       if (0 == program)
+               __init_program(&program, vert_shader, frag_shader);
+
+       if (0 == vao)
+               __init_buffers(&vao, buffers);
+
+       if (0 == texture_rgba)
+               __init_texture(&texture_rgba, GL_RGBA, obj->w, obj->h, NULL);
+
+       abc_obj_t*            type;
+       abc_obj_t*            attr;
+       cairo_text_extents_t  extents;
+       cairo_surface_t*      surface;
+       cairo_t*              cr;
+
+       uint8_t* bgra = calloc(1, obj->w * obj->h * 4);
+       if (!bgra)
+               return -ENOMEM;
+
+       surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4);
+       cr      = cairo_create(surface);
+
+       cairo_set_line_width(cr, 1);
+       cairo_set_source_rgb(cr, 1, 1, 1);
+       cairo_rectangle(cr, 0, 0, obj->w, obj->h);
+       cairo_fill(cr);
+       cairo_stroke(cr);
+
+       cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
+       cairo_set_line_width (cr, 2);
+       cairo_rectangle(cr, 2, 2, obj->w - 4, obj->h - 4);
+       cairo_stroke   (cr);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT);
+       if (attr)
+               cairo_select_font_face(cr, attr->value->data, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_SIZE);
+       if (attr)
+               cairo_set_font_size(cr, atoi(attr->value->data));
+
+       int x_cursor = 6;
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_VALUE);
+       type = abc_obj_find_attr(obj, ABC_HTML_ATTR_TYPE);
+
+       if (attr && attr->value && attr->value->len > 0) {
+
+               if (!strcmp(type->value->data, "password")) {
+
+                       char* passwd = strdup(attr->value->data);
+                       if (!passwd) {
+                               free(bgra);
+                               return -ENOMEM;
+                       }
+
+                       memset(passwd, '*', attr->value->len);
+
+                       cairo_text_extents(cr, passwd, &extents);
+                       cairo_move_to  (cr, extents.x_bearing + 4, -extents.y_bearing + (obj->h - extents.height) / 2);
+                       cairo_show_text(cr, passwd);
+
+                       free(passwd);
+                       passwd = NULL;
+               } else {
+                       cairo_text_extents(cr, attr->value->data, &extents);
+                       cairo_move_to  (cr, extents.x_bearing + 4, -extents.y_bearing + (obj->h - extents.height) / 2);
+                       cairo_show_text(cr, attr->value->data);
+               }
+               cairo_stroke(cr);
+
+               x_cursor = 6 + extents.x_bearing + extents.width;
+       }
+
+       if (obj->clicked && obj->jiffies % 72 < 36) {
+               cairo_set_line_width (cr, 1);
+
+               cairo_move_to(cr, x_cursor, 4);
+               cairo_line_to(cr, x_cursor, obj->h - 4);
+               cairo_stroke (cr);
+       }
+
+       cairo_surface_write_to_png(surface, "tmp.png");
+
+       cairo_destroy(cr);
+       cairo_surface_destroy(surface);
+       surface = NULL;
+       cr = NULL;
+
+       float mvp[16];
+       __compute_mvp(mvp, 0, 0, 0);
+
+       scf_logd("x: %d, y: %d, w: %d, h: %d\n", obj->x, obj->y, obj->w, obj->h);
+
+       GLfloat vert_update[] =
+       {
+                2.0 *  obj->x           / (float)width  - 1.0,
+               -2.0 * (obj->y + obj->h) / (float)height + 1.0,
+
+                2.0 * (obj->x + obj->w) / (float)width  - 1.0,
+               -2.0 * (obj->y + obj->h) / (float)height + 1.0,
+
+                2.0 *  obj->x           / (float)width  - 1.0,
+               -2.0 *  obj->y           / (float)height + 1.0,
+
+                2.0 * (obj->x + obj->w) / (float)width  - 1.0,
+               -2.0 *  obj->y           / (float)height + 1.0,
+       };
+
+       glUseProgram(program);
+       uniform_rgba = glGetUniformLocation(program, "tex_rgba");
+       uniform_mvp  = glGetUniformLocation(program, "mvp");
+
+       glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, mvp);
+
+       // board
+       glActiveTexture(GL_TEXTURE0);
+       glBindTexture  (GL_TEXTURE_2D, texture_rgba);
+       glTexImage2D   (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
+       glUniform1i(uniform_rgba, 0);
+
+       // draw
+       glBindBuffer   (GL_ARRAY_BUFFER, buffers[0]);
+       glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vert_update), vert_update);
+
+       glBindVertexArray(vao);
+
+       glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+       glBindVertexArray(0);
+       glUseProgram(0);
+
+       free(bgra);
+       return 0;
+}
+
+abc_render_t  abc_render_input =
+{
+       .type = ABC_HTML_INPUT,
+
+       .draw = _render_draw_input,
+       .fini = _render_fini_input,
+};
diff --git a/ui/abc_render_label.c b/ui/abc_render_label.c
new file mode 100644 (file)
index 0000000..c006420
--- /dev/null
@@ -0,0 +1,147 @@
+#include"abc.h"
+
+static const char* vert_shader =
+       "#version 330 core\n"
+       "layout(location = 0) in vec4 position; \n"
+       "layout(location = 1) in vec2 a_texCoord; \n"
+       "out vec2 v_texCoord; \n"
+       "uniform mat4 mvp; \n"
+       "void main() { \n"
+               "gl_Position = mvp * position; \n"
+               "v_texCoord  = a_texCoord; \n"
+       "} \n";
+
+static const char* frag_shader =
+       "#version 330 core\n"
+       "in  vec2 v_texCoord; \n"
+       "out vec4 outputColor; \n"
+       "uniform sampler2D tex_rgba; \n"
+       "void main() { \n"
+       "    vec2 xy = v_texCoord; \n"
+       "    vec4 v  = texture2D(tex_rgba, xy).rgba; \n"
+       "    outputColor = vec4(v.b, v.g, v.r, 1.0); \n"
+       "} \n";
+
+
+static GLuint program = 0;
+
+static GLuint vao = 0;
+static GLuint buffers[2]   = {0};
+static GLuint texture_rgba = 0;
+
+static GLuint uniform_mvp;
+static GLuint uniform_rgba;
+
+
+static int _render_fini_label(abc_render_t* render)
+{
+       return 0;
+}
+
+static int _render_draw_label(abc_render_t* render, abc_obj_t* obj, int width, int height)
+{
+       if (!obj->text)
+               return 0;
+
+       if (0 == program)
+               __init_program(&program, vert_shader, frag_shader);
+
+       if (0 == vao)
+               __init_buffers(&vao, buffers);
+
+       if (0 == texture_rgba)
+               __init_texture(&texture_rgba, GL_RGBA, obj->w, obj->h, NULL);
+
+       abc_obj_t*            attr;
+       cairo_text_extents_t  extents;
+       cairo_surface_t*      surface;
+       cairo_t*              cr;
+
+       uint8_t* bgra = calloc(1, obj->w * obj->h * 4);
+       if (!bgra)
+               return -ENOMEM;
+
+       surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4);
+       cr      = cairo_create(surface);
+
+       cairo_set_line_width(cr, 1);
+       cairo_set_source_rgb(cr, 1, 1, 1);
+       cairo_rectangle(cr, 0, 0, obj->w, obj->h);
+       cairo_fill(cr);
+       cairo_stroke(cr);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT);
+       if (attr)
+               cairo_select_font_face(cr, attr->value->data, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_SIZE);
+       if (attr)
+               cairo_set_font_size(cr, atoi(attr->value->data));
+
+       cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
+       cairo_text_extents(cr, obj->text->data, &extents);
+
+       cairo_move_to  (cr, extents.x_bearing + 2, -extents.y_bearing + 2);
+       cairo_show_text(cr, obj->text->data);
+
+//     cairo_surface_write_to_png(surface, "tmp.png");
+
+       cairo_destroy(cr);
+       cairo_surface_destroy(surface);
+       surface = NULL;
+       cr = NULL;
+
+       float mvp[16];
+       __compute_mvp(mvp, 0, 0, 0);
+
+       scf_logd("%s, x: %d, y: %d, w: %d, h: %d\n", obj->text->data, obj->x, obj->y, obj->w, obj->h);
+
+       GLfloat vert_update[] =
+       {
+                2.0 *  obj->x           / (float)width  - 1.0,
+               -2.0 * (obj->y + obj->h) / (float)height + 1.0,
+
+                2.0 * (obj->x + obj->w) / (float)width  - 1.0,
+               -2.0 * (obj->y + obj->h) / (float)height + 1.0,
+
+                2.0 *  obj->x           / (float)width  - 1.0,
+               -2.0 *  obj->y           / (float)height + 1.0,
+
+                2.0 * (obj->x + obj->w) / (float)width  - 1.0,
+               -2.0 *  obj->y           / (float)height + 1.0,
+       };
+
+       glUseProgram(program);
+       uniform_rgba = glGetUniformLocation(program, "tex_rgba");
+       uniform_mvp  = glGetUniformLocation(program, "mvp");
+
+       glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, mvp);
+
+       // board
+       glActiveTexture(GL_TEXTURE0);
+       glBindTexture  (GL_TEXTURE_2D, texture_rgba);
+       glTexImage2D   (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
+       glUniform1i(uniform_rgba, 0);
+
+       // draw
+       glBindBuffer   (GL_ARRAY_BUFFER, buffers[0]);
+       glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vert_update), vert_update);
+
+       glBindVertexArray(vao);
+
+       glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+       glBindVertexArray(0);
+       glUseProgram(0);
+
+       free(bgra);
+       return 0;
+}
+
+abc_render_t  abc_render_label =
+{
+       .type = ABC_HTML_LABEL,
+
+       .draw = _render_draw_label,
+       .fini = _render_fini_label,
+};
index 04e445eea91ce02023c9d2ae8a2b44b225cce152..51d2397055e368874ce62dab04ac53404bc2893d 100644 (file)
--- a/ui/main.c
+++ b/ui/main.c
@@ -7,23 +7,23 @@ static void resize(GtkGLArea* self, gint width, gint height, gpointer user_data)
        gtk_gl_area_make_current(self);
 
        if (gtk_gl_area_get_error(self) != NULL) {
-               printf("%s(),%d, error:\n", __func__, __LINE__);
+               scf_loge("\n");
                return;
        }
 
-       printf("%s(),%d, width: %d, height: %d\n", __func__, __LINE__, width, height);
+       scf_logi("width: %d, height: %d\n", width, height);
 
        context = gtk_gl_area_get_context(self);
 
        if (gdk_gl_context_get_use_es(context))
-               printf("%s(),%d, gles\n", __func__, __LINE__);
+               scf_logi("gles\n");
        else
-               printf("%s(),%d, gl\n", __func__, __LINE__);
+               scf_logi("gl\n");
 }
 
 static void unrealize(GtkWidget *widget)
 {
-       printf("%s(),%d\n", __func__, __LINE__);
+       scf_logi("\n");
 }
 
 static gboolean render(GtkGLArea* self, GdkGLContext* context, gpointer user_data)
@@ -60,6 +60,7 @@ static int __do_button_move(abc_ctx_t* ctx, int x, int y)
 
        abc_obj_t*  prev = ctx->current->current;
        abc_obj_t*  obj  = abc_obj_find(ctx->current->root, x, y);
+       abc_obj_t*  attr;
 
        int ret = 0;
 
@@ -73,6 +74,7 @@ static int __do_button_move(abc_ctx_t* ctx, int x, int y)
                gdk_window_set_cursor(window, cursor);
                g_object_unref(cursor);
 
+               prev->clicked = 0;
                ret = 1;
        }
 
@@ -80,7 +82,6 @@ static int __do_button_move(abc_ctx_t* ctx, int x, int y)
                scf_logd("obj: %s, x: %d, y: %d, w: %d, h: %d, event x: %d, y: %d\n",
                                obj->key->data, obj->x, obj->y, obj->w, obj->h, x, y);
 
-
                switch (obj->type) {
 
                        case ABC_HTML_A:
@@ -93,6 +94,22 @@ static int __do_button_move(abc_ctx_t* ctx, int x, int y)
 
                                ret = 1;
                                break;
+
+                       case ABC_HTML_INPUT:
+                               attr = abc_obj_get_attr(obj, ABC_HTML_ATTR_TYPE);
+                               if (attr) {
+                                       if (!strcmp(attr->value->data, "text") || !strcmp(attr->value->data, "password")) {
+
+                                               display = gtk_widget_get_display(GTK_WIDGET(ctx->gl_area));
+                                               window  = gtk_widget_get_window (GTK_WIDGET(ctx->gl_area));
+                                               cursor  = gdk_cursor_new_for_display(display, GDK_XTERM);
+
+                                               gdk_window_set_cursor(window, cursor);
+                                               g_object_unref(cursor);
+                                               ret = 1;
+                                       }
+                               }
+                               break;
                        default:
                                break;
                };
@@ -103,56 +120,75 @@ static int __do_button_move(abc_ctx_t* ctx, int x, int y)
        return ret;
 }
 
-static int __do_button_release(abc_ctx_t* ctx, int x, int y)
+static int __do_button_release_a(abc_ctx_t* ctx, abc_obj_t* obj, int x, int y)
 {
-       abc_html_t* html;
-       abc_obj_t*  attr;
-       abc_obj_t*  obj = abc_obj_find(ctx->current->root, x, y);
+       abc_html_t* html = NULL;
+       abc_obj_t*  attr = abc_obj_get_attr(obj, ABC_HTML_ATTR_HREF);
 
-       if (!obj)
-               return -ENOMEM;
+       int ret = abc_html_open(&html, attr->value->data);
+       if (ret < 0)
+               return ret;
 
-       scf_logd("obj: %s, x: %d, y: %d, w: %d, h: %d, event x: %d, y: %d\n",
-                       obj->key->data, obj->x, obj->y, obj->w, obj->h, x, y);
+       ret = abc_html_parse(html);
+       if (ret < 0) {
+               abc_html_close(html);
+               html = NULL;
+               return ret;
+       }
 
-       int ret = 0;
+       scf_list_add_tail(&ctx->html_list, &html->list);
 
-       if (ABC_HTML_A == obj->type) {
+       html->root->gtk_builder = ctx->builder;
 
-               html = NULL;
-               attr = abc_obj_get_attr(obj, ABC_HTML_ATTR_HREF);
+       ctx->current = html;
 
-               ret = abc_html_open(&html, attr->value->data);
-               if (ret < 0)
-                       return ret;
+       int width  = gtk_widget_get_allocated_width (GTK_WIDGET(ctx->gl_area));
+       int height = gtk_widget_get_allocated_height(GTK_WIDGET(ctx->gl_area));
 
-               ret = abc_html_parse(html);
-               if (ret < 0) {
-                       abc_html_close(html);
-                       html = NULL;
-                       return ret;
-               }
+       abc_layout_root(NULL, ctx->current->root, width, height);
 
-               scf_list_add_tail(&ctx->html_list, &html->list);
+       __do_button_move(ctx, x, y);
 
-               html->root->gtk_builder = ctx->builder;
+       gtk_widget_set_sensitive(GTK_WIDGET(ctx->back),    TRUE);
+       gtk_widget_set_sensitive(GTK_WIDGET(ctx->forward), FALSE);
 
-               ctx->current = html;
+       return 1;
+}
 
-               int width  = gtk_widget_get_allocated_width (GTK_WIDGET(ctx->gl_area));
-               int height = gtk_widget_get_allocated_height(GTK_WIDGET(ctx->gl_area));
+static int __do_button_release(abc_ctx_t* ctx, int x, int y)
+{
+       abc_obj_t* attr;
+       abc_obj_t* obj = abc_obj_find(ctx->current->root, x, y);
+       if (!obj)
+               return -ENOMEM;
 
-               abc_layout_root(NULL, ctx->current->root, width, height);
+       scf_logd("obj: %s, x: %d, y: %d, w: %d, h: %d, event x: %d, y: %d\n",
+                       obj->key->data, obj->x, obj->y, obj->w, obj->h, x, y);
 
-               __do_button_move(ctx, x, y);
+       switch (obj->type) {
 
-               gtk_widget_set_sensitive(GTK_WIDGET(ctx->back),    TRUE);
-               gtk_widget_set_sensitive(GTK_WIDGET(ctx->forward), FALSE);
+               case ABC_HTML_A:
+                       return __do_button_release_a(ctx, obj, x, y);
+                       break;
 
-               ret = 1;
-       }
+               case ABC_HTML_INPUT:
+                       obj->clicked = 1;
+                       obj->jiffies = 0;
 
-       return ret;
+                       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_TYPE);
+
+                       if (!strcmp(attr->value->data, "submit")) {
+                               abc_obj_print(ctx->current->root);
+                               return 0;
+                       }
+
+                       return __do_button_move(ctx, x, y);
+                       break;
+               default:
+                       break;
+       };
+
+       return 0;
 }
 
 static void back_clicked(GtkButton* self, gpointer user_data)
@@ -244,6 +280,9 @@ static gboolean button_release_event(GtkWidget* self, GdkEventButton* event, gpo
 
        if (gtk_widget_get_window(GTK_WIDGET(ctx->gl_area)) == event->window) {
 
+               scf_logw("event x_root: %f, y_root: %f, x: %f, y: %f\n",
+                               event->x_root, event->y_root, event->x, event->y);
+
                int ret = __do_button_release(ctx, event->x, event->y);
                if (ret > 0)
                        gtk_gl_area_queue_render(ctx->gl_area);
@@ -252,6 +291,58 @@ static gboolean button_release_event(GtkWidget* self, GdkEventButton* event, gpo
        return TRUE;
 }
 
+static void __utf8_delete(abc_ctx_t* ctx)
+{
+       abc_obj_t* obj;
+       abc_obj_t* attr;
+
+       if (!ctx->current || !ctx->current->current)
+               return;
+
+       obj = ctx->current->current;
+       if (ABC_HTML_INPUT != obj->type)
+               return;
+
+       attr = abc_obj_get_attr(obj, ABC_HTML_ATTR_TYPE);
+
+       if (!strcmp(attr->value->data, "text") || !strcmp(attr->value->data, "password")) {
+               uint8_t c;
+               int     i;
+
+               attr = abc_obj_get_attr(obj, ABC_HTML_ATTR_VALUE);
+
+               for (i = attr->value->len - 1; i >= 0; i--) {
+                       c  = attr->value->data[i];
+
+                       attr->value->data[--attr->value->len] = '\0';
+
+                       if (c < 0x80)
+                               break;
+
+                       if ((c >> 6) != 0x2)
+                               break;
+               }
+       }
+}
+
+static gboolean key_press_event(GtkWidget* self, GdkEventKey* event, gpointer user_data)
+{
+       abc_ctx_t* ctx = user_data;
+
+       scf_logi("event keyval: %c, %d\n", event->keyval, event->keyval);
+
+       switch (event->keyval) {
+               case GDK_KEY_BackSpace:
+               case GDK_KEY_Delete:
+                       __utf8_delete(ctx);
+                       break;
+               default:
+                       break;
+       };
+
+       return gtk_im_context_filter_keypress(ctx->im, event);
+}
+
 static gboolean button_move_event(GtkWidget* self, GdkEventMotion* event, gpointer user_data)
 {
        abc_ctx_t* ctx  = user_data;
@@ -263,6 +354,67 @@ static gboolean button_move_event(GtkWidget* self, GdkEventMotion* event, gpoint
        return TRUE;
 }
 
+static gboolean timer_handler(gpointer user_data)
+{
+       abc_ctx_t* ctx = user_data;
+       abc_obj_t* obj;
+
+       if (ctx->current) {
+               obj = ctx->current->current;
+
+               if (obj) {
+                       obj->jiffies++;
+                       gtk_gl_area_queue_render(ctx->gl_area);
+               }
+       }
+
+       return TRUE;
+}
+
+static void im_preedit_start(GtkIMContext* self, gpointer user_data)
+{
+}
+
+static void im_preedit_end(GtkIMContext* self, gpointer user_data)
+{
+}
+
+static void im_preedit_changed(GtkIMContext* self, gpointer user_data)
+{
+}
+
+static gboolean im_retrieve_surrounding(GtkIMContext* self, gpointer user_data)
+{
+       return TRUE;
+}
+
+static gboolean im_delete_surrounding(GtkIMContext* self, gint offset, gint n_chars, gpointer user_data)
+{
+       scf_logi("offset: %d, n_chars: %d\n", offset, n_chars);
+       return TRUE;
+}
+
+static void im_commit(GtkIMContext* self, gchar* str, gpointer user_data)
+{
+       abc_ctx_t* ctx = user_data;
+       abc_obj_t* obj;
+       abc_obj_t* attr;
+
+       scf_logw("str: %s\n", str);
+
+       if (ctx->current) {
+               obj = ctx->current->current;
+
+               if (obj && ABC_HTML_INPUT == obj->type) {
+                       attr = abc_obj_get_attr(obj, ABC_HTML_ATTR_VALUE);
+
+                       scf_string_cat_cstr(attr->value, str);
+
+                       gtk_gl_area_queue_render(ctx->gl_area);
+               }
+       }
+}
+
 int main(int argc, char *argv[])
 {
        abc_ctx_t   ctx = ABC_CTX_INIT(ctx);
@@ -337,8 +489,27 @@ int main(int argc, char *argv[])
        gtk_widget_add_events(GTK_WIDGET(gl_area), GDK_POINTER_MOTION_MASK);
 
        g_signal_connect(window,  "button-release-event", G_CALLBACK(button_release_event), &ctx);
+       g_signal_connect(window,  "key-press-event",      G_CALLBACK(key_press_event),      &ctx);
        g_signal_connect(gl_area, "motion-notify-event",  G_CALLBACK(button_move_event),    &ctx);
 
+       g_timeout_add(10, timer_handler, &ctx);
+
+       ctx.im = gtk_im_multicontext_new();
+       if (!ctx.im) {
+               scf_loge("\n");
+               return -ENOMEM;
+       }
+
+       gtk_im_context_set_client_window(ctx.im, gtk_widget_get_window(GTK_WIDGET(window)));
+       gtk_im_context_focus_in         (ctx.im);
+
+       g_signal_connect(ctx.im,  "commit",               G_CALLBACK(im_commit),             &ctx);
+       g_signal_connect(ctx.im,  "retrieve-surrounding", G_CALLBACK(im_preedit_changed),    &ctx);
+       g_signal_connect(ctx.im,  "delete-surrounding",   G_CALLBACK(im_delete_surrounding), &ctx);
+       g_signal_connect(ctx.im,  "preedit-changed",      G_CALLBACK(im_preedit_changed),    &ctx);
+       g_signal_connect(ctx.im,  "preedit-start",        G_CALLBACK(im_preedit_start),      &ctx);
+       g_signal_connect(ctx.im,  "preedit-end",          G_CALLBACK(im_preedit_end),        &ctx);
+
        gtk_widget_show_all(GTK_WIDGET(window));
 
        gtk_main();