From 6ebea9612c496ee0800e56779373f830cc37f761 Mon Sep 17 00:00:00 2001
From: "yu.dongliang" <18588496441@163.com>
Date: Tue, 10 Jun 2025 23:48:19 +0800
Subject: [PATCH] UI: support buttons of 'undo', 'redo', 'back', 'forward'
---
scf_eda_pack.h | 35 +--
scf_list.h | 102 ++++++++
ses_ui.c | 693 ++++++++++++++++++++++++++++++++++++++++++++-----
ses_ui.glade | 22 +-
ses_ui.h | 53 +++-
udiv.cpk | Bin 1080 -> 0 bytes
6 files changed, 821 insertions(+), 84 deletions(-)
create mode 100644 scf_list.h
delete mode 100644 udiv.cpk
diff --git a/scf_eda_pack.h b/scf_eda_pack.h
index eb0866b..1d1f871 100644
--- a/scf_eda_pack.h
+++ b/scf_eda_pack.h
@@ -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
index 0000000..e08644f
--- /dev/null
+++ b/scf_list.h
@@ -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
diff --git a/ses_ui.c b/ses_ui.c
index c641e73..5f87dcd 100644
--- 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);
diff --git a/ses_ui.glade b/ses_ui.glade
index 2931598..a5374bb 100644
--- a/ses_ui.glade
+++ b/ses_ui.glade
@@ -69,6 +69,7 @@
False
True
True
+ True
@@ -144,6 +145,7 @@
gtk-go-back
True
True
+ False
True
True
True
@@ -159,6 +161,7 @@
gtk-go-forward
True
True
+ False
True
True
True
@@ -174,6 +177,7 @@
gtk-undo
True
True
+ False
True
True
True
@@ -189,6 +193,7 @@
gtk-redo
True
True
+ False
True
True
True
@@ -294,6 +299,21 @@
10
+
+
+
+ False
+ True
+ 11
+
+
diff --git a/ses_ui.h b/ses_ui.h
index c6927b9..03c0e90 100644
--- 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
#include
@@ -13,15 +14,55 @@
#include
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
index 320e57be97c5004e8dd064e1e76eaa6c271c2ce7..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 1080
zcma)*JxT;Y5QR&4NTJ1ALI)if7#WESi;;n#coYr1fH(12n|cP1VZAn3oPGli%un-8
zRek-KLB76!*p}*Uk6&-R0x%;_YyF
zI(ETJwXQPG6SWvfwsqLUP8J0W-6JBa>+F*(ba%td8f<^&EmYl6`uE9iE0>zEr9O~W
zCqk+rF_4^JyV;v}>AiLfx>c7gw}G@<7(DAThZC%Vb_=?-f4SvSZngO>w}G@9kroId
zhBs?x+B5T+$vU;h)Y`V$K-!Fm4)c&8LS1H*L|q2DR_pgARzKlZXai|ABG+m}O`_}^
LB|d_+*jWDn>{$_4
--
2.25.1