support 'open', 'save', 'save as', 'quit' of 'file' menu
authoryu.dongliang <18588496441@163.com>
Thu, 12 Jun 2025 16:12:32 +0000 (00:12 +0800)
committeryu.dongliang <18588496441@163.com>
Thu, 12 Jun 2025 16:12:32 +0000 (00:12 +0800)
ses_ui.c
ses_ui.glade
ses_ui.h

index 54b3bc4fba3026f8df5f0c3406adf03337541ab7..fa8ae6a5df3fa8ad0c9fcf05097c18ba91f9ded4 100644 (file)
--- a/ses_ui.c
+++ b/ses_ui.c
@@ -209,46 +209,22 @@ static void ui_print_logs(ses_ui_t* ui)
        }
 }
 
-static void ui_add_log(ses_ui_t* ui, ui_log_t* log)
+static void ui_free_log(ui_log_t* log, int unused)
 {
-       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);
-
+       if (log) {
                switch (log->type) {
                        case UI_ADD_COMPONENT:
                                scf_logw("free: add %p, c%ld\n", log->c, log->c->id);
 
-                               ScfEcomponent_free(log->c);
+                               if (unused)
+                                       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);
+                               if (unused)
+                                       ScfEline_free(log->el);
                                break;
 
                        case UI_MOV_COMPONENT:
@@ -279,8 +255,69 @@ static void ui_add_log(ses_ui_t* ui, ui_log_t* log)
                };
 
                free(log);
+       }
+}
+
+static void ui_free_unused_logs(ses_ui_t* ui)
+{
+       scf_list_t*  l;
+       ui_log_t*    log;
+
+       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);
+
+               ui_free_log(log, 1);
                log = NULL;
        }
+}
+
+static void ui_free_logs(ses_ui_t* ui)
+{
+       scf_list_t*  l;
+       ui_log_t*    log;
+
+       ui_free_unused_logs(ui);
+
+       for (l  = scf_list_head(&ui->log); 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);
+
+               ui_free_log(log, 0);
+               log = NULL;
+       }
+
+       ui->current = &ui->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");
+       ui_free_unused_logs(ui);
 
        if (scf_list_sentinel(&ui->log) == scf_list_next(ui->current))
                gtk_widget_set_sensitive(ui->redo, FALSE);
@@ -861,6 +898,8 @@ static gboolean button_press_event(GtkWidget* self, GdkEventButton* event, gpoin
 
                scf_logi("x: %f, y: %f\n", event->x, event->y);
 
+               gtk_window_set_focus(ui->window, GTK_WIDGET(ui->gl_area));
+
                if (ui->f) {
                        ui->c = NULL;
                        ui->p = NULL;
@@ -889,8 +928,8 @@ static gboolean button_press_event(GtkWidget* self, GdkEventButton* event, gpoin
                                if (ui->p)
                                        fprintf(stderr, "p%ld", ui->p->id);
                        }
+                       fprintf(stderr, "\n");
                }
-               fprintf(stderr, "\n");
        }
 
        return TRUE;
@@ -905,47 +944,52 @@ static gboolean button_release_event(GtkWidget* self, GdkEventButton* event, gpo
                ui->status = SES_UI_EDIT;
 
                scf_logw("x: %f, y: %f\n", event->x, event->y);
+               if (ui->f) {
+                       if (ui->c && !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;
+                                       }
 
-               if (ui->c && !ui->p) {
-                       int dx = ui->c->x - ui->cx;
-                       int dy = ui->c->y - ui->cy;
+                                       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;
 
-                       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;
+                                       ui_add_log(ui, log);
                                }
 
-                               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;
+                               button_connect_pins(ui);
+                       } else {
+                               int dx = event->x - ui->press_x;
+                               int dy = event->y - ui->press_y;
 
-                               ui_add_log(ui, log);
+                               if (dx * dx + dy * dy > 25)
+                                       button_line_to(ui, ui->press_x, ui->press_y, event->x, event->y);
                        }
 
-                       button_connect_pins(ui);
-               } else {
-                       button_line_to(ui, ui->press_x, ui->press_y, event->x, event->y);
-               }
-
-               if (!scf_list_empty(&ui->log)) {
-                       log = scf_list_data(scf_list_tail(&ui->log), ui_log_t, list);
-                       log->ok_flag = 1;
-               }
+                       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->cx = 0;
-               ui->cy = 0;
+                       ui->c  = NULL;
+                       ui->p  = NULL;
+                       ui->cx = 0;
+                       ui->cy = 0;
 
-               ui->press_x = 0;
-               ui->press_y = 0;
-               ui->move_x  = 0;
-               ui->move_y  = 0;
+                       ui->press_x = 0;
+                       ui->press_y = 0;
+                       ui->move_x  = 0;
+                       ui->move_y  = 0;
+               }
        }
 
        return TRUE;
@@ -996,17 +1040,19 @@ static gboolean button_move_event(GtkWidget* self, GdkEventMotion* event, gpoint
        return TRUE;
 }
 
-static void apply_clicked(GtkButton* self, gpointer user_data)
+static int ui_save_file(ses_ui_t* ui)
 {
-       ses_ui_t* ui = user_data;
+       if (!ui->f || !ui->save_path)
+               return -EINVAL;
 
        ScfEboard* b = scf_eboard__alloc();
        if (!b)
-               return;
+               return -ENOMEM;
 
-       if (scf_eboard__add_function(b, ui->f) < 0) {
+       long ret = scf_eboard__add_function(b, ui->f);
+       if (ret < 0) {
                ScfEboard_free(b);
-               return;
+               return ret;
        }
 
        ui->f->x = 0;
@@ -1016,18 +1062,19 @@ static void apply_clicked(GtkButton* self, gpointer user_data)
 
        uint8_t* buf = NULL;
        long     len = 0;
-       long     ret = ScfEboard_pack(b, &buf, &len);
+
+       ret = ScfEboard_pack(b, &buf, &len);
 
        assert(0 == scf_eboard__del_function(b, ui->f));
 
        ScfEboard_free(b);
        b = NULL;
        if (ret < 0)
-               return;
+               return ret;
 
-       FILE* fp = fopen("./tmp.cpk", "wb");
+       FILE* fp = fopen(ui->save_path, "wb");
        if (!fp)
-               return;
+               return -1;
 
        fwrite(buf, len, 1, fp);
        fclose(fp);
@@ -1035,11 +1082,21 @@ static void apply_clicked(GtkButton* self, gpointer user_data)
 
        free(buf);
        buf = NULL;
+       return 0;
+}
+
+static void apply_clicked(GtkButton* self, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       int ret = ui_save_file(ui);
+       if (ret < 0)
+               return;
 
        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);
+       printf("./ses %s -l 0 -t %fns -c %d\n", ui->save_path, ns, count);
        fflush(stdout);
 
        gtk_widget_set_sensitive(ui->back,    FALSE);
@@ -1051,6 +1108,164 @@ static void apply_clicked(GtkButton* self, gpointer user_data)
        ui->status = SES_UI_RUN;
 }
 
+static int load_file(ses_ui_t* ui, const char* cpk)
+{
+       ScfEfunction*  f = NULL;
+       ScfEboard*     b = NULL;
+
+       uint8_t* buf = NULL;
+
+       long len = scf_pack_read(&buf, cpk);
+       if (len < 0) {
+               scf_loge("scf_pack_read '%s' error: %ld\n", cpk, len);
+               return len;
+       }
+
+       long ret = ScfEboard_unpack(&b, buf, len);
+       free(buf);
+       buf = NULL;
+
+       if (ret < 0) {
+               scf_loge("ScfEboard__unpack error: %ld\n", ret);
+               ScfEboard_free(b);
+               return ret;
+       }
+
+       if (b->n_functions <= 0) {
+               scf_loge("NO electronic function found in '%s'\n", cpk);
+               ScfEboard_free(b);
+               return -EINVAL;
+       }
+
+       f = b->functions[0];
+       assert(0 == scf_eboard__del_function(b, f));
+       ScfEboard_free(b);
+       b = NULL;
+
+       char* path = ui->save_path;
+
+       ui->save_path = strdup(cpk);
+       if (ui->save_path) {
+               free(path);
+               path = NULL;
+       } else {
+               ui->save_path = path;
+               ScfEfunction_free(f);
+               return -ENOMEM;
+       }
+
+       ui_free_logs(ui);
+       gtk_widget_set_sensitive(ui->undo, FALSE);
+       gtk_widget_set_sensitive(ui->redo, FALSE);
+
+       if (ui->f)
+               ScfEfunction_free(ui->f);
+
+       ui->f = f;
+       if (f->w > 0 && f->h > 0) {
+               ui->width  = f->w;
+               ui->height = f->h;
+       }
+
+       ui->c  = NULL;
+       ui->p  = NULL;
+       ui->cx = 0;
+       ui->cy = 0;
+
+       ui->press_us = 0;
+       ui->press_x  = 0;
+       ui->press_y  = 0;
+       ui->move_x   = 0;
+       ui->move_y   = 0;
+       return 0;
+}
+
+static void open_activate(GtkMenuItem* self, gpointer user_data)
+{
+       scf_logi("\n");
+
+       ses_ui_t*   ui = user_data;
+       GtkWidget*  dialog;
+       gint        res;
+
+       dialog = gtk_file_chooser_dialog_new("Open File",
+                       ui->window,
+                       GTK_FILE_CHOOSER_ACTION_OPEN,
+                       "_Cancel",
+                       GTK_RESPONSE_CANCEL,
+                       "_Open",
+                       GTK_RESPONSE_ACCEPT,
+                       NULL);
+
+       res = gtk_dialog_run(GTK_DIALOG(dialog));
+       if (res == GTK_RESPONSE_ACCEPT) {
+               GtkFileChooser* chooser = GTK_FILE_CHOOSER(dialog);
+
+               char* file = gtk_file_chooser_get_filename(chooser);
+
+               int ret = load_file(ui, file);
+               if (ret < 0)
+                       scf_loge("load '%s' failed\n", file);
+
+               g_free(file);
+       }
+
+       gtk_widget_destroy(dialog);
+}
+
+static void save_activate(GtkMenuItem* self, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       scf_logi("\n");
+
+       ui_save_file(ui);
+}
+
+static void save_as_activate(GtkMenuItem* self, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       scf_logi("\n");
+
+       GtkWidget*       dialog;
+       GtkFileChooser*  chooser;
+
+       dialog = gtk_file_chooser_dialog_new("Save File",
+                       ui->window,
+                       GTK_FILE_CHOOSER_ACTION_SAVE,
+                       "_Cancel",
+                       GTK_RESPONSE_CANCEL,
+                       "_Save",
+                       GTK_RESPONSE_ACCEPT,
+                       NULL);
+
+       chooser = GTK_FILE_CHOOSER(dialog);
+
+       gtk_file_chooser_set_do_overwrite_confirmation(chooser, TRUE);
+       gtk_file_chooser_set_filename(chooser, ui->save_path);
+
+       gint res = gtk_dialog_run(GTK_DIALOG(dialog));
+       if (res == GTK_RESPONSE_ACCEPT)
+       {
+               char* file = gtk_file_chooser_get_filename(chooser);
+               char* path = ui->save_path;
+
+               ui->save_path = strdup(file);
+               if (ui->save_path) {
+                       free(path);
+                       path = NULL;
+               } else
+                       ui->save_path = path;
+
+               ui_save_file(ui);
+
+               g_free(file);
+       }
+
+       gtk_widget_destroy(dialog);
+}
+
 static gboolean key_press_event(GtkWidget* self, GdkEventKey* event, gpointer user_data)
 {
        ses_ui_t* ui = user_data;
@@ -1061,6 +1276,10 @@ static gboolean key_press_event(GtkWidget* self, GdkEventKey* event, gpointer us
                case GDK_KEY_BackSpace:
                case GDK_KEY_Delete:
                        break;
+
+               case 's':
+                       save_activate(NULL, user_data);
+                       break;
                default:
                        break;
        };
@@ -1417,7 +1636,13 @@ int main(int argc, char* argv[])
        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;
+               return -1;
+       }
+
+       ui.save_path = strdup("./tmp.cpk");
+       if (!ui.save_path) {
+               scf_loge("no memory for 'default save path'\n");
+               goto exit;
        }
 
        window   = gtk_builder_get_object(builder, "main_window");
@@ -1444,6 +1669,16 @@ int main(int argc, char* argv[])
        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*    open       = gtk_builder_get_object(builder, "file_open");
+       GObject*    save       = gtk_builder_get_object(builder, "file_save");
+       GObject*    save_as    = gtk_builder_get_object(builder, "file_save_as");
+       GObject*    quit       = gtk_builder_get_object(builder, "file_quit");
+
+       g_signal_connect(open,      "activate",   G_CALLBACK(open_activate),     &ui);
+       g_signal_connect(save,      "activate",   G_CALLBACK(save_activate),     &ui);
+       g_signal_connect(save_as,   "activate",   G_CALLBACK(save_as_activate),  &ui);
+       g_signal_connect(quit,      "activate",   G_CALLBACK(gtk_main_quit),     NULL);
+
        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");
@@ -1486,7 +1721,7 @@ int main(int argc, char* argv[])
        gtk_widget_show_all(GTK_WIDGET(window));
 
        gtk_main();
-
+exit:
        printf("q\n");
        fflush(stdout);
 
index a5374bb83b944ffe4ec5cce8d3a5e36b26faf18b..33ee01dd7f521b4c27dcce302d14c483f143deed 100644 (file)
                       <object class="GtkGLArea" id="gl_area">
                         <property name="visible">True</property>
                         <property name="app-paintable">True</property>
-                        <property name="can-focus">False</property>
+                        <property name="can-focus">True</property>
                       </object>
                       <packing>
                         <property name="resize">False</property>
index 827d449d24af59d3ac294467059a440267f33524..1bddc66bd33e30004890c28d4f67ccc0a7aba220 100644 (file)
--- a/ses_ui.h
+++ b/ses_ui.h
@@ -70,6 +70,8 @@ struct ses_ui_s
        cairo_t*          cr;
        uint8_t*          bgra;
 
+       uint8_t*          save_path;
+
        ScfEfunction*     f;
        ScfEcomponent*    c;
        ScfEpin*          p;
@@ -103,6 +105,7 @@ struct ses_ui_s
        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}