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) {
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;
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));
}
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");
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;
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) {
GtkBuilder* builder;
GObject* window;
GObject* gl_area;
+ GObject* draw_VA;
GObject* text_log;
GError* error = NULL;
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"));
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);
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");
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);
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);
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");