From: yu.dongliang <18588496441@163.com> Date: Wed, 2 Jul 2025 14:19:25 +0000 (+0800) Subject: draw VA waves X-Git-Url: http://baseworks.info/?a=commitdiff_plain;h=1f7e477b625ebd4ed6025d13d02740a955e276f2;p=ses.git draw VA waves --- diff --git a/ses_ui.c b/ses_ui.c index 8913f1a..27cc426 100644 --- 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"); diff --git a/ses_ui.h b/ses_ui.h index 8fca0f9..90617af 100644 --- a/ses_ui.h +++ b/ses_ui.h @@ -15,6 +15,13 @@ 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, \