Line data Source code
1 : /* File: gui_sketch_area.c; Copyright and License: see below */
2 :
3 : #include "sketch/gui_sketch_area.h"
4 : #include "gui_sketch_card_layouter.h"
5 : #include "gui_tool.h"
6 : #include "pencil_diagram_maker.h"
7 : #include "geometry/geometry_rectangle.h"
8 : #include "data_table.h"
9 : #include "data_id.h"
10 : #include "u8/u8_trace.h"
11 : #include "u8/u8_log.h"
12 : #include <gdk/gdk.h>
13 : #include <gtk/gtk.h>
14 : #include <stdint.h>
15 : #include <stdbool.h>
16 :
17 0 : void gui_sketch_area_init( gui_sketch_area_t *this_,
18 : GtkWidget *drawing_area,
19 : gui_marked_set_t *marker,
20 : gui_toolbox_t *toolbox,
21 : gui_simple_message_to_user_t *message_to_user,
22 : gui_resources_t *resources,
23 : ctrl_controller_t *controller,
24 : data_database_reader_t *db_reader )
25 : {
26 0 : U8_TRACE_BEGIN();
27 0 : assert( NULL != drawing_area );
28 0 : assert( NULL != marker );
29 0 : assert( NULL != toolbox );
30 0 : assert( NULL != message_to_user );
31 0 : assert( NULL != resources );
32 0 : assert( NULL != controller );
33 0 : assert( NULL != db_reader );
34 :
35 : /* init pointers to external objects */
36 0 : (*this_).drawing_area = drawing_area;
37 0 : (*this_).toolbox = toolbox;
38 0 : (*this_).message_to_user = message_to_user;
39 0 : (*this_).resources = resources;
40 0 : (*this_).db_reader = db_reader;
41 0 : (*this_).controller = controller;
42 :
43 : /* init instance of requested tool-mode and diagram-ids */
44 0 : gui_sketch_request_init( &((*this_).request) );
45 :
46 : /* init instances of own objects */
47 0 : (*this_).card_num = 0;
48 0 : (*this_).marker = marker;
49 0 : gui_sketch_texture_init( &((*this_).texture_downloader) );
50 0 : gui_sketch_nav_tree_init( &((*this_).nav_tree), resources, &((*this_).texture_downloader) );
51 0 : gui_sketch_result_list_init( &((*this_).result_list), resources, &((*this_).texture_downloader) );
52 0 : gui_sketch_drag_state_init ( &((*this_).drag_state) );
53 0 : gui_sketch_overlay_init( &((*this_).overlay) );
54 0 : gui_sketch_background_init( &((*this_).background), resources, &((*this_).texture_downloader) );
55 0 : gui_sketch_object_creator_init ( &((*this_).object_creator), controller, db_reader, message_to_user );
56 :
57 : /* connect draw/update and mouse move and key signals to the controllers of this widget */
58 0 : gtk_drawing_area_set_draw_func( GTK_DRAWING_AREA((*this_).drawing_area),
59 : (GtkDrawingAreaDrawFunc) gui_sketch_area_draw_callback,
60 : this_,
61 : NULL
62 : );
63 0 : gtk_widget_set_sensitive( (*this_).drawing_area, true );
64 0 : gtk_widget_set_can_focus( (*this_).drawing_area, true );
65 0 : gtk_widget_set_focusable( (*this_).drawing_area, true );
66 0 : gtk_widget_set_can_target( (*this_).drawing_area, true );
67 0 : gtk_widget_set_focus_on_click( (*this_).drawing_area, true );
68 :
69 0 : GtkEventController *evt_move = gtk_event_controller_motion_new();
70 0 : g_signal_connect( evt_move, "enter", G_CALLBACK(gui_sketch_area_motion_notify_callback), this_ );
71 0 : g_signal_connect( evt_move, "motion", G_CALLBACK(gui_sketch_area_motion_notify_callback), this_ );
72 0 : g_signal_connect( evt_move, "leave", G_CALLBACK(gui_sketch_area_leave_notify_callback), this_ );
73 0 : gtk_widget_add_controller( (*this_).drawing_area, GTK_EVENT_CONTROLLER(evt_move) );
74 :
75 0 : GtkEventController *evt_key = gtk_event_controller_key_new();
76 0 : g_signal_connect( evt_key, "key-pressed", G_CALLBACK(gui_sketch_area_key_press_callback), this_ );
77 : /*
78 : g_signal_connect( evt_key, "modifiers", G_CALLBACK(gui_sketch_area_key_callback), this_ );
79 : g_signal_connect( evt_key, "key-released", G_CALLBACK(gui_sketch_area_key_release_callback), this_ );
80 : */
81 0 : gtk_widget_add_controller( (*this_).drawing_area, GTK_EVENT_CONTROLLER(evt_key) );
82 :
83 0 : GtkGesture *evt_button = gtk_gesture_click_new();
84 0 : g_signal_connect( evt_button, "pressed", G_CALLBACK(gui_sketch_area_button_press_callback), this_ );
85 0 : g_signal_connect( evt_button, "released", G_CALLBACK(gui_sketch_area_button_release_callback), this_ );
86 0 : gtk_widget_add_controller( (*this_).drawing_area, GTK_EVENT_CONTROLLER(evt_button) );
87 :
88 : /* fetch initial data from the database */
89 0 : gui_sketch_area_show_diagram( this_, DATA_ID_VOID );
90 :
91 0 : U8_TRACE_END();
92 0 : }
93 :
94 0 : void gui_sketch_area_destroy( gui_sketch_area_t *this_ )
95 : {
96 0 : U8_TRACE_BEGIN();
97 :
98 : /* destroy instances of own objects */
99 0 : gui_sketch_result_list_destroy( &((*this_).result_list) );
100 0 : gui_sketch_nav_tree_destroy( &((*this_).nav_tree) );
101 :
102 : /* destroy all cards */
103 0 : for ( int idx = 0; idx < (*this_).card_num; idx ++ )
104 : {
105 0 : gui_sketch_card_destroy( &((*this_).cards[idx]) );
106 : }
107 0 : (*this_).card_num = 0;
108 :
109 : /* destroy instances of own objects */
110 0 : gui_sketch_object_creator_destroy ( &((*this_).object_creator) );
111 0 : gui_sketch_overlay_destroy( &((*this_).overlay) );
112 0 : gui_sketch_background_destroy( &((*this_).background) );
113 0 : gui_sketch_drag_state_destroy ( &((*this_).drag_state) );
114 0 : gui_sketch_texture_destroy( &((*this_).texture_downloader) );
115 :
116 : /* destroy instance of requested tool-mode and diagram-ids */
117 0 : gui_sketch_request_destroy( &((*this_).request) );
118 :
119 : /* unset pointers to external objects */
120 0 : (*this_).drawing_area = NULL;
121 0 : (*this_).marker = NULL;
122 0 : (*this_).toolbox = NULL;
123 0 : (*this_).message_to_user = NULL;
124 0 : (*this_).resources = NULL;
125 0 : (*this_).db_reader = NULL;
126 0 : (*this_).controller = NULL;
127 :
128 0 : U8_TRACE_END();
129 0 : }
130 :
131 0 : void gui_sketch_area_show_result_list ( gui_sketch_area_t *this_, const data_search_result_list_t *result_list )
132 : {
133 0 : U8_TRACE_BEGIN();
134 0 : assert( NULL != result_list );
135 :
136 0 : data_search_result_list_trace(result_list);
137 :
138 : /* copy non-duplicate diagram ids to request list */
139 0 : data_small_set_t* requested_diagrams = gui_sketch_request_get_search_result_diagrams_ptr( &((*this_).request) );
140 0 : data_small_set_clear( requested_diagrams );
141 0 : unsigned int dropped_duplicates = 0;
142 0 : unsigned int dropped_too_many = 0;
143 0 : const uint_fast32_t d_count = data_search_result_list_get_length( result_list );
144 0 : for ( uint_fast32_t index = 0; index < d_count; index ++ )
145 : {
146 0 : const data_search_result_t *diag_rec = data_search_result_list_get_const( result_list, index );
147 0 : const data_id_t diag_id = data_search_result_get_diagram_id( diag_rec );
148 0 : const u8_error_t d_err = data_small_set_add_obj( requested_diagrams, diag_id );
149 0 : if ( d_err == U8_ERROR_DUPLICATE_ID )
150 : {
151 0 : dropped_duplicates ++;
152 : }
153 0 : else if ( d_err == U8_ERROR_ARRAY_BUFFER_EXCEEDED )
154 : {
155 0 : dropped_too_many ++;
156 : }
157 : }
158 0 : if ( (dropped_duplicates + dropped_too_many) > 0 )
159 : {
160 0 : U8_TRACE_INFO_INT_INT( "dropped_duplicates, dropped_too_many:", dropped_duplicates, dropped_too_many );
161 : }
162 :
163 : /* load new data */
164 0 : gui_sketch_area_private_load_cards_data ( this_ );
165 :
166 : /* load new data in subwidgets */
167 0 : gui_sketch_result_list_load_data( &((*this_).result_list), result_list, (*this_).db_reader );
168 :
169 : /* notify listener */
170 0 : gui_marked_set_clear_focused( (*this_).marker );
171 0 : gui_marked_set_clear_selected_set( (*this_).marker );
172 :
173 : /* mark dirty rect */
174 0 : gtk_widget_queue_draw( (*this_).drawing_area );
175 :
176 0 : U8_TRACE_END();
177 0 : }
178 :
179 0 : void gui_sketch_area_draw_callback( GtkDrawingArea *widget, cairo_t *cr, int width, int height, gpointer data )
180 : {
181 0 : U8_TRACE_BEGIN();
182 0 : U8_TRACE_TIMESTAMP();
183 0 : assert( NULL != cr );
184 0 : gui_sketch_area_t *this_ = data;
185 0 : assert( NULL != this_ );
186 0 : assert( GTK_WIDGET(widget) == (*this_).drawing_area );
187 :
188 0 : gui_sketch_area_draw( this_, width, height, cr );
189 :
190 0 : U8_TRACE_END();
191 0 : }
192 :
193 0 : void gui_sketch_area_draw( gui_sketch_area_t *this_, int width, int height, cairo_t *cr )
194 : {
195 0 : U8_TRACE_BEGIN();
196 0 : assert( NULL != cr );
197 :
198 0 : if ( ! data_database_reader_is_open( (*this_).db_reader ) )
199 : {
200 : shape_int_rectangle_t bounds;
201 0 : shape_int_rectangle_init( &bounds, 0, 0, width, height );
202 0 : gui_sketch_background_set_bounds( &((*this_).background), bounds );
203 0 : gui_sketch_background_draw_introduction( &((*this_).background), cr );
204 : }
205 : else
206 : {
207 : shape_int_rectangle_t bounds;
208 0 : shape_int_rectangle_init( &bounds, 0, 0, width, height );
209 0 : if ( ! gui_sketch_drag_state_is_dragging ( &((*this_).drag_state) ) )
210 : {
211 0 : gui_sketch_area_private_layout_subwidgets( this_, bounds, cr );
212 : }
213 0 : gui_sketch_area_private_draw_subwidgets( this_, bounds, cr );
214 : }
215 :
216 0 : U8_TRACE_END();
217 0 : }
218 :
219 0 : void gui_sketch_area_show_diagram ( gui_sketch_area_t *this_, data_id_t main_diagram_id )
220 : {
221 0 : U8_TRACE_BEGIN();
222 :
223 0 : data_id_trace( &main_diagram_id );
224 : const uint32_t src_results_cnt
225 0 : = data_small_set_get_count( gui_sketch_request_get_search_result_diagrams_const( &((*this_).request) ) );
226 0 : U8_TRACE_INFO_INT( "src_results_cnt:", src_results_cnt );
227 :
228 : /* determine diagram id of root diagram */
229 0 : if ( ! data_id_is_valid( &main_diagram_id ) )
230 : {
231 : /* load all without parent */
232 : data_small_set_t roots;
233 0 : data_small_set_init( &roots );
234 : const u8_error_t db_err
235 0 : = data_database_reader_get_diagram_ids_by_parent_id( (*this_).db_reader,
236 : DATA_ROW_ID_VOID,
237 : &roots
238 : );
239 0 : const uint32_t count = data_small_set_get_count( &roots );
240 0 : if ( u8_error_contains( db_err, U8_ERROR_NO_DB ) )
241 : {
242 0 : U8_TRACE_INFO( "database not open.");
243 : }
244 0 : else if ( U8_ERROR_NONE != db_err )
245 : {
246 0 : U8_LOG_ERROR_HEX( "data_database_reader_get_diagrams_by_parent_id failed.", db_err );
247 : }
248 0 : else if ( count > 1 )
249 : {
250 0 : U8_LOG_ERROR_INT( "more than one root diagram exists!", count );
251 : }
252 0 : else if ( count < 1 )
253 : {
254 0 : U8_TRACE_INFO( "no root diagram exists!" );
255 : }
256 : else
257 : {
258 0 : main_diagram_id = data_small_set_get_id( &roots, 0 );
259 0 : U8_TRACE_INFO_INT( "main_diagram_id:", data_id_get_row_id( &main_diagram_id ));
260 : }
261 :
262 : /* cleanup */
263 0 : data_small_set_destroy( &roots );
264 : }
265 :
266 : /* store request */
267 0 : gui_sketch_request_set_focused_diagram( &((*this_).request), main_diagram_id );
268 :
269 : /* load data to be drawn */
270 0 : gui_sketch_area_private_load_cards_data ( this_ );
271 :
272 0 : U8_TRACE_END();
273 0 : }
274 :
275 0 : void gui_sketch_area_private_refocus_and_reload_data ( gui_sketch_area_t *this_ )
276 : {
277 0 : U8_TRACE_BEGIN();
278 :
279 : /* determine currently selected diagram id and parent id from cache for emergency-fallback */
280 0 : const data_id_t former_diagram_id = gui_sketch_request_get_focused_diagram( &((*this_).request) );
281 0 : const data_id_t former_parent_diagram_id = gui_sketch_request_get_parent_diagram( &((*this_).request) );
282 :
283 : /* reload diagram data */
284 0 : gui_sketch_area_show_diagram( this_, former_diagram_id );
285 :
286 0 : if ( GUI_TOOL_SEARCH != gui_sketch_request_get_tool_mode( &((*this_).request) ) )
287 : {
288 0 : if ( data_id_is_valid( &former_diagram_id )
289 0 : &&( DATA_ROW_ID_VOID == gui_sketch_area_private_get_focused_diagram_id( this_ ) ))
290 : {
291 : /* the requested diagram was not loaded, try the parent: */
292 0 : gui_sketch_area_show_diagram( this_, former_parent_diagram_id );
293 :
294 0 : if ( data_id_is_valid( &former_parent_diagram_id )
295 0 : &&( DATA_ROW_ID_VOID == gui_sketch_area_private_get_focused_diagram_id( this_ ) ))
296 : {
297 : /* the requested diagram was not loaded, go back to root diagram: */
298 0 : gui_sketch_area_show_diagram( this_, DATA_ID_VOID );
299 : }
300 :
301 : /* clear the selected set */
302 0 : gui_marked_set_clear_selected_set( (*this_).marker );
303 : }
304 : }
305 :
306 0 : U8_TRACE_END();
307 0 : }
308 :
309 0 : void gui_sketch_area_private_load_cards_data ( gui_sketch_area_t *this_ )
310 : {
311 0 : U8_TRACE_BEGIN();
312 :
313 : /* destroy _all_ old cards */
314 0 : for ( uint_fast32_t idx = 0; idx < (*this_).card_num; idx ++ )
315 : {
316 0 : gui_sketch_card_destroy( &((*this_).cards[idx]) );
317 : }
318 0 : (*this_).card_num = 0;
319 :
320 : /* load new cards */
321 0 : switch ( gui_sketch_request_get_tool_mode( &((*this_).request) ) )
322 : {
323 0 : case GUI_TOOL_SEARCH:
324 : {
325 : const data_small_set_t* requested_diagrams
326 0 : = gui_sketch_request_get_search_result_diagrams_const( &((*this_).request) );
327 :
328 0 : const uint_fast32_t d_count = data_small_set_get_count( requested_diagrams );
329 0 : for ( uint_fast32_t index = 0; index < d_count; index ++ )
330 : {
331 0 : const data_id_t diag_id = data_small_set_get_id( requested_diagrams, index );
332 0 : if ( (*this_).card_num < GUI_SKETCH_AREA_CONST_MAX_CARDS )
333 : {
334 0 : gui_sketch_card_init( &((*this_).cards[(*this_).card_num]) );
335 0 : gui_sketch_card_load_data( &((*this_).cards[(*this_).card_num]), diag_id, (*this_).db_reader );
336 0 : if ( gui_sketch_card_is_valid( &((*this_).cards[(*this_).card_num]) ) )
337 : {
338 0 : (*this_).card_num ++;
339 : }
340 : else
341 : {
342 0 : U8_TRACE_INFO_INT( "could not load diagram:", data_id_get_row_id(&diag_id) );
343 : }
344 : }
345 : else
346 : {
347 0 : U8_TRACE_INFO_INT( "max diagrams exeeded, dropping diagram:", data_id_get_row_id(&diag_id) );
348 : }
349 : }
350 : }
351 0 : break;
352 :
353 0 : default:
354 : {
355 0 : const data_id_t main_diagram_id = gui_sketch_request_get_focused_diagram( &((*this_).request) );
356 :
357 0 : gui_sketch_card_init( &((*this_).cards[GUI_SKETCH_AREA_CONST_FOCUSED_CARD]) );
358 0 : gui_sketch_card_load_data( &((*this_).cards[GUI_SKETCH_AREA_CONST_FOCUSED_CARD]), main_diagram_id, (*this_).db_reader );
359 0 : (*this_).card_num = 1;
360 0 : gui_sketch_nav_tree_load_data( &((*this_).nav_tree), data_id_get_row_id( &main_diagram_id ), (*this_).db_reader );
361 :
362 : /* determine ids */
363 0 : const data_diagram_t *selected_diag = gui_sketch_area_private_get_focused_diagram_ptr( this_ );
364 0 : const data_row_id_t selected_diagram_row_id = data_diagram_get_row_id( selected_diag );
365 0 : const data_id_t selected_diagram_id = data_diagram_get_data_id( selected_diag );
366 0 : U8_TRACE_INFO_INT( "selected_diagram_row_id:", selected_diagram_row_id );
367 0 : const data_id_t parent_diagram_id = data_diagram_get_parent_data_id( selected_diag );
368 0 : U8_TRACE_INFO_INT( "parent_diagram_id:", data_id_get_row_id( &parent_diagram_id ) );
369 :
370 0 : const data_id_t former_focused_diag = gui_marked_set_get_focused_diagram( (*this_).marker);
371 0 : gui_sketch_request_set_parent_diagram( &((*this_).request), parent_diagram_id );
372 0 : if ( ! data_id_equals_or_both_void( &former_focused_diag, &selected_diagram_id ) )
373 : {
374 : /* clear focused but keep selected_diagram_id, needed for gui_toolbox_paste */
375 0 : gui_marked_set_set_focused( (*this_).marker, DATA_FULL_ID_VOID, selected_diagram_id );
376 : }
377 : else
378 : {
379 : /* DO NOT NOTIFY CHANGES IN A POSSIBLE DATA CHANGE CALLBACK - MAY CAUSE ENDLESS RECURSION */
380 : }
381 :
382 : const gui_tool_t selected_tool
383 0 : = gui_sketch_request_get_tool_mode( &((*this_).request) );
384 0 : if ( GUI_TOOL_NAVIGATE == selected_tool )
385 : {
386 :
387 : /* load parent even if there is no parent (-->VOID) */
388 0 : gui_sketch_card_init( &((*this_).cards[GUI_SKETCH_AREA_CONST_PARENT_CARD]) );
389 0 : gui_sketch_card_load_data( &((*this_).cards[GUI_SKETCH_AREA_CONST_PARENT_CARD]), parent_diagram_id, (*this_).db_reader );
390 0 : (*this_).card_num = 2;
391 :
392 : /* load all children (up to GUI_SKETCH_AREA_CONST_MAX_TEMP_DIAGRAMS)*/
393 : data_small_set_t children;
394 0 : data_small_set_init( &children );
395 : const u8_error_t db_err
396 0 : = data_database_reader_get_diagram_ids_by_parent_id( (*this_).db_reader,
397 : selected_diagram_row_id,
398 : &children
399 : );
400 0 : if ( u8_error_contains( db_err, U8_ERROR_NO_DB ) )
401 : {
402 0 : U8_TRACE_INFO( "database not open.");
403 : }
404 0 : else if ( U8_ERROR_NONE != db_err )
405 : {
406 0 : U8_LOG_ERROR_HEX( "data_database_reader_get_diagram_ids_by_parent_id failed.", db_err );
407 : }
408 : else
409 : {
410 0 : for ( uint_fast32_t index = 0; index < data_small_set_get_count( &children ); index ++ )
411 : {
412 0 : const data_id_t child = data_small_set_get_id( &children, index );
413 0 : if ( (*this_).card_num < GUI_SKETCH_AREA_CONST_MAX_CARDS )
414 : {
415 0 : gui_sketch_card_init( &((*this_).cards[(*this_).card_num]) );
416 0 : gui_sketch_card_load_data( &((*this_).cards[(*this_).card_num]), child, (*this_).db_reader );
417 0 : (*this_).card_num ++;
418 : }
419 : else
420 : {
421 0 : U8_LOG_ERROR_INT( "more children diagrams exist than fit into cards array:", data_id_get_row_id( &child ) );
422 : }
423 : }
424 : }
425 : /* cleanup */
426 0 : data_small_set_destroy( &children );
427 : }
428 :
429 : }
430 0 : break;
431 : }
432 :
433 0 : U8_TRACE_END();
434 0 : }
435 :
436 : static const uint32_t NAV_TREE_WIDTH = 224;
437 : static const uint32_t RESULT_LIST_WIDTH = 240;
438 :
439 0 : void gui_sketch_area_private_layout_subwidgets ( gui_sketch_area_t *this_, shape_int_rectangle_t area_bounds, cairo_t *cr )
440 : {
441 0 : U8_TRACE_BEGIN();
442 0 : assert( NULL != cr );
443 0 : assert((*this_).card_num <= GUI_SKETCH_AREA_CONST_MAX_CARDS);
444 :
445 : gui_tool_t selected_tool;
446 0 : selected_tool = gui_sketch_request_get_tool_mode( &((*this_).request) );
447 :
448 : /* fetch area bounds */
449 0 : const uint32_t width = shape_int_rectangle_get_width( &area_bounds );
450 0 : const uint32_t height = shape_int_rectangle_get_height( &area_bounds );
451 0 : const int32_t left = shape_int_rectangle_get_left( &area_bounds );
452 0 : const int32_t top = shape_int_rectangle_get_top( &area_bounds );
453 0 : U8_TRACE_INFO_INT_INT( "width, height", width, height );
454 :
455 : /* layout result list */
456 0 : const bool result_list_visible = ( GUI_TOOL_SEARCH == selected_tool );
457 : {
458 : shape_int_rectangle_t result_list_bounds;
459 0 : shape_int_rectangle_init( &result_list_bounds, left, top, RESULT_LIST_WIDTH, height );
460 0 : gui_sketch_result_list_set_bounds( &((*this_).result_list ), result_list_bounds );
461 0 : gui_sketch_result_list_set_visible( &((*this_).result_list), result_list_visible );
462 0 : if ( result_list_visible )
463 : {
464 0 : gui_sketch_result_list_do_layout( &((*this_).result_list), cr );
465 : }
466 : }
467 :
468 : /* layout nav tree */
469 0 : const bool nav_tree_visible = ( GUI_TOOL_NAVIGATE == selected_tool );
470 : {
471 : shape_int_rectangle_t nav_tree_bounds;
472 0 : shape_int_rectangle_init( &nav_tree_bounds, left, top, NAV_TREE_WIDTH, height );
473 0 : gui_sketch_nav_tree_set_bounds( &((*this_).nav_tree), nav_tree_bounds );
474 0 : gui_sketch_nav_tree_set_visible( &((*this_).nav_tree), nav_tree_visible );
475 0 : if ( nav_tree_visible )
476 : {
477 0 : gui_sketch_nav_tree_do_layout( &((*this_).nav_tree), cr );
478 : }
479 : }
480 :
481 : /* layout cards */
482 0 : const int32_t cards_left = left + (nav_tree_visible ? NAV_TREE_WIDTH : (result_list_visible ? RESULT_LIST_WIDTH : 0 ));
483 0 : const uint32_t cards_width = (width > (cards_left-left)) ? (width - (cards_left-left)) : 0;
484 : {
485 : shape_int_rectangle_t cards_bounds;
486 0 : shape_int_rectangle_init( &cards_bounds, cards_left, top, cards_width, height );
487 : gui_sketch_card_layouter_t cards_layouter;
488 0 : gui_sketch_card_layouter_init ( &cards_layouter, &cards_bounds );
489 0 : gui_sketch_card_layouter_layout ( &cards_layouter, selected_tool, &((*this_).cards[0]), (*this_).card_num, cr );
490 0 : gui_sketch_card_layouter_destroy ( &cards_layouter );
491 : }
492 :
493 : /* layout background */
494 : {
495 : shape_int_rectangle_t background_bounds;
496 0 : shape_int_rectangle_init( &background_bounds, cards_left, top, cards_width, height );
497 0 : gui_sketch_background_set_bounds( &((*this_).background), background_bounds );
498 : }
499 :
500 0 : U8_TRACE_END();
501 0 : }
502 :
503 0 : void gui_sketch_area_private_draw_subwidgets ( gui_sketch_area_t *this_, shape_int_rectangle_t area_bounds, cairo_t *cr )
504 : {
505 0 : U8_TRACE_BEGIN();
506 0 : assert( NULL != cr );
507 :
508 0 : const gui_tool_t selected_tool = gui_sketch_request_get_tool_mode( &((*this_).request) );
509 :
510 : /* draw background */
511 0 : switch( selected_tool )
512 : {
513 0 : case GUI_TOOL_SEARCH:
514 : {
515 0 : gui_sketch_background_draw_search( &((*this_).background), cr );
516 : }
517 0 : break;
518 :
519 0 : case GUI_TOOL_NAVIGATE:
520 : {
521 0 : const unsigned int depth
522 0 : = ( gui_sketch_card_is_valid( &((*this_).cards[GUI_SKETCH_AREA_CONST_PARENT_CARD]) ) ) ? 1 : 0; /* currently, only root and non-root can be distinguished */
523 0 : const unsigned int children
524 0 : = (*this_).card_num-2;
525 0 : gui_sketch_background_draw_navigation( &((*this_).background), depth, children, cr );
526 : }
527 0 : break;
528 :
529 0 : case GUI_TOOL_EDIT:
530 : {
531 0 : gui_sketch_background_draw_edit( &((*this_).background), cr );
532 : }
533 0 : break;
534 :
535 0 : case GUI_TOOL_CREATE:
536 : {
537 0 : gui_sketch_background_draw_create( &((*this_).background), cr );
538 : }
539 0 : break;
540 :
541 0 : default:
542 : {
543 0 : assert(false);
544 : }
545 : break;
546 : }
547 :
548 : /* draw result list */
549 : {
550 0 : gui_sketch_result_list_draw( &((*this_).result_list), (*this_).marker, cr );
551 : }
552 :
553 : /* draw nav tree */
554 : {
555 0 : gui_sketch_nav_tree_draw( &((*this_).nav_tree), (*this_).marker, cr );
556 : }
557 :
558 : /* draw all cards, backwards */
559 0 : for ( signed int card_idx = (*this_).card_num-1; card_idx >= 0; card_idx -- )
560 : {
561 0 : gui_sketch_card_draw( &((*this_).cards[card_idx]), (*this_).marker, cr );
562 : }
563 :
564 : /* overlay tool-helper lines */
565 0 : const int32_t mouse_x = gui_sketch_drag_state_get_to_x( &((*this_).drag_state) );
566 0 : const int32_t mouse_y = gui_sketch_drag_state_get_to_y( &((*this_).drag_state) );
567 0 : gui_sketch_overlay_draw( &((*this_).overlay),
568 : selected_tool,
569 0 : &((*this_).drag_state),
570 0 : gui_sketch_area_private_get_card_at_pos ( this_, mouse_x, mouse_y ),
571 0 : &((*this_).nav_tree),
572 : (*this_).marker,
573 : cr
574 : );
575 :
576 0 : U8_TRACE_END();
577 0 : }
578 :
579 0 : void gui_sketch_area_leave_notify_callback( GtkEventControllerMotion* self, gpointer user_data )
580 : {
581 0 : U8_TRACE_BEGIN();
582 0 : U8_TRACE_TIMESTAMP();
583 0 : gui_sketch_area_t *this_ = user_data;
584 0 : assert( NULL != this_ );
585 :
586 0 : gui_marked_set_clear_highlighted( (*this_).marker );
587 : /* mark dirty rect */
588 0 : gtk_widget_queue_draw( (*this_).drawing_area );
589 :
590 0 : U8_TRACE_END();
591 0 : }
592 :
593 0 : void gui_sketch_area_motion_notify_callback( GtkEventControllerMotion* self,
594 : gdouble in_x,
595 : gdouble in_y,
596 : gpointer user_data )
597 : {
598 0 : U8_TRACE_BEGIN();
599 0 : gui_sketch_area_t *this_ = user_data;
600 0 : assert( NULL != this_ );
601 :
602 0 : gui_sketch_area_motion_notify( this_, (int)in_x, (int)in_y );
603 :
604 0 : U8_TRACE_END();
605 0 : }
606 :
607 0 : void gui_sketch_area_motion_notify( gui_sketch_area_t *this_, int x, int y )
608 : {
609 0 : U8_TRACE_BEGIN();
610 0 : U8_TRACE_INFO_INT_INT( "x/y", x, y );
611 :
612 : /* update drag coordinates */
613 0 : gui_sketch_drag_state_set_to ( &((*this_).drag_state), x, y );
614 :
615 : /* do highlight */
616 0 : const gui_tool_t selected_tool = gui_sketch_request_get_tool_mode( &((*this_).request) );
617 0 : switch ( selected_tool )
618 : {
619 0 : case GUI_TOOL_SEARCH: /* or */
620 : case GUI_TOOL_NAVIGATE:
621 : {
622 0 : if ( gui_sketch_drag_state_is_dragging ( &((*this_).drag_state) ) )
623 : {
624 : /* always redraw while dragging */
625 0 : gtk_widget_queue_draw( (*this_).drawing_area );
626 : }
627 : else /* not dragging */
628 : {
629 0 : data_id_t object_under_mouse = DATA_ID_VOID;
630 0 : data_id_t diag_under_mouse = DATA_ID_VOID;
631 0 : gui_sketch_area_private_get_diagram_and_object_id_at_pos ( this_, x, y, &diag_under_mouse, &object_under_mouse );
632 0 : gui_sketch_action_t btn_under_mouse = GUI_SKETCH_ACTION_NONE;
633 0 : if ( selected_tool == GUI_TOOL_NAVIGATE )
634 : {
635 0 : gui_sketch_nav_tree_get_button_at_pos( &((*this_).nav_tree), x, y, &btn_under_mouse );
636 : }
637 :
638 : const data_id_t object_highlighted
639 0 : = gui_marked_set_get_highlighted( (*this_).marker );
640 : const data_id_t diag_highlighted
641 0 : = gui_marked_set_get_highlighted_diagram( (*this_).marker );
642 : const gui_sketch_action_t btn_highlighted
643 0 : = gui_marked_set_get_highlighted_button( (*this_).marker );
644 0 : const bool obj_both_void
645 0 : = ( ! data_id_is_valid( &object_under_mouse ) )&&( ! data_id_is_valid( &object_highlighted ) );
646 0 : const bool obj_equal_or_both_void
647 0 : = data_id_equals( &object_under_mouse, &object_highlighted ) || obj_both_void;
648 0 : const bool diag_both_void
649 0 : = ( ! data_id_is_valid( &diag_under_mouse ) )&&( ! data_id_is_valid( &diag_highlighted ) );
650 0 : const bool diag_equal_or_both_void
651 0 : = data_id_equals( &diag_under_mouse, &diag_highlighted ) || diag_both_void;
652 0 : const bool btn_changed = ( btn_under_mouse != btn_highlighted );
653 0 : if (( btn_under_mouse != GUI_SKETCH_ACTION_NONE )&&( btn_changed ))
654 : {
655 : /* highlighted button is activated and has changed */
656 0 : gui_marked_set_set_highlighted_button( (*this_).marker, btn_under_mouse );
657 :
658 : /* mark dirty rect */
659 0 : gtk_widget_queue_draw( (*this_).drawing_area );
660 : }
661 0 : else if (( ! obj_equal_or_both_void )||( ! diag_equal_or_both_void )||( btn_changed ))
662 : {
663 : /* highlight changed */
664 0 : gui_marked_set_set_highlighted( (*this_).marker, object_under_mouse, diag_under_mouse );
665 :
666 : /* mark dirty rect */
667 0 : gtk_widget_queue_draw( (*this_).drawing_area );
668 : }
669 : }
670 : }
671 0 : break;
672 :
673 0 : case GUI_TOOL_EDIT:
674 : {
675 0 : if ( gui_sketch_drag_state_is_dragging ( &((*this_).drag_state) ) )
676 : {
677 : /* what is dragged? */
678 : const data_full_id_t *const dragged_object
679 0 : = gui_sketch_drag_state_get_dragged_object_ptr ( &((*this_).drag_state) );
680 : const data_id_t dragged_element
681 0 : = data_full_id_get_primary_id( dragged_object );
682 : const data_id_t dragged_classifier
683 0 : = data_full_id_get_secondary_id( dragged_object );
684 :
685 : /* what is the target location? */
686 0 : gui_sketch_card_t *target_card = gui_sketch_area_private_get_card_at_pos ( this_, x, y );
687 0 : if ( NULL != target_card )
688 : {
689 : /* mark again - in case the marker was lost when mouse was outside window */
690 0 : const data_id_t diag_id = gui_sketch_card_get_diagram_id( target_card );
691 0 : gui_marked_set_set_highlighted( (*this_).marker, dragged_element, diag_id );
692 :
693 : layout_order_t layout_order;
694 0 : if ( DATA_TABLE_DIAGRAMELEMENT == data_id_get_table( &dragged_element ) )
695 : {
696 0 : layout_order = gui_sketch_card_get_order_at_pos( target_card, dragged_classifier, x, y );
697 0 : layout_order_trace( &layout_order );
698 0 : gui_sketch_card_move_object_to_order( target_card, dragged_classifier, &layout_order );
699 : }
700 : else
701 : {
702 0 : layout_order = gui_sketch_card_get_order_at_pos( target_card, dragged_element, x, y );
703 0 : layout_order_trace( &layout_order );
704 0 : gui_sketch_card_move_object_to_order( target_card, dragged_element, &layout_order );
705 : }
706 :
707 : /* mark dirty rect */
708 0 : gtk_widget_queue_draw( (*this_).drawing_area );
709 : }
710 : else
711 : {
712 0 : gui_marked_set_clear_highlighted( (*this_).marker );
713 0 : U8_TRACE_INFO( "mouse click outside sketch card." );
714 : }
715 : }
716 : else /* not dragging */
717 : {
718 : data_full_id_t object_under_mouse;
719 : data_id_t diag_id;
720 0 : gui_sketch_area_private_get_object_id_at_pos( this_,
721 : x,
722 : y,
723 : PENCIL_TYPE_FILTER_LIFELINE,
724 : &object_under_mouse,
725 : &diag_id
726 : );
727 : const data_id_t object_highlighted
728 0 : = gui_marked_set_get_highlighted( (*this_).marker );
729 : const data_id_t mouseover_element
730 0 : = data_full_id_get_primary_id( &object_under_mouse );
731 0 : if ( ! data_id_equals( &mouseover_element, &object_highlighted ) )
732 : {
733 0 : if ( data_full_id_is_valid( &object_under_mouse ) || data_id_is_valid( &object_highlighted ) )
734 : {
735 : /* highlight changed */
736 0 : gui_marked_set_set_highlighted( (*this_).marker, mouseover_element, diag_id );
737 :
738 : /* mark dirty rect */
739 0 : gtk_widget_queue_draw( (*this_).drawing_area );
740 : }
741 : }
742 : }
743 : }
744 0 : break;
745 :
746 0 : case GUI_TOOL_CREATE:
747 : {
748 : data_full_id_t object_under_mouse;
749 : data_id_t diag_id;
750 0 : gui_sketch_area_private_get_object_id_at_pos( this_,
751 : x,
752 : y,
753 : PENCIL_TYPE_FILTER_NONE,
754 : &object_under_mouse,
755 : &diag_id
756 : );
757 : const data_id_t classifier_under_mouse
758 0 : = data_full_id_get_primary_id( &object_under_mouse );
759 :
760 : const data_id_t object_highlighted
761 0 : = gui_marked_set_get_highlighted( (*this_).marker );
762 0 : if ( ! data_id_equals( &classifier_under_mouse, &object_highlighted ) )
763 : {
764 0 : if ( data_id_is_valid( &classifier_under_mouse ) || data_id_is_valid( &object_highlighted ) )
765 : {
766 0 : gui_marked_set_set_highlighted( (*this_).marker, classifier_under_mouse, diag_id );
767 :
768 : /* mark dirty rect */
769 0 : gtk_widget_queue_draw( (*this_).drawing_area );
770 : }
771 : }
772 0 : else if ( gui_sketch_drag_state_is_dragging ( &((*this_).drag_state) ) )
773 : {
774 : /* always redraw while dragging */
775 0 : gtk_widget_queue_draw( (*this_).drawing_area );
776 : }
777 : else
778 : {
779 : /* always redraw while moving the mouse to move the new-box-and-arrow icon */
780 0 : gtk_widget_queue_draw( (*this_).drawing_area );
781 : }
782 : }
783 0 : break;
784 :
785 0 : default:
786 : {
787 0 : U8_LOG_ERROR("selected_tool is out of range");
788 : }
789 0 : break;
790 : }
791 :
792 0 : U8_TRACE_END();
793 0 : }
794 :
795 0 : void gui_sketch_area_button_press_callback( GtkGestureClick* self,
796 : gint n_press,
797 : gdouble x,
798 : gdouble y,
799 : gpointer user_data )
800 : {
801 0 : U8_TRACE_BEGIN();
802 0 : U8_TRACE_TIMESTAMP();
803 0 : gui_sketch_area_t *this_ = user_data;
804 0 : assert( NULL != this_ );
805 :
806 0 : gui_sketch_area_button_press( this_, (int)x, (int)y );
807 :
808 0 : U8_TRACE_END();
809 0 : }
810 :
811 0 : void gui_sketch_area_button_press( gui_sketch_area_t *this_, int x, int y )
812 : {
813 0 : U8_TRACE_BEGIN();
814 :
815 : /* in general, hide the last message */
816 0 : gui_simple_message_to_user_hide( (*this_).message_to_user );
817 :
818 0 : U8_TRACE_INFO("press");
819 :
820 : /* cause the text edit widgets to lose the focus so that these can store the latest changes */
821 0 : gtk_widget_grab_focus( (*this_).drawing_area );
822 :
823 : /* get position */
824 0 : U8_TRACE_INFO_INT_INT( "x/y", x, y );
825 :
826 : /* check that drag state is false */
827 0 : if ( ( gui_sketch_drag_state_is_dragging( &((*this_).drag_state) ) )
828 0 : || ( gui_sketch_drag_state_is_waiting_for_move( &((*this_).drag_state) ) ) )
829 : {
830 0 : U8_LOG_ERROR("drag state indicates dragging - but button was not pressed before!");
831 : }
832 :
833 : /* update drag coordinates */
834 0 : gui_sketch_drag_state_set_from ( &((*this_).drag_state), x, y );
835 0 : gui_sketch_drag_state_set_to ( &((*this_).drag_state), x, y );
836 :
837 : /* do action */
838 0 : const gui_tool_t selected_tool = gui_sketch_request_get_tool_mode( &((*this_).request) );
839 0 : switch ( selected_tool )
840 : {
841 0 : case GUI_TOOL_NAVIGATE:
842 : {
843 0 : U8_TRACE_INFO( "GUI_TOOL_NAVIGATE" );
844 :
845 : /* determine clicked diagram */
846 0 : data_id_t clicked_diagram_id = DATA_ID_VOID;
847 0 : data_id_t clicked_object_id = DATA_ID_VOID;
848 0 : gui_sketch_area_private_get_diagram_and_object_id_at_pos ( this_, x, y, &clicked_diagram_id, &clicked_object_id );
849 0 : data_id_trace( &clicked_diagram_id );
850 0 : data_id_trace( &clicked_object_id );
851 :
852 : /* load diagram */
853 0 : if ( data_id_is_valid( &clicked_diagram_id ) )
854 : {
855 : /* update drag state */
856 : data_full_id_t dragged_object;
857 0 : data_full_id_init_solo ( &dragged_object, clicked_diagram_id );
858 0 : gui_sketch_drag_state_start_dragging_when_move ( &((*this_).drag_state), dragged_object );
859 : }
860 : else
861 : {
862 0 : U8_TRACE_INFO("invalid clicked object at gui_sketch_area_button_press_callback");
863 :
864 : gui_sketch_action_t action_button_id;
865 0 : gui_sketch_nav_tree_get_button_at_pos ( &((*this_).nav_tree), x, y, &action_button_id );
866 0 : if ( action_button_id != GUI_SKETCH_ACTION_NONE )
867 : {
868 : /* create a new diagram */
869 0 : u8_error_t c_result = U8_ERROR_NONE;
870 0 : data_row_id_t new_diag_id = DATA_ROW_ID_VOID;
871 :
872 : {
873 : const data_diagram_t *selected_diag;
874 0 : selected_diag = gui_sketch_nav_tree_get_diagram_ptr ( &((*this_).nav_tree) );
875 0 : switch ( action_button_id )
876 : {
877 0 : case GUI_SKETCH_ACTION_NEW_SIBLING_DIAGRAM:
878 : {
879 0 : assert( data_diagram_is_valid( selected_diag ) );
880 : data_row_id_t parent_diagram_id;
881 0 : parent_diagram_id = data_diagram_get_parent_row_id( selected_diag );
882 : int32_t list_order;
883 0 : list_order = gui_sketch_nav_tree_get_siblings_highest_order ( &((*this_).nav_tree) );
884 :
885 :
886 0 : c_result = gui_sketch_object_creator_create_diagram( &((*this_).object_creator),
887 : parent_diagram_id,
888 : list_order + 32768,
889 : &new_diag_id
890 : );
891 : }
892 0 : break;
893 :
894 0 : case GUI_SKETCH_ACTION_NEW_CHILD_DIAGRAM:
895 : {
896 0 : assert( data_diagram_is_valid( selected_diag ) );
897 : data_row_id_t selected_diagram_id;
898 0 : selected_diagram_id = data_diagram_get_row_id( selected_diag );
899 : int32_t list_order;
900 0 : list_order = gui_sketch_nav_tree_get_children_highest_order ( &((*this_).nav_tree) );
901 0 : c_result = gui_sketch_object_creator_create_diagram( &((*this_).object_creator),
902 : selected_diagram_id,
903 : list_order + 32768,
904 : &new_diag_id
905 : );
906 : }
907 0 : break;
908 :
909 0 : case GUI_SKETCH_ACTION_NEW_ROOT_DIAGRAM:
910 : {
911 0 : c_result = gui_sketch_object_creator_create_diagram( &((*this_).object_creator),
912 : DATA_ROW_ID_VOID,
913 : 0,
914 : &new_diag_id
915 : );
916 : }
917 0 : break;
918 :
919 0 : default:
920 : {
921 0 : U8_LOG_ERROR_INT("illegal action value in gui_sketch_action_t:",action_button_id);
922 0 : assert(false);
923 : c_result = U8_ERROR_INVALID_REQUEST;
924 : }
925 : break;
926 : }
927 : }
928 :
929 0 : if ( U8_ERROR_NONE != c_result )
930 : {
931 0 : U8_LOG_ERROR("unexpected error at gui_sketch_object_creator_create_diagram");
932 : }
933 : else
934 : {
935 : data_id_t focused_id;
936 0 : data_id_init( &focused_id, DATA_TABLE_DIAGRAM, new_diag_id );
937 :
938 : /* load/reload data to be drawn */
939 0 : gui_sketch_area_show_diagram( this_, focused_id );
940 :
941 : /* update marked set */
942 : data_full_id_t focused_full_id;
943 0 : data_full_id_init_solo( &focused_full_id, focused_id );
944 :
945 0 : gui_marked_set_set_focused( (*this_).marker, focused_full_id, focused_id );
946 0 : gui_marked_set_clear_selected_set( (*this_).marker );
947 : }
948 : }
949 : }
950 : }
951 0 : break;
952 :
953 0 : case GUI_TOOL_EDIT:
954 : {
955 0 : U8_TRACE_INFO( "GUI_TOOL_EDIT" );
956 :
957 : /* determine the focused object */
958 : data_full_id_t focused_object;
959 : data_id_t diag_id;
960 0 : gui_sketch_area_private_get_object_id_at_pos( this_,
961 : x,
962 : y,
963 : PENCIL_TYPE_FILTER_LIFELINE,
964 : &focused_object,
965 : &diag_id
966 : );
967 0 : data_full_id_trace( &focused_object );
968 :
969 : /* update drag state */
970 0 : gui_sketch_drag_state_start_dragging_when_move ( &((*this_).drag_state), focused_object );
971 :
972 : /* toggle objects according to rules of gui_marked_set_t */
973 0 : gui_marked_set_toggle_obj( (*this_).marker, focused_object, diag_id );
974 :
975 : /* mark dirty rect */
976 0 : gtk_widget_queue_draw( (*this_).drawing_area );
977 : }
978 0 : break;
979 :
980 0 : case GUI_TOOL_SEARCH:
981 : {
982 0 : U8_TRACE_INFO( "GUI_TOOL_SEARCH" );
983 :
984 : /* determine clicked diagram */
985 0 : data_id_t clicked_diagram_id = DATA_ID_VOID;
986 0 : data_id_t clicked_object_id = DATA_ID_VOID;
987 0 : gui_sketch_area_private_get_diagram_and_object_id_at_pos ( this_, x, y, &clicked_diagram_id, &clicked_object_id );
988 0 : data_id_trace( &clicked_diagram_id );
989 0 : data_id_trace( &clicked_object_id );
990 :
991 : /* store diagram id to drag_state */
992 0 : if ( data_id_is_valid( &clicked_diagram_id ) )
993 : {
994 : /* update drag state */
995 : data_full_id_t dragged_object;
996 0 : data_full_id_init_solo ( &dragged_object, clicked_diagram_id );
997 0 : gui_sketch_drag_state_start_dragging_when_move ( &((*this_).drag_state), dragged_object );
998 : }
999 :
1000 : /* which object is currently focused? */
1001 0 : const data_id_t focused_before = gui_marked_set_get_focused_obj( (*this_).marker );
1002 :
1003 0 : if ( data_id_equals ( &clicked_object_id, &focused_before ) )
1004 : {
1005 : /* the clicked object is already focused */
1006 : }
1007 : else
1008 : {
1009 : /* set focused object */
1010 0 : assert( DATA_TABLE_DIAGRAMELEMENT != data_id_get_table( &clicked_object_id ) );
1011 : data_full_id_t focused_object;
1012 0 : data_full_id_init_solo ( &focused_object, clicked_object_id );
1013 :
1014 0 : gui_marked_set_set_focused( (*this_).marker, focused_object, clicked_diagram_id );
1015 : }
1016 : }
1017 0 : break;
1018 :
1019 0 : case GUI_TOOL_CREATE:
1020 : {
1021 0 : U8_TRACE_INFO( "GUI_TOOL_CREATE" );
1022 :
1023 : /* what is the target location? */
1024 0 : gui_sketch_card_t *target_card = gui_sketch_area_private_get_card_at_pos ( this_, x, y );
1025 :
1026 0 : if ( NULL == target_card )
1027 : {
1028 0 : U8_TRACE_INFO_INT_INT("No card at",x,y);
1029 :
1030 : /* if this happens, invalidate the marked object. */
1031 0 : gui_marked_set_clear_focused( (*this_).marker );
1032 : }
1033 : else
1034 : {
1035 : /* determine the object at click location */
1036 : data_full_id_t clicked_object;
1037 : data_full_id_t surrounding_object;
1038 : data_id_t diag_id;
1039 0 : gui_sketch_area_private_get_object_ids_at_pos( this_,
1040 : x,
1041 : y,
1042 : PENCIL_TYPE_FILTER_NONE,
1043 : &clicked_object,
1044 : &surrounding_object,
1045 : &diag_id
1046 : );
1047 0 : data_full_id_trace( &clicked_object );
1048 0 : data_full_id_trace( &surrounding_object );
1049 : const data_id_t *const clicked_classifier
1050 0 : = data_full_id_get_secondary_id_ptr( &clicked_object );
1051 : const data_id_t *const surrounding_classifier
1052 0 : = data_full_id_get_secondary_id_ptr( &surrounding_object );
1053 :
1054 0 : if ( DATA_TABLE_CLASSIFIER == data_id_get_table( clicked_classifier ) )
1055 : {
1056 : /* update drag state */
1057 0 : gui_sketch_drag_state_start_dragging_when_move ( &((*this_).drag_state), clicked_object );
1058 :
1059 : /* set focused object (either a diagramelement or a feature) */
1060 0 : gui_marked_set_set_focused( (*this_).marker, clicked_object, diag_id );
1061 : }
1062 : else /* clicked either into inner space of a classifier or at a relation or outside any classifier */
1063 : {
1064 : /* stop dragging */
1065 0 : gui_sketch_drag_state_stop_dragging ( &((*this_).drag_state) );
1066 :
1067 : /* create a new classifier */
1068 0 : const data_diagram_t *const target_diag = gui_sketch_card_get_diagram_ptr ( target_card );
1069 0 : const data_row_id_t selected_diagram_id = data_diagram_get_row_id( target_diag );
1070 0 : U8_TRACE_INFO_INT( "selected_diagram_id:", selected_diagram_id );
1071 :
1072 : data_id_t dummy_classifier;
1073 0 : data_id_init( &dummy_classifier, DATA_TABLE_CLASSIFIER, DATA_ROW_ID_VOID );
1074 0 : layout_order_t layout_order = gui_sketch_card_get_order_at_pos( target_card, dummy_classifier, x, y );
1075 0 : const int32_t x_order = layout_order_get_first( &layout_order );
1076 0 : const int32_t y_order = layout_order_get_second( &layout_order );
1077 0 : U8_TRACE_INFO_INT_INT( "x-order/y-order", x_order, y_order );
1078 :
1079 : /* create a classifier or a child-classifier */
1080 : u8_error_t c_result;
1081 : data_row_id_t new_diagele_id;
1082 : data_row_id_t new_classifier_id;
1083 0 : if ( DATA_TABLE_CLASSIFIER == data_id_get_table( surrounding_classifier ) )
1084 : {
1085 : data_row_id_t new_relationship_id;
1086 0 : c_result = gui_sketch_object_creator_create_classifier_as_child( &((*this_).object_creator),
1087 : selected_diagram_id,
1088 : data_id_get_row_id( surrounding_classifier ),
1089 : x_order,
1090 : y_order,
1091 : &new_diagele_id,
1092 : &new_classifier_id,
1093 : &new_relationship_id
1094 : );
1095 : }
1096 : else
1097 : {
1098 0 : c_result = gui_sketch_object_creator_create_classifier( &((*this_).object_creator),
1099 : selected_diagram_id,
1100 : x_order,
1101 : y_order,
1102 : &new_diagele_id,
1103 : &new_classifier_id
1104 : );
1105 : }
1106 :
1107 0 : if ( U8_ERROR_DUPLICATE_NAME == c_result )
1108 : {
1109 : /* this should not happen: names are auto-generated */
1110 0 : gui_simple_message_to_user_show_message_with_name( (*this_).message_to_user,
1111 : GUI_SIMPLE_MESSAGE_TYPE_ERROR,
1112 : GUI_SIMPLE_MESSAGE_CONTENT_NAME_NOT_UNIQUE,
1113 : ""
1114 : );
1115 : }
1116 0 : else if ( U8_ERROR_NONE != c_result )
1117 : {
1118 0 : U8_LOG_ERROR("unexpected error at gui_sketch_object_creator_create_classifier/_as_child");
1119 : }
1120 : else
1121 : {
1122 : /* set focused object and notify listener */
1123 0 : const data_full_id_t focused_object
1124 : = DATA_FULL_ID( DATA_TABLE_DIAGRAMELEMENT, new_diagele_id, new_classifier_id );
1125 0 : gui_marked_set_set_focused( (*this_).marker, focused_object, diag_id );
1126 0 : gui_marked_set_clear_selected_set( (*this_).marker );
1127 :
1128 0 : U8_TRACE_INFO_INT( "new_classifier_id:", new_classifier_id );
1129 : }
1130 : }
1131 : }
1132 : }
1133 0 : break;
1134 :
1135 0 : default:
1136 : {
1137 0 : U8_LOG_ERROR( "selected_tool is out of range" );
1138 : }
1139 0 : break;
1140 : }
1141 :
1142 0 : U8_TRACE_END();
1143 0 : }
1144 :
1145 0 : void gui_sketch_area_button_release_callback( GtkGestureClick* self,
1146 : gint n_press,
1147 : gdouble x,
1148 : gdouble y,
1149 : gpointer user_data )
1150 : {
1151 0 : U8_TRACE_BEGIN();
1152 0 : U8_TRACE_TIMESTAMP();
1153 0 : gui_sketch_area_t *this_ = user_data;
1154 0 : assert( NULL != this_ );
1155 :
1156 0 : gui_sketch_area_button_release( this_, (int)x, (int)y );
1157 :
1158 0 : U8_TRACE_END();
1159 0 : }
1160 :
1161 0 : void gui_sketch_area_button_release( gui_sketch_area_t *this_, int x, int y )
1162 : {
1163 0 : U8_TRACE_BEGIN();
1164 :
1165 0 : U8_TRACE_INFO("release");
1166 :
1167 : /* get position */
1168 0 : U8_TRACE_INFO_INT_INT("x/y",x,y);
1169 :
1170 : /* update drag coordinates */
1171 0 : gui_sketch_drag_state_set_to ( &((*this_).drag_state), x, y );
1172 :
1173 : /* check that drag state is true */
1174 0 : if ( ( ! gui_sketch_drag_state_is_dragging( &((*this_).drag_state) ) )
1175 0 : && ( ! gui_sketch_drag_state_is_waiting_for_move( &((*this_).drag_state) ) ) )
1176 : {
1177 0 : U8_TRACE_INFO("drag state indicates no dragging and no waiting - but button was pressed before!");
1178 : }
1179 :
1180 : /* do action */
1181 : const gui_tool_t selected_tool
1182 0 : = gui_sketch_request_get_tool_mode( &((*this_).request) );
1183 0 : switch ( selected_tool )
1184 : {
1185 0 : case GUI_TOOL_NAVIGATE:
1186 : {
1187 0 : U8_TRACE_INFO("GUI_TOOL_NAVIGATE");
1188 0 : if ( gui_sketch_drag_state_is_dragging ( &((*this_).drag_state) ) )
1189 : {
1190 : /* which diagram was dragged? */
1191 : data_full_id_t *dragged_object;
1192 0 : dragged_object = gui_sketch_drag_state_get_dragged_object_ptr ( &((*this_).drag_state) );
1193 : data_id_t dragged_diagram;
1194 0 : dragged_diagram = data_full_id_get_primary_id( dragged_object );
1195 :
1196 : /* to which diagram-gap was it dragged to? */
1197 : gui_error_t gui_err;
1198 : data_id_t target_parent_id;
1199 : int32_t target_list_order;
1200 : shape_int_rectangle_t dummy_gap_marker_border;
1201 0 : gui_err = gui_sketch_nav_tree_get_gap_info_at_pos( &((*this_).nav_tree),
1202 : x,
1203 : y,
1204 : &target_parent_id,
1205 : &target_list_order,
1206 : &dummy_gap_marker_border
1207 : );
1208 :
1209 0 : if (( DATA_TABLE_DIAGRAM == data_id_get_table( &dragged_diagram ) )
1210 0 : && ( DATA_TABLE_DIAGRAM == data_id_get_table( &target_parent_id ) )
1211 0 : && ( GUI_ERROR_NONE == gui_err ))
1212 : {
1213 0 : U8_TRACE_INFO_INT( "dragged_diagram:", data_id_get_row_id( &dragged_diagram ) );
1214 0 : U8_TRACE_INFO_INT( "target_parent_id:", data_id_get_row_id( &target_parent_id ) );
1215 0 : U8_TRACE_INFO_INT( "target_list_order:", target_list_order );
1216 : bool is_descendant;
1217 : bool is_self;
1218 : gui_error_t not_found;
1219 0 : not_found = gui_sketch_nav_tree_is_descendant( &((*this_).nav_tree),
1220 : data_id_get_row_id( &dragged_diagram ),
1221 : data_id_get_row_id( &target_parent_id ),
1222 : &is_descendant
1223 : );
1224 0 : is_self = ( data_id_get_row_id( &dragged_diagram ) == data_id_get_row_id( &target_parent_id ) );
1225 0 : if ( ( ! is_self ) && ( not_found == GUI_ERROR_NONE ) && ( ! is_descendant ) )
1226 0 : {
1227 : ctrl_diagram_controller_t *diag_control;
1228 0 : diag_control = ctrl_controller_get_diagram_control_ptr ( (*this_).controller );
1229 :
1230 : u8_error_t c_err;
1231 0 : c_err = ctrl_diagram_controller_update_diagram_list_order( diag_control,
1232 : data_id_get_row_id( &dragged_diagram ),
1233 : target_list_order
1234 : );
1235 0 : if ( U8_ERROR_NONE != c_err )
1236 : {
1237 0 : U8_LOG_ERROR_HEX( "U8_ERROR_NONE !=", c_err );
1238 : }
1239 0 : c_err = ctrl_diagram_controller_update_diagram_parent_id( diag_control,
1240 : data_id_get_row_id( &dragged_diagram ),
1241 : data_id_get_row_id( &target_parent_id ),
1242 : CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND
1243 : );
1244 0 : if ( U8_ERROR_NONE != c_err )
1245 : {
1246 0 : U8_LOG_ERROR_HEX( "U8_ERROR_NONE !=", c_err );
1247 : }
1248 : }
1249 0 : else if ( DATA_ROW_ID_VOID == data_id_get_row_id( &target_parent_id ) )
1250 : {
1251 : /* a diagram is dragged to the root location */
1252 : ctrl_diagram_controller_t *const diag_control2
1253 0 : = ctrl_controller_get_diagram_control_ptr ( (*this_).controller );
1254 :
1255 : const data_row_id_t root_id
1256 0 : = gui_sketch_nav_tree_get_root_diagram_id ( &((*this_).nav_tree) );
1257 0 : if (( root_id != DATA_ROW_ID_VOID )&&( root_id != data_id_get_row_id( &dragged_diagram ) ))
1258 0 : {
1259 : u8_error_t c_err;
1260 0 : c_err = ctrl_diagram_controller_update_diagram_parent_id( diag_control2,
1261 : data_id_get_row_id( &dragged_diagram ),
1262 : DATA_ROW_ID_VOID,
1263 : CTRL_UNDO_REDO_ACTION_BOUNDARY_START_NEW
1264 : );
1265 0 : if ( U8_ERROR_NONE != c_err )
1266 : {
1267 0 : U8_LOG_ERROR_HEX( "U8_ERROR_NONE !=", c_err );
1268 : }
1269 0 : c_err = ctrl_diagram_controller_update_diagram_parent_id( diag_control2,
1270 : root_id,
1271 : data_id_get_row_id( &dragged_diagram ),
1272 : CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND
1273 : );
1274 0 : if ( U8_ERROR_NONE != c_err )
1275 : {
1276 0 : U8_LOG_ERROR_HEX( "U8_ERROR_NONE !=", c_err );
1277 : }
1278 : }
1279 : else
1280 : {
1281 0 : U8_LOG_WARNING("dragging a diagram to the root location but no root exists or dragged diagram is root?");
1282 : }
1283 : }
1284 : else
1285 : {
1286 0 : U8_LOG_WARNING("diagram dragging to invalid target location");
1287 : /* current diagram is root */
1288 0 : gui_simple_message_to_user_show_message( (*this_).message_to_user,
1289 : GUI_SIMPLE_MESSAGE_TYPE_ERROR,
1290 : GUI_SIMPLE_MESSAGE_CONTENT_ANCESTOR_IS_NOT_DESCENDANT
1291 : );
1292 : }
1293 : }
1294 : }
1295 0 : else if ( gui_sketch_drag_state_is_waiting_for_move( &((*this_).drag_state) ) )
1296 : {
1297 : /* click on diagram without drag */
1298 : const data_full_id_t *const dragged_object
1299 0 : = gui_sketch_drag_state_get_dragged_object_ptr ( &((*this_).drag_state) );
1300 : const data_id_t dragged_diagram
1301 0 : = data_full_id_get_primary_id( dragged_object );
1302 0 : if ( DATA_TABLE_DIAGRAM == data_id_get_table( &dragged_diagram ) )
1303 : {
1304 0 : const data_row_id_t drag_id = data_id_get_row_id( &dragged_diagram );
1305 0 : const data_row_id_t focus_id = gui_sketch_area_private_get_focused_diagram_id( this_ );
1306 0 : if ( ( focus_id != DATA_ROW_ID_VOID )&&( focus_id == drag_id ) )
1307 : {
1308 : /* if clicked diagram is already the focused diagram, switch to edit mode */
1309 0 : gui_toolbox_set_selected_tool( (*this_).toolbox, GUI_TOOL_EDIT );
1310 : }
1311 : else
1312 : {
1313 : /* load/reload data to be drawn */
1314 0 : gui_sketch_area_show_diagram( this_, dragged_diagram );
1315 :
1316 : /* set focus */
1317 0 : gui_marked_set_set_focused( (*this_).marker, *dragged_object, dragged_diagram );
1318 0 : gui_marked_set_clear_selected_set( (*this_).marker );
1319 :
1320 : /* mark dirty rect */
1321 0 : gtk_widget_queue_draw( (*this_).drawing_area );
1322 : }
1323 : }
1324 : else
1325 : {
1326 0 : U8_LOG_ANOMALY("GUI_TOOL_NAVIGATE released mouse button but not a diagram clicked before");
1327 : }
1328 : }
1329 : }
1330 0 : break;
1331 :
1332 0 : case GUI_TOOL_EDIT:
1333 : {
1334 0 : U8_TRACE_INFO("GUI_TOOL_EDIT");
1335 :
1336 0 : if ( gui_sketch_drag_state_is_dragging ( &((*this_).drag_state) ) )
1337 : {
1338 : /* which object is selected? */
1339 : const data_full_id_t *const dragged_object
1340 0 : = gui_sketch_drag_state_get_dragged_object_ptr ( &((*this_).drag_state) );
1341 : const data_id_t dragged_element
1342 0 : = data_full_id_get_primary_id( dragged_object );
1343 : const data_id_t dragged_classifier
1344 0 : = data_full_id_get_secondary_id( dragged_object );
1345 :
1346 : /* what is the target location? */
1347 0 : const gui_sketch_card_t *const target_card = gui_sketch_area_private_get_card_at_pos ( this_, x, y );
1348 0 : if ( NULL == target_card )
1349 : {
1350 0 : U8_TRACE_INFO_INT_INT("No card at",x,y);
1351 : }
1352 0 : else if ( DATA_TABLE_DIAGRAMELEMENT == data_id_get_table( &dragged_element ) )
1353 : {
1354 0 : layout_order_t layout_order = gui_sketch_card_get_order_at_pos( target_card, dragged_classifier, x, y );
1355 0 : if ( PENCIL_LAYOUT_ORDER_TYPE_LIST == layout_order_get_order_type( &layout_order ) )
1356 : {
1357 0 : int32_t list_order = layout_order_get_first( &layout_order );
1358 0 : U8_TRACE_INFO_INT( "list_order", list_order );
1359 :
1360 : /* update db */
1361 : ctrl_classifier_controller_t *const classifier_control
1362 0 : = ctrl_controller_get_classifier_control_ptr ( (*this_).controller );
1363 : const u8_error_t mov_result
1364 0 : = ctrl_classifier_controller_update_classifier_list_order( classifier_control,
1365 : data_id_get_row_id( &dragged_classifier ),
1366 : list_order
1367 : );
1368 0 : if ( U8_ERROR_NONE != mov_result )
1369 : {
1370 0 : U8_LOG_ERROR( "changing order failed: ctrl_classifier_controller_update_classifier_list_order" );
1371 : }
1372 : }
1373 0 : else if ( PENCIL_LAYOUT_ORDER_TYPE_X_Y == layout_order_get_order_type( &layout_order ) )
1374 : {
1375 0 : int32_t x_order = layout_order_get_first( &layout_order );
1376 0 : int32_t y_order = layout_order_get_second( &layout_order );
1377 0 : U8_TRACE_INFO_INT_INT( "x-order/y-order", x_order, y_order );
1378 :
1379 : /* update db */
1380 : ctrl_classifier_controller_t *const classifier_control
1381 0 : = ctrl_controller_get_classifier_control_ptr ( (*this_).controller );
1382 : const u8_error_t mov_result
1383 0 : = ctrl_classifier_controller_update_classifier_x_order_y_order( classifier_control,
1384 : data_id_get_row_id( &dragged_classifier ),
1385 : x_order,
1386 : y_order
1387 : );
1388 0 : if ( U8_ERROR_NONE != mov_result )
1389 : {
1390 0 : U8_LOG_ERROR( "changing order failed: ctrl_classifier_controller_update_classifier_x_order_y_order" );
1391 : }
1392 : }
1393 : }
1394 0 : else if ( DATA_TABLE_RELATIONSHIP == data_id_get_table( &dragged_element ) )
1395 : {
1396 0 : layout_order_t layout_order = gui_sketch_card_get_order_at_pos( target_card, dragged_element, x, y );
1397 0 : if ( PENCIL_LAYOUT_ORDER_TYPE_LIST == layout_order_get_order_type( &layout_order ) )
1398 : {
1399 0 : int32_t list_order = layout_order_get_first( &layout_order );
1400 0 : U8_TRACE_INFO_INT( "list_order", list_order );
1401 :
1402 : /* update db */
1403 : ctrl_classifier_controller_t *const classifier_control
1404 0 : = ctrl_controller_get_classifier_control_ptr ( (*this_).controller );
1405 : const u8_error_t mov_result
1406 0 : = ctrl_classifier_controller_update_relationship_list_order( classifier_control,
1407 : data_id_get_row_id( &dragged_element ),
1408 : list_order
1409 : );
1410 0 : if ( U8_ERROR_NONE != mov_result )
1411 : {
1412 0 : U8_LOG_ERROR( "changing order failed: ctrl_classifier_controller_update_relationship_list_order" );
1413 : }
1414 : }
1415 : }
1416 0 : else if ( DATA_TABLE_FEATURE == data_id_get_table( &dragged_element ) )
1417 : {
1418 0 : layout_order_t layout_order = gui_sketch_card_get_order_at_pos( target_card, dragged_element, x, y );
1419 0 : if ( PENCIL_LAYOUT_ORDER_TYPE_LIST == layout_order_get_order_type( &layout_order ) )
1420 : {
1421 0 : int32_t list_order = layout_order_get_first( &layout_order );
1422 0 : U8_TRACE_INFO_INT( "list_order", list_order );
1423 :
1424 : /* update db */
1425 : ctrl_classifier_controller_t *const classifier_control
1426 0 : = ctrl_controller_get_classifier_control_ptr ( (*this_).controller );
1427 : const u8_error_t mov_result
1428 0 : = ctrl_classifier_controller_update_feature_list_order( classifier_control,
1429 : data_id_get_row_id( &dragged_element ),
1430 : list_order
1431 : );
1432 0 : if ( U8_ERROR_NONE != mov_result )
1433 : {
1434 0 : U8_LOG_ERROR( "changing order failed: ctrl_classifier_controller_update_feature_list_order" );
1435 : }
1436 : }
1437 : }
1438 : else
1439 : {
1440 0 : U8_TRACE_INFO("Dragged object is neither relationship nor classifier nor feature");
1441 : }
1442 : }
1443 : }
1444 0 : break;
1445 :
1446 0 : case GUI_TOOL_SEARCH:
1447 : {
1448 0 : U8_TRACE_INFO("GUI_TOOL_SEARCH");
1449 :
1450 0 : if ( gui_sketch_drag_state_is_waiting_for_move( &((*this_).drag_state) ) )
1451 : {
1452 : /* click on diagram without drag */
1453 : const data_full_id_t *const dragged_object
1454 0 : = gui_sketch_drag_state_get_dragged_object_ptr ( &((*this_).drag_state) );
1455 : const data_id_t dragged_diagram
1456 0 : = data_full_id_get_primary_id( dragged_object );
1457 0 : if ( DATA_TABLE_DIAGRAM == data_id_get_table( &dragged_diagram ) )
1458 : {
1459 : /* load/reload data to be drawn */
1460 0 : gui_sketch_area_show_diagram( this_, dragged_diagram );
1461 :
1462 : /* clear selected set but do not change focused object */
1463 0 : gui_marked_set_clear_selected_set( (*this_).marker );
1464 :
1465 : /* switch to edit mode */
1466 0 : gui_toolbox_set_selected_tool( (*this_).toolbox, GUI_TOOL_EDIT );
1467 : }
1468 : else
1469 : {
1470 0 : U8_TRACE_INFO("GUI_TOOL_SEARCH released mouse button but not a diagram clicked before");
1471 : }
1472 : }
1473 : }
1474 0 : break;
1475 :
1476 0 : case GUI_TOOL_CREATE:
1477 : {
1478 0 : U8_TRACE_INFO("GUI_TOOL_CREATE");
1479 :
1480 0 : if ( gui_sketch_drag_state_is_dragging ( &((*this_).drag_state) ) )
1481 : {
1482 : /* which object is selected? */
1483 : const data_full_id_t *const dragged_object
1484 0 : = gui_sketch_drag_state_get_dragged_object_ptr ( &((*this_).drag_state) );
1485 0 : data_full_id_trace( dragged_object );
1486 : const data_id_t dragged_element
1487 0 : = data_full_id_get_primary_id( dragged_object );
1488 : const data_id_t dragged_classifier
1489 0 : = data_full_id_get_secondary_id( dragged_object );
1490 :
1491 : /* which object is at the target location? */
1492 : data_full_id_t destination_object;
1493 : data_id_t diag_id;
1494 0 : gui_sketch_area_private_get_object_id_at_pos( this_,
1495 : x,
1496 : y,
1497 : PENCIL_TYPE_FILTER_NONE,
1498 : &destination_object,
1499 : &diag_id
1500 : );
1501 0 : data_full_id_trace( &destination_object );
1502 : const data_id_t destination_element
1503 0 : = data_full_id_get_primary_id( &destination_object );
1504 : const data_id_t destination_classifier
1505 0 : = data_full_id_get_secondary_id( &destination_object );
1506 :
1507 0 : gui_sketch_card_t *target_card = gui_sketch_area_private_get_card_at_pos ( this_, x, y );
1508 0 : if ( data_id_is_valid( &dragged_classifier ) && data_id_is_valid( &destination_classifier ) && ( NULL != target_card ))
1509 : {
1510 0 : if ( ( DATA_TABLE_CLASSIFIER == data_id_get_table( &dragged_classifier ) )
1511 0 : && ( DATA_TABLE_CLASSIFIER == data_id_get_table( &destination_classifier ) ) )
1512 : {
1513 : /* get the diagram type */
1514 0 : const data_diagram_t *const target_diag = gui_sketch_card_get_diagram_ptr ( target_card );
1515 0 : assert ( target_diag != NULL );
1516 0 : data_diagram_type_t diag_type = data_diagram_get_diagram_type ( target_diag );
1517 :
1518 : /* determine source and destionation */
1519 : data_row_id_t new_from_classifier_id;
1520 : data_row_id_t new_to_classifier_id;
1521 : data_row_id_t new_from_feature_id;
1522 : data_row_id_t new_to_feature_id;
1523 : {
1524 0 : new_from_classifier_id = data_id_get_row_id( &dragged_classifier );
1525 0 : if ( DATA_TABLE_FEATURE == data_id_get_table( &dragged_element ) )
1526 : {
1527 0 : new_from_feature_id = data_id_get_row_id( &dragged_element );
1528 : }
1529 : else
1530 : {
1531 0 : new_from_feature_id = DATA_ROW_ID_VOID;
1532 : }
1533 0 : new_to_classifier_id = data_id_get_row_id( &destination_classifier );
1534 0 : if ( DATA_TABLE_FEATURE == data_id_get_table( &destination_element ) )
1535 : {
1536 0 : new_to_feature_id = data_id_get_row_id( &destination_element );
1537 : }
1538 : else
1539 : {
1540 0 : new_to_feature_id = DATA_ROW_ID_VOID;
1541 : }
1542 : }
1543 :
1544 : /* propose a list_order for the relationship */
1545 0 : int32_t list_order_proposal = 0;
1546 : {
1547 : /* propose a list order */
1548 : data_id_t fake_relationship;
1549 0 : data_id_init ( &fake_relationship, DATA_TABLE_RELATIONSHIP, DATA_ROW_ID_VOID );
1550 : const layout_order_t layout_order
1551 0 : = gui_sketch_card_get_order_at_pos( target_card, fake_relationship, x, y );
1552 0 : if ( PENCIL_LAYOUT_ORDER_TYPE_LIST == layout_order_get_order_type( &layout_order ) )
1553 : {
1554 0 : list_order_proposal = layout_order_get_first( &layout_order );
1555 : }
1556 : else /* PENCIL_LAYOUT_ORDER_TYPE_NONE */
1557 : {
1558 0 : list_order_proposal = gui_sketch_card_get_highest_rel_list_order( target_card ) + 32768;
1559 : }
1560 : }
1561 :
1562 : data_row_id_t new_relationship_id;
1563 : const u8_error_t c_result
1564 0 : = gui_sketch_object_creator_create_relationship( &((*this_).object_creator),
1565 : diag_type,
1566 : new_from_classifier_id,
1567 : new_from_feature_id,
1568 : new_to_classifier_id,
1569 : new_to_feature_id,
1570 : list_order_proposal,
1571 : &new_relationship_id
1572 : );
1573 :
1574 0 : if ( U8_ERROR_NONE != c_result )
1575 : {
1576 0 : U8_LOG_ANOMALY_HEX("anomaly at gui_sketch_object_creator_create_relationship",c_result);
1577 : }
1578 : else
1579 : {
1580 : /* set focused object */
1581 0 : const data_full_id_t focused_id
1582 : = DATA_FULL_ID_SOLO( DATA_TABLE_RELATIONSHIP, new_relationship_id );
1583 0 : gui_marked_set_set_focused( (*this_).marker, focused_id, diag_id );
1584 0 : gui_marked_set_clear_selected_set( (*this_).marker );
1585 : }
1586 : }
1587 : }
1588 : }
1589 0 : else if ( gui_sketch_drag_state_is_waiting_for_move( &((*this_).drag_state) ) )
1590 : {
1591 : /* click on classifier without drag */
1592 : const data_full_id_t *const dragged_object
1593 0 : = gui_sketch_drag_state_get_dragged_object_ptr ( &((*this_).drag_state) );
1594 : const data_id_t dragged_classifier
1595 0 : = data_full_id_get_secondary_id( dragged_object );
1596 :
1597 : const gui_sketch_card_t *const target_card
1598 0 : = gui_sketch_area_private_get_card_at_pos ( this_, x, y );
1599 0 : if ( data_id_is_valid( &dragged_classifier ) && ( NULL != target_card ) )
1600 0 : {
1601 0 : const data_id_t diag_id = gui_sketch_card_get_diagram_id( target_card );
1602 0 : if ( DATA_TABLE_CLASSIFIER == data_id_get_table( &dragged_classifier ) )
1603 : {
1604 : /* get the diagram type */
1605 : const data_diagram_t *const target_diag
1606 0 : = gui_sketch_card_get_diagram_const ( target_card );
1607 0 : assert ( target_diag != NULL );
1608 0 : const data_diagram_type_t diag_type = data_diagram_get_diagram_type ( target_diag );
1609 :
1610 : /* determine id of classifier to which the clicked object belongs */
1611 0 : const data_row_id_t classifier_id = data_id_get_row_id( &dragged_classifier );
1612 :
1613 : /* propose a list_order for the feature */
1614 0 : const int32_t std_list_order_proposal
1615 0 : = gui_sketch_card_get_highest_feat_list_order( target_card, dragged_classifier ) + 32768;
1616 0 : int32_t port_list_order_proposal = 0;
1617 : {
1618 0 : data_feature_init_new( &((*this_).private_temp_fake_feature),
1619 : DATA_FEATURE_TYPE_PORT,
1620 : classifier_id, /* classifier */
1621 : "FAKE_FEATURE",
1622 : "port-type",
1623 : "to determine the list order",
1624 : 0 /* list_order */
1625 : );
1626 0 : port_list_order_proposal = gui_sketch_card_get_feature_order_at_pos( target_card,
1627 0 : &((*this_).private_temp_fake_feature),
1628 : x,
1629 : y
1630 : );
1631 0 : data_feature_destroy ( &((*this_).private_temp_fake_feature) );
1632 : }
1633 :
1634 : /* create a feature */
1635 : data_row_id_t new_feature_id;
1636 : const u8_error_t ctrl_err
1637 0 : = gui_sketch_object_creator_create_feature( &((*this_).object_creator),
1638 : diag_type,
1639 : classifier_id,
1640 : std_list_order_proposal,
1641 : port_list_order_proposal,
1642 : &new_feature_id
1643 : );
1644 :
1645 0 : if ( U8_ERROR_NONE != ctrl_err )
1646 : {
1647 0 : U8_LOG_ANOMALY_HEX("anomaly at gui_sketch_object_creator_create_feature",ctrl_err);
1648 : }
1649 : else
1650 : {
1651 : /* set focused object */
1652 0 : const data_full_id_t new_focused_id
1653 : = DATA_FULL_ID( DATA_TABLE_FEATURE, new_feature_id, classifier_id );
1654 0 : gui_marked_set_set_focused( (*this_).marker, new_focused_id, diag_id );
1655 0 : gui_marked_set_clear_selected_set( (*this_).marker );
1656 : }
1657 : }
1658 : else
1659 : {
1660 0 : U8_LOG_WARNING("unexpected state at gui_sketch_area_button_release_callback");
1661 : }
1662 : }
1663 : else
1664 : {
1665 0 : U8_LOG_WARNING("invalid clicked object at gui_sketch_area_button_release_callback");
1666 : }
1667 : }
1668 : else
1669 : {
1670 0 : U8_TRACE_INFO("according to drag-state, the button press was already handled at press-time");
1671 : }
1672 : }
1673 0 : break;
1674 :
1675 0 : default:
1676 : {
1677 0 : U8_LOG_ERROR("selected_tool is out of range");
1678 : }
1679 0 : break;
1680 : }
1681 :
1682 : /* stop dragging */
1683 0 : gui_sketch_drag_state_stop_dragging ( &((*this_).drag_state) );
1684 :
1685 : /* mark dirty rect */
1686 0 : gtk_widget_queue_draw( (*this_).drawing_area );
1687 :
1688 0 : U8_TRACE_END();
1689 0 : }
1690 :
1691 0 : gboolean gui_sketch_area_key_press_callback( GtkEventControllerKey* self,
1692 : guint keyval,
1693 : guint keycode,
1694 : GdkModifierType state,
1695 : gpointer user_data )
1696 : {
1697 0 : U8_TRACE_BEGIN();
1698 0 : U8_TRACE_TIMESTAMP();
1699 0 : gui_sketch_area_t *this_ = user_data;
1700 0 : assert( NULL != this_ );
1701 :
1702 0 : const gboolean result_event_handled = gui_sketch_area_key_press( this_, 0 != (GDK_CONTROL_MASK&state), keyval );
1703 :
1704 0 : U8_TRACE_END();
1705 0 : return result_event_handled;
1706 : }
1707 :
1708 0 : bool gui_sketch_area_key_press( gui_sketch_area_t *this_, bool ctrl_state, guint keyval )
1709 : {
1710 0 : U8_TRACE_BEGIN();
1711 0 : gboolean result_event_handled = false;
1712 :
1713 : /* keys that have to be handled locally in the gui_sketch_area */
1714 : /* becasue handling them globally would interfere with text entry fields */
1715 0 : if ( ctrl_state )
1716 : {
1717 0 : if ( keyval == GDK_KEY_x )
1718 : {
1719 0 : U8_TRACE_INFO ( "key pressed: Ctrl-X" );
1720 0 : gui_toolbox_cut( (*this_).toolbox );
1721 0 : result_event_handled = true;
1722 : }
1723 0 : else if ( keyval == GDK_KEY_c )
1724 : {
1725 0 : U8_TRACE_INFO ( "key pressed: Ctrl-C" );
1726 0 : gui_toolbox_copy( (*this_).toolbox );
1727 0 : result_event_handled = true;
1728 : }
1729 0 : else if ( keyval == GDK_KEY_v )
1730 : {
1731 0 : U8_TRACE_INFO ( "key pressed: Ctrl-V" );
1732 0 : gui_toolbox_paste( (*this_).toolbox );
1733 0 : result_event_handled = true;
1734 : }
1735 : /* other keys are out of scope */
1736 : }
1737 : else
1738 : {
1739 0 : if ( keyval == GDK_KEY_Delete )
1740 : {
1741 0 : U8_TRACE_INFO ( "key pressed: DEL" );
1742 0 : gui_toolbox_delete( (*this_).toolbox );
1743 0 : result_event_handled = true;
1744 : }
1745 : /* other keys are out of scope */
1746 : }
1747 :
1748 0 : U8_TRACE_END();
1749 0 : return result_event_handled;
1750 : }
1751 :
1752 0 : void gui_sketch_area_data_changed_callback( GtkWidget *widget, data_change_message_t *msg, gpointer data )
1753 : {
1754 0 : U8_TRACE_BEGIN();
1755 0 : assert( NULL != msg );
1756 0 : gui_sketch_area_t *this_ = data;
1757 0 : assert( NULL != this_ );
1758 0 : assert ( NULL != widget );
1759 :
1760 0 : const data_change_event_type_t evt_type = data_change_message_get_event ( msg );
1761 :
1762 0 : if ( evt_type == DATA_CHANGE_EVENT_TYPE_DB_CLOSED )
1763 : {
1764 : /* abort dragging */
1765 0 : gui_sketch_drag_state_reinit( &((*this_).drag_state) );
1766 :
1767 : /* do not keep search results */
1768 0 : gui_sketch_result_list_invalidate_data( &((*this_).result_list) );
1769 :
1770 : /* do not keep selected or focued objects */
1771 0 : gui_marked_set_reinit( (*this_).marker );
1772 :
1773 : /* reset the currently visible diagram */
1774 0 : gui_sketch_request_reinit( &((*this_).request) );
1775 : }
1776 :
1777 0 : if ( evt_type == DATA_CHANGE_EVENT_TYPE_DB_OPENED )
1778 : {
1779 : /* go to navigation mode, show root */
1780 0 : gui_sketch_request_reinit( &((*this_).request) );
1781 0 : gui_toolbox_set_selected_tool( (*this_).toolbox, GUI_TOOL_NAVIGATE );
1782 0 : gui_sketch_area_show_diagram( this_, DATA_ID_VOID );
1783 : }
1784 :
1785 : /* load/reload data to be drawn */
1786 0 : gui_sketch_area_private_refocus_and_reload_data( this_ );
1787 :
1788 : /* mark dirty rect */
1789 0 : gtk_widget_queue_draw( (*this_).drawing_area );
1790 :
1791 0 : U8_TRACE_END();
1792 0 : }
1793 :
1794 0 : void gui_sketch_area_tool_changed_callback( GtkWidget *widget, gui_tool_t tool, gpointer data )
1795 : {
1796 0 : U8_TRACE_BEGIN();
1797 0 : gui_sketch_area_t *this_ = data;
1798 0 : assert( NULL != this_ );
1799 0 : assert ( NULL != widget );
1800 :
1801 : /* info: This function is called once for activating a tool and once for deactiaving it! */
1802 0 : if ( gui_sketch_request_get_tool_mode( &((*this_).request) ) != tool )
1803 : {
1804 0 : gui_sketch_request_set_tool_mode( &((*this_).request), tool );
1805 :
1806 : /* load/reload data to be drawn */
1807 0 : gui_sketch_area_private_refocus_and_reload_data( this_ );
1808 :
1809 : /* mark dirty rect */
1810 0 : gtk_widget_queue_draw( (*this_).drawing_area );
1811 : }
1812 : else
1813 : {
1814 : /* either the already selected tool is selected again or it is unselected */
1815 : /* or the clear selection button was pressed */
1816 :
1817 : /* mark dirty rect */
1818 0 : gtk_widget_queue_draw( (*this_).drawing_area );
1819 : }
1820 :
1821 0 : U8_TRACE_END();
1822 0 : }
1823 :
1824 :
1825 : /*
1826 : Copyright 2016-2024 Andreas Warnke
1827 :
1828 : Licensed under the Apache License, Version 2.0 (the "License");
1829 : you may not use this file except in compliance with the License.
1830 : You may obtain a copy of the License at
1831 :
1832 : http://www.apache.org/licenses/LICENSE-2.0
1833 :
1834 : Unless required by applicable law or agreed to in writing, software
1835 : distributed under the License is distributed on an "AS IS" BASIS,
1836 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1837 : See the License for the specific language governing permissions and
1838 : limitations under the License.
1839 : */
|