add UI with GTK to make the electronic circuit easy
authoryu.dongliang <18588496441@163.com>
Sun, 8 Jun 2025 04:50:13 +0000 (12:50 +0800)
committeryu.dongliang <18588496441@163.com>
Sun, 8 Jun 2025 04:50:13 +0000 (12:50 +0800)
17 files changed:
Makefile
main.c
scf_eda_pack.c
scf_eda_pack.h
ses_core.h
ses_layout.c
ses_layout_function.c
ses_node_analysis.c
ses_step_battery.c
ses_step_draw.c
ses_ui.c [new file with mode: 0644]
ses_ui.glade [new file with mode: 0644]
ses_ui.h [new file with mode: 0644]
ses_ui_gl.c [new file with mode: 0644]
ses_ui_render.c [new file with mode: 0644]
ses_utils.c
test/fft.c

index d6d3cbae23350154560002264acd7a40d70217cc..bb305d96f46a217fd0448dc95bc4f385b2c85e1d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -35,12 +35,23 @@ CFILES += ses_step_draw.c
 CFLAGS += -g -D_GNU_SOURCE #-Wunused-variable
 CFLAGS += -I./
 CFLAGS += -I./pack
+CFLAGS += `pkg-config --cflags gtk+-3.0`
 
 LDFLAGS += -lm
 LDFLAGS += -lcairo
 LDFLAGS += -lgsl #-lgslcblas
+LDFLAGS += -lGL
+LDFLAGS += `pkg-config --libs gtk+-3.0`
+
+UI += ses_ui.c
+UI += ses_ui_gl.c
+UI += ses_ui_render.c
+UI += ses_step_draw.c
+UI += scf_eda_pack.c
+UI += ./pack/scf_pack.c
 
 all:
+       gcc $(CFLAGS) $(UI)     $(LDFLAGS) -o ses_ui
        gcc $(CFLAGS) $(CFILES) $(LDFLAGS) -o ses
 
 clean:
diff --git a/main.c b/main.c
index 5b00d39db057bb9cc0b354de3a190724143f9793..fdfcc3487eeb28f4bf925c354937d3940ec0e1fe 100644 (file)
--- a/main.c
+++ b/main.c
@@ -478,13 +478,15 @@ int main(int argc, char* argv[])
        char* args[256];
 
        usage();
-       printf("# ");
+       fprintf(stderr, "# ");
 
        while ((ret = getline(&buf, &len, stdin)) != -1) {
                char* p0 = buf;
                char* p1 = p0;
                int   i  = 0;
 
+               scf_logi("%s\n", buf);
+
                while (*p1) {
                        if (' ' == *p1 || '\n' == *p1 || '\r' == *p1 || '\t' == *p1) {
                                *p1 = '\0';
@@ -500,6 +502,11 @@ int main(int argc, char* argv[])
                                        return -1;
                                }
 
+                               if (0 == i && !strcmp(p0, "q")) {
+                                       free(buf);
+                                       return 0;
+                               }
+
                                args[i++] = p0;
                                p0 = ++p1;
                        } else
@@ -515,7 +522,7 @@ int main(int argc, char* argv[])
                if (ret < 0)
                        return ret;
 
-               printf("# ");
+               fprintf(stderr, "# ");
        }
 
        free(buf);
index c689c0e8fdbf56f83dd6da3a99fff76fd98b5f5b..eaadc2ee1fa480baf9acd86f3619802bd9045359 100644 (file)
@@ -418,7 +418,7 @@ static ScfEops __741_op_amp_ops =
 static ScfEdata  component_datas[] =
 {
        {SCF_EDA_None,       0,                   0, 0, 0,    0,   0,   0, 0, 0,   NULL, NULL, NULL},
-       {SCF_EDA_Battery,    0,                   0, 0, 0, 1e-9, 1e9,   0, 0, 0,   NULL, NULL, NULL},
+       {SCF_EDA_Battery,    0,                   0, 5, 0, 1e-9, 1e9,   0, 0, 0,   NULL, NULL, NULL},
        {SCF_EDA_Signal,     0,                   0, 0, 0, 1e-9, 1e9,   0, 0, 0,   NULL, NULL, NULL},
                                                                              
        {SCF_EDA_Resistor,   0,                   0, 0, 0,  1e4,   0,   0, 0, 0,   NULL, NULL, NULL},
@@ -568,12 +568,6 @@ int scf_eline__add_line(ScfEline* el, ScfLine*  l)
 
                if (el->lines[i] == l)
                        return 0;
-
-               if (el->lines[i]->x0 == l->x0
-                && el->lines[i]->y0 == l->y0
-                && el->lines[i]->x1 == l->x1
-                && el->lines[i]->y1 == l->y1)
-                       return 0;
        }
 
        void* p = realloc(el->lines, sizeof(ScfLine*) * (el->n_lines + 1));
@@ -721,9 +715,11 @@ int scf_eline__del_conn(ScfEline* el, ScfEconn* ec)
 
 ScfEpin* scf_epin__alloc()
 {
-       ScfEpin* pin = calloc(1, sizeof(ScfEpin));
+       ScfEpin* p = calloc(1, sizeof(ScfEpin));
+       if (p)
+               p->lid = -1;
 
-       return pin;
+       return p;
 }
 
 int scf_epin__add_component(ScfEpin* pin, uint64_t cid, uint64_t pid)
@@ -1322,3 +1318,87 @@ next:
 
        return 0;
 }
+
+void scf_efunction_find_pin(ScfEfunction* f, ScfEcomponent** pc, ScfEpin** pp, int x, int y)
+{
+       ScfEcomponent*  c;
+       ScfEpin*        p;
+
+       long i;
+       long j;
+
+       for (i = 0; i < f->n_components; i++) {
+               c  =        f->components[i];
+
+               scf_logd("c%ld, c->x: %d, c->y: %d, c->w: %d, c->h: %d, x: %d, y: %d\n", c->id, c->x, c->y, c->w, c->y, x, y);
+               if (x > c->x - c->w / 2
+                               && x < c->x + c->w / 2
+                               && y > c->y - c->h / 2
+                               && y < c->y + c->h / 2) {
+                       *pc = c;
+                       *pp = NULL;
+
+                       scf_logd("c%ld, %d,%d, x: %d, y: %d\n", c->id, c->x, c->y, x, y);
+                       return;
+               }
+
+               for (j = 0; j < c->n_pins; j++) {
+                       p  =        c->pins[j];
+
+                       if (x > p->x - 5
+                                       && x < p->x + 5
+                                       && y > p->y - 5
+                                       && y < p->y + 5) {
+                               *pc = c;
+                               *pp = p;
+
+                               scf_logi("c%ldp%ld, %d,%d, x: %d, y: %d\n", c->id, p->id, p->x, p->y, x, y);
+                               return;
+                       }
+               }
+       }
+}
+
+void scf_efunction_find_eline(ScfEfunction* f, ScfEline** pel, ScfLine** pl, int x, int y)
+{
+       ScfEline*  el;
+       ScfLine*   l;
+
+       long i;
+       long j;
+
+       for (i = 0; i < f->n_elines; i++) {
+               el =        f->elines[i];
+
+               for (j = el->n_lines - 1; j >= 0; j--) {
+                       l  = el->lines[j];
+
+                       if (x > l->x0 - 5
+                                       && x < l->x1 + 5
+                                       && y > l->y0 - 5
+                                       && y < l->y1 + 5) {
+
+                               scf_logi("j: %ld, (%d, %d)-->(%d, %d), x: %d, y: %d\n", j, l->x0, l->y0, l->x1, l->y1, x, y);
+
+                               *pel = el;
+                               *pl  = l;
+                               return;
+                       }
+               }
+       }
+}
+
+long scf_find_eline_index(ScfEfunction* f, int64_t lid)
+{
+       ScfEline* el;
+       long      j;
+
+       for (j = 0; j < f->n_elines; j++) {
+               el        = f->elines[j];
+
+               if (el->id == lid)
+                       return j;
+       }
+
+       return -1;
+}
index 3e2c02780d4a1fdbb383f9622035a5caab2693ca..eb0866b87da282aa37ad3e216fdf7407d1836544 100644 (file)
@@ -340,7 +340,7 @@ struct scf_epin_s
 {
        SCF_PACK_DEF_VAR(uint64_t, id);
        SCF_PACK_DEF_VAR(uint64_t, cid);
-       SCF_PACK_DEF_VAR(uint64_t, lid);
+       SCF_PACK_DEF_VAR(int64_t,  lid);
        SCF_PACK_DEF_VAR(uint64_t, flags);
        SCF_PACK_DEF_VARS(uint64_t, tos);
        SCF_PACK_DEF_VAR(uint64_t, c_lid);
@@ -597,7 +597,12 @@ ScfEboard*     scf_eboard__alloc();
 int            scf_eboard__add_function(ScfEboard* b, ScfEfunction* f);
 int            scf_eboard__del_function(ScfEboard* b, ScfEfunction* f);
 
-int            scf_pins_same_line(ScfEfunction* f);
+int            scf_pins_same_line  (ScfEfunction* f);
+
+long           scf_find_eline_index(ScfEfunction* f, int64_t lid);
+
+void           scf_efunction_find_pin  (ScfEfunction* f, ScfEcomponent** pc,  ScfEpin** pp, int x, int y);
+void           scf_efunction_find_eline(ScfEfunction* f, ScfEline**      pel, ScfLine** pl, int x, int y);
 
 #define EDA_INST_ADD_COMPONENT(_ef, _c, _type) \
        do { \
index 412a08363e094c801a6c38137527835833205e29..2bf98dcfa89e9d39fb08d62cfafffb3f94b99a1b 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef SES_CORE_H
 #define SES_CORE_H
 
+#include<cairo/cairo.h>
 #include"scf_vector.h"
 #include"scf_eda_pack.h"
 
@@ -156,6 +157,7 @@ ses_node_t*  ses_node_alloc();
 void         ses_node_free (ses_node_t* node);
 void         ses_node_print(ses_node_t* node);
 
+void         ses_edges_print(scf_vector_t* edges);
 void         ses_nodes_free (scf_vector_t* nodes);
 void         ses_nodes_print(scf_vector_t* nodes);
 void         ses_paths_print(scf_vector_t* paths);
@@ -181,8 +183,6 @@ int ses_steps_analyse(ScfEboard* b, ScfEfunction* f, int64_t ps, int64_t count,
 
 int ses_draw(ScfEfunction* f, const char* file, uint32_t bx, uint32_t by, uint32_t bw, uint32_t bh, int64_t ps, int64_t count);
 
-int  __ses_path_va_branch(ScfEfunction* f, ses_path_t* path, int m, int n, double pr, int* changed, int64_t ps, int64_t count);
-
 int __ses_nodes_paths      (ScfEfunction* f, scf_vector_t* paths, scf_vector_t** pnodes, scf_vector_t** pedges);
 int __ses_nodes_paths_solve(ScfEfunction* f, scf_vector_t* paths, int* changed, int64_t ps, int64_t count);
 
@@ -194,6 +194,17 @@ void __ses_path_lc(ScfEfunction* f, ses_path_t* path, int m, int n, double* cv,
 int  __ses_path_pos(ScfEfunction* f, ScfEline*   el, ScfEline* LP, ScfEline* LN);
 int  __ses_path_neg(ScfEfunction* f, ScfEline*   el, ScfEline* LP, ScfEline* LN);
 
+void __ses_draw_components(cairo_t* cr, ScfEfunction* f);
+void __ses_draw_elines    (cairo_t* cr, ScfEfunction* f, int64_t count);
+
+void __ses_draw_battery  (cairo_t* cr, ScfEcomponent* c);
+void __ses_draw_resistor (cairo_t* cr, ScfEcomponent* c);
+void __ses_draw_capacitor(cairo_t* cr, ScfEcomponent* c);
+void __ses_draw_inductor (cairo_t* cr, ScfEcomponent* c);
+void __ses_draw_crystal  (cairo_t* cr, ScfEcomponent* c);
+void __ses_draw_diode    (cairo_t* cr, ScfEcomponent* c);
+void __ses_draw_npn      (cairo_t* cr, ScfEcomponent* c);
+void __ses_draw_pnp      (cairo_t* cr, ScfEcomponent* c);
 
 static inline ScfEline* ses_top_line(ScfEline* el)
 {
index 62402d3ec1aa91b455c8d43fdea27789d09f9ab6..6b806ef70ea30c127c52d10ebf6acd3ca3884d96 100644 (file)
@@ -1,8 +1,6 @@
 #include<cairo/cairo.h>
 #include"ses_core.h"
 
-void __ses_function_draw(ScfEfunction* f, cairo_t* cr);
-
 int ses_layout_draw(ScfEboard* b, uint32_t bx, uint32_t by, uint32_t bw, uint32_t bh)
 {
        ScfEfunction*    f;
@@ -30,113 +28,8 @@ int ses_layout_draw(ScfEboard* b, uint32_t bx, uint32_t by, uint32_t bw, uint32_
        for (i = 0; i < b->n_functions; i++) {
                f  =        b->functions[i];
 
-               for (j = 0; j < f->n_elines; j++) {
-                       el =        f->elines[j];
-
-                       if (SCF_EDA_PIN_POS & el->flags)
-                               SHOW_COLOR(cr, 1, 0, 0);
-
-                       else if (SCF_EDA_PIN_NEG & el->flags)
-                               SHOW_COLOR(cr, 0, 0, 1);
-
-                       else if (SCF_EDA_PIN_IN0 & el->flags)
-                               SHOW_COLOR(cr, 0.8, 0, 0);
-
-                       else if (SCF_EDA_PIN_IN & el->flags)
-                               SHOW_COLOR(cr, 0.07, 0.6, 1.0);
-
-                       else if (SCF_EDA_PIN_DIV0 & el->flags)
-                               SHOW_COLOR(cr, 0, 1, 0);
-
-                       else if (SCF_EDA_PIN_OUT & el->flags)
-                               SHOW_COLOR(cr, 1, 0, 1);
-
-                       else if (SCF_EDA_PIN_SHIFT & el->flags)
-                               SHOW_COLOR(cr, 0.5, 0, 0.5);
-
-                       else if (SCF_EDA_PIN_CF & el->flags)
-                               SHOW_COLOR(cr, 0.8, 0, 0.8);
-
-                       else if (SCF_EDA_PIN_GND & el->flags)
-                               SHOW_COLOR(cr, 0.0, 0, 0.5);
-                       else
-                               SHOW_COLOR(cr, 1, 0.5, 0.1);
-
-                       uint8_t text[64];
-
-                       cairo_select_font_face(cr, "Calibri", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
-                       cairo_set_font_size   (cr, 22);
-
-                       ScfLine* prev = NULL;
-
-                       for (k = 0; k < el->n_lines; k++) {
-                               l  =        el->lines[k];
-
-                               if (l->x0 > l->x1)
-                                       continue;
-
-                               if (!prev) {
-                                       int n = snprintf(text, sizeof(text) - 1, "%ld", el->id);
-
-                                       cairo_move_to  (cr, l->x0 - 8 - n * 12, l->y0 + 12);
-                                       cairo_show_text(cr, text);
-                                       cairo_stroke(cr);
-
-                                       if (el->flags & (SCF_EDA_PIN_IN | SCF_EDA_PIN_OUT | SCF_EDA_PIN_DIV0 | SCF_EDA_PIN_SHIFT)) {
-                                               cairo_set_font_size(cr, 16);
-
-                                               if (el->flags & SCF_EDA_PIN_DIV0)
-                                                       n = snprintf(text, sizeof(text) - 1, "DIV0");
-
-                                               else if (el->flags & SCF_EDA_PIN_SHIFT)
-                                                       n = snprintf(text, sizeof(text) - 1, "T%ld", el->io_lid);
-                                               else
-                                                       n = snprintf(text, sizeof(text) - 1, "B%ld", el->io_lid);
-
-                                               cairo_move_to  (cr, l->x0 - 2 - n * 10, l->y0 + 28);
-                                               cairo_show_text(cr, text);
-                                               cairo_stroke(cr);
-                                       }
-
-                                       if (el->flags & SCF_EDA_PIN_GND) {
-                                               cairo_move_to(cr, l->x0,     l->y0);
-                                               cairo_line_to(cr, l->x0,     l->y0 + 8);
-                                               cairo_move_to(cr, l->x0 - 6, l->y0 + 8);
-                                               cairo_line_to(cr, l->x0 + 6, l->y0 + 8);
-                                               cairo_move_to(cr, l->x0 - 4, l->y0 + 12);
-                                               cairo_line_to(cr, l->x0 + 4, l->y0 + 12);
-                                               cairo_move_to(cr, l->x0 - 2, l->y0 + 16);
-                                               cairo_line_to(cr, l->x0 + 2, l->y0 + 16);
-                                               cairo_stroke(cr);
-                                       }
-                               }
-
-                               cairo_set_line_width(cr, 3);
-                               cairo_move_to(cr, l->x0, l->y0);
-                               cairo_line_to(cr, l->x1, l->y1);
-                               cairo_stroke(cr);
-
-                               if (prev) {
-                                       if (!(el->flags & SCF_EDA_PIN_BORDER))
-                                               cairo_set_line_width(cr, 1.5);
-
-                                       cairo_move_to(cr, prev->x0, prev->y0);
-                                       cairo_line_to(cr, l->x0,    l->y0);
-                                       cairo_stroke(cr);
-                               }
-
-                               prev = l;
-                       }
-                       cairo_stroke(cr);
-               }
-       }
-
-       cairo_set_line_width(cr, 2.5);
-
-       for (i = 0; i < b->n_functions; i++) {
-               f  =        b->functions[i];
-
-               __ses_function_draw(f, cr);
+               __ses_draw_elines    (cr, f, -1);
+               __ses_draw_components(cr, f);
        }
 
        cairo_surface_write_to_png(surface, "./2.png");
index 58410fb603c0f282499032b5a2b929d1f8c72fbc..b9e4565f2719f2397987327d6fbe4eb85f96ece3 100644 (file)
@@ -133,22 +133,6 @@ int ecomponent_cmp_cx(const void* v0, const void* v1)
        return 0;
 }
 
-static inline int __ses_find_eline_index(ScfEfunction* f, uint64_t lid)
-{
-       ScfEline* el;
-       size_t    j;
-
-       for (j = 0; j < f->n_elines; j++) {
-               el        = f->elines[j];
-
-               if (el->id == lid)
-                       break;
-       }
-       assert(j < f->n_elines);
-
-       return j;
-}
-
 int ses_lines_same_components(ScfEfunction* f)
 {
        ScfEline* el0;
@@ -285,7 +269,7 @@ static void __ses_layout_path2(ScfEfunction* f, ses_path_t* path, ses_path_t* ba
        long __n;
 
        bp  = base->pins->data[base->pins->size - 1];
-       __n = __ses_find_eline_index(f, bp->lid);
+       __n = scf_find_eline_index(f, bp->lid);
 
        scf_logd("path: %d, __n: %ld, l%ld\n", path->index, __n, f->elines[__n]->id);
 
@@ -298,14 +282,14 @@ static void __ses_layout_path2(ScfEfunction* f, ses_path_t* path, ses_path_t* ba
                        bp = base->pins->data[k];
 
                        if (p->lid == bp->lid) {
-                               __n = __ses_find_eline_index(f, bp->lid);
+                               __n = scf_find_eline_index(f, bp->lid);
 
                                scf_logd("__n: %ld, l%ld\n\n", __n, f->elines[__n]->id);
                                break;
                        }
                }
 
-               n = __ses_find_eline_index(f, p->lid);
+               n = scf_find_eline_index(f, p->lid);
 
                if (!f->elines[n]->vflag) {
                        f->elines[n]->vflag = 1;
@@ -380,13 +364,13 @@ static int __ses_layout_lines4(ScfEfunction* f)
        for (j = 0; j < base->pins->size; j += 2) {
                p  =        base->pins->data[j];
 
-               n  = __ses_find_eline_index(f, p->lid);
+               n  = scf_find_eline_index(f, p->lid);
 
                SCF_XCHG(f->elines[n], f->elines[j / 2]);
        }
 
        p = base->pins->data[j - 1];
-       n = __ses_find_eline_index(f, p->lid);
+       n = scf_find_eline_index(f, p->lid);
        SCF_XCHG(f->elines[n], f->elines[j / 2]);
 
        for (i = 0; i < f->n_elines; i++)
@@ -433,7 +417,7 @@ static void __ses_layout_key_components(ScfEfunction* f)
                for (j = LAYOUT_P0(c); j < c->n_pins; j++) {
                        p  = c->pins[j];
 
-                       n = __ses_find_eline_index(f, p->lid);
+                       n = scf_find_eline_index(f, p->lid);
 
                        if (!(f->elines[n]->flags & SCF_EDA_PIN_POS))
                                break;
@@ -445,7 +429,7 @@ static void __ses_layout_key_components(ScfEfunction* f)
                for (++j; j < c->n_pins; j++) {
                        p       = c->pins[j];
 
-                       k = __ses_find_eline_index(f, p->lid);
+                       k = scf_find_eline_index(f, p->lid);
 
                        if (f->elines[k]->flags & SCF_EDA_PIN_POS)
                                continue;
@@ -489,7 +473,7 @@ static int __ses_layout_lines2(ScfEfunction* f)
 
                        for (j = 0; j < el0->n_conns; j++) {
 
-                               int k = __ses_find_eline_index(f, el0->conns[j]->lid);
+                               int k = scf_find_eline_index(f, el0->conns[j]->lid);
                                if (max < k) {
                                        max = k;
                                        lid = el0->conns[j]->lid;
@@ -503,7 +487,7 @@ static int __ses_layout_lines2(ScfEfunction* f)
                for (j = i + 1; j < f->n_elines; j++)
                        f->elines[j - 1] = f->elines[j];
 
-               j = __ses_find_eline_index(f, lid);
+               j = scf_find_eline_index(f, lid);
 
                el1 = f->elines[j];
 
index b9328ada17a497ff2bd5cb34a08bf256471071dd..3bac660aaca8ab9bd69f324e329d8abafc3ded74 100644 (file)
@@ -1066,6 +1066,9 @@ static int __ses_nodes_split(scf_vector_t* groups, scf_vector_t* nodes, scf_vect
        ses_node_t*  node;
        ses_edge_t*  edge;
 
+       if (nodes->size <= 0)
+               return 0;
+
        while (nodes->size > 0) {
                node = nodes->data[0];
 
@@ -1159,6 +1162,13 @@ int __ses_nodes_paths_solve(ScfEfunction* f, scf_vector_t* paths, int* changed,
        if (ret < 0)
                goto error;
 
+       if (0 == nodes->size) {
+               ses_edges_print(edges);
+
+               ret = __ses_nodes_solve(f, nodes, edges, changed, ps, count);
+               goto error;
+       }
+
        ret = __ses_nodes_split(groups, nodes, edges);
        if (ret < 0)
                goto error;
index e6388b7c29fa30a6df83a7e30119adf150fe8465..7ab6b1401761adf61682ee98b2a79160c6e62d1e 100644 (file)
@@ -30,6 +30,9 @@ static int _battery_handler(ScfEfunction* f, int64_t ps, int64_t count, ses_ctx_
                LP = f->elines[Bp->lid];
                LN = f->elines[Bn->lid];
 
+               LP->flags |= SCF_EDA_PIN_POS;
+               LN->flags |= SCF_EDA_PIN_NEG;
+
                if (!LP->vconst) {
                        if (!LN->vconst) {
                                Bp->v = c->v;
@@ -55,7 +58,8 @@ static int _battery_handler(ScfEfunction* f, int64_t ps, int64_t count, ses_ctx_
 
                        LN->vconst = 1;
 
-                       LP->flags |= SCF_EDA_PIN_GND;
+                       LP->flags &= ~(SCF_EDA_PIN_POS | SCF_EDA_PIN_NEG);
+                       LP->flags |=   SCF_EDA_PIN_GND;
 
                } else if (LP->v - LN->v != c->v) {
                        scf_loge("Battery '%lgV' connected between line '%lgV' and '%lgV', diff: %lgV\n",
index 001a9675f0e75f40f01fc33766e3c2f872c6128b..83ca72353d00b65386d3641ef532800f32aaf362 100644 (file)
@@ -1,4 +1,3 @@
-#include<cairo/cairo.h>
 #include"ses_core.h"
 
 #define SHOW_BITS     1000.0
@@ -68,7 +67,371 @@ static void ses_text_v(cairo_t* cr, int x, int y, double v)
        }
 }
 
-void __ses_function_draw(ScfEfunction* f, cairo_t* cr)
+void __ses_draw_battery(cairo_t* cr, ScfEcomponent* c)
+{
+       ScfEpin*  p = c->pins[SCF_EDA_Battery_POS];
+
+       if (p->y < c->y) {
+               cairo_move_to(cr, c->x - 12, c->y - 5);
+               cairo_line_to(cr, c->x + 12, c->y - 5);
+
+               cairo_move_to(cr, c->x, c->y - 5);
+               cairo_line_to(cr, p->x, p->y);
+
+               cairo_move_to(cr, c->x - 8, c->y + 5);
+               cairo_line_to(cr, c->x + 8, c->y + 5);
+
+               p = c->pins[SCF_EDA_Battery_NEG];
+               cairo_move_to(cr, c->x, c->y + 5);
+               cairo_line_to(cr, p->x, p->y);
+
+       } else {
+               cairo_move_to(cr, c->x - 12, c->y + 5);
+               cairo_line_to(cr, c->x + 12, c->y + 5);
+
+               cairo_move_to(cr, c->x, c->y + 5);
+               cairo_line_to(cr, p->x, p->y);
+
+               cairo_move_to(cr, c->x - 8, c->y - 5);
+               cairo_line_to(cr, c->x + 8, c->y - 5);
+
+               p = c->pins[SCF_EDA_Battery_NEG];
+               cairo_move_to(cr, c->x, c->y - 5);
+               cairo_line_to(cr, p->x, p->y);
+       }
+
+       cairo_stroke(cr);
+}
+
+void __ses_draw_crystal(cairo_t* cr, ScfEcomponent* c)
+{
+       ScfEpin*  p0 = c->pins[0];
+       ScfEpin*  p1 = c->pins[1];
+
+       cairo_rectangle(cr, c->x - 8, c->y - 3, 16, 6);
+       cairo_fill(cr);
+       cairo_stroke(cr);
+
+       if (p0->y < c->y) {
+               cairo_move_to(cr, p0->x, p0->y);
+               cairo_line_to(cr, c->x,  c->y - 6);
+
+               cairo_move_to(cr, p1->x, p1->y);
+               cairo_line_to(cr, c->x,  c->y + 6);
+
+               cairo_move_to(cr, c->x - 6, c->y + 6);
+               cairo_line_to(cr, c->x + 6, c->y + 6);
+               cairo_stroke(cr);
+
+               SHOW_COLOR(cr, 0.0, 0.0, 0.8);
+               cairo_move_to(cr, c->x - 6, c->y - 6);
+               cairo_line_to(cr, c->x + 6, c->y - 6);
+               cairo_stroke(cr);
+       } else {
+               cairo_move_to(cr, p0->x, p0->y);
+               cairo_line_to(cr, c->x,  c->y + 6);
+
+               cairo_move_to(cr, p1->x, p1->y);
+               cairo_line_to(cr, c->x,  c->y - 6);
+
+               cairo_move_to(cr, c->x - 6, c->y - 6);
+               cairo_line_to(cr, c->x + 6, c->y - 6);
+               cairo_stroke(cr);
+
+               SHOW_COLOR(cr, 0.0, 0.0, 0.8);
+               cairo_move_to(cr, c->x - 6, c->y + 6);
+               cairo_line_to(cr, c->x + 6, c->y + 6);
+               cairo_stroke(cr);
+       }
+}
+
+void __ses_draw_capacitor(cairo_t* cr, ScfEcomponent* c)
+{
+       ScfEpin*  p;
+
+       SHOW_COLOR(cr, 0.8, 0.0, 0.0);
+       p = c->pins[SCF_EDA_Battery_POS];
+       if (p->y < c->y) {
+               cairo_move_to(cr, c->x - 8, c->y - 5);
+               cairo_line_to(cr, c->x + 8, c->y - 5);
+               cairo_stroke(cr);
+
+               SHOW_COLOR(cr, 0.6, 0.6, 0.0);
+               cairo_move_to(cr, c->x, c->y - 5);
+       } else {
+               cairo_move_to(cr, c->x - 8, c->y + 5);
+               cairo_line_to(cr, c->x + 8, c->y + 5);
+               cairo_stroke(cr);
+
+               SHOW_COLOR(cr, 0.6, 0.6, 0.0);
+               cairo_move_to(cr, c->x, c->y + 5);
+       }
+       cairo_line_to(cr, p->x, p->y);
+       cairo_stroke(cr);
+
+       SHOW_COLOR(cr, 0.0, 0.0, 0.8);
+       p = c->pins[SCF_EDA_Battery_NEG];
+       if (p->y < c->y) {
+               cairo_move_to(cr, c->x - 8, c->y - 5);
+               cairo_line_to(cr, c->x + 8, c->y - 5);
+               cairo_stroke(cr);
+
+               SHOW_COLOR(cr, 0.6, 0.6, 0.0);
+               cairo_move_to(cr, c->x, c->y - 5);
+       } else {
+               cairo_move_to(cr, c->x - 8, c->y + 5);
+               cairo_line_to(cr, c->x + 8, c->y + 5);
+               cairo_stroke(cr);
+
+               SHOW_COLOR(cr, 0.6, 0.6, 0.0);
+               cairo_move_to(cr, c->x, c->y + 5);
+       }
+       cairo_line_to(cr, p->x, p->y);
+       cairo_stroke(cr);
+}
+
+void __ses_draw_inductor(cairo_t* cr, ScfEcomponent* c)
+{
+       ScfEpin*  p;
+
+       SHOW_COLOR(cr, 0.8, 0.0, 0.0);
+       p = c->pins[SCF_EDA_Battery_POS];
+#define DRAW_Inductor() \
+       do { \
+               if (p->y < c->y) { \
+                       cairo_arc(cr, c->x + 1, c->y - 15, 5, M_PI * 0.45, M_PI * 1.55); \
+                       cairo_stroke(cr); \
+                       cairo_arc(cr, c->x + 1, c->y - 5, 5, M_PI * 0.45, M_PI * 1.55); \
+                       cairo_stroke(cr); \
+                       SHOW_COLOR(cr, 0.6, 0.6, 0.0); \
+                       cairo_move_to(cr, c->x, c->y - 19); \
+               } else { \
+                       cairo_arc(cr, c->x + 1, c->y + 15, 5, M_PI * 0.45, M_PI * 1.55); \
+                       cairo_stroke(cr); \
+                       cairo_arc(cr, c->x + 1, c->y + 5, 5, M_PI * 0.45, M_PI * 1.55); \
+                       cairo_stroke(cr); \
+                       SHOW_COLOR(cr, 0.6, 0.6, 0.0); \
+                       cairo_move_to(cr, c->x, c->y + 19); \
+               } \
+               cairo_line_to(cr, p->x, p->y); \
+       } while (0)
+
+       DRAW_Inductor();
+       cairo_stroke(cr);
+
+       SHOW_COLOR(cr, 0.0, 0.0, 0.8);
+       p = c->pins[SCF_EDA_Battery_NEG];
+       DRAW_Inductor();
+       cairo_stroke(cr);
+}
+
+void __ses_draw_resistor(cairo_t* cr, ScfEcomponent* c)
+{
+       ScfEpin*  p = c->pins[0];
+
+       int dx0;
+       int dx1;
+       int dy0;
+       int dy1;
+
+       vertical(&dx0, &dy0, c->x - p->x, c->y - p->y, 6);
+       forward (&dx1, &dy1, c->x - p->x, c->y - p->y, 12);
+
+       cairo_move_to(cr, p->x,       p->y);
+       cairo_line_to(cr, c->x - dx1, c->y - dy1);
+       cairo_stroke(cr);
+
+       SHOW_COLOR(cr, 0.0, 0.0, 0.8);
+
+       cairo_move_to    (cr,  c->x - dx1 + dx0, c->y - dy1 + dy0);
+       cairo_rel_line_to(cr,        -dx0 * 2,         -dy0 * 2);
+       cairo_stroke(cr);
+
+       SHOW_COLOR(cr, 0.6, 0.6, 0.0);
+
+       cairo_move_to    (cr,  c->x - dx1 - dx0, c->y - dy1 - dy0);
+       cairo_rel_line_to(cr,         dx1 * 2,          dy1 * 2);
+       cairo_rel_line_to(cr,         dx0 * 2,          dy0 * 2);
+       cairo_rel_line_to(cr,        -dx1 * 2,         -dy1 * 2);
+
+       p = c->pins[1];
+       cairo_move_to(cr,  p->x,       p->y);
+       cairo_line_to(cr,  c->x + dx1, c->y + dy1);
+       cairo_stroke(cr);
+}
+
+void __ses_draw_diode(cairo_t* cr, ScfEcomponent* c)
+{
+       ScfEpin*  p = c->pins[SCF_EDA_Diode_POS];
+
+       int dx0;
+       int dx1;
+       int dy0;
+       int dy1;
+
+       vertical(&dx0, &dy0, c->x - p->x, c->y - p->y,  8);
+       forward (&dx1, &dy1, c->x - p->x, c->y - p->y,  8);
+
+       cairo_move_to(cr, p->x,       p->y);
+       cairo_line_to(cr, c->x - dx1, c->y - dy1);
+
+       cairo_rel_move_to(cr,  dx0,              dy0);
+       cairo_rel_line_to(cr, -dx0 * 2,         -dy0 * 2);
+       cairo_line_to    (cr,  c->x + dx1,       c->y + dy1);
+       cairo_line_to    (cr,  c->x + dx0 - dx1, c->y + dy0 - dy1);
+
+       p = c->pins[SCF_EDA_Diode_NEG];
+
+       cairo_move_to    (cr,  p->x,        p->y);
+       cairo_line_to    (cr,  c->x + dx1,  c->y + dy1);
+       cairo_rel_move_to(cr,  dx0,         dy0);
+       cairo_rel_line_to(cr, -dx0 * 2,    -dy0 * 2);
+       cairo_stroke(cr);
+}
+
+void __ses_draw_npn(cairo_t* cr, ScfEcomponent* c)
+{
+       ScfEpin*  pb = c->pins[SCF_EDA_NPN_B];
+       ScfEpin*  pc = c->pins[SCF_EDA_NPN_C];
+       ScfEpin*  pe = c->pins[SCF_EDA_NPN_E];
+
+       int dx0;
+       int dy0;
+       int dx1;
+       int dy1;
+
+       int dx3;
+       int dy3;
+       int dx4;
+       int dy4;
+
+       vertical(&dx0, &dy0, c->x - pb->x, c->y - pb->y,  8);
+       forward (&dx3, &dy3, c->x - pb->x, c->y - pb->y,  8);
+
+       cairo_arc(cr, c->x - dx3 / 2, c->y - dy3 / 2, 12, 0, 2 * M_PI);
+
+       cairo_move_to    (cr,  pb->x,       pb->y);
+       cairo_line_to    (cr,  c->x - dx3,  c->y - dy3);
+       cairo_rel_move_to(cr,  dx0,         dy0);
+       cairo_rel_line_to(cr, -dx0 * 2,    -dy0 * 2);
+       cairo_stroke(cr);
+
+       if ((c->x + dx3 + dx0 > c->x + dx3 - dx0 && pe->x > pc->x)
+                       || (c->x + dx3 + dx0 < c->x + dx3 - dx0 && pe->x < pc->x)) {
+
+               cairo_move_to(cr, c->x - dx3,       c->y - dy3);
+               cairo_line_to(cr, c->x + dx3 + dx0, c->y + dy3 + dy0);
+               cairo_line_to(cr, pe->x,            c->y + dy3 + dy0);
+               cairo_line_to(cr, pe->x,            pe->y);
+
+               vertical(&dx1, &dy1, dx3 * 2 + dx0, dy3 * 2 + dy0, 3);
+               forward (&dx4, &dy4, dx3 * 2 + dx0, dy3 * 2 + dy0, 8);
+
+               cairo_move_to(cr, c->x + dx3 + dx0,        c->y + dy3 + dy0);
+               cairo_line_to(cr, c->x - dx3 + dx4 + dx1,  c->y - dy3 + dy4 + dy1);
+               cairo_move_to(cr, c->x + dx3 + dx0,        c->y + dy3 + dy0);
+               cairo_line_to(cr, c->x - dx3 + dx4 - dx1,  c->y - dy3 + dy4 - dy1);
+               cairo_stroke(cr);
+
+               cairo_move_to(cr, c->x - dx3,        c->y - dy3);
+               cairo_line_to(cr, c->x + dx3 - dx0,  c->y + dy3 - dy0);
+               cairo_line_to(cr, pc->x,             c->y + dy3 - dy0);
+               cairo_line_to(cr, pc->x,             pc->y);
+               cairo_stroke(cr);
+       } else {
+               cairo_move_to(cr, c->x - dx3,       c->y - dy3);
+               cairo_line_to(cr, c->x + dx3 + dx0, c->y + dy3 + dy0);
+               cairo_line_to(cr, pc->x,            c->y + dy3 + dy0);
+               cairo_line_to(cr, pc->x,            pc->y);
+               cairo_stroke(cr);
+
+               cairo_move_to(cr, c->x - dx3,        c->y - dy3);
+               cairo_line_to(cr, c->x + dx3 - dx0,  c->y + dy3 - dy0);
+               cairo_line_to(cr, pe->x,             c->y + dy3 - dy0);
+               cairo_line_to(cr, pe->x,             pe->y);
+
+               vertical(&dx1, &dy1, dx3 * 2 - dx0, dy3 * 2 - dy0, 3);
+               forward (&dx4, &dy4, dx3 * 2 - dx0, dy3 * 2 - dy0, 8);
+
+               cairo_move_to(cr, c->x + dx3 - dx0,        c->y + dy3 - dy0);
+               cairo_line_to(cr, c->x - dx3 + dx4 + dx1,  c->y - dy3 + dy4 + dy1);
+               cairo_move_to(cr, c->x + dx3 - dx0,        c->y + dy3 - dy0);
+               cairo_line_to(cr, c->x - dx3 + dx4 - dx1,  c->y - dy3 + dy4 - dy1);
+               cairo_stroke(cr);
+       }
+}
+
+void __ses_draw_pnp(cairo_t* cr, ScfEcomponent* c)
+{
+       ScfEpin*  pb = c->pins[SCF_EDA_PNP_B];
+       ScfEpin*  pc = c->pins[SCF_EDA_PNP_C];
+       ScfEpin*  pe = c->pins[SCF_EDA_PNP_E];
+
+       int dx0;
+       int dy0;
+       int dx1;
+       int dy1;
+
+       int dx3;
+       int dy3;
+       int dx4;
+       int dy4;
+
+       vertical(&dx0, &dy0, c->x - pb->x, c->y - pb->y,  8);
+       forward (&dx3, &dy3, c->x - pb->x, c->y - pb->y,  8);
+
+       cairo_arc(cr, c->x - dx3 / 2, c->y - dy3 / 2, 12, 0, 2 * M_PI);
+
+       cairo_move_to    (cr,  pb->x,       pb->y);
+       cairo_line_to    (cr,  c->x - dx3,  c->y - dy3);
+       cairo_rel_move_to(cr,  dx0,         dy0);
+       cairo_rel_line_to(cr, -dx0 * 2,    -dy0 * 2);
+       cairo_stroke(cr);
+
+       if ((c->x + dx3 + dx0 > c->x + dx3 - dx0 && pe->x > pc->x)
+        || (c->x + dx3 + dx0 < c->x + dx3 - dx0 && pe->x < pc->x)) {
+
+               cairo_move_to(cr, c->x - dx3,       c->y - dy3);
+               cairo_line_to(cr, c->x + dx3 + dx0, c->y + dy3 + dy0);
+               cairo_line_to(cr, pe->x,            c->y + dy3 + dy0);
+               cairo_line_to(cr, pe->x,            pe->y);
+
+               vertical(&dx1, &dy1, dx3 * 2 + dx0, dy3 * 2 + dy0, 4);
+               forward (&dx4, &dy4, dx3 * 2 + dx0, dy3 * 2 + dy0, 12);
+
+               cairo_move_to(cr, c->x - dx3 + dx4 + dx1,  c->y - dy3 + dy4 + dy1);
+               cairo_line_to(cr, c->x - dx3,              c->y - dy3);
+               cairo_line_to(cr, c->x - dx3 + dx4 - dx1,  c->y - dy3 + dy4 - dy1);
+               cairo_stroke(cr);
+
+               cairo_move_to(cr, c->x - dx3,        c->y - dy3);
+               cairo_line_to(cr, c->x + dx3 - dx0,  c->y + dy3 - dy0);
+               cairo_line_to(cr, pc->x,             c->y + dy3 - dy0);
+               cairo_line_to(cr, pc->x,             pc->y);
+               cairo_stroke(cr);
+       } else {
+               cairo_move_to(cr, c->x - dx3,       c->y - dy3);
+               cairo_line_to(cr, c->x + dx3 + dx0, c->y + dy3 + dy0);
+               cairo_line_to(cr, pc->x,            c->y + dy3 + dy0);
+               cairo_line_to(cr, pc->x,            pc->y);
+               cairo_stroke(cr);
+
+               cairo_move_to(cr, c->x - dx3,        c->y - dy3);
+               cairo_line_to(cr, c->x + dx3 - dx0,  c->y + dy3 - dy0);
+               cairo_line_to(cr, pe->x,             c->y + dy3 - dy0);
+               cairo_line_to(cr, pe->x,             pe->y);
+
+               vertical(&dx1, &dy1, dx3 * 2 - dx0, dy3 * 2 - dy0, 4);
+               forward (&dx4, &dy4, dx3 * 2 - dx0, dy3 * 2 - dy0, 12);
+
+               cairo_move_to(cr, c->x - dx3 + dx4 + dx1,  c->y - dy3 + dy4 + dy1);
+               cairo_line_to(cr, c->x - dx3,              c->y - dy3);
+               cairo_line_to(cr, c->x - dx3 + dx4 - dx1,  c->y - dy3 + dy4 - dy1);
+               cairo_stroke(cr);
+       }
+}
+
+void __ses_draw_components(cairo_t* cr, ScfEfunction* f)
 {
        ScfEcomponent*   c;
        ScfEpin*         p;
@@ -98,7 +461,7 @@ void __ses_function_draw(ScfEfunction* f, cairo_t* cr)
                switch (c->type) {
                        case SCF_EDA_Resistor:
                                n = snprintf(text, sizeof(text) - 1, "R%ld", c->id);
-
                                cairo_move_to(cr, c->x + 10, c->y + 8);
                                break;
 
@@ -206,14 +569,15 @@ void __ses_function_draw(ScfEfunction* f, cairo_t* cr)
                for (k = 0; k < c->n_pins; k++) {
                        p  =        c->pins[k];
 
-                       cairo_arc (cr, p->x, p->y, 4, 0, 2 * M_PI);
-                       cairo_fill(cr);
+                       if (p->lid >= 0) {
+                               cairo_arc (cr, p->x, p->y, 4, 0, 2 * M_PI);
+                               cairo_fill(cr);
+                       }
                }
                cairo_stroke(cr);
 
                int dx0;
                int dy0;
-
                int dx1;
                int dy1;
 
@@ -225,79 +589,15 @@ void __ses_function_draw(ScfEfunction* f, cairo_t* cr)
                switch (c->type) {
 
                        case SCF_EDA_Battery:
-                               p = c->pins[SCF_EDA_Battery_POS];
-
-                               if (p->y < c->y) {
-                                       cairo_move_to(cr, c->x - 12, c->y - 5);
-                                       cairo_line_to(cr, c->x + 12, c->y - 5);
-
-                                       cairo_move_to(cr, c->x, c->y - 5);
-                                       cairo_line_to(cr, p->x, p->y);
-
-                                       cairo_move_to(cr, c->x - 8, c->y + 5);
-                                       cairo_line_to(cr, c->x + 8, c->y + 5);
+                               __ses_draw_battery(cr, c);
 
-                                       p = c->pins[SCF_EDA_Battery_NEG];
-                                       cairo_move_to(cr, c->x, c->y + 5);
-                                       cairo_line_to(cr, p->x, p->y);
-
-                               } else {
-                                       cairo_move_to(cr, c->x - 12, c->y + 5);
-                                       cairo_line_to(cr, c->x + 12, c->y + 5);
-
-                                       cairo_move_to(cr, c->x, c->y + 5);
-                                       cairo_line_to(cr, p->x, p->y);
-
-                                       cairo_move_to(cr, c->x - 8, c->y - 5);
-                                       cairo_line_to(cr, c->x + 8, c->y - 5);
-
-                                       p = c->pins[SCF_EDA_Battery_NEG];
-                                       cairo_move_to(cr, c->x, c->y - 5);
-                                       cairo_line_to(cr, p->x, p->y);
-                               }
+                               cairo_select_font_face(cr, "Georgia", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
 
-                               cairo_stroke(cr);
+                               ses_text_v(cr, c->x + 12, c->y + 8, c->v);
                                break;
 
                        case SCF_EDA_Crystal:
-                               cairo_rectangle(cr, c->x - 8, c->y - 3, 16, 6);
-                               cairo_fill(cr);
-                               cairo_stroke(cr);
-
-                               p0 = c->pins[0];
-                               p1 = c->pins[1];
-
-                               if (p0->y < c->y) {
-                                       cairo_move_to(cr, p0->x, p0->y);
-                                       cairo_line_to(cr, c->x,  c->y - 6);
-
-                                       cairo_move_to(cr, p1->x, p1->y);
-                                       cairo_line_to(cr, c->x,  c->y + 6);
-
-                                       cairo_move_to(cr, c->x - 6, c->y + 6);
-                                       cairo_line_to(cr, c->x + 6, c->y + 6);
-                                       cairo_stroke(cr);
-
-                                       SHOW_COLOR(cr, 0.0, 0.0, 0.8);
-                                       cairo_move_to(cr, c->x - 6, c->y - 6);
-                                       cairo_line_to(cr, c->x + 6, c->y - 6);
-                                       cairo_stroke(cr);
-                               } else {
-                                       cairo_move_to(cr, p0->x, p0->y);
-                                       cairo_line_to(cr, c->x,  c->y + 6);
-
-                                       cairo_move_to(cr, p1->x, p1->y);
-                                       cairo_line_to(cr, c->x,  c->y - 6);
-
-                                       cairo_move_to(cr, c->x - 6, c->y - 6);
-                                       cairo_line_to(cr, c->x + 6, c->y - 6);
-                                       cairo_stroke(cr);
-
-                                       SHOW_COLOR(cr, 0.0, 0.0, 0.8);
-                                       cairo_move_to(cr, c->x - 6, c->y + 6);
-                                       cairo_line_to(cr, c->x + 6, c->y + 6);
-                                       cairo_stroke(cr);
-                               }
+                               __ses_draw_crystal(cr, c);
 
                                cairo_select_font_face(cr, "Georgia", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
 
@@ -318,46 +618,7 @@ void __ses_function_draw(ScfEfunction* f, cairo_t* cr)
                                break;
 
                        case SCF_EDA_Capacitor:
-                               SHOW_COLOR(cr, 0.8, 0.0, 0.0);
-
-                               p = c->pins[SCF_EDA_Battery_POS];
-                               if (p->y < c->y) {
-                                       cairo_move_to(cr, c->x - 8, c->y - 5);
-                                       cairo_line_to(cr, c->x + 8, c->y - 5);
-                                       cairo_stroke(cr);
-
-                                       SHOW_COLOR(cr, 0.6, 0.6, 0.0);
-                                       cairo_move_to(cr, c->x, c->y - 5);
-                               } else {
-                                       cairo_move_to(cr, c->x - 8, c->y + 5);
-                                       cairo_line_to(cr, c->x + 8, c->y + 5);
-                                       cairo_stroke(cr);
-
-                                       SHOW_COLOR(cr, 0.6, 0.6, 0.0);
-                                       cairo_move_to(cr, c->x, c->y + 5);
-                               }
-                               cairo_line_to(cr, p->x, p->y);
-                               cairo_stroke(cr);
-
-                               SHOW_COLOR(cr, 0.0, 0.0, 0.8);
-                               p = c->pins[SCF_EDA_Battery_NEG];
-                               if (p->y < c->y) {
-                                       cairo_move_to(cr, c->x - 8, c->y - 5);
-                                       cairo_line_to(cr, c->x + 8, c->y - 5);
-                                       cairo_stroke(cr);
-
-                                       SHOW_COLOR(cr, 0.6, 0.6, 0.0);
-                                       cairo_move_to(cr, c->x, c->y - 5);
-                               } else {
-                                       cairo_move_to(cr, c->x - 8, c->y + 5);
-                                       cairo_line_to(cr, c->x + 8, c->y + 5);
-                                       cairo_stroke(cr);
-
-                                       SHOW_COLOR(cr, 0.6, 0.6, 0.0);
-                                       cairo_move_to(cr, c->x, c->y + 5);
-                               }
-                               cairo_line_to(cr, p->x, p->y);
-                               cairo_stroke(cr);
+                               __ses_draw_capacitor(cr, c);
 
                                cairo_select_font_face(cr, "Georgia", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
 
@@ -379,35 +640,7 @@ void __ses_function_draw(ScfEfunction* f, cairo_t* cr)
                                break;
 
                        case SCF_EDA_Inductor:
-                               SHOW_COLOR(cr, 0.8, 0.0, 0.0);
-                               p = c->pins[SCF_EDA_Battery_POS];
-#define DRAW_Inductor() \
-                               do { \
-                                       if (p->y < c->y) { \
-                                               cairo_arc(cr, c->x + 1, c->y - 15, 5, M_PI * 0.45, M_PI * 1.55); \
-                                               cairo_stroke(cr); \
-                                               cairo_arc(cr, c->x + 1, c->y - 5, 5, M_PI * 0.45, M_PI * 1.55); \
-                                               cairo_stroke(cr); \
-                                               SHOW_COLOR(cr, 0.6, 0.6, 0.0); \
-                                               cairo_move_to(cr, c->x, c->y - 19); \
-                                       } else { \
-                                               cairo_arc(cr, c->x + 1, c->y + 15, 5, M_PI * 0.45, M_PI * 1.55); \
-                                               cairo_stroke(cr); \
-                                               cairo_arc(cr, c->x + 1, c->y + 5, 5, M_PI * 0.45, M_PI * 1.55); \
-                                               cairo_stroke(cr); \
-                                               SHOW_COLOR(cr, 0.6, 0.6, 0.0); \
-                                               cairo_move_to(cr, c->x, c->y + 19); \
-                                       } \
-                                       cairo_line_to(cr, p->x, p->y); \
-                               } while (0)
-
-                               DRAW_Inductor();
-                               cairo_stroke(cr);
-
-                               SHOW_COLOR(cr, 0.0, 0.0, 0.8);
-                               p = c->pins[SCF_EDA_Battery_NEG];
-                               DRAW_Inductor();
-                               cairo_stroke(cr);
+                               __ses_draw_inductor(cr, c);
 
                                cairo_select_font_face(cr, "Georgia", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
 
@@ -431,32 +664,7 @@ void __ses_function_draw(ScfEfunction* f, cairo_t* cr)
                                break;
 
                        case SCF_EDA_Resistor:
-                               p = c->pins[0];
-
-                               vertical(&dx0, &dy0, c->x - p->x, c->y - p->y, 6);
-                               forward (&dx1, &dy1, c->x - p->x, c->y - p->y, 12);
-
-                               cairo_move_to(cr, p->x,       p->y);
-                               cairo_line_to(cr, c->x - dx1, c->y - dy1);
-                               cairo_stroke(cr);
-
-                               SHOW_COLOR(cr, 0.0, 0.0, 0.8);
-
-                               cairo_move_to    (cr,  c->x - dx1 + dx0, c->y - dy1 + dy0);
-                               cairo_rel_line_to(cr, -dx0 * 2,   -dy0 * 2);
-                               cairo_stroke(cr);
-
-                               SHOW_COLOR(cr, 0.6, 0.6, 0.0);
-
-                               cairo_move_to    (cr,  c->x - dx1 - dx0, c->y - dy1 - dy0);
-                               cairo_rel_line_to(cr,  dx1 * 2,    dy1 * 2);
-                               cairo_rel_line_to(cr,  dx0 * 2,    dy0 * 2);
-                               cairo_rel_line_to(cr, -dx1 * 2,   -dy1 * 2);
-
-                               p = c->pins[1];
-                               cairo_move_to    (cr,  p->x,       p->y);
-                               cairo_line_to    (cr,  c->x + dx1, c->y + dy1);
-                               cairo_stroke(cr);
+                               __ses_draw_resistor(cr, c);
 
                                cairo_select_font_face(cr, "Georgia", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
 
@@ -476,92 +684,20 @@ void __ses_function_draw(ScfEfunction* f, cairo_t* cr)
                                break;
 
                        case SCF_EDA_Diode:
-                               p = c->pins[SCF_EDA_Diode_POS];
-
-                               vertical(&dx0, &dy0, c->x - p->x, c->y - p->y,  8);
-                               forward (&dx1, &dy1, c->x - p->x, c->y - p->y,  8);
-
-                               cairo_move_to(cr, p->x,       p->y);
-                               cairo_line_to(cr, c->x - dx1, c->y - dy1);
-
-                               cairo_rel_move_to(cr,  dx0,              dy0);
-                               cairo_rel_line_to(cr, -dx0 * 2,         -dy0 * 2);
-                               cairo_line_to    (cr,  c->x + dx1,       c->y + dy1);
-                               cairo_line_to    (cr,  c->x + dx0 - dx1, c->y + dy0 - dy1);
-
-                               p = c->pins[SCF_EDA_Diode_NEG];
-
-                               cairo_move_to    (cr,  p->x,        p->y);
-                               cairo_line_to    (cr,  c->x + dx1,  c->y + dy1);
-                               cairo_rel_move_to(cr,  dx0,         dy0);
-                               cairo_rel_line_to(cr, -dx0 * 2,    -dy0 * 2);
-                               cairo_stroke(cr);
+                               __ses_draw_diode(cr, c);
 
                                ses_text_a(cr, c->x + 10, c->y + 25, c->a);
                                cairo_stroke(cr);
                                break;
 
                        case SCF_EDA_NPN:
-                               pb = c->pins[SCF_EDA_NPN_B];
-                               pc = c->pins[SCF_EDA_NPN_C];
-                               pe = c->pins[SCF_EDA_NPN_E];
-
-                               vertical(&dx0, &dy0, c->x - pb->x, c->y - pb->y,  8);
-                               forward (&dx3, &dy3, c->x - pb->x, c->y - pb->y,  8);
-
-                               cairo_arc(cr, c->x - dx3 / 2, c->y - dy3 / 2, 12, 0, 2 * M_PI);
-
-                               cairo_move_to    (cr,  pb->x,       pb->y);
-                               cairo_line_to    (cr,  c->x - dx3,  c->y - dy3);
-                               cairo_rel_move_to(cr,  dx0,         dy0);
-                               cairo_rel_line_to(cr, -dx0 * 2,    -dy0 * 2);
-                               cairo_stroke(cr);
+                               __ses_draw_npn(cr, c);
 
                                cairo_select_font_face(cr, "Georgia", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
 
-                               if ((c->x + dx3 + dx0 > c->x + dx3 - dx0 && pe->x > pc->x)
-                                               || (c->x + dx3 + dx0 < c->x + dx3 - dx0 && pe->x < pc->x)) {
-
-                                       cairo_move_to(cr, c->x - dx3,       c->y - dy3);
-                                       cairo_line_to(cr, c->x + dx3 + dx0, c->y + dy3 + dy0);
-                                       cairo_line_to(cr, pe->x,            c->y + dy3 + dy0);
-                                       cairo_line_to(cr, pe->x,            pe->y);
-
-                                       vertical(&dx1, &dy1, dx3 * 2 + dx0, dy3 * 2 + dy0, 3);
-                                       forward (&dx4, &dy4, dx3 * 2 + dx0, dy3 * 2 + dy0, 8);
-
-                                       cairo_move_to(cr, c->x + dx3 + dx0,        c->y + dy3 + dy0);
-                                       cairo_line_to(cr, c->x - dx3 + dx4 + dx1,  c->y - dy3 + dy4 + dy1);
-                                       cairo_move_to(cr, c->x + dx3 + dx0,        c->y + dy3 + dy0);
-                                       cairo_line_to(cr, c->x - dx3 + dx4 - dx1,  c->y - dy3 + dy4 - dy1);
-                                       cairo_stroke(cr);
-
-                                       cairo_move_to(cr, c->x - dx3,        c->y - dy3);
-                                       cairo_line_to(cr, c->x + dx3 - dx0,  c->y + dy3 - dy0);
-                                       cairo_line_to(cr, pc->x,             c->y + dy3 - dy0);
-                                       cairo_line_to(cr, pc->x,             pc->y);
-                                       cairo_stroke(cr);
-                               } else {
-                                       cairo_move_to(cr, c->x - dx3,       c->y - dy3);
-                                       cairo_line_to(cr, c->x + dx3 + dx0, c->y + dy3 + dy0);
-                                       cairo_line_to(cr, pc->x,            c->y + dy3 + dy0);
-                                       cairo_line_to(cr, pc->x,            pc->y);
-                                       cairo_stroke(cr);
-
-                                       cairo_move_to(cr, c->x - dx3,        c->y - dy3);
-                                       cairo_line_to(cr, c->x + dx3 - dx0,  c->y + dy3 - dy0);
-                                       cairo_line_to(cr, pe->x,             c->y + dy3 - dy0);
-                                       cairo_line_to(cr, pe->x,             pe->y);
-
-                                       vertical(&dx1, &dy1, dx3 * 2 - dx0, dy3 * 2 - dy0, 3);
-                                       forward (&dx4, &dy4, dx3 * 2 - dx0, dy3 * 2 - dy0, 8);
-
-                                       cairo_move_to(cr, c->x + dx3 - dx0,        c->y + dy3 - dy0);
-                                       cairo_line_to(cr, c->x - dx3 + dx4 + dx1,  c->y - dy3 + dy4 + dy1);
-                                       cairo_move_to(cr, c->x + dx3 - dx0,        c->y + dy3 - dy0);
-                                       cairo_line_to(cr, c->x - dx3 + dx4 - dx1,  c->y - dy3 + dy4 - dy1);
-                                       cairo_stroke(cr);
-                               }
+                               pb = c->pins[SCF_EDA_NPN_B];
+                               pc = c->pins[SCF_EDA_NPN_C];
+                               pe = c->pins[SCF_EDA_NPN_E];
 
                                if (pb->y > c->y) {
                                        ses_text_a(cr, c->x + 2, c->y + 32, pb->a);
@@ -588,65 +724,14 @@ void __ses_function_draw(ScfEfunction* f, cairo_t* cr)
                                break;
 
                        case SCF_EDA_PNP:
+                               __ses_draw_pnp(cr, c);
+
+                               cairo_select_font_face(cr, "Georgia", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+
                                pb = c->pins[SCF_EDA_PNP_B];
                                pc = c->pins[SCF_EDA_PNP_C];
                                pe = c->pins[SCF_EDA_PNP_E];
 
-                               vertical(&dx0, &dy0, c->x - pb->x, c->y - pb->y,  8);
-                               forward (&dx3, &dy3, c->x - pb->x, c->y - pb->y,  8);
-
-                               cairo_arc(cr, c->x - dx3 / 2, c->y - dy3 / 2, 12, 0, 2 * M_PI);
-
-                               cairo_move_to    (cr,  pb->x,       pb->y);
-                               cairo_line_to    (cr,  c->x - dx3,  c->y - dy3);
-                               cairo_rel_move_to(cr,  dx0,         dy0);
-                               cairo_rel_line_to(cr, -dx0 * 2,    -dy0 * 2);
-                               cairo_stroke(cr);
-
-                               if ((c->x + dx3 + dx0 > c->x + dx3 - dx0 && pe->x > pc->x)
-                                               || (c->x + dx3 + dx0 < c->x + dx3 - dx0 && pe->x < pc->x)) {
-
-                                       cairo_move_to(cr, c->x - dx3,       c->y - dy3);
-                                       cairo_line_to(cr, c->x + dx3 + dx0, c->y + dy3 + dy0);
-                                       cairo_line_to(cr, pe->x,            c->y + dy3 + dy0);
-                                       cairo_line_to(cr, pe->x,            pe->y);
-
-                                       vertical(&dx1, &dy1, dx3 * 2 + dx0, dy3 * 2 + dy0, 4);
-                                       forward (&dx4, &dy4, dx3 * 2 + dx0, dy3 * 2 + dy0, 12);
-
-                                       cairo_move_to(cr, c->x - dx3 + dx4 + dx1,  c->y - dy3 + dy4 + dy1);
-                                       cairo_line_to(cr, c->x - dx3,              c->y - dy3);
-                                       cairo_line_to(cr, c->x - dx3 + dx4 - dx1,  c->y - dy3 + dy4 - dy1);
-                                       cairo_stroke(cr);
-
-                                       cairo_move_to(cr, c->x - dx3,        c->y - dy3);
-                                       cairo_line_to(cr, c->x + dx3 - dx0,  c->y + dy3 - dy0);
-                                       cairo_line_to(cr, pc->x,             c->y + dy3 - dy0);
-                                       cairo_line_to(cr, pc->x,             pc->y);
-                                       cairo_stroke(cr);
-                               } else {
-                                       cairo_move_to(cr, c->x - dx3,       c->y - dy3);
-                                       cairo_line_to(cr, c->x + dx3 + dx0, c->y + dy3 + dy0);
-                                       cairo_line_to(cr, pc->x,            c->y + dy3 + dy0);
-                                       cairo_line_to(cr, pc->x,            pc->y);
-                                       cairo_stroke(cr);
-
-                                       cairo_move_to(cr, c->x - dx3,        c->y - dy3);
-                                       cairo_line_to(cr, c->x + dx3 - dx0,  c->y + dy3 - dy0);
-                                       cairo_line_to(cr, pe->x,             c->y + dy3 - dy0);
-                                       cairo_line_to(cr, pe->x,             pe->y);
-
-                                       vertical(&dx1, &dy1, dx3 * 2 - dx0, dy3 * 2 - dy0, 4);
-                                       forward (&dx4, &dy4, dx3 * 2 - dx0, dy3 * 2 - dy0, 12);
-
-                                       cairo_move_to(cr, c->x - dx3 + dx4 + dx1,  c->y - dy3 + dy4 + dy1);
-                                       cairo_line_to(cr, c->x - dx3,              c->y - dy3);
-                                       cairo_line_to(cr, c->x - dx3 + dx4 - dx1,  c->y - dy3 + dy4 - dy1);
-                                       cairo_stroke(cr);
-                               }
-
-                               cairo_select_font_face(cr, "Georgia", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
-
                                if (pb->y > c->y) {
                                        ses_text_a(cr, c->x + 2, c->y + 32, pb->a);
 
@@ -1363,51 +1448,15 @@ void __ses_function_draw(ScfEfunction* f, cairo_t* cr)
        }
 }
 
-int ses_draw(ScfEfunction* f, const char* file, uint32_t bx, uint32_t by, uint32_t bw, uint32_t bh, int64_t ps, int64_t count)
+void __ses_draw_elines(cairo_t* cr, ScfEfunction* f, int64_t count)
 {
-       ScfEcomponent*   B;
-       ScfEline*        el;
-       ScfLine*         l;
-
-       cairo_surface_t* surface;
-       cairo_t*         cr;
-
-       surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, bx + bw, by + bh);
-       cr      = cairo_create (surface);
-
-       cairo_set_line_width(cr, 2);
-       cairo_set_source_rgb(cr, 1, 1, 1);
-       cairo_rectangle     (cr, 0, 0, bx + bw, by + bh);
-       cairo_fill(cr);
-       cairo_stroke(cr);
-
-       cairo_select_font_face(cr, "Calibri", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
-       cairo_set_font_size (cr, 20);
-       cairo_set_source_rgb(cr, 0, 0, 0);
-
-       if (count >= 0) {
-               int64_t t = ps * count;
-               int64_t s = t / (1000000LL * 1000000LL);
-               t %= 1000000LL * 1000000LL;
-               int64_t ms = t / (1000000LL * 1000LL);
-               t %= 1000000LL * 1000LL;
-               int64_t us = t / 1000000;
-               t %= 1000000;
-               int64_t ns = t / 1000;
-               t %= 1000;
-
-               uint8_t time[512];
-               snprintf(time, sizeof(time) - 1, "%03ld,%03ld,%03ld,%03ld,%03ldps", s, ms, us, ns, t);
-               cairo_move_to  (cr, 10, 20);
-               cairo_show_text(cr, time);
-               cairo_stroke(cr);
-       }
+       ScfEcomponent*  B = f->components[0];
+       ScfEline*       el;
+       ScfLine*        l;
 
        long j;
        long k;
 
-       B = f->components[0];
-
        for (j = 0; j < f->n_elines; j++) {
                el =        f->elines[j];
 
@@ -1531,16 +1580,58 @@ int ses_draw(ScfEfunction* f, const char* file, uint32_t bx, uint32_t by, uint32
                        cairo_set_font_size(cr, 18);
 
                        if (prev->x1 == prev->x0)
-                               cairo_move_to(cr, prev->x1 + 4, prev->y0 - 5);
+                               cairo_move_to(cr, prev->x1 + 4, prev->y1 - 5);
                        else
-                               cairo_move_to(cr, prev->x1 - 12 - n * 10, prev->y0 - 5);
+                               cairo_move_to(cr, prev->x1 - 12 - n * 10, prev->y1 - 5);
 
                        cairo_show_text(cr, text);
                        cairo_stroke(cr);
                }
        }
+}
+
+int ses_draw(ScfEfunction* f, const char* file, uint32_t bx, uint32_t by, uint32_t bw, uint32_t bh, int64_t ps, int64_t count)
+{
+       ScfEcomponent*   B;
+       ScfEline*        el;
+       ScfLine*         l;
+
+       cairo_surface_t* surface;
+       cairo_t*         cr;
 
-       __ses_function_draw(f, cr);
+       surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, bx + bw, by + bh);
+       cr      = cairo_create (surface);
+
+       cairo_set_line_width(cr, 2);
+       cairo_set_source_rgb(cr, 1, 1, 1);
+       cairo_rectangle     (cr, 0, 0, bx + bw, by + bh);
+       cairo_fill(cr);
+       cairo_stroke(cr);
+
+       cairo_select_font_face(cr, "Calibri", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+       cairo_set_font_size (cr, 20);
+       cairo_set_source_rgb(cr, 0, 0, 0);
+
+       if (count >= 0) {
+               int64_t t = ps * count;
+               int64_t s = t / (1000000LL * 1000000LL);
+               t %= 1000000LL * 1000000LL;
+               int64_t ms = t / (1000000LL * 1000LL);
+               t %= 1000000LL * 1000LL;
+               int64_t us = t / 1000000;
+               t %= 1000000;
+               int64_t ns = t / 1000;
+               t %= 1000;
+
+               uint8_t time[512];
+               snprintf(time, sizeof(time) - 1, "%03ld,%03ld,%03ld,%03ld,%03ldps", s, ms, us, ns, t);
+               cairo_move_to  (cr, 10, 20);
+               cairo_show_text(cr, time);
+               cairo_stroke(cr);
+       }
+
+       __ses_draw_elines    (cr, f, count);
+       __ses_draw_components(cr, f);
 
        cairo_surface_write_to_png(surface, file);
 
@@ -1686,6 +1777,7 @@ static int print_a(ScfEfunction* f, ses_ctx_t* ctx)
        }
 
        printf("\n");
+       fflush(stdout);
        return 0;
 }
 
@@ -1751,6 +1843,7 @@ static int print_v(ScfEfunction* f, ses_ctx_t* ctx)
        }
 
        printf("\n");
+       fflush(stdout);
        return 0;
 }
 
@@ -1774,6 +1867,9 @@ static int _draw_handler(ScfEfunction* f, int64_t ps, int64_t count, ses_ctx_t*
                }
 
                ctx->i++;
+
+               printf("ok: %d\n", ctx->i);
+               fflush(stdout);
        }
 
        return 0;
diff --git a/ses_ui.c b/ses_ui.c
new file mode 100644 (file)
index 0000000..c641e73
--- /dev/null
+++ b/ses_ui.c
@@ -0,0 +1,854 @@
+#include"ses_ui.h"
+
+static void resize(GtkGLArea* self, gint width, gint height, gpointer user_data)
+{
+       GdkGLContext *context;
+
+       gtk_gl_area_make_current(self);
+
+       if (gtk_gl_area_get_error(self) != NULL) {
+               scf_loge("\n");
+               return;
+       }
+
+       scf_logi("width: %d, height: %d\n", width, height);
+
+       context = gtk_gl_area_get_context(self);
+
+       if (gdk_gl_context_get_use_es(context))
+               scf_logi("gles\n");
+       else
+               scf_logi("gl\n");
+}
+
+static void unrealize(GtkWidget *widget)
+{
+       scf_logi("\n");
+}
+
+static gboolean render(GtkGLArea* self, GdkGLContext* context, gpointer user_data)
+{
+       if (gtk_gl_area_get_error(self) != NULL)
+               return FALSE;
+
+       ses_ui_t* ui = user_data;
+
+       int width  = gtk_widget_get_allocated_width (GTK_WIDGET(self));
+       int height = gtk_widget_get_allocated_height(GTK_WIDGET(self));
+
+       scf_logd("width: %d, height: %d\n\n", width, height);
+
+       glViewport(0, 0, width, height);
+
+       glClearColor(1.0, 1.0, 1.0, 1.0);
+       glClear(GL_COLOR_BUFFER_BIT);
+
+       if ((ui->width != width || ui->height != height) && SES_UI_EDIT == ui->status) {
+               ui->width  = width;
+               ui->height = height;
+
+               if (ui->bgra) {
+                       cairo_destroy(ui->cr);
+                       cairo_surface_destroy(ui->surface);
+                       free(ui->bgra);
+
+                       ui->bgra    = NULL;
+                       ui->surface = NULL;
+                       ui->cr      = NULL;
+               }
+
+               ui->bgra = calloc(1, width * height * 4);
+               if (!ui->bgra)
+                       return TRUE;
+
+               ui->surface = cairo_image_surface_create_for_data(ui->bgra, CAIRO_FORMAT_ARGB32, width, height, width * 4);
+               if (!ui->surface) {
+                       free(ui->bgra);
+                       return TRUE;
+               }
+
+               ui->cr = cairo_create(ui->surface);
+               if (!ui->cr) {
+                       cairo_surface_destroy(ui->surface);
+                       free(ui->bgra);
+                       return TRUE;
+               }
+
+               cairo_set_line_width(ui->cr, 2);
+               cairo_set_source_rgb(ui->cr, 1, 1, 1);
+
+               cairo_rectangle(ui->cr, 0, 0, width, height);
+               cairo_fill(ui->cr);
+               cairo_stroke(ui->cr);
+       }
+
+       if (ui->f) {
+               int ret = ses_gl_render(ui, width, height, 0, 0, width, height);
+       }
+
+       glFlush();
+       return TRUE;
+}
+
+static int button_2pins_clicked(ses_ui_t* ui, int type)
+{
+       ScfEcomponent*  B;
+       ScfEcomponent*  c;
+
+       if (!ui->f) {
+               ui->f = scf_efunction__alloc("tmp");
+               if (!ui->f)
+                       return 0;
+
+               EDA_INST_ADD_COMPONENT(ui->f, B, SCF_EDA_Battery);
+               B->x = 100;
+               B->y = 100;
+               B->w = 16;
+               B->h = 10;
+
+               B->pins[0]->x = B->x;
+               B->pins[1]->x = B->x;
+
+               B->pins[0]->y = B->y + 50;
+               B->pins[1]->y = B->y - 50;
+       }
+
+       EDA_INST_ADD_COMPONENT(ui->f, c, type);
+       c->x = 200 + rand() % 100;
+       c->y = 200 + rand() % 100;
+       c->w = 12;
+       c->h = 24;
+
+       c->pins[0]->x = c->x;
+       c->pins[1]->x = c->x;
+
+       c->pins[0]->y = c->y + 50;
+       c->pins[1]->y = c->y - 50;
+       return 0;
+}
+
+static int button_transistor_clicked(ses_ui_t* ui, int type)
+{
+       ScfEcomponent*  B;
+       ScfEcomponent*  c;
+
+       if (!ui->f) {
+               ui->f = scf_efunction__alloc("tmp");
+               if (!ui->f)
+                       return 0;
+
+               EDA_INST_ADD_COMPONENT(ui->f, B, SCF_EDA_Battery);
+               B->x = 100;
+               B->y = 100;
+               B->w = 16;
+               B->h = 10;
+
+               B->pins[0]->x = B->x;
+               B->pins[1]->x = B->x;
+
+               B->pins[0]->y = B->y + 50;
+               B->pins[1]->y = B->y - 50;
+       }
+
+       EDA_INST_ADD_COMPONENT(ui->f, c, type);
+       c->x = 200 + rand() % 100;
+       c->y = 200 + rand() % 100;
+       c->w = 12;
+       c->h = 24;
+
+       c->pins[SCF_EDA_NPN_B]->x = c->x;
+       c->pins[SCF_EDA_NPN_B]->y = c->y - 50;
+
+       c->pins[SCF_EDA_NPN_C]->x = c->x - 100 * 7 / 8;
+       c->pins[SCF_EDA_NPN_C]->y = c->y + 50;
+
+       c->pins[SCF_EDA_NPN_E]->x = c->x + 100 * 7 / 8;
+       c->pins[SCF_EDA_NPN_E]->y = c->y + 50;
+       return 0;
+}
+
+static void button_R_clicked(GtkButton* self, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       ui->status = SES_UI_EDIT;
+
+       button_2pins_clicked(ui, SCF_EDA_Resistor);
+       gtk_gl_area_queue_render(ui->gl_area);
+}
+
+static void button_C_clicked(GtkButton* self, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       ui->status = SES_UI_EDIT;
+
+       button_2pins_clicked(ui, SCF_EDA_Capacitor);
+       gtk_gl_area_queue_render(ui->gl_area);
+}
+
+static void button_L_clicked(GtkButton* self, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       ui->status = SES_UI_EDIT;
+
+       button_2pins_clicked(ui, SCF_EDA_Inductor);
+       gtk_gl_area_queue_render(ui->gl_area);
+}
+
+static void button_B_clicked(GtkButton* self, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       ui->status = SES_UI_EDIT;
+
+       button_2pins_clicked(ui, SCF_EDA_Battery);
+       gtk_gl_area_queue_render(ui->gl_area);
+}
+
+static void button_D_clicked(GtkButton* self, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       ui->status = SES_UI_EDIT;
+
+       button_2pins_clicked(ui, SCF_EDA_Diode);
+       gtk_gl_area_queue_render(ui->gl_area);
+}
+
+static void button_X_clicked(GtkButton* self, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       ui->status = SES_UI_EDIT;
+
+       button_2pins_clicked(ui, SCF_EDA_Crystal);
+       gtk_gl_area_queue_render(ui->gl_area);
+}
+
+static void button_NPN_clicked(GtkButton* self, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       ui->status = SES_UI_EDIT;
+
+       button_transistor_clicked(ui, SCF_EDA_NPN);
+       gtk_gl_area_queue_render(ui->gl_area);
+}
+
+static void button_PNP_clicked(GtkButton* self, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       ui->status = SES_UI_EDIT;
+
+       button_transistor_clicked(ui, SCF_EDA_PNP);
+       gtk_gl_area_queue_render(ui->gl_area);
+}
+
+static int button_add_line(ScfEline* el, ScfLine** pl, int x0, int y0, int x1, int y1)
+{
+       ScfLine* l = calloc(1, sizeof(ScfLine));
+       if (!l)
+               return -ENOMEM;
+
+       l->x0 = x0;
+       l->y0 = y0;
+       l->x1 = x1;
+       l->y1 = y1;
+
+       int ret = scf_eline__add_line(el, l);
+       if (ret < 0) {
+               free(l);
+               return ret;
+       }
+
+       *pl = l;
+       return 0;
+}
+
+static int button_add_eline(ses_ui_t* ui, ScfEline** pel, ScfLine** pl, int x0, int y0, int x1, int y1)
+{
+       ScfLine*  l  = NULL;
+       ScfEline* el = scf_eline__alloc();
+       if (!el)
+               return -ENOMEM;
+
+       int ret = button_add_line(el, &l, x0, y0, x1, y1);
+       if (ret < 0) {
+               ScfEline_free(el);
+               return ret;
+       }
+
+       ret = scf_efunction__add_eline(ui->f, el);
+       if (ret < 0) {
+               ScfEline_free(el);
+               return ret;
+       }
+
+       el->id = ui->f->n_elines - 1;
+
+       *pel = el;
+       *pl  = l;
+       return 0;
+}
+
+static int button_connect_pin(ses_ui_t* ui, ScfEpin* p0, ScfEpin* p1)
+{
+       ScfEline*  el = NULL;
+       ScfLine*   l  = NULL;
+
+       int ret;
+
+       scf_efunction_find_eline(ui->f, &el, &l, p0->x, p0->y);
+       if (!el) {
+               ret = button_add_eline(ui, &el, &l, p0->x, p0->y, p1->x, p1->y);
+               if (ret < 0)
+                       return ret;
+
+               ret = scf_eline__add_pin(el, p0->cid, p0->id);
+               if (ret < 0)
+                       return ret;
+
+               p0->lid = el->id;
+       } else {
+               ret = button_add_line(el, &l, p0->x, p0->y, p1->x, p1->y);
+               if (ret < 0)
+                       return ret;
+       }
+
+       ret = scf_eline__add_pin(el, p1->cid, p1->id);
+       if (ret < 0)
+               return ret;
+
+       scf_logi("\033[32m el%ld add c%ldp%ld, c%ldp%ld\033[0m\n", el->id, p0->cid, p0->id, p1->cid, p1->id);
+
+       p1->lid = el->id;
+       return 0;
+}
+
+static int button_connect_pins(ses_ui_t* ui)
+{
+       ScfEpin*  p;
+       long      i;
+       long      j;
+
+       for (i = 0; i < ui->c->n_pins; i++) {
+               p  =        ui->c->pins[i];
+
+               int x = p->x;
+               int y = p->y;
+
+               p->x = 0;
+               p->y = 0;
+
+               ScfEcomponent* c2 = NULL;
+               ScfEpin*       p2 = NULL;
+               ScfEline*      el = NULL;
+               ScfLine*       l  = NULL;
+
+               scf_efunction_find_pin(ui->f, &c2, &p2, x, y);
+               p->x = x;
+               p->y = y;
+
+               if (p2) {
+                       scf_logi("\033[33m c%ldp%ld, c%ldp%ld\033[0m\n", p->cid, p->id, p2->cid, p2->id);
+
+                       scf_efunction_find_eline(ui->f, &el, &l, x, y);
+                       if (!el) {
+                               scf_efunction_find_eline(ui->f, &el, &l, p2->x, p2->y);
+                               if (!el) {
+                                       int ret = button_add_eline(ui, &el, &l, x, y, x, y);
+                                       if (ret < 0)
+                                               return ret;
+                               }
+                       }
+
+                       int ret = scf_eline__add_pin(el, p->cid, p->id);
+                       if (ret < 0)
+                               return ret;
+
+                       ret = scf_eline__add_pin(el, p2->cid, p2->id);
+                       if (ret < 0)
+                               return ret;
+
+                       scf_logi("\033[32m el%ld add c%ldp%ld, c%ldp%ld\033[0m\n", el->id, p->cid, p->id, p2->cid, p2->id);
+
+                       p ->lid = el->id;
+                       p2->lid = el->id;
+
+               } else {
+                       scf_efunction_find_eline(ui->f, &el, &l, x, y);
+                       if (!el) {
+                               j = scf_find_eline_index(ui->f, p->lid);
+
+                               if (j >= 0) {
+                                       el = ui->f->elines[j];
+
+                                       assert(0 == scf_eline__del_pin(el, p->cid, p->id));
+                                       p->lid = -1;
+
+                                       scf_logi("\033[31m el%ld del c%ldp%ld\033[0m\n", el->id, p->cid, p->id);
+
+                                       if (2 == el->n_pins) {
+                                               c2 = ui->f->components[el->pins[0]];
+                                               p2 = c2->pins         [el->pins[1]];
+
+                                               assert(0 == scf_eline__del_pin(el, p2->cid, p2->id));
+                                               p2->lid = -1;
+
+                                               scf_logi("\033[31m el%ld del c%ldp%ld\033[0m\n", el->id, p2->cid, p2->id);
+
+                                               assert(0 == scf_efunction__del_eline(ui->f, el));
+                                               ScfEline_free(el);
+                                               el = NULL;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static gboolean button_press_event(GtkWidget* self, GdkEventButton* event, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+       ScfEline* el = NULL;
+       ScfLine*  l  = NULL;
+
+       if (gtk_widget_get_window(GTK_WIDGET(ui->gl_area)) == event->window) {
+               ui->status = SES_UI_EDIT;
+
+               scf_logi("x: %f, y: %f", event->x, event->y);
+
+               if (ui->f) {
+                       ui->c  = NULL;
+                       ui->p  = NULL;
+
+                       scf_efunction_find_pin  (ui->f, &ui->c,  &ui->p, event->x, event->y);
+                       scf_efunction_find_eline(ui->f, &el,     &l,     event->x, event->y);
+
+                       ui->press_x = event->x;
+                       ui->press_y = event->y;
+
+                       if (ui->c) {
+                               fprintf(stderr, ", c%ld", ui->c->id);
+                               if (ui->p)
+                                       fprintf(stderr, "p%ld", ui->p->id);
+                       }
+
+                       if (el)
+                               fprintf(stderr, ", el%ld", el->id);
+               }
+               fprintf(stderr, "\n");
+       }
+
+       return TRUE;
+}
+
+static gboolean button_release_event(GtkWidget* self, GdkEventButton* event, gpointer user_data)
+{
+       ses_ui_t*  ui = user_data;
+
+       if (gtk_widget_get_window(GTK_WIDGET(ui->gl_area)) == event->window) {
+               ui->status = SES_UI_EDIT;
+
+               scf_logw("x: %f, y: %f\n", event->x, event->y);
+
+               if (ui->c) {
+                       if (!ui->p) {
+                               button_connect_pins(ui);
+                       } else {
+                               ScfEpin* p = ui->p;
+
+                               ui->c = NULL;
+                               ui->p = NULL;
+
+                               scf_efunction_find_pin(ui->f, &ui->c, &ui->p, event->x, event->y);
+                               if (ui->p)
+                                       button_connect_pin(ui, p, ui->p);
+                       }
+
+                       ui->c = NULL;
+                       ui->p = NULL;
+
+                       ui->press_x = 0;
+                       ui->press_y = 0;
+                       ui->move_x  = 0;
+                       ui->move_y  = 0;
+               }
+       }
+
+       return TRUE;
+}
+
+static gboolean button_move_event(GtkWidget* self, GdkEventMotion* event, gpointer user_data)
+{
+       ses_ui_t*  ui = user_data;
+       ScfEpin*   p;
+       long       i;
+
+       if (ui->c) {
+               scf_logd("event x: %f, y: %f, c%ld\n", event->x, event->y, ui->c->id);
+
+               if (!ui->p) {
+                       int dx = event->x - ui->c->x;
+                       int dy = event->y - ui->c->y;
+
+                       for (i = 0; i < ui->c->n_pins; i++) {
+                               p  =        ui->c->pins[i];
+
+                               p->x += dx;
+                               p->y += dy;
+                       }
+
+                       ui->c->x += dx;
+                       ui->c->y += dy;
+               } else {
+                       ui->move_x = event->x;
+                       ui->move_y = event->y;
+               }
+
+               gtk_gl_area_queue_render(ui->gl_area);
+       }
+
+       return TRUE;
+}
+
+static void apply_clicked(GtkButton* self, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       ScfEboard* b = scf_eboard__alloc();
+       if (!b)
+               return;
+
+       if (scf_eboard__add_function(b, ui->f) < 0) {
+               ScfEboard_free(b);
+               return;
+       }
+
+       ui->f->x = 0;
+       ui->f->y = 0;
+       ui->f->w = ui->width;
+       ui->f->h = ui->height;
+
+       uint8_t* buf = NULL;
+       long     len = 0;
+       long     ret = ScfEboard_pack(b, &buf, &len);
+
+       assert(0 == scf_eboard__del_function(b, ui->f));
+
+       ScfEboard_free(b);
+       b = NULL;
+       if (ret < 0)
+               return;
+
+       FILE* fp = fopen("./tmp.cpk", "wb");
+       if (!fp)
+               return;
+
+       fwrite(buf, len, 1, fp);
+       fclose(fp);
+       fp = NULL;
+
+       free(buf);
+       buf = NULL;
+
+       float ns    = atof(gtk_entry_get_text(ui->entry_ns));
+       int   count = atoi(gtk_entry_get_text(ui->entry_count));
+
+       printf("./ses ./tmp.cpk -l 0 -t %fns -c %d\n", ns, count);
+       fflush(stdout);
+
+       ui->apply_index = -1;
+       ui->show_index  = -1;
+
+       ui->status = SES_UI_RUN;
+}
+
+static gboolean key_press_event(GtkWidget* self, GdkEventKey* event, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       scf_logi("event keyval: %c, %d\n", event->keyval, event->keyval);
+
+       switch (event->keyval) {
+               case GDK_KEY_BackSpace:
+               case GDK_KEY_Delete:
+                       break;
+               default:
+                       break;
+       };
+
+       return TRUE;
+}
+
+static int load_png(ses_ui_t* ui)
+{
+       if (ui->apply_index <= 0
+                       || ui->show_index < 0
+                       || ui->show_index >= ui->apply_index)
+               return -1;
+
+       char file[128];
+       snprintf(file, sizeof(file) - 1, "./draw_%d.png", ui->show_index);
+
+       cairo_surface_t* tmp = cairo_image_surface_create_from_png(file);
+
+       if (CAIRO_STATUS_SUCCESS == cairo_surface_status(tmp)) {
+               int    width  = cairo_image_surface_get_width(tmp);
+               int    height = cairo_image_surface_get_height(tmp);
+               int    stride = cairo_image_surface_get_stride(tmp);
+
+               int    format = cairo_image_surface_get_format(tmp);
+               char*  data   = cairo_image_surface_get_data  (tmp);
+
+               assert(CAIRO_FORMAT_ARGB32 == format || CAIRO_FORMAT_RGB24 == format);
+
+               scf_logi("apply_index: %d, show_index: %d, %dx%d, %s\n", ui->apply_index, ui->show_index, width, height, file);
+
+               uint8_t* bgra = malloc(width * height * 4);
+               if (bgra) {
+                       int i;
+                       int j;
+
+                       for (i = 0; i < height; i++) {
+                               uint8_t* dst = bgra + i * width * 4;
+                               uint8_t* src = data + i * stride;
+
+                               for (j = 0; j < width; j++) {
+                                       dst[j * 4    ] = src[j * 4    ];
+                                       dst[j * 4 + 1] = src[j * 4 + 1];
+                                       dst[j * 4 + 2] = src[j * 4 + 2];
+                                       dst[j * 4 + 3] = src[j * 4 + 3];
+                               }
+                       }
+
+                       cairo_surface_t* surface;
+                       cairo_t*         cr;
+
+                       surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, width, height, width * 4);
+                       if (surface) {
+                               cr = cairo_create(surface);
+
+                               if (cr) {
+                                       if (ui->bgra) {
+                                               cairo_destroy(ui->cr);
+                                               cairo_surface_destroy(ui->surface);
+                                               free(ui->bgra);
+                                       }
+
+                                       ui->cr      = cr;
+                                       ui->surface = surface;
+                                       ui->bgra    = bgra;
+
+                                       ui->width  = width;
+                                       ui->height = height;
+                               } else {
+                                       cairo_surface_destroy(surface);
+                                       free(bgra);
+                                       surface = NULL;
+                                       bgra    = NULL;
+                               }
+                       } else {
+                               free(bgra);
+                               bgra = NULL;
+                       }
+               }
+       }
+
+       cairo_surface_destroy(tmp);
+       return 0;
+}
+
+static void forward_clicked(GtkButton* self, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       if (ui->show_index < ui->apply_index - 1)
+               ui->show_index++;
+
+       load_png(ui);
+       gtk_gl_area_queue_render(ui->gl_area);
+}
+
+static void back_clicked(GtkButton* self, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       if (ui->show_index > 0)
+               ui->show_index--;
+
+       load_png(ui);
+       gtk_gl_area_queue_render(ui->gl_area);
+}
+
+static gboolean timer_handler(gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       if (SES_UI_EDIT == ui->status) {
+               gtk_gl_area_queue_render(ui->gl_area);
+               return TRUE;
+       }
+
+       char buf[PIPE_BUF];
+
+       int ret = read(0, buf, PIPE_BUF);
+       if (ret <= 0) {
+               gtk_gl_area_queue_render(ui->gl_area);
+               return TRUE;
+       }
+
+       if (!strncmp(buf, "ok: ", 3))
+               ui->apply_index = atol(buf + 4);
+
+       if (ui->show_index < 0 && ui->apply_index > 0) {
+               ui->show_index = 0;
+               load_png(ui);
+       }
+
+       gtk_gl_area_queue_render(ui->gl_area);
+       return TRUE;
+}
+
+int main(int argc, char* argv[])
+{
+       int rfd[2];
+       int wfd[2];
+
+       if (-1 == pipe2(rfd, O_DIRECT))
+               return -1;
+       if (-1 == pipe2(wfd, O_DIRECT))
+               return -1;
+
+       pid_t cpid = fork();
+
+       if (cpid < 0) {
+               scf_loge("\n");
+               return -1;
+
+       } else if (0 == cpid) {
+               close(rfd[0]);
+               close(wfd[1]);
+
+               dup2(rfd[1], 1);
+               dup2(wfd[0], 0);
+
+               close(rfd[1]);
+               close(wfd[0]);
+
+               char* argv[] = {"./ses", NULL};
+
+               execve(argv[0], argv, NULL);
+               exit(-1);
+
+       } else {
+               close(rfd[1]);
+               close(wfd[0]);
+
+               dup2(rfd[0], 0);
+               dup2(wfd[1], 1);
+
+               close(rfd[0]);
+               close(wfd[1]);
+
+               int flags = fcntl(0, F_GETFL);
+               flags |= O_NONBLOCK;
+               fcntl(0, F_SETFL, flags);
+       }
+
+       ses_ui_t    ui = SES_UI_INIT();
+
+       GtkBuilder* builder;
+       GObject*    window;
+       GObject*    gl_area;
+       GError*     error = NULL;
+
+       gtk_init(&argc, &argv);
+
+       builder = gtk_builder_new();
+
+       if (gtk_builder_add_from_file(builder, "ses_ui.glade", &error) == 0) {
+               g_printerr("Error loading file: %s\n", error->message);
+               g_clear_error(&error);
+               return 1;
+       }
+
+       window  = gtk_builder_get_object(builder, "main_window");
+       gl_area = gtk_builder_get_object(builder, "gl_area");
+
+       ui.builder     = builder;
+       ui.gl_area     = GTK_GL_AREA(gl_area);
+       ui.entry_ns    = GTK_ENTRY(gtk_builder_get_object(builder, "entry_ns"));
+       ui.entry_count = GTK_ENTRY(gtk_builder_get_object(builder, "entry_count"));
+
+       g_signal_connect(window,  "destroy",   G_CALLBACK(gtk_main_quit),   NULL);
+       g_signal_connect(gl_area, "resize",    G_CALLBACK(resize),          NULL);
+       g_signal_connect(gl_area, "unrealize", G_CALLBACK(unrealize),       NULL);
+       g_signal_connect(gl_area, "render",    G_CALLBACK(render),          &ui);
+
+       gtk_widget_add_events(GTK_WIDGET(gl_area), GDK_POINTER_MOTION_MASK);
+
+       g_signal_connect(gl_area, "key-press-event",      G_CALLBACK(key_press_event),      &ui);
+       g_signal_connect(window,  "button-press-event",   G_CALLBACK(button_press_event),   &ui);
+       g_signal_connect(window,  "button-release-event", G_CALLBACK(button_release_event), &ui);
+       g_signal_connect(window,  "motion-notify-event",  G_CALLBACK(button_move_event),    &ui);
+
+       GObject*    back       = gtk_builder_get_object(builder, "button_back");
+       GObject*    forward    = gtk_builder_get_object(builder, "button_forward");
+       GObject*    undo       = gtk_builder_get_object(builder, "button_undo");
+       GObject*    redo       = gtk_builder_get_object(builder, "button_redo");
+       GObject*    zoom_in    = gtk_builder_get_object(builder, "button_zoom_in");
+       GObject*    zoom_out   = gtk_builder_get_object(builder, "button_zoom_out");
+       GObject*    apply      = gtk_builder_get_object(builder, "button_apply");
+
+       g_signal_connect(forward,   "clicked",   G_CALLBACK(forward_clicked),  &ui);
+       g_signal_connect(back,      "clicked",   G_CALLBACK(back_clicked),     &ui);
+       g_signal_connect(apply,     "clicked",   G_CALLBACK(apply_clicked),    &ui);
+
+       GObject*    button_B   = gtk_builder_get_object(builder, "button_Battery");
+       GObject*    button_R   = gtk_builder_get_object(builder, "button_R");
+       GObject*    button_C   = gtk_builder_get_object(builder, "button_C");
+       GObject*    button_L   = gtk_builder_get_object(builder, "button_L");
+       GObject*    button_X   = gtk_builder_get_object(builder, "button_X");
+       GObject*    button_D   = gtk_builder_get_object(builder, "button_D");
+       GObject*    button_NPN = gtk_builder_get_object(builder, "button_NPN");
+       GObject*    button_PNP = gtk_builder_get_object(builder, "button_PNP");
+
+       g_signal_connect(button_B,     "clicked",   G_CALLBACK(button_B_clicked),    &ui);
+       g_signal_connect(button_R,     "clicked",   G_CALLBACK(button_R_clicked),    &ui);
+       g_signal_connect(button_C,     "clicked",   G_CALLBACK(button_C_clicked),    &ui);
+       g_signal_connect(button_L,     "clicked",   G_CALLBACK(button_L_clicked),    &ui);
+       g_signal_connect(button_X,     "clicked",   G_CALLBACK(button_X_clicked),    &ui);
+       g_signal_connect(button_D,     "clicked",   G_CALLBACK(button_D_clicked),    &ui);
+       g_signal_connect(button_NPN,   "clicked",   G_CALLBACK(button_NPN_clicked),  &ui);
+       g_signal_connect(button_PNP,   "clicked",   G_CALLBACK(button_PNP_clicked),  &ui);
+
+       g_timeout_add(1, timer_handler, &ui);
+
+       gtk_widget_show_all(GTK_WIDGET(window));
+
+       gtk_main();
+#if 0
+       printf("./ses examples/sin_oscillator.cpk -t 1us -V v4\n");
+       fflush(stdout);
+
+       char* buf = NULL;
+       long  len = 0;
+
+       if (getline(&buf, &len, stdin) != -1)
+               scf_logw("parent pid %d: %s\n", getpid(), buf);
+#endif
+       printf("q\n");
+       fflush(stdout);
+
+       int status = 0;
+       wait(&status);
+
+       scf_logi("main ok\n");
+       return 0;
+}
diff --git a/ses_ui.glade b/ses_ui.glade
new file mode 100644 (file)
index 0000000..2931598
--- /dev/null
@@ -0,0 +1,596 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface>
+  <requires lib="gtk+" version="3.24"/>
+  <object class="GtkWindow" id="main_window">
+    <property name="can-focus">False</property>
+    <property name="title" translatable="yes">ses电路仿真</property>
+    <property name="default-width">1280</property>
+    <property name="default-height">720</property>
+    <child>
+      <object class="GtkPaned" id="main_log">
+        <property name="visible">True</property>
+        <property name="can-focus">True</property>
+        <property name="orientation">vertical</property>
+        <property name="position">600</property>
+        <child>
+          <object class="GtkPaned" id="main_menus">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="orientation">vertical</property>
+            <property name="position">63</property>
+            <child>
+              <object class="GtkBox" id="menus_buttons">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="can-focus">False</property>
+                    <child>
+                      <object class="GtkMenuBar">
+                        <property name="visible">True</property>
+                        <property name="can-focus">False</property>
+                        <child>
+                          <object class="GtkMenuItem">
+                            <property name="visible">True</property>
+                            <property name="can-focus">False</property>
+                            <property name="label" translatable="yes">_File</property>
+                            <property name="use-underline">True</property>
+                            <child type="submenu">
+                              <object class="GtkMenu">
+                                <property name="visible">True</property>
+                                <property name="can-focus">False</property>
+                                <child>
+                                  <object class="GtkImageMenuItem" id="file_open">
+                                    <property name="label">gtk-open</property>
+                                    <property name="visible">True</property>
+                                    <property name="can-focus">False</property>
+                                    <property name="use-underline">True</property>
+                                    <property name="use-stock">True</property>
+                                    <property name="always-show-image">True</property>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="GtkImageMenuItem" id="file_save">
+                                    <property name="label">gtk-save</property>
+                                    <property name="visible">True</property>
+                                    <property name="can-focus">False</property>
+                                    <property name="use-underline">True</property>
+                                    <property name="use-stock">True</property>
+                                    <property name="always-show-image">True</property>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="GtkImageMenuItem" id="file_save_as">
+                                    <property name="label">gtk-save-as</property>
+                                    <property name="visible">True</property>
+                                    <property name="can-focus">False</property>
+                                    <property name="use-underline">True</property>
+                                    <property name="use-stock">True</property>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="GtkSeparatorMenuItem">
+                                    <property name="visible">True</property>
+                                    <property name="can-focus">False</property>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="GtkImageMenuItem" id="file_quit">
+                                    <property name="label">gtk-quit</property>
+                                    <property name="visible">True</property>
+                                    <property name="can-focus">False</property>
+                                    <property name="use-underline">True</property>
+                                    <property name="use-stock">True</property>
+                                    <property name="always-show-image">True</property>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkMenuItem">
+                            <property name="visible">True</property>
+                            <property name="can-focus">False</property>
+                            <property name="label" translatable="yes">_Help</property>
+                            <property name="use-underline">True</property>
+                            <child type="submenu">
+                              <object class="GtkMenu">
+                                <property name="visible">True</property>
+                                <property name="can-focus">False</property>
+                                <child>
+                                  <object class="GtkImageMenuItem" id="help_about">
+                                    <property name="label">gtk-about</property>
+                                    <property name="visible">True</property>
+                                    <property name="can-focus">False</property>
+                                    <property name="use-underline">True</property>
+                                    <property name="use-stock">True</property>
+                                    <property name="always-show-image">True</property>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="can-focus">False</property>
+                    <child>
+                      <object class="GtkButton" id="button_back">
+                        <property name="label">gtk-go-back</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                        <property name="use-stock">True</property>
+                        <property name="always-show-image">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_forward">
+                        <property name="label">gtk-go-forward</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                        <property name="use-stock">True</property>
+                        <property name="always-show-image">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_undo">
+                        <property name="label">gtk-undo</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                        <property name="use-stock">True</property>
+                        <property name="always-show-image">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_redo">
+                        <property name="label">gtk-redo</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                        <property name="use-stock">True</property>
+                        <property name="always-show-image">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_zoom_out">
+                        <property name="label">gtk-zoom-out</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                        <property name="use-stock">True</property>
+                        <property name="always-show-image">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">4</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_zoom_in">
+                        <property name="label">gtk-zoom-in</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                        <property name="use-stock">True</property>
+                        <property name="always-show-image">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">5</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="entry_ns">
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="width-chars">6</property>
+                        <property name="text" translatable="yes">10</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">6</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="can-focus">False</property>
+                        <property name="label" translatable="yes">  ns/纳秒  </property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">7</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="entry_count">
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="width-chars">6</property>
+                        <property name="text" translatable="yes">1</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">8</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="can-focus">False</property>
+                        <property name="label" translatable="yes">  count/次数  </property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">9</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_apply">
+                        <property name="label">gtk-apply</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                        <property name="use-stock">True</property>
+                        <property name="always-show-image">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">10</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_help">
+                        <property name="label">gtk-help</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                        <property name="use-stock">True</property>
+                        <property name="always-show-image">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">11</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="resize">False</property>
+                <property name="shrink">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkPaned" id="main_buttons">
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="position">220</property>
+                <child>
+                  <!-- n-columns=3 n-rows=7 -->
+                  <object class="GtkGrid">
+                    <property name="visible">True</property>
+                    <property name="can-focus">False</property>
+                    <child>
+                      <object class="GtkButton" id="button_R">
+                        <property name="label" translatable="yes">R</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">0</property>
+                        <property name="top-attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_C">
+                        <property name="label" translatable="yes">C</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">1</property>
+                        <property name="top-attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_L">
+                        <property name="label" translatable="yes">L</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">2</property>
+                        <property name="top-attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_D">
+                        <property name="label" translatable="yes">D</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">0</property>
+                        <property name="top-attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_NPN">
+                        <property name="label" translatable="yes">NPN</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">1</property>
+                        <property name="top-attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_PNP">
+                        <property name="label" translatable="yes">PNP</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">2</property>
+                        <property name="top-attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_X">
+                        <property name="label" translatable="yes">X</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">1</property>
+                        <property name="top-attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_op_amp">
+                        <property name="label" translatable="yes">AMP</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">2</property>
+                        <property name="top-attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_Battery">
+                        <property name="label" translatable="yes">Battery</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">0</property>
+                        <property name="top-attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_NAND">
+                        <property name="label" translatable="yes">NAND</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">0</property>
+                        <property name="top-attach">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_NOR">
+                        <property name="label" translatable="yes">NOR</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">1</property>
+                        <property name="top-attach">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_AND">
+                        <property name="label" translatable="yes">AND</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">0</property>
+                        <property name="top-attach">4</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_OR">
+                        <property name="label" translatable="yes">OR</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">1</property>
+                        <property name="top-attach">4</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_NOT">
+                        <property name="label" translatable="yes">NOT</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">2</property>
+                        <property name="top-attach">4</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_XOR">
+                        <property name="label" translatable="yes">XOR</property>
+                        <property name="visible">True</property>
+                        <property name="can-focus">True</property>
+                        <property name="receives-default">True</property>
+                      </object>
+                      <packing>
+                        <property name="left-attach">2</property>
+                        <property name="top-attach">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="resize">False</property>
+                    <property name="shrink">True</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkPaned" id="main_VA">
+                    <property name="visible">True</property>
+                    <property name="can-focus">True</property>
+                    <property name="position">900</property>
+                    <child>
+                      <object class="GtkGLArea" id="gl_area">
+                        <property name="visible">True</property>
+                        <property name="app-paintable">True</property>
+                        <property name="can-focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="resize">False</property>
+                        <property name="shrink">True</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkDrawingArea" id="draw_VA">
+                        <property name="visible">True</property>
+                        <property name="can-focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="resize">True</property>
+                        <property name="shrink">True</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="resize">True</property>
+                    <property name="shrink">True</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="resize">True</property>
+                <property name="shrink">True</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="resize">False</property>
+            <property name="shrink">True</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkTextView" id="text_log">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+          </object>
+          <packing>
+            <property name="resize">True</property>
+            <property name="shrink">True</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/ses_ui.h b/ses_ui.h
new file mode 100644 (file)
index 0000000..c6927b9
--- /dev/null
+++ b/ses_ui.h
@@ -0,0 +1,79 @@
+#ifndef SES_UI_H
+#define SES_UI_H
+
+#include"ses_core.h"
+
+#include<sys/types.h>
+#include<sys/wait.h>
+#include<fcntl.h>
+#include<gtk/gtk.h>
+
+#define  GL_GLEXT_PROTOTYPES
+#include <GL/gl.h>
+#include <GL/glext.h>
+
+typedef struct ses_ui_s     ses_ui_t;
+
+struct ses_ui_s
+{
+       GtkBuilder*       builder;
+       GtkGLArea*        gl_area;
+
+       GtkEntry*         entry_ns;
+       GtkEntry*         entry_count;
+
+       cairo_surface_t*  surface;
+       cairo_t*          cr;
+       uint8_t*          bgra;
+
+       ScfEfunction*     f;
+       ScfEcomponent*    c;
+       ScfEpin*          p;
+
+       int               press_x;
+       int               press_y;
+       int               move_x;
+       int               move_y;
+
+       int               width;
+       int               height;
+
+       int               x;
+       int               y;
+       int               w;
+       int               h;
+
+       int               apply_index;
+       int               show_index;
+#define SES_UI_EDIT 0
+#define SES_UI_RUN  1
+       int               status;
+};
+
+#define SES_UI_INIT() {NULL,NULL,  NULL,NULL,  NULL,NULL,NULL,  NULL,NULL,NULL,  0,0,0,0,  0,0,  0,0,0,0, -1,-1, 0}
+
+static const GLfloat vert_array[] = {
+       -1.0f,  -1.0f,
+        1.0f,  -1.0f,
+       -1.0f,   1.0f,
+        1.0f,   1.0f
+};
+
+static const GLfloat texture_array[] = {
+       0.0f,   1.0f,
+       1.0f,   1.0f,
+       0.0f,   0.0f,
+       1.0f,   0.0f,
+};
+
+void __compute_mvp(float *res, float  phi, float  theta, float  psi);
+
+int  __init_texture(GLuint* ptex, GLenum format, int w, int h, uint8_t* data);
+
+int  __init_program(GLuint* pprog, const char* vert_shader, const char* frag_shader);
+
+int  __init_buffers(GLuint* vao, GLuint buffers[2]);
+
+int  ses_gl_render(ses_ui_t* ui, int width, int height, int x, int y, int w, int h);
+
+#endif
diff --git a/ses_ui_gl.c b/ses_ui_gl.c
new file mode 100644 (file)
index 0000000..f2607ad
--- /dev/null
@@ -0,0 +1,152 @@
+#include"ses_ui.h"
+
+void __compute_mvp(float *res, float  phi, float  theta, float  psi)
+{
+       float x = phi   * (M_PI / 180.f);
+       float y = theta * (M_PI / 180.f);
+       float z = psi   * (M_PI / 180.f);
+       float c1 = cosf (x), s1 = sinf (x);
+       float c2 = cosf (y), s2 = sinf (y);
+       float c3 = cosf (z), s3 = sinf (z);
+       float c3c2 = c3 * c2;
+       float s3c1 = s3 * c1;
+       float c3s2s1 = c3 * s2 * s1;
+       float s3s1 = s3 * s1;
+       float c3s2c1 = c3 * s2 * c1;
+       float s3c2 = s3 * c2;
+       float c3c1 = c3 * c1;
+       float s3s2s1 = s3 * s2 * s1;
+       float c3s1 = c3 * s1;
+       float s3s2c1 = s3 * s2 * c1;
+       float c2s1 = c2 * s1;
+       float c2c1 = c2 * c1;
+
+       /* initialize to the identity matrix */
+       res[0] = 1.f; res[4] = 0.f;  res[8] = 0.f; res[12] = 0.f;
+       res[1] = 0.f; res[5] = 1.f;  res[9] = 0.f; res[13] = 0.f;
+       res[2] = 0.f; res[6] = 0.f; res[10] = 1.f; res[14] = 0.f;
+       res[3] = 0.f; res[7] = 0.f; res[11] = 0.f; res[15] = 1.f;
+
+       /* apply all three rotations using the three matrices:
+        *
+        * ⎡  c3 s3 0 ⎤ ⎡ c2  0 -s2 ⎤ ⎡ 1   0  0 ⎤
+        * ⎢ -s3 c3 0 ⎥ ⎢  0  1   0 ⎥ ⎢ 0  c1 s1 ⎥
+        * ⎣   0  0 1 ⎦ ⎣ s2  0  c2 ⎦ ⎣ 0 -s1 c1 ⎦
+        */
+       res[0] = c3c2;  res[4] = s3c1 + c3s2s1;  res[8] = s3s1 - c3s2c1; res[12] = 0.f;
+       res[1] = -s3c2; res[5] = c3c1 - s3s2s1;  res[9] = c3s1 + s3s2c1; res[13] = 0.f;
+       res[2] = s2;    res[6] = -c2s1;         res[10] = c2c1;          res[14] = 0.f;
+       res[3] = 0.f;   res[7] = 0.f;           res[11] = 0.f;           res[15] = 1.f;
+}
+
+int __init_texture(GLuint* ptex, GLenum format, int w, int h, uint8_t* data)
+{
+       GLuint  tex;
+
+       glGenTextures(1, &tex);
+       glBindTexture(GL_TEXTURE_2D, tex);
+       glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, format, GL_UNSIGNED_BYTE, data);
+
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+       glBindTexture(GL_TEXTURE_2D, 0);
+
+       *ptex = tex;
+       return 0;
+}
+
+int __init_buffers(GLuint* vao, GLuint buffers[2])
+{
+       glGenBuffers(2, buffers);
+       glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
+       glBufferData(GL_ARRAY_BUFFER, sizeof(vert_array), vert_array, GL_STATIC_DRAW);
+       glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
+       glBufferData(GL_ARRAY_BUFFER, sizeof(texture_array), texture_array, GL_STATIC_DRAW);
+
+       glGenVertexArrays(1, vao);
+       glBindVertexArray(*vao);
+
+       glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
+       glEnableVertexAttribArray(0);
+       glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
+       glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
+       glEnableVertexAttribArray(1);
+       glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
+       glBindVertexArray(0);
+       return 0;
+}
+
+int __init_program(GLuint* pprog, const char* vert_shader, const char* frag_shader)
+{
+       GLint status = 0;
+       GLint len    = 0;
+
+       GLuint vshader = glCreateShader(GL_VERTEX_SHADER);
+
+       glShaderSource (vshader, 1, &vert_shader, NULL);
+       glCompileShader(vshader);
+       glGetShaderiv  (vshader, GL_COMPILE_STATUS, &status);
+
+       if (!status) {
+               glGetShaderiv(vshader, GL_INFO_LOG_LENGTH, &len);
+
+               char* log = calloc(1, len + 1);
+               if (!log)
+                       return -ENOMEM;
+
+               glGetShaderInfoLog(vshader, len, NULL, log);
+
+               scf_loge("%s\n", log);
+               free(log);
+               log = NULL;
+       }
+
+       GLuint fshader = glCreateShader(GL_FRAGMENT_SHADER);
+
+       glShaderSource (fshader, 1, &frag_shader, NULL);
+       glCompileShader(fshader);
+       glGetShaderiv  (fshader, GL_COMPILE_STATUS, &status);
+
+       if (!status) {
+               glGetShaderiv(fshader, GL_INFO_LOG_LENGTH, &len);
+
+               char* log = calloc(1, len + 1);
+               if (!log)
+                       return -ENOMEM;
+
+               glGetShaderInfoLog(fshader, len, NULL, log);
+
+               scf_loge("%s\n", log);
+               free(log);
+               log = NULL;
+       }
+
+       GLuint program = glCreateProgram();
+
+       glAttachShader(program, vshader);
+       glAttachShader(program, fshader);
+       glLinkProgram (program);
+       glGetProgramiv(program, GL_LINK_STATUS, &status);
+
+       if (!status) {
+               glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len);
+
+               char* log = calloc(1, len + 1);
+               if (!log)
+                       return -ENOMEM;
+
+               glGetProgramInfoLog(program, len, NULL, log);
+
+               scf_loge("%s\n", log);
+               free(log);
+               log = NULL;
+       }
+
+       *pprog = program;
+       return 0;
+}
diff --git a/ses_ui_render.c b/ses_ui_render.c
new file mode 100644 (file)
index 0000000..127faa3
--- /dev/null
@@ -0,0 +1,113 @@
+#include"ses_ui.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;
+
+
+int ses_gl_render(ses_ui_t* ui, int width, int height, int x, int y, int w, int h)
+{
+       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, ui->width, ui->height, NULL);
+
+       float mvp[16];
+       __compute_mvp(mvp, 0, 0, 0);
+
+       if (SES_UI_EDIT == ui->status) {
+               cairo_set_line_width(ui->cr, 2);
+               cairo_set_source_rgb(ui->cr, 1, 1, 1);
+
+               cairo_rectangle(ui->cr, 0, 0, width, height);
+               cairo_fill(ui->cr);
+               cairo_stroke(ui->cr);
+
+               __ses_draw_elines    (ui->cr, ui->f, -1);
+               __ses_draw_components(ui->cr, ui->f);
+
+               if (ui->press_x > 0
+                               && ui->press_y > 0
+                               && ui->move_x  > 0
+                               && ui->move_y  > 0) {
+                       cairo_set_source_rgb(ui->cr, 1, 0.5, 0.1);
+
+                       cairo_move_to(ui->cr, ui->press_x, ui->press_y);
+                       cairo_line_to(ui->cr, ui->move_x,  ui->move_y);
+                       cairo_stroke(ui->cr);
+               }
+       }
+
+       cairo_surface_write_to_png(ui->surface, "tmp.png");
+
+       GLfloat vert_update[] =
+       {
+                2.0 *  x      / (float)width  - 1.0,
+               -2.0 * (y + h) / (float)height + 1.0,
+
+                2.0 * (x + w) / (float)width  - 1.0,
+               -2.0 * (y + h) / (float)height + 1.0,
+
+                2.0 *  x      / (float)width  - 1.0,
+               -2.0 *  y      / (float)height + 1.0,
+
+                2.0 * (x + w) / (float)width  - 1.0,
+               -2.0 *  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, ui->width, ui->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, ui->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);
+       return 0;
+}
index 4d04a9597a13bda5f8d33c4d54885bb3383d17ec..b499863ae4502692e2190ab31a2f4849aca41497 100644 (file)
@@ -94,6 +94,19 @@ void ses_edge_print(ses_edge_t* edge)
        fprintf(stderr, "; ");
 }
 
+void ses_edges_print(scf_vector_t* edges)
+{
+       if (!edges)
+               return;
+
+       int i;
+       for (i = 0; i < edges->size; i++) {
+
+               ses_edge_print(edges->data[i]);
+       }
+       fprintf(stderr, "\n");
+}
+
 ses_node_t* ses_node_alloc()
 {
        ses_node_t* node = calloc(1, sizeof(ses_node_t));
@@ -136,12 +149,8 @@ void ses_node_print(ses_node_t* node)
 
        fprintf(stderr, "node %d: \n", node->index);
 
-       for (i = 0; i < node->edges->size; i++) {
-               edge      = node->edges->data[i];
+       ses_edges_print(node->edges);
 
-               ses_edge_print(edge);
-               fprintf(stderr, "\n");
-       }
        fprintf(stderr, "\n");
 }
 
index 44c331014e083620fe61ed05138d34a5064ba439..1bfb3a3060e74d483551b474e8e7360b31a52b9b 100644 (file)
@@ -9,7 +9,7 @@
 #define REAL(z,i) ((z)[2*(i)])
 #define IMAG(z,i) ((z)[2*(i)+1])
 
-#define N 1024
+#define N 2048
 
 int main()
 {
@@ -117,7 +117,7 @@ int main()
                printf("%d, %lg %lg\n", i, REAL(data, i) / sqrt(N), IMAG(data, i) / sqrt(N));
        }
 
-       double f = 2000.0 * 1e6 * imax / N;
+       double f = 1000.0 * 1e6 * imax / N;
 
        printf("avg: %lg, Zmax: %lg, imax: %d, f: %lg\n", sum / (N - 1), Zmax, imax, f);