draw VA waves
authoryu.dongliang <18588496441@163.com>
Wed, 2 Jul 2025 14:19:25 +0000 (22:19 +0800)
committeryu.dongliang <18588496441@163.com>
Wed, 2 Jul 2025 14:19:25 +0000 (22:19 +0800)
ses_ui.c
ses_ui.h

index 8913f1a629b8de4a35251bdac9f5fd18df1da37a..27cc42673ef5ee47ab9b182f5f5c108a53246b8d 100644 (file)
--- a/ses_ui.c
+++ b/ses_ui.c
@@ -158,6 +158,70 @@ static gboolean render(GtkGLArea* self, GdkGLContext* context, gpointer user_dat
        return TRUE;
 }
 
+static void draw_VA(scf_vector_t* vec, cairo_t* cr)
+{
+       if (!vec || vec->size <= 0)
+               return;
+
+       va_data_t* va = vec->data[0];
+
+       int N = va->size;
+       int i;
+       int j;
+
+       for (i = 1; i < N; i++) {
+
+               double max = DBL_MIN;
+               double min = DBL_MAX;
+
+               for (j = 0; j < vec->size; j++) {
+                       va =        vec->data[j];
+
+                       assert(i < va->size);
+
+                       if (max < va->data[i])
+                               max = va->data[i];
+
+                       if (min > va->data[i])
+                               min = va->data[i];
+               }
+
+               double pix = 50.0 / (max - min + 1e-15);
+               double y0  = 60.0 * i;
+
+               scf_logd("i: %d, vec->size: %d, max: %lg, min: %lg, pix: %lg, y0: %lg\n", i, vec->size, max, min, pix, y0);
+
+               for (j = 0; j < vec->size; j++) {
+                       va =        vec->data[j];
+
+                       if (0 == j)
+                               cairo_move_to(cr, 20 + 3 * j, y0 - pix * (va->data[i] - min));
+                       else
+                               cairo_line_to(cr, 20 + 3 * j, y0 - pix * (va->data[i] - min));
+               }
+               cairo_stroke(cr);
+       }
+}
+
+static gboolean draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
+{
+       ses_ui_t* ui = user_data;
+
+       GtkStyleContext* context = gtk_widget_get_style_context   (widget);
+       guint            width   = gtk_widget_get_allocated_width (widget);
+       guint            height  = gtk_widget_get_allocated_height(widget);
+
+       gtk_render_background(context, cr, 0, 0, width, height);
+
+       cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 1.0);
+       draw_VA(ui->V_wave, cr);
+
+       cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 1.0);
+       draw_VA(ui->A_wave, cr);
+
+       return FALSE;
+}
+
 static void ui_print_log(ui_log_t* log)
 {
        switch (log->type) {
@@ -1128,7 +1192,9 @@ static int ui_save_file(ses_ui_t* ui)
 
 static void apply_response(GtkDialog* self, gint response_id, gpointer user_data)
 {
-       scf_logi("\n");
+       if (GTK_RESPONSE_NONE != response_id)
+               return;
+       scf_logi("response_id: %d, %d\n", response_id, GTK_RESPONSE_NONE);
 
        ses_ui_t*   ui    = user_data;
 
@@ -1160,6 +1226,18 @@ static void apply_response(GtkDialog* self, gint response_id, gpointer user_data
        ui->entry_V = NULL;
        ui->entry_A = NULL;
 
+       if (ui->V_wave) {
+               scf_vector_clear(ui->V_wave, ( void (*)(void*) )free);
+               scf_vector_free(ui->V_wave);
+               ui->V_wave = NULL;
+       }
+
+       if (ui->A_wave) {
+               scf_vector_clear(ui->A_wave, ( void (*)(void*) )free);
+               scf_vector_free (ui->A_wave);
+               ui->A_wave = NULL;
+       }
+
        gtk_widget_destroy(GTK_WIDGET(self));
 }
 
@@ -1411,6 +1489,43 @@ static void flip_v_activate(GtkMenuItem* self, gpointer user_data)
        ui->setc = NULL;
 }
 
+static void help_about(ses_ui_t* ui)
+{
+       GtkWidget*  dialog;
+
+       dialog = gtk_about_dialog_new();
+       if (!dialog)
+               return;
+
+       const char* authors[] = {"yu.dongliang", NULL};
+
+       gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(dialog), authors);
+       gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(dialog), "LGPL-3.0");
+       gtk_about_dialog_set_license_type(GTK_ABOUT_DIALOG(dialog), GTK_LICENSE_LGPL_3_0);
+       gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), "Copyright (c) 2025 Yu Dongliang");
+       gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(dialog), "the GUI to Simple Electronic Simulator (SES)");
+
+       gtk_widget_show_all(dialog);
+}
+
+static void about_activate(GtkMenuItem* self, gpointer user_data)
+{
+       scf_logi("\n");
+
+       ses_ui_t* ui = user_data;
+
+       help_about(ui);
+}
+
+static void help_clicked(GtkButton* self, gpointer user_data)
+{
+       scf_logi("\n");
+
+       ses_ui_t* ui = user_data;
+
+       help_about(ui);
+}
+
 static void open_activate(GtkMenuItem* self, gpointer user_data)
 {
        scf_logi("\n");
@@ -1784,6 +1899,98 @@ static void back_clicked(GtkButton* self, gpointer user_data)
        gtk_gl_area_queue_render(ui->gl_area);
 }
 
+static int add_wave_data(scf_vector_t** pvec, char* buf)
+{
+       scf_vector_t* vec = *pvec;
+       if (!vec) {
+               vec = scf_vector_alloc();
+               if (!vec)
+                       return -ENOMEM;
+
+               *pvec = vec;
+       }
+
+       va_data_t* va = calloc(1, sizeof(va_data_t));
+       if (!va)
+               return -ENOMEM;
+
+       char* p0 = NULL;
+       char* p1;
+
+       for (p1 = buf + 2; *p1; p1++) {
+
+               switch (*p1) {
+                       case '0':
+                       case '1':
+                       case '2':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                       case '8':
+                       case '9':
+                       case '.':
+                       case '-':
+                               if (!p0)
+                                       p0 = p1;
+                               break;
+
+                       case ',':
+                       case '\n':
+                               if (p0) {
+                                       void* p = realloc(va, sizeof(va_data_t) + sizeof(double) * (va->size + 1));
+                                       if (!p) {
+                                               free(va);
+                                               return -ENOMEM;
+                                       }
+
+                                       va = p;
+                                       va->data[va->size++] = atof(p0);
+                                       p0 = NULL;
+                               }
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       if (va->size <= 0) {
+               free(va);
+               va = NULL;
+       }
+
+       int ret = scf_vector_add(vec, va);
+       if (ret < 0) {
+               free(va);
+               return ret;
+       }
+
+       if (vec->size > 256) {
+               va = vec->data[0];
+               assert(0 == scf_vector_del(vec, va));
+
+               free(va);
+               va = NULL;
+       }
+#if 0
+       int i;
+       int j;
+
+       for (i = 0; i < vec->size; i++) {
+               va =        vec->data[i];
+
+               fprintf(stderr, "i: %d, ", i);
+
+               for (j = 0; j < va->size; j++) {
+                       fprintf(stderr, "%lg ", va->data[j]);
+               }
+               fprintf(stderr, "\n");
+       }
+#endif
+       return 0;
+}
+
 static gboolean timer_handler(gpointer user_data)
 {
        ses_ui_t* ui = user_data;
@@ -1808,8 +2015,16 @@ static gboolean timer_handler(gpointer user_data)
                GtkTextBuffer* log = gtk_text_view_get_buffer(ui->text_log);
 
                gtk_text_buffer_set_text(log, buf, -1);
-       } else {
-               scf_logi("%s\n", buf);
+
+       } else if (!strncmp(buf, "V,", 2)) {
+               add_wave_data(&ui->V_wave, buf);
+
+               gtk_widget_queue_draw(ui->draw_VA);
+
+       } else if (!strncmp(buf, "A,", 2)) {
+               add_wave_data(&ui->A_wave, buf);
+
+               gtk_widget_queue_draw(ui->draw_VA);
        }
 
        if (ui->show_index < 0 && ui->apply_index > 0) {
@@ -1875,6 +2090,7 @@ int main(int argc, char* argv[])
        GtkBuilder* builder;
        GObject*    window;
        GObject*    gl_area;
+       GObject*    draw_VA;
        GObject*    text_log;
        GError*     error = NULL;
 
@@ -1897,10 +2113,12 @@ int main(int argc, char* argv[])
        window   = gtk_builder_get_object(builder, "main_window");
        gl_area  = gtk_builder_get_object(builder, "gl_area");
        text_log = gtk_builder_get_object(builder, "text_log");
+       draw_VA  = gtk_builder_get_object(builder, "draw_VA");
 
        ui.builder     = builder;
        ui.window      = GTK_WINDOW(window);
        ui.gl_area     = GTK_GL_AREA(gl_area);
+       ui.draw_VA     = GTK_WIDGET(draw_VA);
        ui.text_log    = GTK_TEXT_VIEW(text_log);
 
        ui.popup       = GTK_MENU (gtk_builder_get_object(builder, "menu_popup"));
@@ -1911,6 +2129,7 @@ int main(int argc, char* argv[])
        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);
+       g_signal_connect(draw_VA, "draw",      G_CALLBACK(draw),            &ui);
 
        gtk_widget_add_events(GTK_WIDGET(gl_area), GDK_POINTER_MOTION_MASK);
 
@@ -1923,6 +2142,7 @@ int main(int argc, char* argv[])
        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");
+       GObject*    about      = gtk_builder_get_object(builder, "help_about");
 
        GObject*    flip_h     = gtk_builder_get_object(builder, "flip_h");
        GObject*    flip_v     = gtk_builder_get_object(builder, "flip_v");
@@ -1933,6 +2153,7 @@ int main(int argc, char* argv[])
        g_signal_connect(quit,      "activate",   G_CALLBACK(gtk_main_quit),     NULL);
        g_signal_connect(flip_h,    "activate",   G_CALLBACK(flip_h_activate),   &ui);
        g_signal_connect(flip_v,    "activate",   G_CALLBACK(flip_v_activate),   &ui);
+       g_signal_connect(about,     "activate",   G_CALLBACK(about_activate),    &ui);
 
        ui.flip_h = GTK_WIDGET(flip_h);
        ui.flip_v = GTK_WIDGET(flip_v);
@@ -1944,6 +2165,7 @@ int main(int argc, char* argv[])
        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");
+       GObject*    help       = gtk_builder_get_object(builder, "button_help");
 
        ui.back    = GTK_WIDGET(back);
        ui.forward = GTK_WIDGET(forward);
@@ -1955,6 +2177,7 @@ int main(int argc, char* argv[])
        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);
+       g_signal_connect(help,      "clicked",   G_CALLBACK(help_clicked),     &ui);
 
        GObject*    button_B   = gtk_builder_get_object(builder, "button_Battery");
        GObject*    button_R   = gtk_builder_get_object(builder, "button_R");
index 8fca0f9f06ca28654508dc90975e83cccf13f9a6..90617afc5a7fea2af5ddc1940e5cbe5e1ed744ad 100644 (file)
--- a/ses_ui.h
+++ b/ses_ui.h
 
 typedef struct ses_ui_s     ses_ui_t;
 typedef struct ui_log_s     ui_log_t;
+typedef struct va_data_s    va_data_t;
+
+struct va_data_s
+{
+       int    size;
+       double data[0];
+};
 
 struct ui_log_s
 {
@@ -52,9 +59,13 @@ struct ses_ui_s
        scf_list_t        log;
        scf_list_t*       current;
 
+       scf_vector_t*     V_wave;
+       scf_vector_t*     A_wave;
+
        GtkBuilder*       builder;
        GtkWindow*        window;
        GtkGLArea*        gl_area;
+       GtkWidget*        draw_VA;
        GtkTextView*      text_log;
 
        GtkWidget*        undo;
@@ -108,7 +119,8 @@ struct ses_ui_s
 };
 
 #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,NULL, \
        NULL,NULL,NULL,NULL, \