Line data Source code
1 : /* File: gui_main_window.c; Copyright and License: see below */
2 :
3 : #include "gui_main_window.h"
4 : #include "gui_clipboard.h"
5 : #include "gui_type_resource.h"
6 : #include "u8/u8_trace.h"
7 : #include "entity/data_diagram_type.h"
8 : #include "entity/data_classifier_type.h"
9 : #include "entity/data_feature_type.h"
10 : #include "entity/data_relationship_type.h"
11 : #include "storage/data_database.h"
12 : #include "storage/data_change_notifier.h"
13 : #include "meta/meta_info.h"
14 : #include "gui_gtk.h"
15 : #include "gui_gdk.h"
16 : #include <stdio.h>
17 : #include <stdbool.h>
18 :
19 0 : void gui_main_window_init( gui_main_window_t *this_,
20 : ctrl_controller_t *controller,
21 : io_data_file_t *data_file,
22 : data_database_reader_t *db_reader,
23 : gui_resources_t *resources,
24 : GtkApplication *gtk_app,
25 : observer_t *window_close_observer,
26 : observer_t *window_open_observer )
27 : {
28 0 : U8_TRACE_BEGIN();
29 0 : assert( gtk_app != NULL );
30 :
31 : /* init own attributes */
32 0 : (*this_).window_close_observer = window_close_observer;
33 0 : (*this_).window_open_observer = window_open_observer;
34 0 : (*this_).data_file = data_file;
35 0 : (*this_).resources = resources;
36 :
37 : /* init window */
38 : {
39 0 : (*this_).window = gtk_application_window_new( gtk_app );
40 : const char *window_title;
41 0 : window_title = io_data_file_get_filename_const( data_file );
42 0 : gtk_window_set_title(GTK_WINDOW( (*this_).window ), ( window_title == NULL ) ? META_INFO_PROGRAM_NAME_STR : window_title );
43 0 : gtk_widget_set_size_request( (*this_).window, 800, 400 );
44 0 : gtk_window_set_default_size( GTK_WINDOW( (*this_).window ), 16*70, 9*70 );
45 : }
46 :
47 : /* init the message widgets */
48 0 : gui_main_window_private_init_simple_message_to_user( this_ );
49 0 : gui_simple_message_to_user_init( &((*this_).message_to_user), (*this_).message_text_label, (*this_).message_icon_image, resources );
50 :
51 : /* init the keyboard shortcuts */
52 : {
53 0 : (*this_).keyboard_shortcut_ctrl = GTK_SHORTCUT_CONTROLLER(gtk_shortcut_controller_new());
54 0 : gtk_widget_add_controller( (*this_).window, GTK_EVENT_CONTROLLER((*this_).keyboard_shortcut_ctrl) );
55 : }
56 :
57 : /* init tools */
58 0 : gui_main_window_private_init_toolbox( this_ );
59 :
60 : /* determine the current/main clipboard */
61 0 : GdkClipboard *current_clipboard = NULL;
62 : {
63 0 : current_clipboard = gtk_widget_get_clipboard( GTK_WIDGET((*this_).window) ); /* idea taken from gtk demo */
64 : }
65 :
66 0 : gui_marked_set_init( &((*this_).marker_data),
67 0 : G_OBJECT((*this_).window),
68 : &gui_sketch_area_show_diagram,
69 0 : &((*this_).sketcharea_data)
70 : );
71 0 : gui_toolbox_init( &((*this_).tools_data),
72 0 : GTK_WIDGET( (*this_).tool_row ),
73 0 : gui_button_get_widget_ptr( &((*this_).view_navigate) ),
74 0 : gui_button_get_widget_ptr( &((*this_).view_edit) ),
75 0 : gui_button_get_widget_ptr( &((*this_).view_create) ),
76 0 : gui_button_get_widget_ptr( &((*this_).view_search) ),
77 : current_clipboard,
78 : &((*this_).marker_data),
79 : &((*this_).message_to_user),
80 : db_reader,
81 : controller
82 : );
83 :
84 : /* init search widgets and sketch area */
85 : observer_t search_result_observer;
86 0 : observer_init( &search_result_observer,
87 0 : &((*this_).sketcharea_data),
88 : (void(*)(void*,void*))&gui_sketch_area_show_result_list,
89 : "search_results_available"
90 : );
91 0 : gui_main_window_private_init_search_and_sketch_area( this_ );
92 0 : gui_search_runner_init( &((*this_).search_runner),
93 : &((*this_).message_to_user),
94 : db_reader,
95 : io_data_file_get_database_ptr( data_file ),
96 : search_result_observer
97 : );
98 0 : gui_search_request_init( &((*this_).search_request),
99 : (*this_).search_label,
100 : (*this_).search_entry,
101 : (*this_).search_button,
102 : &((*this_).marker_data),
103 : &((*this_).search_runner)
104 : );
105 0 : gui_sketch_area_init( &((*this_).sketcharea_data),
106 : (*this_).sketcharea,
107 : &((*this_).marker_data),
108 : &((*this_).tools_data),
109 : &((*this_).search_runner),
110 : &((*this_).message_to_user),
111 : resources,
112 : controller,
113 : db_reader
114 : );
115 :
116 : /* init attribute editor widgets */
117 0 : gui_main_window_private_init_attributes_editor( this_ );
118 :
119 0 : gui_attributes_editor_init( &((*this_).attributes_editor),
120 0 : GTK_LABEL( (*this_).id_label ),
121 0 : GTK_ENTRY( (*this_).name_entry ),
122 0 : GTK_ENTRY( (*this_).stereotype_entry ),
123 : (*this_).type_dropdown,
124 0 : GTK_WIDGET( (*this_).type_diag_grid ),
125 0 : GTK_WIDGET( (*this_).type_clas_grid ),
126 0 : GTK_WIDGET( (*this_).type_feat_grid ),
127 0 : GTK_WIDGET( (*this_).type_rel_grid ),
128 0 : GTK_TEXT_VIEW( (*this_).description_text_view ),
129 0 : gui_button_get_button_ptr( &((*this_).file_save ) ),
130 : resources,
131 : controller,
132 : db_reader,
133 : io_data_file_get_database_ptr( data_file ),
134 : &((*this_).message_to_user)
135 : );
136 :
137 : /* init the file choosers */
138 0 : gui_file_action_init( &((*this_).file_action),
139 : controller,
140 : data_file,
141 : &((*this_).message_to_user)
142 : );
143 0 : gui_file_use_db_dialog_init( &((*this_).file_use_db_dialog),
144 0 : GTK_WINDOW( (*this_).window ),
145 : &((*this_).file_action)
146 : );
147 0 : gui_file_export_dialog_init( &((*this_).file_export_dialog),
148 : io_data_file_get_database_ptr( data_file ),
149 : db_reader,
150 0 : GTK_WINDOW( (*this_).window ),
151 : &((*this_).message_to_user)
152 : );
153 :
154 0 : U8_TRACE_INFO("GTK+ Widgets are created.");
155 :
156 0 : (*this_).two_panes = gtk_paned_new( GTK_ORIENTATION_HORIZONTAL );
157 0 : gtk_paned_set_start_child( GTK_PANED((*this_).two_panes), (*this_).sketch_stack_column );
158 0 : gtk_paned_set_resize_start_child( GTK_PANED((*this_).two_panes), true );
159 0 : gtk_paned_set_shrink_start_child( GTK_PANED((*this_).two_panes), false );
160 0 : gtk_paned_set_end_child( GTK_PANED((*this_).two_panes), (*this_).attr_edit_column );
161 0 : gtk_paned_set_resize_end_child( GTK_PANED((*this_).two_panes), false );
162 0 : gtk_paned_set_shrink_end_child( GTK_PANED((*this_).two_panes), true );
163 0 : gtk_widget_set_vexpand( GTK_WIDGET( (*this_).sketch_stack_column ), true );
164 0 : gtk_widget_set_hexpand( GTK_WIDGET( (*this_).sketch_stack_column ), true );
165 0 : gtk_widget_set_vexpand( GTK_WIDGET( (*this_).attr_edit_column ), true );
166 0 : gtk_widget_set_hexpand( GTK_WIDGET( (*this_).attr_edit_column ), false );
167 0 : gtk_paned_set_position( GTK_PANED((*this_).two_panes), 11*70 );
168 :
169 0 : (*this_).main_stack_column = gtk_box_new( GTK_ORIENTATION_VERTICAL, /*spacing:*/ 0 );
170 0 : gtk_box_append( GTK_BOX((*this_).main_stack_column), GTK_WIDGET((*this_).tool_row) );
171 0 : (*this_).options_layout = gui_file_export_dialog_get_options( &((*this_).file_export_dialog) );
172 0 : gtk_box_append( GTK_BOX((*this_).main_stack_column), (*this_).options_layout );
173 0 : gtk_box_append( GTK_BOX((*this_).main_stack_column), GTK_WIDGET((*this_).two_panes) );
174 0 : gtk_box_append( GTK_BOX((*this_).main_stack_column), GTK_WIDGET((*this_).message_row) );
175 0 : gtk_widget_set_vexpand( GTK_WIDGET( (*this_).tool_row ), false );
176 0 : gtk_widget_set_hexpand( GTK_WIDGET( (*this_).tool_row ), true );
177 0 : gtk_widget_set_vexpand( GTK_WIDGET( (*this_).two_panes ), true );
178 0 : gtk_widget_set_hexpand( GTK_WIDGET( (*this_).two_panes ), true );
179 0 : gtk_widget_set_vexpand( GTK_WIDGET( (*this_).message_row ), false );
180 0 : gtk_widget_set_hexpand( GTK_WIDGET( (*this_).message_row ), true );
181 :
182 0 : gtk_window_set_child( GTK_WINDOW((*this_).window), (*this_).main_stack_column );
183 0 : gtk_window_set_resizable( GTK_WINDOW((*this_).window), true );
184 :
185 0 : U8_TRACE_INFO("GTK+ Widgets are added to containers.");
186 :
187 : /* inject dependencies by signals */
188 : /* parameter info: g_signal_connect( instance-that-emits-the-signal, signal-name, callback-handler, data-to-be-passed-to-callback-handler) */
189 0 : g_signal_connect( G_OBJECT((*this_).window), "close-request", G_CALLBACK(gui_main_window_delete_event_callback), this_ );
190 0 : g_signal_connect( G_OBJECT((*this_).window), "destroy", G_CALLBACK(gui_main_window_destroy_event_callback), this_ );
191 0 : g_signal_connect( G_OBJECT((*this_).window), "state-flags-changed", G_CALLBACK( gui_main_window_state_callback ), this_ );
192 0 : g_signal_connect( G_OBJECT((*this_).window), DATA_CHANGE_NOTIFIER_GLIB_SIGNAL_NAME, G_CALLBACK(gui_main_window_data_changed_callback), this_ );
193 0 : g_signal_connect( G_OBJECT((*this_).sketcharea), DATA_CHANGE_NOTIFIER_GLIB_SIGNAL_NAME, G_CALLBACK(gui_sketch_area_data_changed_callback), &((*this_).sketcharea_data) );
194 0 : g_signal_connect( G_OBJECT((*this_).tool_row), GUI_TOOLBOX_GLIB_SIGNAL_NAME, G_CALLBACK(gui_sketch_area_tool_changed_callback), &((*this_).sketcharea_data) );
195 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).file_new) ), "clicked", G_CALLBACK(gui_main_window_new_db_btn_callback), this_ );
196 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).file_open) ), "clicked", G_CALLBACK(gui_main_window_open_db_btn_callback), this_ );
197 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).file_save) ), "clicked", G_CALLBACK(gui_main_window_save_btn_callback), this_ );
198 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).file_export) ), "clicked", G_CALLBACK(gui_main_window_export_btn_callback), this_ );
199 :
200 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).view_new_window) ), "clicked", G_CALLBACK(gui_main_window_new_window_btn_callback), this_ );
201 :
202 0 : gui_toolbox_t *const tools = &((*this_).tools_data);
203 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).view_navigate) ), "clicked", G_CALLBACK(gui_toolbox_navigate_btn_callback), tools );
204 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).view_edit) ), "clicked", G_CALLBACK(gui_toolbox_edit_btn_callback), tools );
205 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).view_create) ), "clicked", G_CALLBACK(gui_toolbox_create_btn_callback), tools );
206 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).view_search) ), "clicked", G_CALLBACK(gui_toolbox_search_btn_callback), tools );
207 :
208 : /* The search id button is connected to two callback functions: one to switch to search mode, one to perform a search: */
209 0 : g_signal_connect( G_OBJECT((*this_).id_search_btn),
210 : "clicked",
211 : G_CALLBACK(gui_toolbox_search_id_btn_callback),
212 : tools
213 : );
214 0 : g_signal_connect( G_OBJECT((*this_).id_search_btn),
215 : "clicked",
216 : G_CALLBACK(gui_search_request_id_search_callback),
217 : &((*this_).search_request)
218 : );
219 :
220 0 : g_signal_connect( G_OBJECT((*this_).tool_row), GUI_TOOLBOX_GLIB_SIGNAL_NAME, G_CALLBACK(gui_search_request_tool_changed_callback), &((*this_).search_request) );
221 0 : g_signal_connect( G_OBJECT((*this_).search_entry), DATA_CHANGE_NOTIFIER_GLIB_SIGNAL_NAME, G_CALLBACK(gui_search_request_data_changed_callback), &((*this_).search_request) );
222 0 : g_signal_connect( G_OBJECT((*this_).search_entry), "activate", G_CALLBACK(gui_search_request_search_start_callback), &((*this_).search_request) );
223 0 : g_signal_connect( G_OBJECT((*this_).search_button), "clicked", G_CALLBACK(gui_search_request_search_start_callback), &((*this_).search_request) );
224 :
225 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_undo) ), "clicked", G_CALLBACK(gui_toolbox_undo_btn_callback), tools );
226 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_redo) ), "clicked", G_CALLBACK(gui_toolbox_redo_btn_callback), tools );
227 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_cut) ), "clicked", G_CALLBACK(gui_toolbox_cut_btn_callback), tools );
228 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_copy) ), "clicked", G_CALLBACK(gui_toolbox_copy_btn_callback), tools );
229 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_paste) ), "clicked", G_CALLBACK(gui_toolbox_paste_btn_callback), tools );
230 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_delete) ), "clicked", G_CALLBACK(gui_toolbox_delete_btn_callback), tools );
231 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_instantiate) ), "clicked", G_CALLBACK(gui_toolbox_instantiate_btn_callback), tools );
232 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_highlight) ), "clicked", G_CALLBACK(gui_toolbox_highlight_btn_callback), tools );
233 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_reset) ), "clicked", G_CALLBACK(gui_toolbox_reset_btn_callback), tools );
234 :
235 0 : g_signal_connect( G_OBJECT((*this_).name_entry),
236 : "activate",
237 : G_CALLBACK(gui_attributes_editor_name_enter_callback),
238 : &((*this_).attributes_editor)
239 : );
240 : {
241 0 : GtkEventControllerFocus *evt_focus_n = GTK_EVENT_CONTROLLER_FOCUS(gtk_event_controller_focus_new());
242 0 : g_signal_connect( evt_focus_n,
243 : "leave",
244 : G_CALLBACK(gui_attributes_editor_name_focus_left_callback),
245 : &((*this_).attributes_editor)
246 : );
247 0 : gtk_widget_add_controller( (*this_).name_entry, GTK_EVENT_CONTROLLER(evt_focus_n) );
248 : }
249 : {
250 0 : GtkEventControllerFocus *evt_focus_s = GTK_EVENT_CONTROLLER_FOCUS(gtk_event_controller_focus_new());
251 0 : g_signal_connect( evt_focus_s,
252 : "leave",
253 : G_CALLBACK(gui_attributes_editor_stereotype_focus_left_callback),
254 : &((*this_).attributes_editor)
255 : );
256 0 : gtk_widget_add_controller( (*this_).stereotype_entry, GTK_EVENT_CONTROLLER(evt_focus_s) );
257 : }
258 : {
259 0 : GtkEventControllerFocus *evt_focus_d = GTK_EVENT_CONTROLLER_FOCUS(gtk_event_controller_focus_new());
260 0 : g_signal_connect( evt_focus_d,
261 : "leave",
262 : G_CALLBACK(gui_attributes_editor_description_focus_left_callback),
263 : &((*this_).attributes_editor)
264 : );
265 0 : gtk_widget_add_controller( (*this_).description_text_view, GTK_EVENT_CONTROLLER(evt_focus_d) );
266 : }
267 0 : g_signal_connect( G_OBJECT((*this_).stereotype_entry), "activate", G_CALLBACK(gui_attributes_editor_stereotype_enter_callback), &((*this_).attributes_editor) );
268 0 : g_signal_connect_after( G_OBJECT((*this_).type_dropdown), "notify::selected", G_CALLBACK(gui_attributes_editor_type_changed_callback), &((*this_).attributes_editor));
269 0 : for( int_fast32_t diag_idx = 0; diag_idx < GUI_TYPE_RESOURCE_LIST_DIAGRAMS; diag_idx ++ )
270 : {
271 0 : g_signal_connect( G_OBJECT((*this_).type_diag_btn[ diag_idx ]),
272 : "clicked",
273 : G_CALLBACK( gui_attributes_editor_type_of_diagram_btn_callback ),
274 : &((*this_).type_diag_data[diag_idx])
275 : );
276 : }
277 0 : for( int_fast32_t clas_idx = 0; clas_idx < GUI_TYPE_RESOURCE_LIST_CLASSIFIERS; clas_idx ++ )
278 : {
279 0 : g_signal_connect( G_OBJECT((*this_).type_clas_btn[ clas_idx ]),
280 : "clicked",
281 : G_CALLBACK( gui_attributes_editor_type_of_classifier_btn_callback ),
282 : &((*this_).type_clas_data[clas_idx])
283 : );
284 : }
285 0 : for( int_fast32_t feat_idx = 0; feat_idx < GUI_TYPE_RESOURCE_LIST_INV_FEATURES; feat_idx ++ )
286 : {
287 0 : g_signal_connect( G_OBJECT((*this_).type_feat_btn[ feat_idx ]),
288 : "clicked",
289 : G_CALLBACK( gui_attributes_editor_type_of_feature_btn_callback ),
290 : &((*this_).type_feat_data[feat_idx])
291 : );
292 : }
293 0 : for( int_fast32_t rel_idx = 0; rel_idx < GUI_TYPE_RESOURCE_LIST_RELATIONS; rel_idx ++ )
294 : {
295 0 : g_signal_connect( G_OBJECT((*this_).type_rel_btn[ rel_idx ]),
296 : "clicked",
297 : G_CALLBACK( gui_attributes_editor_type_of_relationship_btn_callback ),
298 : &((*this_).type_rel_data[rel_idx])
299 : );
300 : }
301 0 : g_signal_connect( G_OBJECT((*this_).window), GUI_MARKED_SET_GLIB_SIGNAL_NAME, G_CALLBACK(gui_attributes_editor_focused_object_changed_callback), &((*this_).attributes_editor) );
302 0 : g_signal_connect( G_OBJECT((*this_).name_entry), DATA_CHANGE_NOTIFIER_GLIB_SIGNAL_NAME, G_CALLBACK(gui_attributes_editor_data_changed_callback), &((*this_).attributes_editor) );
303 : /* ^-- name_entry is the proxy for all widgets of attributes_editor */
304 :
305 0 : g_signal_connect( gui_button_get_widget_ptr( &((*this_).help_about) ), "clicked", G_CALLBACK(gui_main_window_about_btn_callback), this_ );
306 :
307 0 : U8_TRACE_INFO("GTK+ Callbacks are connected to widget events.");
308 :
309 : /* register observers */
310 :
311 0 : (*this_).data_notifier = data_database_get_notifier_ptr( io_data_file_get_database_ptr( data_file ) );
312 0 : data_change_notifier_add_listener( (*this_).data_notifier, G_OBJECT((*this_).window) );
313 0 : data_change_notifier_add_listener( (*this_).data_notifier, G_OBJECT((*this_).sketcharea) );
314 0 : data_change_notifier_add_listener( (*this_).data_notifier, G_OBJECT((*this_).name_entry) );
315 : /* ^-- name_entry is the proxy for all widgets of attributes_editor */
316 0 : data_change_notifier_add_listener( (*this_).data_notifier, G_OBJECT((*this_).search_entry) );
317 :
318 0 : U8_TRACE_INFO("GTK+ Widgets are registered as listeners at signal emitter.");
319 :
320 0 : gtk_widget_set_visible( (*this_).window, TRUE );
321 0 : gtk_widget_set_sensitive( GTK_WIDGET((*this_).window), TRUE ); /* idea taken from gtk demo */
322 :
323 0 : GdkSurface *surface = gtk_native_get_surface( GTK_NATIVE((*this_).window) );
324 0 : gdk_surface_set_cursor( surface, NULL ); /* idea taken from gtk3->4 guide */
325 :
326 0 : gui_attributes_editor_update_widgets( &((*this_).attributes_editor) ); /* hide some widgets again */
327 : #ifdef NDEBUG
328 : gui_simple_message_to_user_hide( &((*this_).message_to_user) );
329 : #else
330 0 : gui_simple_message_to_user_show_message ( &((*this_).message_to_user), GUI_SIMPLE_MESSAGE_TYPE_INFO, GUI_SIMPLE_MESSAGE_CONTENT_DEBUG_MODE );
331 : #endif
332 0 : gui_search_request_hide( &((*this_).search_request) );
333 0 : U8_TRACE_INFO("GTK+ Widgets are shown.");
334 0 : U8_TRACE_END();
335 0 : }
336 :
337 0 : void gui_main_window_destroy( gui_main_window_t *this_ )
338 : {
339 0 : U8_TRACE_BEGIN();
340 :
341 : /* Note: The widgets may be destroyed already. A cast by G_OBJECT is therefore illegal. */
342 0 : data_change_notifier_remove_listener( (*this_).data_notifier, (GObject*)(*this_).window );
343 0 : data_change_notifier_remove_listener( (*this_).data_notifier, (GObject*)(*this_).name_entry );
344 0 : data_change_notifier_remove_listener( (*this_).data_notifier, (GObject*)(*this_).sketcharea );
345 0 : data_change_notifier_remove_listener( (*this_).data_notifier, (GObject*)(*this_).search_entry );
346 :
347 0 : U8_TRACE_INFO("GTK+ Widgets are unregistered as listeners from data module.");
348 0 : gui_file_export_dialog_destroy ( &((*this_).file_export_dialog) );
349 0 : gui_file_use_db_dialog_destroy ( &((*this_).file_use_db_dialog) );
350 0 : U8_TRACE_INFO("GTK+ hidden windows are destroyed.");
351 0 : gui_file_action_destroy( &((*this_).file_action) );
352 :
353 0 : gui_search_request_destroy( &((*this_).search_request) );
354 0 : gui_search_runner_destroy( &((*this_).search_runner) );
355 0 : gui_sketch_area_destroy( &((*this_).sketcharea_data) );
356 0 : gui_toolbox_destroy( &((*this_).tools_data) );
357 0 : gui_marked_set_destroy( &((*this_).marker_data) );
358 0 : gui_attributes_editor_destroy( &((*this_).attributes_editor) );
359 0 : gui_simple_message_to_user_destroy( &((*this_).message_to_user) );
360 0 : (*this_).data_file = NULL;
361 0 : (*this_).resources = NULL;
362 :
363 0 : gui_button_destroy( &((*this_).file_new) );
364 0 : gui_button_destroy( &((*this_).file_open) );
365 0 : gui_button_destroy( &((*this_).file_save) );
366 0 : gui_button_destroy( &((*this_).file_export) );
367 0 : gui_button_destroy( &((*this_).view_new_window) );
368 0 : gui_button_destroy( &((*this_).view_navigate) );
369 0 : gui_button_destroy( &((*this_).view_edit) );
370 0 : gui_button_destroy( &((*this_).view_create) );
371 0 : gui_button_destroy( &((*this_).view_search) );
372 0 : gui_button_destroy( &((*this_).edit_undo) );
373 0 : gui_button_destroy( &((*this_).edit_redo) );
374 0 : gui_button_destroy( &((*this_).edit_cut) );
375 0 : gui_button_destroy( &((*this_).edit_copy) );
376 0 : gui_button_destroy( &((*this_).edit_paste) );
377 0 : gui_button_destroy( &((*this_).edit_delete) );
378 0 : gui_button_destroy( &((*this_).edit_instantiate) );
379 0 : gui_button_destroy( &((*this_).edit_highlight) );
380 0 : gui_button_destroy( &((*this_).edit_reset) );
381 0 : gui_button_destroy( &((*this_).help_about) );
382 :
383 0 : U8_TRACE_END();
384 0 : }
385 :
386 0 : static inline void gtk_button_set_image( GtkButton *btn, GtkWidget *icon )
387 : {
388 0 : gtk_button_set_child( btn, icon );
389 0 : }
390 :
391 0 : void gui_main_window_private_init_toolbox( gui_main_window_t *this_ )
392 : {
393 0 : U8_TRACE_BEGIN();
394 0 : const gui_resources_t *const res = (*this_).resources;
395 :
396 0 : gui_button_init( &((*this_).file_new),
397 0 : GDK_PAINTABLE( gui_resources_get_file_new( res ) ),
398 : "new",
399 : "New"
400 : );
401 :
402 0 : gui_button_init( &((*this_).file_open),
403 0 : GDK_PAINTABLE( gui_resources_get_file_open( res ) ),
404 : "open",
405 : "Open"
406 : );
407 :
408 : /* save icon depends if latest changes are already saved */
409 0 : const bool is_saved = io_data_file_is_in_sync( (*this_).data_file );
410 0 : gui_button_init( &((*this_).file_save),
411 : is_saved
412 0 : ? GDK_PAINTABLE( gui_resources_get_file_saved( res ) )
413 0 : : GDK_PAINTABLE( gui_resources_get_file_save( res ) ),
414 : "save",
415 : "Save (Ctrl-S)"
416 : );
417 0 : GtkShortcutTrigger *commit_trig = gtk_shortcut_trigger_parse_string( "<Control>S" );
418 0 : GtkShortcutAction *commit_act = gtk_callback_action_new( &gui_main_window_save_shortcut_callback,
419 : this_,
420 : NULL
421 : );
422 0 : GtkShortcut* ctrl_s = gtk_shortcut_new_with_arguments( commit_trig,
423 : commit_act,
424 : NULL /* = format_string */
425 : );
426 0 : gtk_shortcut_controller_add_shortcut( (*this_).keyboard_shortcut_ctrl, ctrl_s );
427 :
428 0 : gui_button_init( &((*this_).file_export),
429 0 : GDK_PAINTABLE( gui_resources_get_file_export( res ) ),
430 : "export",
431 : "Export"
432 : );
433 :
434 0 : (*this_).tool_sect_1_icon = gtk_image_new_from_paintable( GDK_PAINTABLE ( gui_resources_get_tool_sect( res ) ) );
435 0 : gtk_widget_set_size_request( GTK_WIDGET((*this_).tool_sect_1_icon), 12 /*=w*/ , 32 /*=h*/ );
436 0 : gtk_image_set_pixel_size( GTK_IMAGE((*this_).tool_sect_1_icon), 32 /*=max(w,h)*/ );
437 0 : gtk_widget_set_halign( (*this_).tool_sect_1_icon, GTK_ALIGN_START );
438 :
439 0 : gui_button_init( &((*this_).view_new_window),
440 0 : GDK_PAINTABLE( gui_resources_get_view_new_window( res ) ),
441 : "win",
442 : "New Window"
443 : );
444 :
445 0 : gui_button_init_toggle( &((*this_).view_navigate),
446 0 : GDK_PAINTABLE( gui_resources_get_view_navigate( res ) ),
447 : "nav",
448 : "Navigate"
449 : );
450 :
451 0 : gui_button_init_toggle( &((*this_).view_edit),
452 0 : GDK_PAINTABLE( gui_resources_get_view_edit( res ) ),
453 : "edit",
454 : "Edit"
455 : );
456 0 : gtk_toggle_button_set_group( GTK_TOGGLE_BUTTON( gui_button_get_widget_ptr( &((*this_).view_edit) ) ),
457 0 : GTK_TOGGLE_BUTTON( gui_button_get_widget_ptr( &((*this_).view_navigate) ) )
458 : );
459 :
460 0 : gui_button_init_toggle( &((*this_).view_create),
461 0 : GDK_PAINTABLE( gui_resources_get_view_create( res ) ),
462 : "create",
463 : "Create"
464 : );
465 0 : gtk_toggle_button_set_group( GTK_TOGGLE_BUTTON( gui_button_get_widget_ptr( &((*this_).view_create) ) ),
466 0 : GTK_TOGGLE_BUTTON( gui_button_get_widget_ptr( &((*this_).view_edit) ) )
467 : );
468 :
469 0 : gui_button_init_toggle( &((*this_).view_search),
470 0 : GDK_PAINTABLE( gui_resources_get_view_search( res ) ),
471 : "search",
472 : "Search"
473 : );
474 0 : gtk_toggle_button_set_group( GTK_TOGGLE_BUTTON( gui_button_get_widget_ptr( &((*this_).view_search) ) ),
475 0 : GTK_TOGGLE_BUTTON( gui_button_get_widget_ptr( &((*this_).view_create) ) )
476 : );
477 :
478 0 : (*this_).tool_sect_2_icon = gtk_image_new_from_paintable( GDK_PAINTABLE ( gui_resources_get_tool_sect( res ) ) );
479 0 : gtk_widget_set_size_request( GTK_WIDGET((*this_).tool_sect_2_icon), 12 /*=w*/ , 32 /*=h*/ );
480 0 : gtk_image_set_pixel_size( GTK_IMAGE((*this_).tool_sect_2_icon), 32 /*=max(w,h)*/ );
481 0 : gtk_widget_set_halign( (*this_).tool_sect_2_icon, GTK_ALIGN_START );
482 :
483 0 : gui_button_init( &((*this_).edit_undo),
484 0 : GDK_PAINTABLE( gui_resources_get_edit_undo( res ) ),
485 : "undo",
486 : "Undo (Ctrl-Z)"
487 : );
488 0 : GtkShortcutTrigger *undo_trig = gtk_shortcut_trigger_parse_string( "<Control>Z" );
489 0 : GtkShortcutAction *undo_act = gtk_callback_action_new( &gui_toolbox_undo_shortcut_callback,
490 0 : &((*this_).tools_data),
491 : NULL
492 : );
493 0 : GtkShortcut* ctrl_z = gtk_shortcut_new_with_arguments( undo_trig,
494 : undo_act,
495 : NULL /* = format_string */
496 : );
497 0 : gtk_shortcut_controller_add_shortcut( (*this_).keyboard_shortcut_ctrl, ctrl_z );
498 :
499 0 : gui_button_init( &((*this_).edit_redo),
500 0 : GDK_PAINTABLE( gui_resources_get_edit_redo( res ) ),
501 : "redo",
502 : "Redo (Ctrl-Y)"
503 : );
504 0 : GtkShortcutTrigger *redo_trig = gtk_shortcut_trigger_parse_string( "<Control>Y" );
505 0 : GtkShortcutAction *redo_act = gtk_callback_action_new( &gui_toolbox_redo_shortcut_callback,
506 0 : &((*this_).tools_data),
507 : NULL
508 : );
509 0 : GtkShortcut* ctrl_y = gtk_shortcut_new_with_arguments( redo_trig,
510 : redo_act,
511 : NULL /* = format_string */
512 : );
513 0 : gtk_shortcut_controller_add_shortcut( (*this_).keyboard_shortcut_ctrl, ctrl_y );
514 :
515 0 : gui_button_init( &((*this_).edit_cut),
516 0 : GDK_PAINTABLE( gui_resources_get_edit_cut( res ) ),
517 : "cut",
518 : "Cut (Ctrl-X)"
519 : );
520 : /*
521 : GDK_KEY_x + GDK_CONTROL_MASK handling see gui_sketch_area_key_press_callback();
522 : moved there to not interfere with text input fields
523 : */
524 :
525 0 : gui_button_init( &((*this_).edit_copy),
526 0 : GDK_PAINTABLE( gui_resources_get_edit_copy( res ) ),
527 : "copy",
528 : "Copy (Ctrl-C)"
529 : );
530 : /*
531 : GDK_KEY_c + GDK_CONTROL_MASK handling see gui_sketch_area_key_press_callback();
532 : moved there to not interfere with text input fields
533 : */
534 :
535 0 : gui_button_init( &((*this_).edit_paste),
536 0 : GDK_PAINTABLE( gui_resources_get_edit_paste( res ) ),
537 : "paste",
538 : "Paste (Ctrl-V)"
539 : );
540 : /*
541 : GK_KEY_v + GDK_CONTROL_MASK handling see gui_sketch_area_key_press_callback();
542 : moved there to not interfere with text input fields
543 : */
544 :
545 0 : gui_button_init( &((*this_).edit_delete),
546 0 : GDK_PAINTABLE( gui_resources_get_edit_delete( res ) ),
547 : "del",
548 : "Delete (DEL)"
549 : );
550 : /*
551 : GDK_KEY_Delete handling see gui_sketch_area_key_press_callback();
552 : moved there to not interfere with text input fields
553 : */
554 :
555 0 : gui_button_init( &((*this_).edit_instantiate),
556 0 : GDK_PAINTABLE( gui_resources_get_edit_instantiate( res ) ),
557 : "inst",
558 : "Instantiate"
559 : );
560 :
561 0 : gui_button_init( &((*this_).edit_highlight),
562 0 : GDK_PAINTABLE( gui_resources_get_edit_highlight( res ) ),
563 : "mark",
564 : "Mark"
565 : );
566 :
567 0 : gui_button_init( &((*this_).edit_reset),
568 0 : GDK_PAINTABLE( gui_resources_get_edit_reset( res ) ),
569 : "zero",
570 : "Reset Selection"
571 : );
572 :
573 0 : gui_button_init( &((*this_).help_about),
574 0 : GDK_PAINTABLE( gui_resources_get_crystal_facet_uml( res ) ),
575 : "info",
576 : "About"
577 : );
578 :
579 : /* insert widgets to box container */
580 : {
581 0 : (*this_).tool_row = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, /*spacing:*/ 4 );
582 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).file_new) ) );
583 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).file_open) ) );
584 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).file_save) ) );
585 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).file_export) ) );
586 0 : gtk_box_append( GTK_BOX((*this_).tool_row), GTK_WIDGET((*this_).tool_sect_1_icon) );
587 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).view_new_window) ) );
588 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).view_search) ) );
589 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).view_navigate) ) );
590 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).view_edit) ) );
591 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).view_create) ) );
592 0 : gtk_box_append( GTK_BOX((*this_).tool_row), GTK_WIDGET((*this_).tool_sect_2_icon) );
593 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_undo) ) );
594 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_redo) ) );
595 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_cut) ) );
596 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_copy) ) );
597 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_paste) ) );
598 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_delete) ) );
599 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_instantiate) ) );
600 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_highlight) ) );
601 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_reset) ) );
602 0 : gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).help_about) ) );
603 : }
604 :
605 0 : U8_TRACE_END();
606 0 : }
607 :
608 0 : void gui_main_window_private_init_attributes_editor( gui_main_window_t *this_ )
609 : {
610 0 : U8_TRACE_BEGIN();
611 0 : const gui_resources_t *const res = (*this_).resources;
612 :
613 0 : (*this_).attr_section_icon = gtk_image_new_from_paintable( GDK_PAINTABLE ( gui_resources_get_edit_attributes_sect( res ) ) );
614 0 : gtk_widget_set_size_request( GTK_WIDGET((*this_).attr_section_icon), 32 /*=w*/ , 24 /*=h*/ );
615 0 : gtk_widget_set_margin_start( GTK_WIDGET((*this_).attr_section_icon), 8 );
616 0 : gtk_widget_set_margin_end( GTK_WIDGET((*this_).attr_section_icon), 8 );
617 0 : gtk_widget_set_margin_top( GTK_WIDGET((*this_).attr_section_icon), 0 );
618 0 : gtk_widget_set_margin_bottom( GTK_WIDGET((*this_).attr_section_icon), 0 );
619 0 : gtk_image_set_pixel_size( GTK_IMAGE((*this_).attr_section_icon), 32 /*=max(w,h)*/ );
620 0 : gtk_widget_set_halign( (*this_).attr_section_icon, GTK_ALIGN_START );
621 :
622 0 : (*this_).id_label = gtk_label_new( "" );
623 0 : gtk_label_set_selectable( GTK_LABEL( (*this_).id_label ), true );
624 0 : (*this_).name_label = gtk_label_new( "Name:" );
625 0 : (*this_).description_label = gtk_label_new( "Description:" );
626 0 : (*this_).stereotype_label = gtk_label_new( "Stereotype:" );
627 0 : (*this_).type_label = gtk_label_new( "Type:" );
628 0 : gtk_label_set_xalign( GTK_LABEL( (*this_).id_label ), 1.0 ); /* align right */
629 0 : gtk_label_set_xalign( GTK_LABEL( (*this_).name_label ), 0.0 );
630 0 : gtk_label_set_xalign( GTK_LABEL( (*this_).description_label ), 0.0 );
631 0 : gtk_label_set_xalign( GTK_LABEL( (*this_).stereotype_label ), 0.0 );
632 0 : gtk_label_set_xalign( GTK_LABEL( (*this_).type_label ), 0.0 );
633 :
634 0 : (*this_).id_search_btn = gtk_button_new();
635 0 : (*this_).id_search_btn_icon = gtk_image_new_from_paintable( GDK_PAINTABLE( gui_resources_get_view_search_now( res ) ) );
636 0 : gtk_button_set_image( GTK_BUTTON((*this_).id_search_btn), (*this_).id_search_btn_icon );
637 0 : gtk_widget_set_tooltip_text( GTK_WIDGET((*this_).id_search_btn), "Find Occurrences" );
638 0 : gtk_widget_set_size_request( GTK_WIDGET((*this_).id_search_btn_icon), 32 /*=w*/ , 32 /*=h*/ );
639 :
640 : /* insert widgets to box container */
641 : {
642 0 : (*this_).id_row = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, /*spacing:*/ 8 );
643 0 : gtk_box_append( GTK_BOX((*this_).id_row), GTK_WIDGET((*this_).attr_section_icon) );
644 0 : gtk_box_append( GTK_BOX((*this_).id_row), GTK_WIDGET((*this_).id_label) );
645 0 : gtk_box_append( GTK_BOX((*this_).id_row), GTK_WIDGET((*this_).id_search_btn) );
646 :
647 0 : gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).attr_section_icon ), false );
648 0 : gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).attr_section_icon ), false );
649 0 : gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).id_label ), false );
650 0 : gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).id_label ), true );
651 0 : gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).id_search_btn ), false );
652 0 : gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).id_search_btn ), false );
653 : }
654 :
655 0 : (*this_).name_entry = gtk_entry_new();
656 :
657 0 : (*this_).stereotype_entry = gtk_entry_new();
658 :
659 0 : (*this_).description_text_view = gtk_text_view_new();
660 0 : gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( (*this_).description_text_view ),
661 : GTK_WRAP_WORD_CHAR
662 : );
663 0 : gtk_widget_set_vexpand( GTK_WIDGET( (*this_).description_text_view ), true );
664 0 : gtk_widget_set_hexpand( GTK_WIDGET( (*this_).description_text_view ), false );
665 : //gtk_widget_set_size_request( GTK_WIDGET((*this_).description_text_view), 128 /*=w*/ , 48 /*=h*/ );
666 : /* need own scroll window container */
667 0 : gtk_text_view_set_bottom_margin( GTK_TEXT_VIEW( (*this_).description_text_view ), 12 );
668 0 : gtk_text_view_set_left_margin( GTK_TEXT_VIEW( (*this_).description_text_view ), 12 );
669 0 : gtk_text_view_set_right_margin( GTK_TEXT_VIEW( (*this_).description_text_view ), 12 );
670 0 : gtk_text_view_set_top_margin( GTK_TEXT_VIEW( (*this_).description_text_view ), 12 );
671 0 : (*this_).description_scroll_win = gtk_scrolled_window_new();
672 0 : gtk_scrolled_window_set_child( GTK_SCROLLED_WINDOW((*this_).description_scroll_win), (*this_).description_text_view );
673 0 : gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( (*this_).description_scroll_win ),
674 : GTK_POLICY_AUTOMATIC,
675 : GTK_POLICY_AUTOMATIC
676 : );
677 :
678 0 : GListStore *model = NULL; /* the model is set later */
679 0 : GtkExpression *expression = NULL; /* not needed: there is no search entry that could find list elements */
680 0 : (*this_).type_dropdown = GTK_DROP_DOWN( gtk_drop_down_new ( G_LIST_MODEL( model ), expression ) );
681 0 : GtkBuilderScope *scope = gtk_builder_cscope_new();
682 : static const char bytes[] =
683 : "<interface>\n"
684 : "<template class=\"GtkListItem\">\n"
685 : " <property name=\"child\">\n"
686 : " <object class=\"GtkPaned\">\n"
687 : " <property name=\"start-child\">\n"
688 : " <object class=\"GtkImage\">\n"
689 : " <property name=\"width-request\">32</property>\n"
690 : " <property name=\"height-request\">24</property>\n"
691 : " <binding name=\"paintable\">\n"
692 : " <lookup name=\"icon\" type=\"GuiTypeResource\">\n"
693 : " <lookup name=\"item\">GtkListItem</lookup>\n"
694 : " </lookup>\n"
695 : " </binding>\n"
696 : " </object>\n"
697 : " </property>\n"
698 : " <property name=\"end-child\">\n"
699 : " <object class=\"GtkLabel\">\n"
700 : " <property name=\"xalign\">0</property>\n"
701 : " <binding name=\"label\">\n"
702 : " <lookup name=\"name\" type=\"GuiTypeResource\">\n"
703 : " <lookup name=\"item\">GtkListItem</lookup>\n"
704 : " </lookup>\n"
705 : " </binding>\n"
706 : " </object>\n"
707 : " </property>\n"
708 : " <property name=\"position\">48</property>\n"
709 : " </object>\n"
710 : " </property>\n"
711 : "</template>\n"
712 : "</interface>\n";
713 0 : GBytes *byteptr = g_bytes_new( &bytes, sizeof(bytes)-sizeof(char) );
714 0 : GtkListItemFactory *factory = gtk_builder_list_item_factory_new_from_bytes( scope, byteptr );
715 0 : gtk_drop_down_set_factory( (*this_).type_dropdown, factory );
716 0 : g_object_unref( scope );
717 0 : g_object_unref( factory );
718 0 : g_bytes_unref( byteptr );
719 :
720 : static gui_type_resource_list_t res_select;
721 0 : gui_type_resource_list_init( &res_select, res );
722 : {
723 0 : (*this_).type_diag_grid = GTK_GRID( gtk_grid_new() );
724 0 : gtk_widget_set_halign( GTK_WIDGET( (*this_).type_diag_grid ), GTK_ALIGN_END );
725 : const gui_type_resource_t (*diag_data)[];
726 : unsigned int diag_data_length;
727 0 : gui_type_resource_list_get_all_diagram_types( &res_select, &diag_data, &diag_data_length );
728 0 : assert( diag_data_length == GUI_TYPE_RESOURCE_LIST_DIAGRAMS );
729 0 : for( int_fast32_t diag_idx = 0; diag_idx < GUI_TYPE_RESOURCE_LIST_DIAGRAMS; diag_idx ++ )
730 : {
731 0 : const gui_type_resource_t *const type_data = &((*diag_data)[diag_idx]);
732 0 : const data_diagram_type_t diag_type = data_type_get_diagram_type( gui_type_resource_get_type_id( type_data ) );
733 0 : GdkTexture *const diag_icon = gui_type_resource_get_icon( type_data );
734 0 : const char *const diag_name = gui_type_resource_get_name( type_data );
735 :
736 0 : gui_attribute_type_of_diagram_init( &((*this_).type_diag_data[diag_idx]), diag_type, &((*this_).attributes_editor) );
737 0 : (*this_).type_diag_img[ diag_idx ] = GTK_IMAGE( gtk_image_new_from_paintable( GDK_PAINTABLE( diag_icon ) ) );
738 0 : gtk_widget_set_size_request( GTK_WIDGET( (*this_).type_diag_img[ diag_idx ] ), 32 /*=w*/ , 24 /*=h*/ );
739 0 : (*this_).type_diag_btn[ diag_idx ] = GTK_BUTTON( gtk_button_new() );
740 0 : gtk_button_set_image( (*this_).type_diag_btn[ diag_idx ], GTK_WIDGET( (*this_).type_diag_img[ diag_idx ] ) );
741 0 : gtk_widget_set_tooltip_text( GTK_WIDGET( (*this_).type_diag_btn[ diag_idx ] ), diag_name );
742 0 : gtk_grid_attach( (*this_).type_diag_grid, GTK_WIDGET( (*this_).type_diag_btn[ diag_idx ] ), diag_idx%7, diag_idx/7, 1, 1 );
743 : }
744 :
745 0 : (*this_).type_clas_grid = GTK_GRID( gtk_grid_new() );
746 0 : gtk_widget_set_halign( GTK_WIDGET( (*this_).type_clas_grid ), GTK_ALIGN_END );
747 : const gui_type_resource_t (*clas_data)[];
748 : unsigned int clas_data_length;
749 0 : gui_type_resource_list_get_all_classifier_types( &res_select, &clas_data, &clas_data_length );
750 0 : assert( clas_data_length == GUI_TYPE_RESOURCE_LIST_CLASSIFIERS );
751 0 : for( int_fast32_t clas_idx = 0; clas_idx < GUI_TYPE_RESOURCE_LIST_CLASSIFIERS; clas_idx ++ )
752 : {
753 0 : const gui_type_resource_t *const type_data = &((*clas_data)[clas_idx]);
754 0 : const data_classifier_type_t clas_type = data_type_get_classifier_type( gui_type_resource_get_type_id( type_data ) );
755 0 : GdkTexture *const clas_icon = gui_type_resource_get_icon( type_data );
756 0 : const char *const clas_name = gui_type_resource_get_name( type_data );
757 :
758 0 : gui_attribute_type_of_classifier_init( &((*this_).type_clas_data[clas_idx]), clas_type, &((*this_).attributes_editor) );
759 0 : (*this_).type_clas_img[ clas_idx ] = GTK_IMAGE( gtk_image_new_from_paintable( GDK_PAINTABLE( clas_icon ) ) );
760 0 : gtk_widget_set_size_request( GTK_WIDGET( (*this_).type_clas_img[ clas_idx ] ), 32 /*=w*/ , 24 /*=h*/ );
761 0 : (*this_).type_clas_btn[ clas_idx ] = GTK_BUTTON( gtk_button_new() );
762 0 : gtk_button_set_image( (*this_).type_clas_btn[ clas_idx ], GTK_WIDGET( (*this_).type_clas_img[ clas_idx ] ) );
763 0 : gtk_widget_set_tooltip_text( GTK_WIDGET( (*this_).type_clas_btn[ clas_idx ] ), clas_name );
764 0 : gtk_grid_attach( (*this_).type_clas_grid, GTK_WIDGET( (*this_).type_clas_btn[ clas_idx ] ), clas_idx%7, clas_idx/7, 1, 1 );
765 : }
766 :
767 0 : (*this_).type_feat_grid = GTK_GRID( gtk_grid_new() );
768 0 : gtk_widget_set_halign( GTK_WIDGET( (*this_).type_feat_grid ), GTK_ALIGN_END );
769 : const gui_type_resource_t (*feat_data)[];
770 : unsigned int feat_data_length;
771 0 : gui_type_resource_list_get_invariant_feature_types( &res_select, &feat_data, &feat_data_length );
772 0 : assert( feat_data_length == GUI_TYPE_RESOURCE_LIST_INV_FEATURES );
773 0 : for( int_fast32_t feat_idx = 0; feat_idx < GUI_TYPE_RESOURCE_LIST_INV_FEATURES; feat_idx ++ ) /* ignore the lifeline */
774 : {
775 0 : const gui_type_resource_t *const type_data = &((*feat_data)[feat_idx]);
776 0 : const data_feature_type_t feat_type = data_type_get_feature_type( gui_type_resource_get_type_id( type_data ) );
777 0 : GdkTexture *const feat_icon = gui_type_resource_get_icon( type_data );
778 0 : const char *const feat_name = gui_type_resource_get_name( type_data );
779 :
780 0 : gui_attribute_type_of_feature_init( &((*this_).type_feat_data[feat_idx]), feat_type, &((*this_).attributes_editor) );
781 0 : (*this_).type_feat_img[ feat_idx ] = GTK_IMAGE( gtk_image_new_from_paintable( GDK_PAINTABLE( feat_icon ) ) );
782 0 : gtk_widget_set_size_request( GTK_WIDGET( (*this_).type_feat_img[ feat_idx ] ), 32 /*=w*/ , 24 /*=h*/ );
783 0 : (*this_).type_feat_btn[ feat_idx ] = GTK_BUTTON( gtk_button_new() );
784 0 : gtk_button_set_image( (*this_).type_feat_btn[ feat_idx ], GTK_WIDGET( (*this_).type_feat_img[ feat_idx ] ) );
785 0 : gtk_widget_set_tooltip_text( GTK_WIDGET( (*this_).type_feat_btn[ feat_idx ] ), feat_name );
786 0 : gtk_grid_attach( (*this_).type_feat_grid, GTK_WIDGET( (*this_).type_feat_btn[ feat_idx ] ), feat_idx%7, feat_idx/7, 1, 1 );
787 : }
788 :
789 0 : (*this_).type_rel_grid = GTK_GRID( gtk_grid_new() );
790 0 : gtk_widget_set_halign( GTK_WIDGET( (*this_).type_rel_grid ), GTK_ALIGN_END );
791 : const gui_type_resource_t (*rel_data)[];
792 : unsigned int rel_data_length;
793 0 : gui_type_resource_list_get_all_relationship_types( &res_select, &rel_data, &rel_data_length );
794 0 : assert( rel_data_length == GUI_TYPE_RESOURCE_LIST_RELATIONS );
795 0 : for( int_fast32_t rel_idx = 0; rel_idx < GUI_TYPE_RESOURCE_LIST_RELATIONS; rel_idx ++ )
796 : {
797 0 : const gui_type_resource_t *const type_data = &((*rel_data)[rel_idx]);
798 0 : const data_relationship_type_t rel_type = data_type_get_relationship_type( gui_type_resource_get_type_id( type_data ) );
799 0 : GdkTexture *const rel_icon = gui_type_resource_get_icon( type_data );
800 0 : const char *const rel_name = gui_type_resource_get_name( type_data );
801 :
802 0 : gui_attribute_type_of_relationship_init( &((*this_).type_rel_data[rel_idx]), rel_type, &((*this_).attributes_editor) );
803 0 : (*this_).type_rel_img[ rel_idx ] = GTK_IMAGE( gtk_image_new_from_paintable( GDK_PAINTABLE( rel_icon ) ) );
804 0 : gtk_widget_set_size_request( GTK_WIDGET( (*this_).type_rel_img[ rel_idx ] ), 32 /*=w*/ , 24 /*=h*/ );
805 0 : (*this_).type_rel_btn[ rel_idx ] = GTK_BUTTON( gtk_button_new() );
806 0 : gtk_button_set_image( (*this_).type_rel_btn[ rel_idx ], GTK_WIDGET( (*this_).type_rel_img[ rel_idx ] ) );
807 0 : gtk_widget_set_tooltip_text( GTK_WIDGET( (*this_).type_rel_btn[ rel_idx ] ), rel_name );
808 0 : gtk_grid_attach( (*this_).type_rel_grid, GTK_WIDGET( (*this_).type_rel_btn[ rel_idx ] ), rel_idx%7, rel_idx/7, 1, 1 );
809 : }
810 : }
811 0 : gui_type_resource_list_destroy( &res_select );
812 :
813 : /* insert widgets to box container */
814 : {
815 0 : (*this_).attr_edit_column = gtk_box_new( GTK_ORIENTATION_VERTICAL, /*spacing:*/ 4 );
816 0 : gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).id_row) );
817 0 : gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).name_label) );
818 0 : gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).name_entry) );
819 0 : gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).stereotype_label) );
820 0 : gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).stereotype_entry) );
821 0 : gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).type_label) );
822 0 : gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).type_dropdown) );
823 0 : gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).type_diag_grid) );
824 0 : gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).type_clas_grid) );
825 0 : gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).type_feat_grid) );
826 0 : gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).type_rel_grid) );
827 0 : gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).description_label) );
828 0 : gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).description_scroll_win) );
829 :
830 0 : gtk_widget_set_vexpand( GTK_WIDGET( (*this_).description_scroll_win ), true );
831 0 : gtk_widget_set_hexpand( GTK_WIDGET( (*this_).description_scroll_win ), true );
832 : }
833 :
834 0 : U8_TRACE_END();
835 0 : }
836 :
837 0 : void gui_main_window_private_init_simple_message_to_user( gui_main_window_t *this_ )
838 : {
839 0 : U8_TRACE_BEGIN();
840 0 : const gui_resources_t *const res = (*this_).resources;
841 :
842 0 : (*this_).message_text_label = gtk_label_new( "" );
843 0 : gtk_label_set_xalign(GTK_LABEL( (*this_).message_text_label ), 0.0 );
844 :
845 0 : (*this_).message_icon_image = gtk_image_new_from_paintable( GDK_PAINTABLE ( gui_resources_get_crystal_facet_uml( res ) ) );
846 0 : gtk_widget_set_size_request( GTK_WIDGET((*this_).message_icon_image), 32 /*=w*/ , 32 /*=h*/ );
847 0 : gtk_widget_set_margin_start( GTK_WIDGET((*this_).message_icon_image), 8 );
848 0 : gtk_widget_set_margin_end( GTK_WIDGET((*this_).message_icon_image), 8 );
849 0 : gtk_widget_set_margin_top( GTK_WIDGET((*this_).message_icon_image), 0 );
850 0 : gtk_widget_set_margin_bottom( GTK_WIDGET((*this_).message_icon_image), 0 );
851 :
852 : /* insert widgets to box container */
853 : {
854 0 : (*this_).message_row = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, /*spacing:*/ 20 );
855 0 : gtk_box_append( GTK_BOX((*this_).message_row), GTK_WIDGET((*this_).message_icon_image) );
856 0 : gtk_box_append( GTK_BOX((*this_).message_row), GTK_WIDGET((*this_).message_text_label) );
857 :
858 0 : gtk_widget_set_vexpand( GTK_WIDGET( (*this_).message_icon_image ), false );
859 0 : gtk_widget_set_hexpand( GTK_WIDGET( (*this_).message_icon_image ), false );
860 0 : gtk_widget_set_vexpand( GTK_WIDGET( (*this_).message_text_label ), false );
861 0 : gtk_widget_set_hexpand( GTK_WIDGET( (*this_).message_text_label ), true );
862 : }
863 :
864 0 : U8_TRACE_END();
865 0 : }
866 :
867 0 : void gui_main_window_private_init_search_and_sketch_area( gui_main_window_t *this_ )
868 : {
869 0 : U8_TRACE_BEGIN();
870 0 : const gui_resources_t *const res = (*this_).resources;
871 :
872 : /* init search widgets */
873 : {
874 0 : (*this_).search_label = gtk_label_new ( "Search:" );
875 0 : gtk_label_set_xalign( GTK_LABEL( (*this_).search_label ), 1.0 ); /* align right */
876 0 : gtk_label_set_yalign( GTK_LABEL( (*this_).search_label ), 0.5 ); /* align middle-height */
877 :
878 0 : (*this_).search_entry = gtk_entry_new();
879 :
880 0 : (*this_).search_button = gtk_button_new();
881 0 : (*this_).search_btn_icon = gtk_image_new_from_paintable( GDK_PAINTABLE( gui_resources_get_view_search_now( res ) ) );
882 0 : gtk_button_set_image( GTK_BUTTON((*this_).search_button), (*this_).search_btn_icon );
883 0 : gtk_widget_set_tooltip_text( GTK_WIDGET((*this_).search_button), "Search" );
884 0 : gtk_widget_set_size_request( GTK_WIDGET((*this_).search_btn_icon), 32 /*=w*/ , 32 /*=h*/ );
885 : }
886 :
887 : /* insert widgets to box container */
888 : {
889 0 : (*this_).search_row = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, /*spacing:*/ 4 );
890 0 : gtk_box_append( GTK_BOX((*this_).search_row), GTK_WIDGET((*this_).search_label) );
891 0 : gtk_box_append( GTK_BOX((*this_).search_row), GTK_WIDGET((*this_).search_entry) );
892 0 : gtk_box_append( GTK_BOX((*this_).search_row), GTK_WIDGET((*this_).search_button) );
893 :
894 0 : gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).search_label ), false );
895 0 : gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).search_label ), false );
896 0 : gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).search_entry ), false );
897 0 : gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).search_entry ), true );
898 0 : gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).search_button ), false );
899 0 : gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).search_button ), false );
900 : }
901 :
902 : /* init sketch area */
903 : {
904 0 : (*this_).sketcharea = gtk_drawing_area_new();
905 0 : gtk_widget_set_can_focus( GTK_WIDGET( (*this_).sketcharea ), TRUE ); /* this allows the text entry widgets to lose the focus */
906 0 : gtk_widget_set_size_request( GTK_WIDGET( (*this_).sketcharea ), 600, 360); /* set a minimum initial size */
907 : /*gtk_widget_set_focus_on_click( GTK_WIDGET( (*this_).sketcharea ), TRUE ); not yet existing: since GTK 3.2 */
908 : }
909 :
910 : /* insert widgets to box container */
911 : {
912 0 : (*this_).sketch_stack_column = gtk_box_new( GTK_ORIENTATION_VERTICAL, /*spacing:*/ 0 );
913 0 : gtk_box_append( GTK_BOX((*this_).sketch_stack_column), GTK_WIDGET((*this_).search_row) );
914 0 : gtk_box_append( GTK_BOX((*this_).sketch_stack_column), GTK_WIDGET((*this_).sketcharea) );
915 :
916 0 : gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).search_row ), false );
917 0 : gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).search_row ), true );
918 0 : gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).sketcharea ), true );
919 0 : gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).sketcharea ), true );
920 : }
921 :
922 0 : U8_TRACE_END();
923 0 : }
924 :
925 0 : void gui_main_window_destroy_event_callback( GtkWidget *widget, gpointer data )
926 : {
927 0 : U8_TRACE_BEGIN();
928 0 : gui_main_window_t *this_ = data;
929 0 : assert( (*this_).window == (void*)widget );
930 :
931 : /* forward destroy request to gui_window_manager: */
932 0 : observer_notify( (*this_).window_close_observer, this_ );
933 :
934 0 : U8_TRACE_TIMESTAMP();
935 0 : U8_TRACE_END();
936 0 : }
937 :
938 0 : gboolean gui_main_window_delete_event_callback( GtkWindow *widget, gpointer data )
939 : {
940 0 : U8_TRACE_BEGIN();
941 0 : gui_main_window_t *this_ = data;
942 0 : assert( (*this_).window == (void*)widget );
943 : (void) this_; /* unused in case of NDEBUG */
944 :
945 0 : U8_TRACE_TIMESTAMP();
946 0 : U8_TRACE_END();
947 0 : return false; /* return false to trigger destroy event */
948 : }
949 :
950 0 : void gui_main_window_new_db_btn_callback( GtkWidget* button, gpointer data )
951 : {
952 0 : U8_TRACE_BEGIN();
953 0 : gui_main_window_t *this_ = data;
954 :
955 0 : gui_simple_message_to_user_hide( &((*this_).message_to_user) );
956 :
957 0 : gui_file_use_db_dialog_show( &((*this_).file_use_db_dialog), false /* open_existing*/ );
958 :
959 0 : U8_TRACE_TIMESTAMP();
960 0 : U8_TRACE_END();
961 0 : }
962 :
963 0 : void gui_main_window_open_db_btn_callback( GtkWidget* button, gpointer data )
964 : {
965 0 : U8_TRACE_BEGIN();
966 0 : gui_main_window_t *this_ = data;
967 :
968 0 : gui_simple_message_to_user_hide( &((*this_).message_to_user) );
969 :
970 0 : gui_file_use_db_dialog_show( &((*this_).file_use_db_dialog), true /* open_existing*/ );
971 :
972 0 : U8_TRACE_TIMESTAMP();
973 0 : U8_TRACE_END();
974 0 : }
975 :
976 0 : void gui_main_window_save_btn_callback( GtkButton *button, gpointer user_data )
977 : {
978 0 : U8_TRACE_BEGIN();
979 : gui_main_window_t *this_;
980 0 : this_ = (gui_main_window_t*) user_data;
981 0 : assert( this_ != NULL );
982 :
983 0 : gui_simple_message_to_user_hide( &((*this_).message_to_user) );
984 :
985 0 : gui_attributes_editor_commit_changes ( &((*this_).attributes_editor) );
986 :
987 0 : const u8_error_t err = gui_file_action_save( &((*this_).file_action) );
988 0 : if ( err == U8_ERROR_NONE )
989 : {
990 0 : GtkImage *const save_image = gui_button_get_icon_ptr( &((*this_).file_save) );
991 0 : const GdkPaintable *const shown_icon = gtk_image_get_paintable( save_image );
992 0 : GdkPaintable *const saved_icon = GDK_PAINTABLE( gui_resources_get_file_saved( (*this_).resources ) );
993 0 : if ( shown_icon != saved_icon )
994 : {
995 0 : gtk_image_set_from_paintable( save_image, saved_icon );
996 0 : U8_TRACE_INFO("icon of save button set to SAVED(/)");
997 : }
998 : }
999 :
1000 0 : U8_TRACE_TIMESTAMP();
1001 0 : U8_TRACE_END();
1002 0 : }
1003 :
1004 0 : gboolean gui_main_window_save_shortcut_callback( GtkWidget* widget, GVariant* args, gpointer user_data )
1005 : {
1006 0 : gui_main_window_save_btn_callback( (GtkButton*)widget, user_data );
1007 0 : return TRUE;
1008 : }
1009 :
1010 0 : void gui_main_window_export_btn_callback( GtkWidget* button, gpointer data )
1011 : {
1012 0 : U8_TRACE_BEGIN();
1013 0 : gui_main_window_t *this_ = data;
1014 :
1015 0 : gui_simple_message_to_user_hide( &((*this_).message_to_user) );
1016 :
1017 0 : const bool was_visible = gtk_widget_get_visible( (*this_).options_layout );
1018 0 : gtk_widget_set_visible( (*this_).options_layout, ! was_visible );
1019 :
1020 0 : U8_TRACE_TIMESTAMP();
1021 0 : U8_TRACE_END();
1022 0 : }
1023 :
1024 0 : void gui_main_window_new_window_btn_callback( GtkWidget* button, gpointer data )
1025 : {
1026 0 : U8_TRACE_BEGIN();
1027 0 : gui_main_window_t *this_ = data;
1028 :
1029 : /* hide last message */
1030 0 : gui_simple_message_to_user_hide( &((*this_).message_to_user) );
1031 :
1032 : /* forward new window request to gui_window_manager: */
1033 0 : observer_notify( (*this_).window_open_observer, &((*this_).message_to_user) );
1034 :
1035 0 : U8_TRACE_TIMESTAMP();
1036 0 : U8_TRACE_END();
1037 0 : }
1038 :
1039 0 : void gui_main_window_about_btn_callback( GtkWidget* button, gpointer data )
1040 : {
1041 0 : U8_TRACE_BEGIN();
1042 0 : gui_main_window_t *this_ = data;
1043 :
1044 0 : if ( GUI_SIMPLE_MESSAGE_TYPE_ABOUT == gui_simple_message_to_user_get_type_id( &((*this_).message_to_user) ) )
1045 : {
1046 : /* hide the already visible about message */
1047 0 : gui_simple_message_to_user_hide( &((*this_).message_to_user) );
1048 : }
1049 : else
1050 : {
1051 0 : gui_simple_message_to_user_show_message( &((*this_).message_to_user),
1052 : GUI_SIMPLE_MESSAGE_TYPE_ABOUT,
1053 : GUI_SIMPLE_MESSAGE_CONTENT_ABOUT
1054 : );
1055 : }
1056 :
1057 0 : U8_TRACE_TIMESTAMP();
1058 0 : U8_TRACE_END();
1059 0 : }
1060 :
1061 0 : void gui_main_window_data_changed_callback( GtkWidget *window, data_change_message_t *msg, gpointer user_data )
1062 : {
1063 0 : U8_TRACE_BEGIN();
1064 0 : gui_main_window_t *this_ = user_data;
1065 :
1066 : /* update the window title */
1067 0 : if (( DATA_CHANGE_EVENT_TYPE_DB_OPENED == data_change_message_get_event( msg ) )
1068 0 : || ( DATA_CHANGE_EVENT_TYPE_DB_CLOSED == data_change_message_get_event( msg ) ))
1069 : {
1070 : /* the database has changed */
1071 0 : const char *filename = io_data_file_get_filename_const( (*this_).data_file );
1072 0 : if ( NULL == filename )
1073 : {
1074 0 : gtk_window_set_title(GTK_WINDOW((*this_).window), META_INFO_PROGRAM_NAME_STR );
1075 : }
1076 : else
1077 : {
1078 0 : gtk_window_set_title(GTK_WINDOW((*this_).window), filename );
1079 : }
1080 : }
1081 :
1082 : /* update the save button status indicator */
1083 0 : GtkImage *const save_image = gui_button_get_icon_ptr( &((*this_).file_save) );
1084 0 : const GdkPaintable *const shown_icon = gtk_image_get_paintable( save_image );
1085 :
1086 0 : if (( DATA_CHANGE_EVENT_TYPE_DB_OPENED == data_change_message_get_event( msg ) )
1087 0 : || ( DATA_CHANGE_EVENT_TYPE_DB_CLOSED == data_change_message_get_event( msg ) ))
1088 0 : {
1089 0 : GdkPaintable *const saved_icon = GDK_PAINTABLE( gui_resources_get_file_saved( (*this_).resources ) );
1090 0 : if ( shown_icon != saved_icon )
1091 : {
1092 0 : gtk_image_set_from_paintable( save_image, saved_icon );
1093 0 : U8_TRACE_INFO("icon of save button set to SAVED(/)");
1094 : }
1095 : }
1096 0 : else if ( DATA_CHANGE_EVENT_TYPE_DB_PREPARE_CLOSE != data_change_message_get_event( msg ) )
1097 : {
1098 0 : GdkPaintable *const save_icon = GDK_PAINTABLE( gui_resources_get_file_save( (*this_).resources ) );
1099 0 : if ( shown_icon != save_icon )
1100 : {
1101 0 : gtk_image_set_from_paintable( save_image, save_icon );
1102 0 : U8_TRACE_INFO("icon of save button set to NOT-SAVED(*)");
1103 : }
1104 : }
1105 :
1106 0 : U8_TRACE_TIMESTAMP();
1107 0 : U8_TRACE_END();
1108 0 : }
1109 :
1110 0 : void gui_main_window_state_callback( GtkWidget* window, GtkStateFlags old_flags, gpointer user_data )
1111 : {
1112 0 : U8_TRACE_BEGIN();
1113 0 : gui_main_window_t *this_ = user_data;
1114 :
1115 : /* GTK_STATE_FLAG_ACTIVE is close to what is needed */
1116 : /* but it is sometimes not called when window loses focus */
1117 : /* and it is sometimes activated multiple times when window gains focus */
1118 :
1119 0 : GtkStateFlags new_flags = gtk_widget_get_state_flags ( window );
1120 0 : GtkStateFlags changed = old_flags ^ new_flags;
1121 :
1122 0 : if ( 0 != ( changed & GTK_STATE_FLAG_BACKDROP ) )
1123 : {
1124 0 : U8_TRACE_INFO_INT("GTK_STATE_FLAGS & GTK_STATE_FLAG_BACKDROP:", changed & GTK_STATE_FLAG_BACKDROP );
1125 :
1126 : /* check if latest changes are already saved */
1127 0 : const bool is_saved = io_data_file_is_in_sync( (*this_).data_file );
1128 :
1129 : /* update the icon of the save button */
1130 0 : GtkImage *const save_image = gui_button_get_icon_ptr( &((*this_).file_save) );
1131 0 : const GdkPaintable *const shown_icon = gtk_image_get_paintable( save_image );
1132 :
1133 0 : GdkPaintable *const current_icon
1134 : = is_saved
1135 0 : ? GDK_PAINTABLE( gui_resources_get_file_saved( (*this_).resources ) )
1136 0 : : ( 0 != ( new_flags & GTK_STATE_FLAG_BACKDROP ) )
1137 0 : ? GDK_PAINTABLE( gui_resources_get_file_unsaved( (*this_).resources ) )
1138 0 : : GDK_PAINTABLE( gui_resources_get_file_save( (*this_).resources ) );
1139 :
1140 : /* update the save button status indicator */
1141 0 : if ( shown_icon != current_icon )
1142 : {
1143 0 : gtk_image_set_from_paintable( save_image, current_icon );
1144 0 : U8_TRACE_INFO("icon of save button updated");
1145 : }
1146 : // U8_TRACE_FLUSH();
1147 : }
1148 :
1149 0 : U8_TRACE_TIMESTAMP();
1150 0 : U8_TRACE_END();
1151 0 : }
1152 :
1153 :
1154 : /*
1155 : Copyright 2016-2025 Andreas Warnke
1156 :
1157 : Licensed under the Apache License, Version 2.0 (the "License");
1158 : you may not use this file except in compliance with the License.
1159 : You may obtain a copy of the License at
1160 :
1161 : http://www.apache.org/licenses/LICENSE-2.0
1162 :
1163 : Unless required by applicable law or agreed to in writing, software
1164 : distributed under the License is distributed on an "AS IS" BASIS,
1165 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1166 : See the License for the specific language governing permissions and
1167 : limitations under the License.
1168 : */
|