/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Gem-graph client * * Events management functions * * * * Copyright © 2021 Libre en Communs * * Copyright © 2021 Arthur Menges * * Copyright © 2021-2024 Adrien Bourmault * * Copyright © 2021-2024 Jean Sirmai * * * * This file is part of Gem-graph. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU Affero General Public License * * as published by the Free Software Foundation, * * either version 3 of the License, * * or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; * * without even the implied warranty of MERCHANTABILITY * * or FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU Affero General Public License for more details. * * * * You should have received a copy of the GNU Affero General Public License * * along with this program. If not, see . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "../include/fsm.h" #include "../include/signal.h" #include "../include/widget.h" #include "../include/graphics.h" #include "../include/util.h" static void on_auto_notification (char *message) { // message = "-(any auto notification)-"; // test fsm_journal_event (DEBUG, AUTO_NOTIFICATION, "signal", "auto_notification", ""); /* Ignored (2024-06-06) because I don't know how to get "main_window" easily if (window->toast_revealer == NULL) { g_printerr("Can't find app->toast_overlay !\n"); return; } if (window->toast_text == NULL) { g_printerr("Can't find app->toast_overlay !\n"); return; } gtk_label_set_label(window->toast_text, message); gtk_revealer_set_reveal_child(window->toast_revealer, true); */ g_printerr("%s\n", message); // TODO use the journal to display the message (concat)) } /******************************************************************************/ /* T R E E */ /******************************************************************************/ static void on_user_tree_expander_toggled (GtkExpander *expander, gpointer user_data) { fsm_journal_event (SPEW, EXPANDER, "signal", "user tree expander toggled()", ""); GtkTreeListRow *row = GTK_TREE_LIST_ROW (user_data); gboolean is_expanded = gtk_tree_list_row_get_expanded (row); gtk_tree_list_row_set_expanded (row, ! is_expanded); } void on_setup_user_tree_factory (GtkSignalListItemFactory *factory, GObject* object, gpointer user_data){ fsm_journal_event (SPEW, EXPANDER, "signal", "setup user tree factory()", ""); GtkWidget* expander = gtk_expander_new (NULL); gtk_list_item_set_child (GTK_LIST_ITEM (object), expander); } void on_bind_user_tree_factory (GtkSignalListItemFactory *factory, GObject* object, gpointer user_data) { GtkListItem *list_item = GTK_LIST_ITEM (object); assert (list_item); GtkTreeListRow *row = gtk_list_item_get_item (list_item); assert (row); // if (row != NULL) {...} do something ? TODO Check ! const gchar *text = gtk_string_object_get_string ( GTK_STRING_OBJECT (gtk_tree_list_row_get_item (row))); GtkWidget *expander = gtk_list_item_get_child (list_item); gtk_expander_set_label (GTK_EXPANDER (expander), text); g_signal_handlers_disconnect_by_func (expander, G_CALLBACK (on_user_tree_expander_toggled), row); g_signal_connect (expander, "activate", G_CALLBACK (on_user_tree_expander_toggled), row); gtk_widget_set_margin_start (expander, gtk_tree_list_row_get_depth(row) * 20); fsm_journal_event (SPEW, TREE, "signal", "(tree) bind user tree factory()", text); } /******************************************************************************/ /* G L A R E A */ /******************************************************************************/ gboolean on_glarea_render (GtkGLArea *area, GdkGLContext *context) { fsm_journal_event (DEBUG, GLAREA, "signal", "glarea render()", "(context TODO)"); // Check if the widget is a glarea if(gtk_gl_area_get_error(area) != NULL) { on_auto_notification("An OpenGL error occured !"); return false; } if (util_gl_render_stack(gtk_widget_get_parent(GTK_WIDGET(area))) == false) { on_auto_notification("Failed to render corresponding graphic stack !"); return false; } return true; } /* We need to set up our state when we realize the GtkGLArea widget */ void on_glarea_realize (GtkWidget *widget) { fsm_journal_event (DEBUG, GLAREA, "signal", "glarea realize()", ""); GError *internal_error = NULL; // Make the GL context current to be able to call the GL API gtk_gl_area_make_current(GTK_GL_AREA(widget)); // Check if the widget is a glarea if(gtk_gl_area_get_error(GTK_GL_AREA(widget)) != NULL) { on_auto_notification("An OpenGL error occured !"); return; } // Link graphical stack to widget if (util_gl_init_stack(gtk_widget_get_parent(widget), internal_error) == false) { on_auto_notification( "Failed to link the graphic stack to widgets !"); return; } gtk_gl_area_set_auto_render(GTK_GL_AREA(widget), true); } /* We should tear down the state when unrealizing */ void on_glarea_unrealize (GtkWidget *widget) { fsm_journal_event (DEBUG, GLAREA, "signal", "glarea unrealize()", ""); GError *internal_error = NULL; // Make the GL context current to be able to call the GL API gtk_gl_area_make_current(GTK_GL_AREA(widget)); // Check if the widget is a glarea if(gtk_gl_area_get_error(GTK_GL_AREA(widget)) != NULL) { on_auto_notification("An OpenGL error occured !"); return; } // Destroy graphic stack if (util_gl_shutdown_stack(gtk_widget_get_parent(widget), internal_error) == false) { on_auto_notification( "Failed to shutdown the graphic stack !"); return; } } void on_axis_value_change (GtkAdjustment *adjustment, gpointer data) { GtkWidget *slider = gtk_widget_get_parent(GTK_WIDGET(data)); GtkWidget *container_widget = gtk_widget_get_parent(GTK_WIDGET(slider)); const gchar *label_text = gtk_label_get_label(GTK_LABEL(data)); // THANKS ASCIIIII/Unicode/Whateverrr ! int axis = label_text[0] - 'X'; g_assert(axis >= 0 && axis < N_AXIS); /* Update the rotation angle */ int axis_value = gtk_adjustment_get_value(adjustment); util_gl_update_axis(container_widget, axis, axis_value); /* Update the contents of the GL drawing area */ char string_value [10]; sprintf(string_value, " (%d)", axis_value); switch (axis) { case 0 : fsm_journal_event (SPEW, SLIDER_X, "signal", "X value changed()", string_value); break; case 1 : fsm_journal_event (SPEW, SLIDER_Y, "signal", "Y value changed()", string_value); break; case 2 : fsm_journal_event (SPEW, SLIDER_Z, "signal", "Z value changed()", string_value); break; } } /******************************************************************************/ /* D I A L O G W I D G E T S */ /******************************************************************************/ void on_save_current_model_before_editing (GtkWidget *btt_save_current_model, gpointer data) { fsm_journal_event (INFO, BUTTON, "signal", "(dialog) save current model()", ""); on_auto_notification ("save_current_model_before_editing !"); gtk_widget_set_sensitive (GTK_WIDGET (data), TRUE); } void on_discard_current_model_before_editing (GtkWidget *btt_discard_current_model, gpointer data) { fsm_journal_event (INFO, BUTTON, "signal", "(dialog) discard current model()", ""); on_auto_notification ("discard_current_model_before_editing ?"); gtk_window_close (GTK_WINDOW (data)); } void on_write_current_model (GtkWidget *btt_write_current_model, gpointer data) { fsm_journal_event (INFO, BUTTON, "signal", "(dialog) write current model()", ""); on_auto_notification ("writing current_model_before_editing 😄️"); gtk_window_close (GTK_WINDOW (data)); } /******************************************************************************/ /* T O P B A R L E F T W I D G E T S */ /******************************************************************************/ static void switch_state_rules_data(); // ----------------------- E X E C / E D I T -------------------------- // void on_toggle_exec_edit (GtkWidget *toggled_button, gpointer user_data) { fsm_journal_event (INFO, BUTTON, "signal", "toggle exec edit()", "change of status requested"); if (fsm_get_exec_edit ()) { // TODO (or NOT ?) et si je ne suis pas sur la page SYNTH gtk_button_set_icon_name (GTK_BUTTON (toggled_button), "power-profile-balanced-rtl-symbolic"); fsm_set_exec_edit (EXEC); // TODO set_btt_SYNTH_active (TRUE) } else { gtk_button_set_icon_name (GTK_BUTTON (toggled_button), "text-editor-symbolic"); // https://docs.gtk.org/gtk4/class.Window.html TODO 2024-06-30 // gtk_window_present (GTK_WINDOW (widget_get_dialog_window())); // // works onstrcmpce only A window should be created each time fsm_set_exec_edit (EDIT); // TODO set_btt_SYNTH_active (FALSE) } switch_state_rules_data(); } // ------------------ S T A T E / R U L E S / D A T A --------------- // void on_toggle_state_rules_data (GtkWidget *toggled_button, gpointer widget_all_vs_selected_one) { const char *toggled_button_name = gtk_check_button_get_label (GTK_CHECK_BUTTON (toggled_button)); fsm_journal_event (DEBUG, BUTTON, "signal", "toggle_state_rules_data()", concat ("[", toggled_button_name, "]", NULL)); int is_active = gtk_check_button_get_active (GTK_CHECK_BUTTON (toggled_button)); if ( ! strcmp (toggled_button_name, widget_get_btt_label_synth())) fsm_set_state_rules_data (SYNTH); if ( ! strcmp (toggled_button_name, widget_get_btt_label_state())) fsm_set_state_rules_data (STATE); if ( ! strcmp (toggled_button_name, widget_get_btt_label_rules())) fsm_set_state_rules_data (RULES); if ( ! strcmp (toggled_button_name, widget_get_btt_label_data())) fsm_set_state_rules_data (DATA); if (is_active) switch_state_rules_data(); } // ----------------------- S T A T I C S W I T C H -------------------- // static void switch_state_rules_data() { switch (fsm_get_state_rules_data()) { case (SYNTH) : gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_get_page_synth())); break; case (STATE) : gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_get_page_state())); break; case (RULES) : /* * The rules page consists of two half-pages in a GtkPaned widget : * - on the left, widgets for controlling or editing all the rules. * - on the right, widgets for controlling or editing the selected rule. * * Instead of having a: "widget_get_rules_page()" function, * this distribution is moved here. (see also widget/topbar/left design) * window_design_topbar_left() */ GtkPaned *widget_all_vs_selected_one = GTK_PANED (gtk_paned_new (GTK_ORIENTATION_HORIZONTAL)); gtk_paned_set_start_child (widget_all_vs_selected_one, GTK_WIDGET (widget_get_pane_all_rules_left())); gtk_paned_set_end_child (widget_all_vs_selected_one, GTK_WIDGET (widget_get_pane_selected_rule_right())); gtk_paned_set_position (widget_all_vs_selected_one, ALL_VS_SELECTED); gtk_paned_set_wide_handle (widget_all_vs_selected_one, TRUE); gtk_paned_set_shrink_start_child (widget_all_vs_selected_one, FALSE); gtk_paned_set_shrink_end_child (widget_all_vs_selected_one, FALSE); gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_all_vs_selected_one)); break; case (DATA) : gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_get_page_data())); break; default : printf("default in signal.on_toggle_state_rule_data()\n"); fsm_journal_event (INFO, SWITCH_STATE_RULES_DATA, "signal", "(switch) default in : switch state rules data()", ""); } } /******************************************************************************/ /* T O P B A R R I G H T W I D G E T S */ /******************************************************************************/ // ------------ M E N U / S E A R C H / H O M E / E T C ----------- // void on_clicked_topbar_right_search (GtkWidget *btt_menu, gpointer list_box) { fsm_journal_event (DEBUG, BUTTON, "signal", "(topbar right) search()", ""); // next line presents the text_window and works only once.\n // It should present a menu.\n"); // TODO gtk_window_present (GTK_WINDOW (widget_get_text_window())); } void on_clicked_topbar_right_home (GtkWidget *btt_reset, gpointer data) { fsm_journal_event (DEBUG, BUTTON, "signal", "(topbar right) home()", ""); gtk_window_present (GTK_WINDOW (widget_get_dialog_window())); // NB works only once. < TODO } /******************************************************************************/ /* S T A T E W I D G E T S */ /******************************************************************************/ // ---------------------------- O B J E C T S --------------------------- // void on_updating_objects_transparencies (GtkWidget *btt_source, GtkScrollbar *scrollbar) { const char *btt_name = gtk_button_get_icon_name (GTK_BUTTON (btt_source)); int value = gtk_adjustment_get_value (gtk_scrollbar_get_adjustment (scrollbar)); char string_value [12]; sprintf(string_value, "%d", value); printf(string_value); fsm_journal_event (DEBUG, BUTTON, "signal", "updating objects transparencies()", string_value); // TODO TODO (je suis fatigué) if ( ! strcmp (btt_name, "document-revert-rtl-symbolic")) fsm_set_store_restore_reset (STORE, value); if ( ! strcmp (btt_name, "edit-undo-symbolic")) fsm_set_store_restore_reset (RESTORE, value); if ( ! strcmp (btt_name, "view-refresh-symbolic")) fsm_set_store_restore_reset (RESET, value); fsm_set_preferences_modified (TRUE); // << à détailler TODO } void on_resetting_XYZ_in_state_page () { fsm_journal_event (DEBUG, BUTTON, "signal", "resetting XYZ in state page()", ""); widget_state_XYZ_reset_all(); } // -------------------------- S I T U A T I O N S ----------------------- // void on_situations_box_do_reset (GtkWidget *btt_reset, GtkScrollbar *reset_scrollbar) { GtkAdjustment *adj_situ = gtk_scrollbar_get_adjustment (reset_scrollbar); fsm_reset_all_situations_transparencies_at_value (gtk_adjustment_get_value (adj_situ)); char string_value [319]; sprintf(string_value, "(%f)", gtk_adjustment_get_value (adj_situ)); // TODO (marche pas...)) fsm_journal_event (DEBUG, BUTTON, "signal", "situations box do reset()", string_value); } /******************************************************************************/ /* M E A S U R E S */ /******************************************************************************/ void on_topbar_right_measure_clicked (GtkWidget *btt, gpointer button_icon_name) { // ici, il faudrait surtout dire que: widget_get_measure_page // devient un enfant de: widget_get_main_window. fsm_journal_event (DEBUG, BUTTON, "signal", "topbar right measure()", concat ("clicked; icon = ", button_icon_name, NULL)); // fsm_measures_sorted_list_do something (); TODO // ! WARNING ! ce qui suit n'est qu'une maquette: (... delenda est !) // la 'logique' qui va des mesures aux résultats doit changer de forme TODO gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_get_page_measure())); } void on_start_new_measure (GtkWidget *btt, gpointer btt_label) { fsm_journal_event (DEBUG, BUTTON, "signal", "start a new measure()", btt_label); gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_measure_do_select_rules_first())); } void on_select_rules_first (GtkWidget *btt, gpointer data) { fsm_journal_event (DEBUG, BUTTON, "signal", "select rules first()", ""); gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_measure_do_depends_on_one_or_two_events())); } void on_measure_depends_on_a_single_event (GtkWidget *btt, gpointer data) { fsm_journal_event (DEBUG, BUTTON, "signal", "measure depends on a single event()", ""); gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_measure_do_depends_on_a_single_event())); } void on_measure_depends_on_two_events (GtkWidget *btt, gpointer data) { fsm_journal_event (DEBUG, BUTTON, "signal", "measure depends on two events()", ""); gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_measure_do_select_a_second_rules_set())); } void on_select_a_second_rules_set (GtkWidget *btt, gpointer data) { fsm_journal_event (DEBUG, BUTTON, "signal", "select a second rules set()", ""); gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_measure_do_choose_an_event_type())); } void on_select_a_second_measurement (GtkWidget *btt, gpointer data) { fsm_journal_event (DEBUG, BUTTON, "signal", "select a second measurement()", ""); gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_measure_do_correlate())); } void on_skip_this_step (GtkWidget *btt, gpointer data) { fsm_journal_event (DEBUG, BUTTON, "signal", "skip this step()", ""); gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_measure_do_insert_in_measurements_list ())); } void on_something_else (GtkWidget *btt, gpointer data) { fsm_journal_event (DEBUG, BUTTON, "signal", "something else()", ""); gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_measure_do_end_creation_of_measurement_process())); } void on_closing_page (GtkWidget *btt, gpointer data) { fsm_journal_event (DEBUG, BUTTON, "signal", "closing page()", ""); gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_get_page_synth())); } void on_measure_single_event_occurences_nb (GtkWidget *btt, gpointer data) { fsm_journal_event (DEBUG, BUTTON, "signal", "measure single event occurences nb()", ""); gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_measure_event_occurences_nb())); } void on_measure_single_event_occurences_dates (GtkWidget *btt, gpointer data) { fsm_journal_event (DEBUG, BUTTON, "signal", "measure single event occurences dates()", ""); gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_measure_event_occurences_dates())); } void on_measure_single_event_occurences_situations (GtkWidget *btt, gpointer data) { fsm_journal_event (DEBUG, BUTTON, "signal", "measure single event occurences situations()", ""); gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_measure_event_occurences_situations())); } void on_measure_time_elapsed_between_two_events (GtkWidget *btt, gpointer data) { fsm_journal_event (DEBUG, BUTTON, "signal", "measure time elapsed between two events()", ""); gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_measure_time_elapsed_between_two_events())); } void on_measure_third_event_occurences_in_between (GtkWidget *btt, gpointer data) { fsm_journal_event (DEBUG, BUTTON, "signal", "measure third event occurences in between()", ""); gtk_window_set_child (GTK_WINDOW (widget_get_main_window ()), GTK_WIDGET (widget_measure_third_event_occurences_in_between())); } /******************************************************************************/ /* R U L E S */ /******************************************************************************/ void on_entry_name_insert_after (GtkWidget *entry, gpointer data) { fsm_journal_event (DEBUG, ENTRY, "signal", "entry name insert after()", ""); } void on_entry_name_delete_after (GtkWidget *entry, gpointer data) { fsm_journal_event (DEBUG, ENTRY, "signal", "entry name delete after()", ""); }