UI: support buttons of 'undo', 'redo', 'back', 'forward'
authoryu.dongliang <18588496441@163.com>
Tue, 10 Jun 2025 15:48:19 +0000 (23:48 +0800)
committeryu.dongliang <18588496441@163.com>
Tue, 10 Jun 2025 15:48:19 +0000 (23:48 +0800)
scf_eda_pack.h
scf_list.h [new file with mode: 0644]
ses_ui.c
ses_ui.glade
ses_ui.h
udiv.cpk [deleted file]

index eb0866b87da282aa37ad3e216fdf7407d1836544..1d1f8715d11cdf2ab2df202db3035ecd3633bcc3 100644 (file)
@@ -297,20 +297,6 @@ typedef struct {
        char*     va_curve;
 } ScfEdata;
 
-typedef struct {
-       SCF_PACK_DEF_VAR(int, x0);
-       SCF_PACK_DEF_VAR(int, y0);
-       SCF_PACK_DEF_VAR(int, x1);
-       SCF_PACK_DEF_VAR(int, y1);
-} ScfLine;
-
-SCF_PACK_TYPE(ScfLine)
-SCF_PACK_INFO_VAR(ScfLine, x0),
-SCF_PACK_INFO_VAR(ScfLine, y0),
-SCF_PACK_INFO_VAR(ScfLine, x1),
-SCF_PACK_INFO_VAR(ScfLine, y1),
-SCF_PACK_END(ScfLine)
-
 typedef struct {
        SCF_PACK_DEF_VAR(double, Vb);
        SCF_PACK_DEF_VAR(double, Ib);
@@ -325,6 +311,7 @@ SCF_PACK_END(ScfEcurve)
 
 typedef struct scf_eops_s        ScfEops;
 typedef struct scf_epin_s        ScfEpin;
+typedef struct scf_eline_s       ScfEline;
 typedef struct scf_ecomponent_s  ScfEcomponent;
 typedef struct scf_efunction_s   ScfEfunction;
 typedef struct scf_eboard_s      ScfEboard;
@@ -336,6 +323,21 @@ struct scf_eops_s
        int (*shared)(ScfEpin* p,  int flags);
 };
 
+typedef struct {
+       SCF_PACK_DEF_VAR(int, x0);
+       SCF_PACK_DEF_VAR(int, y0);
+       SCF_PACK_DEF_VAR(int, x1);
+       SCF_PACK_DEF_VAR(int, y1);
+       SCF_PACK_DEF_OBJ(ScfEline, el);
+} ScfLine;
+
+SCF_PACK_TYPE(ScfLine)
+SCF_PACK_INFO_VAR(ScfLine, x0),
+SCF_PACK_INFO_VAR(ScfLine, y0),
+SCF_PACK_INFO_VAR(ScfLine, x1),
+SCF_PACK_INFO_VAR(ScfLine, y1),
+SCF_PACK_END(ScfLine)
+
 struct scf_epin_s
 {
        SCF_PACK_DEF_VAR(uint64_t, id);
@@ -420,7 +422,8 @@ SCF_PACK_INFO_VAR(ScfEconn, lid),
 SCF_PACK_INFO_VARS(ScfEconn, cids, uint64_t),
 SCF_PACK_END(ScfEconn)
 
-typedef struct {
+struct scf_eline_s
+{
        SCF_PACK_DEF_VAR(uint64_t, id);
        SCF_PACK_DEF_VARS(uint64_t, pins);
        SCF_PACK_DEF_VAR(uint64_t, c_pins);
@@ -440,7 +443,7 @@ typedef struct {
        SCF_PACK_DEF_VAR(uint8_t, aconst);
        SCF_PACK_DEF_VAR(uint8_t, vflag);
        SCF_PACK_DEF_VAR(uint8_t, open_flag);
-} ScfEline;
+};
 
 SCF_PACK_TYPE(ScfEline)
 SCF_PACK_INFO_VAR(ScfEline, id),
diff --git a/scf_list.h b/scf_list.h
new file mode 100644 (file)
index 0000000..e08644f
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef SCF_LIST_H
+#define SCF_LIST_H
+
+#include"scf_def.h"
+
+typedef struct scf_list_s      scf_list_t;
+
+struct scf_list_s {
+       struct scf_list_s*              prev;
+       struct scf_list_s*              next;
+};
+
+static inline void scf_list_init(scf_list_t* h)
+{
+       h->prev = h;
+       h->next = h;
+}
+
+static inline void scf_list_del(scf_list_t* n)
+{
+       n->prev->next = n->next;
+       n->next->prev = n->prev;
+
+       // only to avoid some wrong operations for these 2 invalid pointers
+       n->prev = NULL;
+       n->next = NULL;
+}
+
+static inline void scf_list_add_tail(scf_list_t* h, scf_list_t* n)
+{
+       h->prev->next = n;
+       n->prev = h->prev;
+       n->next = h;
+       h->prev = n;
+}
+
+static inline void scf_list_add_front(scf_list_t* h, scf_list_t* n)
+{
+       h->next->prev = n;
+       n->next = h->next;
+       n->prev = h;
+       h->next = n;
+}
+
+static inline void scf_list_mov2(scf_list_t* h0, scf_list_t* h1)
+{
+       if (h1->next == h1)
+               return;
+
+       h0->prev->next = h1->next;
+       h1->next->prev = h0->prev;
+       h1->prev->next = h0;
+       h0->prev       = h1->prev;
+}
+
+#define SCF_LIST_INIT(h)       {&h, &h}
+
+#define scf_list_data(l, type, member) ((type*)((char*)l - offsetof(type, member)))
+
+#define scf_list_head(h)               ((h)->next)
+#define scf_list_tail(h)               ((h)->prev)
+#define scf_list_sentinel(h)   (h)
+#define scf_list_next(l)               ((l)->next)
+#define scf_list_prev(l)               ((l)->prev)
+#define scf_list_empty(h)              ((h)->next == (h))
+
+#define scf_list_clear(h, type, member, type_free) \
+       do {\
+               scf_list_t* l;\
+               type*       t;\
+               for (l = scf_list_head(h); l != scf_list_sentinel(h);) {\
+                       t  = scf_list_data(l, type, member);\
+                       l  = scf_list_next(l);\
+                       scf_list_del(&t->member);\
+                       type_free(t);\
+                       t = NULL;\
+               }\
+       } while(0)
+
+#define scf_slist_clear(h, type, next, type_free) \
+       do { \
+               while (h) { \
+                       type* p = h; \
+                       h = p->next; \
+                       type_free(p); \
+                       p = NULL; \
+               } \
+       } while (0)
+
+#define scf_list_mov(dst, src, type, member) \
+       do {\
+               scf_list_t* l;\
+               type*       t;\
+               for (l = scf_list_head(src); l != scf_list_sentinel(src);) {\
+                       t  = scf_list_data(l, type, member);\
+                       l  = scf_list_next(l);\
+                       scf_list_del(&t->member);\
+                       scf_list_add_tail(dst, &t->member);\
+               }\
+       } while(0)
+
+#endif
index c641e735ab1ce94d8ff7e9fd9c6601f200428d3e..5f87dcdd1f9f86dec918c6a3a097e2ca17a747f3 100644 (file)
--- a/ses_ui.c
+++ b/ses_ui.c
@@ -1,5 +1,37 @@
 #include"ses_ui.h"
 
+static void ui_add_eline(ses_ui_t* ui, ScfEline* el)
+{
+       ScfEcomponent* c;
+       ScfEpin*       p;
+       long i;
+
+       for (i = 0; i + 1 < el->n_pins; i += 2) {
+               c  = ui->f->components[el->pins[i]];
+               p  = c->pins          [el->pins[i + 1]];
+
+               p->lid = el->id;
+
+               scf_logi("\033[32m el%ld add c%ldp%ld\033[0m\n", el->id, p->cid, p->id);
+       }
+}
+
+static void ui_del_eline(ses_ui_t* ui, ScfEline* el)
+{
+       ScfEcomponent* c;
+       ScfEpin*       p;
+       long i;
+
+       for (i = 0; i + 1 < el->n_pins; i += 2) {
+               c  = ui->f->components[el->pins[i]];
+               p  = c->pins          [el->pins[i + 1]];
+
+               p->lid = -1;
+
+               scf_logi("\033[31m el%ld del c%ldp%ld\033[0m\n", el->id, p->cid, p->id);
+       }
+}
+
 static void resize(GtkGLArea* self, gint width, gint height, gpointer user_data)
 {
        GdkGLContext *context;
@@ -90,6 +122,132 @@ static gboolean render(GtkGLArea* self, GdkGLContext* context, gpointer user_dat
        return TRUE;
 }
 
+static void ui_print_log(ui_log_t* log)
+{
+       switch (log->type) {
+               case UI_ADD_COMPONENT:
+                       fprintf(stderr, "log: add %p c%ld\n", log->c, log->c->id);
+                       break;
+
+               case UI_MOV_COMPONENT:
+                       fprintf(stderr, "log: mov %p c%ld, (%d,%d)-->(%d,%d)\n", log->c, log->c->id, log->old_x, log->old_y, log->new_x, log->new_y);
+                       break;
+
+               case UI_SET_VALUE:
+                       fprintf(stderr, "log: set %p c%ld, %lg-->%lg\n", log->c, log->c->id, log->old_v, log->new_v);
+                       break;
+
+               case UI_ADD_ELINE:
+                       fprintf(stderr, "log: add %p el%ld\n", log->el, log->el->id);
+                       break;
+
+               case UI_DEL_ELINE:
+                       fprintf(stderr, "log: del %p el%ld\n", log->el, log->el->id);
+                       break;
+
+               case UI_ADD_LINE:
+                       fprintf(stderr, "log: add %p el%ld, l: %p\n", log->el, log->el->id, log->l);
+                       break;
+
+               case UI_DEL_LINE:
+                       fprintf(stderr, "log: del %p el%ld, l: %p\n", log->el, log->el->id, log->l);
+                       break;
+               default:
+                       break;
+       };
+}
+
+static void ui_print_logs(ses_ui_t* ui)
+{
+       scf_list_t* l;
+       ui_log_t*   log;
+
+       for (l  = scf_list_head(&ui->log); l != scf_list_sentinel(&ui->log); l = scf_list_next(l)) {
+               log = scf_list_data(l, ui_log_t, list);
+
+               ui_print_log(log);
+       }
+}
+
+static void ui_add_log(ses_ui_t* ui, ui_log_t* log)
+{
+       scf_list_t* l;
+
+       scf_list_add_front(ui->current, &log->list);
+       ui->current = &log->list;
+
+       fprintf(stderr, "\n-----\n");
+       for (l  = scf_list_next(ui->current); l != scf_list_sentinel(&ui->log); ) {
+               log = scf_list_data(l, ui_log_t, list);
+               l   = scf_list_next(l);
+
+               if (UI_ADD_LINE == log->type && !log->l->el) {
+                       scf_list_del(&log->list);
+
+                       scf_logw("free: add line %p, (%d,%d)-->(%d,%d)\n", log->l, log->l->x0, log->l->y0, log->l->x1, log->l->y1);
+
+                       ScfLine_free(log->l);
+                       free(log);
+                       log = NULL;
+               }
+       }
+
+       for (l  = scf_list_next(ui->current); l != scf_list_sentinel(&ui->log); ) {
+               log = scf_list_data(l, ui_log_t, list);
+               l   = scf_list_next(l);
+
+               scf_list_del(&log->list);
+
+               switch (log->type) {
+                       case UI_ADD_COMPONENT:
+                               scf_logw("free: add %p, c%ld\n", log->c, log->c->id);
+
+                               ScfEcomponent_free(log->c);
+                               break;
+
+                       case UI_ADD_ELINE:
+                               scf_logw("free: add %p, el%ld\n", log->el, log->el->id);
+
+                               ScfEline_free(log->el);
+                               break;
+
+                       case UI_MOV_COMPONENT:
+                               scf_logw("free: mov %p, (%d,%d)-->(%d,%d)\n", log->c, log->old_x, log->old_y, log->new_x, log->new_y);
+                               break;
+
+                       case UI_SET_VALUE:
+                               scf_logw("free: set %p\n", log->c);
+                               break;
+
+                       case UI_DEL_ELINE:
+                               scf_logw("free: del el %p\n", log->el);
+                               break;
+
+                       case UI_DEL_LINE:
+                               scf_logw("free: del el %p, l %p\n", log->el, log->l);
+                               break;
+
+                       case UI_ADD_LINE:
+                               scf_logw("free: add el %p, l %p\n", log->el, log->l);
+                               break;
+                       default:
+                               break;
+               };
+
+               free(log);
+               log = NULL;
+       }
+
+       if (scf_list_sentinel(&ui->log) == scf_list_next(ui->current))
+               gtk_widget_set_sensitive(ui->redo, FALSE);
+
+       gtk_widget_set_sensitive(ui->undo, TRUE);
+
+       fprintf(stderr, "\n-----\n");
+       ui_print_logs(ui);
+       fprintf(stderr, "-----\n\n");
+}
+
 static int button_2pins_clicked(ses_ui_t* ui, int type)
 {
        ScfEcomponent*  B;
@@ -103,8 +261,8 @@ static int button_2pins_clicked(ses_ui_t* ui, int type)
                EDA_INST_ADD_COMPONENT(ui->f, B, SCF_EDA_Battery);
                B->x = 100;
                B->y = 100;
-               B->w = 16;
-               B->h = 10;
+               B->w = 24;
+               B->h = 24;
 
                B->pins[0]->x = B->x;
                B->pins[1]->x = B->x;
@@ -116,7 +274,7 @@ static int button_2pins_clicked(ses_ui_t* ui, int type)
        EDA_INST_ADD_COMPONENT(ui->f, c, type);
        c->x = 200 + rand() % 100;
        c->y = 200 + rand() % 100;
-       c->w = 12;
+       c->w = 24;
        c->h = 24;
 
        c->pins[0]->x = c->x;
@@ -124,6 +282,16 @@ static int button_2pins_clicked(ses_ui_t* ui, int type)
 
        c->pins[0]->y = c->y + 50;
        c->pins[1]->y = c->y - 50;
+
+       ui_log_t* log = calloc(1, sizeof(ui_log_t));
+       if (!log)
+               return -ENOMEM;
+
+       log->c       = c;
+       log->type    = UI_ADD_COMPONENT;
+       log->ok_flag = 1;
+
+       ui_add_log(ui, log);
        return 0;
 }
 
@@ -140,8 +308,8 @@ static int button_transistor_clicked(ses_ui_t* ui, int type)
                EDA_INST_ADD_COMPONENT(ui->f, B, SCF_EDA_Battery);
                B->x = 100;
                B->y = 100;
-               B->w = 16;
-               B->h = 10;
+               B->w = 24;
+               B->h = 24;
 
                B->pins[0]->x = B->x;
                B->pins[1]->x = B->x;
@@ -153,7 +321,7 @@ static int button_transistor_clicked(ses_ui_t* ui, int type)
        EDA_INST_ADD_COMPONENT(ui->f, c, type);
        c->x = 200 + rand() % 100;
        c->y = 200 + rand() % 100;
-       c->w = 12;
+       c->w = 24;
        c->h = 24;
 
        c->pins[SCF_EDA_NPN_B]->x = c->x;
@@ -164,6 +332,16 @@ static int button_transistor_clicked(ses_ui_t* ui, int type)
 
        c->pins[SCF_EDA_NPN_E]->x = c->x + 100 * 7 / 8;
        c->pins[SCF_EDA_NPN_E]->y = c->y + 50;
+
+       ui_log_t* log = calloc(1, sizeof(ui_log_t));
+       if (!log)
+               return -ENOMEM;
+
+       log->c       = c;
+       log->type    = UI_ADD_COMPONENT;
+       log->ok_flag = 1;
+
+       ui_add_log(ui, log);
        return 0;
 }
 
@@ -264,6 +442,8 @@ static int button_add_line(ScfEline* el, ScfLine** pl, int x0, int y0, int x1, i
                return ret;
        }
 
+       l->el = el;
+
        *pl = l;
        return 0;
 }
@@ -298,6 +478,7 @@ static int button_connect_pin(ses_ui_t* ui, ScfEpin* p0, ScfEpin* p1)
 {
        ScfEline*  el = NULL;
        ScfLine*   l  = NULL;
+       ui_log_t*  log;
 
        int ret;
 
@@ -310,29 +491,45 @@ static int button_connect_pin(ses_ui_t* ui, ScfEpin* p0, ScfEpin* p1)
                ret = scf_eline__add_pin(el, p0->cid, p0->id);
                if (ret < 0)
                        return ret;
-
                p0->lid = el->id;
+
+               log = calloc(1, sizeof(ui_log_t));
+               if (!log)
+                       return -ENOMEM;
+               log->el   = el;
+               log->type = UI_ADD_ELINE;
+
+               ui_add_log(ui, log);
        } else {
                ret = button_add_line(el, &l, p0->x, p0->y, p1->x, p1->y);
                if (ret < 0)
                        return ret;
+
+               log = calloc(1, sizeof(ui_log_t));
+               if (!log)
+                       return -ENOMEM;
+               log->el   = el;
+               log->l    = l;
+               log->p    = p1;
+               log->type = UI_ADD_LINE;
+
+               ui_add_log(ui, log);
        }
 
        ret = scf_eline__add_pin(el, p1->cid, p1->id);
        if (ret < 0)
                return ret;
+       p1->lid = el->id;
 
        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)
 {
+       ui_log_t* log;
        ScfEpin*  p;
        long      i;
-       long      j;
 
        for (i = 0; i < ui->c->n_pins; i++) {
                p  =        ui->c->pins[i];
@@ -362,6 +559,14 @@ static int button_connect_pins(ses_ui_t* ui)
                                        int ret = button_add_eline(ui, &el, &l, x, y, x, y);
                                        if (ret < 0)
                                                return ret;
+
+                                       log = calloc(1, sizeof(ui_log_t));
+                                       if (!log)
+                                               return -ENOMEM;
+                                       log->el   = el;
+                                       log->type = UI_ADD_ELINE;
+
+                                       ui_add_log(ui, log);
                                }
                        }
 
@@ -381,35 +586,188 @@ static int button_connect_pins(ses_ui_t* ui)
                } else {
                        scf_efunction_find_eline(ui->f, &el, &l, x, y);
                        if (!el) {
-                               j = scf_find_eline_index(ui->f, p->lid);
+                               int dx = ui->cx - ui->c->x;
+                               int dy = ui->cy - ui->c->y;
+
+                               x = p->x + dx;
+                               y = p->y + dy;
+
+                               scf_efunction_find_eline(ui->f, &el, &l, x, y);
+                               if (el) {
+                                       if (4 == el->n_pins) {
+                                               scf_efunction__del_eline(ui->f, el);
+                                               ui_del_eline(ui, el);
+
+                                               log = calloc(1, sizeof(ui_log_t));
+                                               if (!log)
+                                                       return -ENOMEM;
+                                               log->el   = el;
+                                               log->type = UI_DEL_ELINE;
+
+                                               ui_add_log(ui, log);
+                                       } else {
+                                               scf_eline__del_line(el, l);
+                                               l->el  = NULL;
+                                               p->lid = -1;
+
+                                               scf_logi("\033[31m el%ld del c%ldp%ld\033[0m\n", el->id, p->cid, p->id);
+
+                                               log = calloc(1, sizeof(ui_log_t));
+                                               if (!log)
+                                                       return -ENOMEM;
+                                               log->el   = el;
+                                               log->l    = l;
+                                               log->p    = p;
+                                               log->type = UI_DEL_LINE;
+
+                                               ui_add_log(ui, log);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static void set_value(ScfEcomponent* c, double d)
+{
+       switch (c->type) {
+               case SCF_EDA_Battery:
+                       c->v = d;
+                       break;
 
-                               if (j >= 0) {
-                                       el = ui->f->elines[j];
+               case SCF_EDA_Resistor:
+                       c->r = d;
+                       break;
 
-                                       assert(0 == scf_eline__del_pin(el, p->cid, p->id));
-                                       p->lid = -1;
+               case SCF_EDA_Capacitor:
+                       c->uf = d;
+                       break;
+
+               case SCF_EDA_Inductor:
+                       c->uh = d;
+                       break;
+               default:
+                       break;
+       };
+}
 
-                                       scf_logi("\033[31m el%ld del c%ldp%ld\033[0m\n", el->id, p->cid, p->id);
+static void dialog_response(GtkDialog* self, gint response_id, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+       ui_log_t* log;
+
+       double d = atof(gtk_entry_get_text(ui->entry_data));
+       if (d > 0.0) {
+               log = calloc(1, sizeof(ui_log_t));
+               if (!log)
+                       goto end;
+
+               log->c     = ui->setc;
+               log->type  = UI_SET_VALUE;
+               log->new_v = d;
+
+               ui_add_log(ui, log);
+
+               switch (ui->setc->type) {
+                       case SCF_EDA_Battery:
+                               log->old_v  = ui->setc->v;
+                               ui->setc->v = d;
+                               break;
+
+                       case SCF_EDA_Resistor:
+                               log->old_v  = ui->setc->r;
+                               ui->setc->r = d;
+                               break;
+
+                       case SCF_EDA_Capacitor:
+                               log->old_v  = ui->setc->uf;
+                               ui->setc->uf = d;
+                               break;
+
+                       case SCF_EDA_Inductor:
+                               log->old_v  = ui->setc->uh;
+                               ui->setc->uh = d;
+                               break;
+                       default:
+                               break;
+               };
+
+               log->ok_flag = 1;
+       }
 
-                                       if (2 == el->n_pins) {
-                                               c2 = ui->f->components[el->pins[0]];
-                                               p2 = c2->pins         [el->pins[1]];
+end:
+       ui->entry_data = NULL;
+       ui->setc = NULL;
 
-                                               assert(0 == scf_eline__del_pin(el, p2->cid, p2->id));
-                                               p2->lid = -1;
+       gtk_widget_destroy(GTK_WIDGET(self));
+}
 
-                                               scf_logi("\033[31m el%ld del c%ldp%ld\033[0m\n", el->id, p2->cid, p2->id);
+void button_set_data(ses_ui_t* ui)
+{
+       GtkWidget* dialog;
+       GtkWidget* content_area;
+       GtkWidget* label;
+       GtkWidget* entry;
+
+       assert(ui->c);
+       switch (ui->c->type) {
+               case SCF_EDA_Battery:
+                       label = gtk_label_new("V");
+                       break;
 
-                                               assert(0 == scf_efunction__del_eline(ui->f, el));
-                                               ScfEline_free(el);
-                                               el = NULL;
-                                       }
-                               }
-                       }
-               }
+               case SCF_EDA_Resistor:
+                       label = gtk_label_new("Ω");
+                       break;
+
+               case SCF_EDA_Capacitor:
+                       label = gtk_label_new("uF");
+                       break;
+
+               case SCF_EDA_Inductor:
+                       label = gtk_label_new("uH");
+                       break;
+               default:
+                       return;
+                       break;
+       };
+
+       if (!label)
+               return;
+
+       dialog = gtk_dialog_new_with_buttons ("set value",
+                       ui->window,
+                       GTK_DIALOG_DESTROY_WITH_PARENT,
+                       "_OK",
+                       GTK_RESPONSE_NONE,
+                       NULL);
+
+       if (!dialog) {
+               gtk_widget_destroy(label);
+               return;
        }
 
-       return 0;
+       entry = gtk_entry_new();
+       if (!entry) {
+               gtk_widget_destroy(label);
+               gtk_widget_destroy(dialog);
+               return;
+       }
+
+       ui->entry_data = GTK_ENTRY(entry);
+       ui->setc       = ui->c;
+
+       content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+
+       g_signal_connect(dialog, "response", G_CALLBACK(dialog_response), ui);
+
+       gtk_container_add(GTK_CONTAINER(content_area), entry);
+       gtk_container_add(GTK_CONTAINER(content_area), label);
+
+       gtk_orientable_set_orientation(GTK_ORIENTABLE(content_area), GTK_ORIENTATION_HORIZONTAL);
+
+       gtk_widget_show_all(dialog);
 }
 
 static gboolean button_press_event(GtkWidget* self, GdkEventButton* event, gpointer user_data)
@@ -421,7 +779,7 @@ static gboolean button_press_event(GtkWidget* self, GdkEventButton* event, gpoin
        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);
+               scf_logi("x: %f, y: %f\n", event->x, event->y);
 
                if (ui->f) {
                        ui->c  = NULL;
@@ -430,8 +788,22 @@ static gboolean button_press_event(GtkWidget* self, GdkEventButton* event, gpoin
                        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;
+                       int64_t us = gettime();
+
+                       if (ui->c && !ui->p) {
+                               if (us - ui->press_us < 100 * 1000) {
+                                       scf_logw("us - ui->press_us: %ld\n", us - ui->press_us);
+
+                                       button_set_data(ui);
+                               }
+
+                               ui->cx = ui->c->x;
+                               ui->cy = ui->c->y;
+                       }
+
+                       ui->press_us = us;
+                       ui->press_x  = event->x;
+                       ui->press_y  = event->y;
 
                        if (ui->c) {
                                fprintf(stderr, ", c%ld", ui->c->id);
@@ -451,6 +823,7 @@ static gboolean button_press_event(GtkWidget* self, GdkEventButton* event, gpoin
 static gboolean button_release_event(GtkWidget* self, GdkEventButton* event, gpointer user_data)
 {
        ses_ui_t*  ui = user_data;
+       ui_log_t*  log;
 
        if (gtk_widget_get_window(GTK_WIDGET(ui->gl_area)) == event->window) {
                ui->status = SES_UI_EDIT;
@@ -459,7 +832,32 @@ static gboolean button_release_event(GtkWidget* self, GdkEventButton* event, gpo
 
                if (ui->c) {
                        if (!ui->p) {
+                               int dx = ui->c->x - ui->cx;
+                               int dy = ui->c->y - ui->cy;
+
+                               if (dx * dx + dy * dy > 25) {
+                                       log = calloc(1, sizeof(ui_log_t));
+                                       if (!log) {
+                                               gtk_gl_area_queue_render(ui->gl_area);
+                                               return TRUE;
+                                       }
+
+                                       log->c     = ui->c;
+                                       log->old_x = ui->cx;
+                                       log->old_y = ui->cy;
+                                       log->new_x = ui->c->x;
+                                       log->new_y = ui->c->y;
+                                       log->type  = UI_MOV_COMPONENT;
+
+                                       ui_add_log(ui, log);
+                               }
+
                                button_connect_pins(ui);
+
+                               if (!scf_list_empty(&ui->log)) {
+                                       log = scf_list_data(scf_list_tail(&ui->log), ui_log_t, list);
+                                       log->ok_flag = 1;
+                               }
                        } else {
                                ScfEpin* p = ui->p;
 
@@ -467,12 +865,20 @@ static gboolean button_release_event(GtkWidget* self, GdkEventButton* event, gpo
                                ui->p = NULL;
 
                                scf_efunction_find_pin(ui->f, &ui->c, &ui->p, event->x, event->y);
-                               if (ui->p)
+                               if (ui->p) {
                                        button_connect_pin(ui, p, ui->p);
+
+                                       if (!scf_list_empty(&ui->log)) {
+                                               log = scf_list_data(scf_list_tail(&ui->log), ui_log_t, list);
+                                               log->ok_flag = 1;
+                                       }
+                               }
                        }
 
-                       ui->c = NULL;
-                       ui->p = NULL;
+                       ui->c  = NULL;
+                       ui->p  = NULL;
+                       ui->cx = 0;
+                       ui->cy = 0;
 
                        ui->press_x = 0;
                        ui->press_y = 0;
@@ -484,28 +890,35 @@ static gboolean button_release_event(GtkWidget* self, GdkEventButton* event, gpo
        return TRUE;
 }
 
+static void mov_component(ScfEcomponent* c, int x, int y)
+{
+       ScfEpin* p;
+
+       int dx = x - c->x;
+       int dy = y - c->y;
+       int i;
+
+       for (i = 0; i < c->n_pins; i++) {
+               p  =        c->pins[i];
+
+               p->x += dx;
+               p->y += dy;
+       }
+
+       c->x += dx;
+       c->y += dy;
+}
+
 static gboolean button_move_event(GtkWidget* self, GdkEventMotion* event, gpointer user_data)
 {
        ses_ui_t*  ui = user_data;
-       ScfEpin*   p;
-       long       i;
+       ui_log_t*  log;
 
        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;
+                       mov_component(ui->c, event->x, event->y);
                } else {
                        ui->move_x = event->x;
                        ui->move_y = event->y;
@@ -664,14 +1077,156 @@ static int load_png(ses_ui_t* ui)
        return 0;
 }
 
+static void undo_clicked(GtkButton* self, gpointer user_data)
+{
+       ScfEcomponent* c  = NULL;
+       ScfEpin*       p  = NULL;
+       ses_ui_t*      ui = user_data;
+       ui_log_t*      log;
+
+       ui->status = SES_UI_EDIT;
+
+       while (1) {
+               log = scf_list_data(ui->current, ui_log_t, list);
+
+               switch (log->type) {
+                       case UI_ADD_COMPONENT:
+                               scf_efunction__del_component(ui->f, log->c);
+                               break;
+
+                       case UI_MOV_COMPONENT:
+                               mov_component(log->c, log->old_x, log->old_y);
+                               break;
+
+                       case UI_SET_VALUE:
+                               set_value(log->c, log->old_v);
+                               break;
+
+                       case UI_ADD_ELINE:
+                               scf_efunction__del_eline(ui->f, log->el);
+
+                               ui_del_eline(ui, log->el);
+                               break;
+
+                       case UI_DEL_ELINE:
+                               scf_efunction__add_eline(ui->f, log->el);
+
+                               ui_add_eline(ui, log->el);
+                               break;
+
+                       case UI_ADD_LINE:
+                               scf_eline__del_line(log->el, log->l);
+                               log->l->el  = NULL;
+
+                               if (log->p)
+                                       log->p->lid = -1;
+                               break;
+
+                       case UI_DEL_LINE:
+                               scf_eline__add_line(log->el, log->l);
+                               log->l->el = log->el;
+
+                               if (log->p)
+                                       log->p->lid = log->el->id;
+                               break;
+                       default:
+                               break;
+               };
+
+               ui->current = scf_list_prev(ui->current);
+
+               if (scf_list_sentinel(&ui->log) == ui->current) {
+                       gtk_widget_set_sensitive(ui->undo, FALSE);
+                       break;
+               }
+
+               log = scf_list_data(ui->current, ui_log_t, list);
+               if (log->ok_flag)
+                       break;
+       }
+
+       gtk_widget_set_sensitive(ui->redo, TRUE);
+}
+
+static void redo_clicked(GtkButton* self, gpointer user_data)
+{
+       scf_list_t*  l;
+       ses_ui_t*    ui = user_data;
+       ui_log_t*    log;
+
+       ui->status = SES_UI_EDIT;
+
+       for (l  = scf_list_next(ui->current); l != scf_list_sentinel(&ui->log); l = scf_list_next(l)) {
+               log = scf_list_data(l, ui_log_t, list);
+
+               switch (log->type) {
+                       case UI_ADD_COMPONENT:
+                               scf_efunction__add_component(ui->f, log->c);
+                               break;
+
+                       case UI_MOV_COMPONENT:
+                               mov_component(log->c, log->new_x, log->new_y);
+                               break;
+
+                       case UI_SET_VALUE:
+                               set_value(log->c, log->new_v);
+                               break;
+
+                       case UI_ADD_ELINE:
+                               scf_efunction__add_eline(ui->f, log->el);
+
+                               ui_add_eline(ui, log->el);
+                               break;
+
+                       case UI_DEL_ELINE:
+                               scf_efunction__del_eline(ui->f, log->el);
+
+                               ui_del_eline(ui, log->el);
+                               break;
+
+                       case UI_ADD_LINE:
+                               scf_eline__add_line(log->el, log->l);
+                               log->l->el = log->el;
+
+                               if (log->p)
+                                       log->p->lid = log->el->id;
+                               break;
+
+                       case UI_DEL_LINE:
+                               scf_eline__del_line(log->el, log->l);
+                               log->l->el  = NULL;
+
+                               if (log->p)
+                                       log->p->lid = -1;
+                               break;
+                       default:
+                               break;
+               };
+
+               if (log->ok_flag)
+                       break;
+       }
+
+       ui->current = l;
+
+       if (scf_list_sentinel(&ui->log) == scf_list_next(ui->current))
+               gtk_widget_set_sensitive(ui->redo, FALSE);
+
+       gtk_widget_set_sensitive(ui->undo, TRUE);
+}
+
 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++;
-
+       ui->show_index++;
        load_png(ui);
+
+       gtk_widget_set_sensitive(ui->back, TRUE);
+
+       if (ui->show_index >= ui->apply_index - 1)
+               gtk_widget_set_sensitive(ui->forward, FALSE);
+
        gtk_gl_area_queue_render(ui->gl_area);
 }
 
@@ -679,10 +1234,14 @@ static void back_clicked(GtkButton* self, gpointer user_data)
 {
        ses_ui_t* ui = user_data;
 
-       if (ui->show_index > 0)
-               ui->show_index--;
-
+       ui->show_index--;
        load_png(ui);
+
+       gtk_widget_set_sensitive(ui->forward, TRUE);
+
+       if (ui->show_index <= 0)
+               gtk_widget_set_sensitive(ui->back, FALSE);
+
        gtk_gl_area_queue_render(ui->gl_area);
 }
 
@@ -711,6 +1270,9 @@ static gboolean timer_handler(gpointer user_data)
                load_png(ui);
        }
 
+       if (ui->show_index < ui->apply_index - 1)
+               gtk_widget_set_sensitive(ui->forward, TRUE);
+
        gtk_gl_area_queue_render(ui->gl_area);
        return TRUE;
 }
@@ -761,7 +1323,7 @@ int main(int argc, char* argv[])
                fcntl(0, F_SETFL, flags);
        }
 
-       ses_ui_t    ui = SES_UI_INIT();
+       ses_ui_t    ui = SES_UI_INIT(ui);
 
        GtkBuilder* builder;
        GObject*    window;
@@ -782,6 +1344,7 @@ int main(int argc, char* argv[])
        gl_area = gtk_builder_get_object(builder, "gl_area");
 
        ui.builder     = builder;
+       ui.window      = GTK_WINDOW(window);
        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"));
@@ -806,6 +1369,13 @@ int main(int argc, char* argv[])
        GObject*    zoom_out   = gtk_builder_get_object(builder, "button_zoom_out");
        GObject*    apply      = gtk_builder_get_object(builder, "button_apply");
 
+       ui.back    = GTK_WIDGET(back);
+       ui.forward = GTK_WIDGET(forward);
+       ui.undo    = GTK_WIDGET(undo);
+       ui.redo    = GTK_WIDGET(redo);
+
+       g_signal_connect(undo,      "clicked",   G_CALLBACK(undo_clicked),     &ui);
+       g_signal_connect(redo,      "clicked",   G_CALLBACK(redo_clicked),     &ui);
        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);
@@ -833,16 +1403,7 @@ int main(int argc, char* argv[])
        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);
 
index 2931598c4fe3d04e743b467dce4ba7941fc4ab41..a5374bb83b944ffe4ec5cce8d3a5e36b26faf18b 100644 (file)
@@ -69,6 +69,7 @@
                                     <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>
                         <property name="label">gtk-go-back</property>
                         <property name="visible">True</property>
                         <property name="can-focus">True</property>
+                        <property name="sensitive">False</property>
                         <property name="receives-default">True</property>
                         <property name="use-stock">True</property>
                         <property name="always-show-image">True</property>
                         <property name="label">gtk-go-forward</property>
                         <property name="visible">True</property>
                         <property name="can-focus">True</property>
+                        <property name="sensitive">False</property>
                         <property name="receives-default">True</property>
                         <property name="use-stock">True</property>
                         <property name="always-show-image">True</property>
                         <property name="label">gtk-undo</property>
                         <property name="visible">True</property>
                         <property name="can-focus">True</property>
+                        <property name="sensitive">False</property>
                         <property name="receives-default">True</property>
                         <property name="use-stock">True</property>
                         <property name="always-show-image">True</property>
                         <property name="label">gtk-redo</property>
                         <property name="visible">True</property>
                         <property name="can-focus">True</property>
+                        <property name="sensitive">False</property>
                         <property name="receives-default">True</property>
                         <property name="use-stock">True</property>
                         <property name="always-show-image">True</property>
                         <property name="position">10</property>
                       </packing>
                     </child>
+                    <child>
+                      <object class="GtkButton" id="button_refresh">
+                        <property name="label">gtk-refresh</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>
                     <child>
                       <object class="GtkButton" id="button_help">
                         <property name="label">gtk-help</property>
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">True</property>
-                        <property name="position">11</property>
+                        <property name="position">12</property>
                       </packing>
                     </child>
                   </object>
index c6927b96d1c4c828adfa750bf15ed00269ad8e72..03c0e901df2bdbeb024712879150a18c3fc416cc 100644 (file)
--- a/ses_ui.h
+++ b/ses_ui.h
@@ -2,6 +2,7 @@
 #define SES_UI_H
 
 #include"ses_core.h"
+#include"scf_list.h"
 
 #include<sys/types.h>
 #include<sys/wait.h>
 #include <GL/glext.h>
 
 typedef struct ses_ui_s     ses_ui_t;
+typedef struct ui_log_s     ui_log_t;
+
+struct ui_log_s
+{
+       scf_list_t        list;
+
+       ScfEcomponent*    c;
+       ScfEpin*          p;
+       ScfEline*         el;
+       ScfLine*          l;
+
+       double            old_v;
+       double            new_v;
+
+       int               old_x;
+       int               old_y;
+       int               new_x;
+       int               new_y;
+#define UI_ADD_COMPONENT  0
+#define UI_MOV_COMPONENT  1
+#define UI_SET_VALUE      2
+#define UI_ADD_ELINE      3
+#define UI_DEL_ELINE      4
+#define UI_ADD_LINE       5
+#define UI_DEL_LINE       6
+       int               type;
+       uint32_t          ok_flag;
+};
 
 struct ses_ui_s
 {
+       scf_list_t        log;
+       scf_list_t*       current;
+
        GtkBuilder*       builder;
+       GtkWindow*        window;
        GtkGLArea*        gl_area;
 
+       GtkWidget*        undo;
+       GtkWidget*        redo;
+       GtkWidget*        back;
+       GtkWidget*        forward;
+
        GtkEntry*         entry_ns;
        GtkEntry*         entry_count;
 
+       GtkEntry*         entry_data;
+       ScfEcomponent*    setc;
+
        cairo_surface_t*  surface;
        cairo_t*          cr;
        uint8_t*          bgra;
@@ -29,7 +70,10 @@ struct ses_ui_s
        ScfEfunction*     f;
        ScfEcomponent*    c;
        ScfEpin*          p;
+       int               cx;
+       int               cy;
 
+       int64_t           press_us;
        int               press_x;
        int               press_y;
        int               move_x;
@@ -50,7 +94,14 @@ struct ses_ui_s
        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}
+#define SES_UI_INIT(ui) {SCF_LIST_INIT(ui.log), &ui.log, \
+       NULL,NULL,NULL, \
+       NULL,NULL,NULL,NULL, \
+       NULL,NULL, \
+       NULL,NULL, \
+       NULL,NULL,NULL, \
+       NULL,NULL,NULL,0,0, \
+       0,0,0,0,0,  0,0,  0,0,0,0, -1,-1, 0}
 
 static const GLfloat vert_array[] = {
        -1.0f,  -1.0f,
diff --git a/udiv.cpk b/udiv.cpk
deleted file mode 100644 (file)
index 320e57b..0000000
Binary files a/udiv.cpk and /dev/null differ