Line data Source code
1 : /* File: gui_sketch_overlay.c; Copyright and License: see below */
2 :
3 : #include "sketch/gui_sketch_overlay.h"
4 : #include "sketch/gui_sketch_snap_state.h"
5 : #include "u8/u8_trace.h"
6 : #include <gtk/gtk.h>
7 : #include <assert.h>
8 :
9 0 : void gui_sketch_overlay_init( gui_sketch_overlay_t *this_ )
10 : {
11 0 : U8_TRACE_BEGIN();
12 :
13 0 : (*this_).overlay_std_red = 0.0;
14 0 : (*this_).overlay_std_green = 0.6;
15 0 : (*this_).overlay_std_blue = 0.4;
16 0 : (*this_).overlay_std_alpha = 1.0;
17 :
18 0 : U8_TRACE_END();
19 0 : }
20 :
21 0 : void gui_sketch_overlay_destroy( gui_sketch_overlay_t *this_ )
22 : {
23 0 : U8_TRACE_BEGIN();
24 :
25 0 : U8_TRACE_END();
26 0 : }
27 :
28 0 : void gui_sketch_overlay_draw( gui_sketch_overlay_t *this_,
29 : gui_tool_t selected_tool,
30 : const gui_sketch_drag_state_t *drag_state,
31 : const gui_sketch_card_t *card_under_mouse,
32 : const gui_sketch_nav_tree_t *nav_tree,
33 : gui_marked_set_t *marked_objects,
34 : cairo_t *cr )
35 : {
36 0 : U8_TRACE_BEGIN();
37 0 : assert( NULL != drag_state );
38 0 : assert( NULL != cr );
39 0 : assert( NULL != nav_tree );
40 :
41 0 : switch ( selected_tool )
42 : {
43 0 : case GUI_TOOL_NAVIGATE:
44 : {
45 0 : gui_sketch_overlay_private_draw_nav_mode( this_, drag_state, nav_tree, cr );
46 : }
47 0 : break;
48 :
49 0 : case GUI_TOOL_EDIT:
50 : {
51 0 : gui_sketch_overlay_private_draw_edit_mode( this_, drag_state, card_under_mouse, cr );
52 : }
53 0 : break;
54 :
55 0 : case GUI_TOOL_CREATE:
56 : {
57 0 : const data_id_t highlighted = gui_marked_set_get_highlighted( marked_objects );
58 0 : gui_sketch_overlay_private_draw_create_mode( this_, drag_state, card_under_mouse, data_id_get_table(&highlighted), cr );
59 : }
60 0 : break;
61 :
62 0 : case GUI_TOOL_SEARCH:
63 : {
64 : }
65 0 : break;
66 :
67 0 : default:
68 : {
69 0 : U8_LOG_ERROR("selected_tool is out of range");
70 : }
71 0 : break;
72 : }
73 :
74 0 : U8_TRACE_END();
75 0 : }
76 :
77 0 : void gui_sketch_overlay_private_draw_nav_mode( gui_sketch_overlay_t *this_,
78 : const gui_sketch_drag_state_t *drag_state,
79 : const gui_sketch_nav_tree_t *nav_tree,
80 : cairo_t *cr )
81 : {
82 0 : U8_TRACE_BEGIN();
83 0 : assert( NULL != drag_state );
84 0 : assert( NULL != cr );
85 0 : assert( NULL != nav_tree );
86 :
87 0 : if ( gui_sketch_drag_state_is_dragging ( drag_state ) )
88 : {
89 0 : const int32_t to_x = gui_sketch_drag_state_get_to_x ( drag_state );
90 0 : const int32_t to_y = gui_sketch_drag_state_get_to_y ( drag_state );
91 : data_id_t out_parent_id;
92 : int32_t out_list_order;
93 : shape_int_rectangle_t out_gap_line;
94 : gui_error_t gap_err;
95 0 : gap_err = gui_sketch_nav_tree_get_gap_info_at_pos ( nav_tree,
96 : to_x,
97 : to_y,
98 : &out_parent_id,
99 : &out_list_order,
100 : &out_gap_line
101 : );
102 0 : if ( gap_err == GUI_ERROR_NONE )
103 : {
104 0 : cairo_set_source_rgba( cr,
105 : (*this_).overlay_std_red,
106 : (*this_).overlay_std_green,
107 : (*this_).overlay_std_blue,
108 : (*this_).overlay_std_alpha
109 : );
110 0 : cairo_rectangle ( cr,
111 0 : shape_int_rectangle_get_left(&out_gap_line),
112 0 : shape_int_rectangle_get_top(&out_gap_line),
113 0 : shape_int_rectangle_get_width(&out_gap_line),
114 0 : shape_int_rectangle_get_height(&out_gap_line)
115 : );
116 0 : cairo_fill (cr);
117 : }
118 : else
119 : {
120 0 : U8_TRACE_INFO("dragging diagram outside nav_tree");
121 : }
122 : }
123 0 : U8_TRACE_END();
124 0 : }
125 :
126 0 : void gui_sketch_overlay_private_draw_edit_mode( gui_sketch_overlay_t *this_,
127 : const gui_sketch_drag_state_t *drag_state,
128 : const gui_sketch_card_t *card_under_mouse,
129 : cairo_t *cr )
130 : {
131 0 : U8_TRACE_BEGIN();
132 0 : assert( NULL != drag_state );
133 0 : assert( NULL != cr );
134 :
135 0 : if ( gui_sketch_drag_state_is_dragging ( drag_state ) )
136 : {
137 0 : if ( NULL != card_under_mouse )
138 : {
139 0 : const data_diagram_t *diag = gui_sketch_card_get_diagram_const ( card_under_mouse );
140 0 : const data_diagram_type_t diag_type = data_diagram_get_diagram_type( diag );
141 0 : const bool draw_2d_diagram
142 : = (( diag_type != DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM )
143 0 : && ( diag_type != DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM )
144 0 : && ( diag_type != DATA_DIAGRAM_TYPE_LIST ));
145 :
146 0 : if ( draw_2d_diagram )
147 : {
148 : /* draw grid line crossings */
149 0 : gui_sketch_overlay_private_draw_grid( this_, card_under_mouse, cr );
150 :
151 : /* draw snap-to-grid indicator */
152 0 : const int32_t to_x = gui_sketch_drag_state_get_to_x ( drag_state );
153 0 : const int32_t to_y = gui_sketch_drag_state_get_to_y ( drag_state );
154 0 : const gui_sketch_snap_state_t snapped = gui_sketch_card_is_pos_on_grid ( card_under_mouse, to_x, to_y );
155 0 : gui_sketch_overlay_private_draw_snap_indicator( this_, card_under_mouse, snapped, to_x, to_y, cr );
156 : }
157 : }
158 : }
159 :
160 0 : U8_TRACE_END();
161 0 : }
162 :
163 0 : void gui_sketch_overlay_private_draw_create_mode( gui_sketch_overlay_t *this_,
164 : const gui_sketch_drag_state_t *drag_state,
165 : const gui_sketch_card_t *card_under_mouse,
166 : data_table_t highlighted_object_table,
167 : cairo_t *cr )
168 : {
169 0 : U8_TRACE_BEGIN();
170 0 : assert( NULL != drag_state );
171 0 : assert( NULL != cr );
172 :
173 0 : if ( gui_sketch_drag_state_is_dragging ( drag_state ) )
174 : {
175 : /* draw a line */
176 0 : const int32_t from_x = gui_sketch_drag_state_get_from_x ( drag_state );
177 0 : const int32_t from_y = gui_sketch_drag_state_get_from_y ( drag_state );
178 0 : const int32_t to_x = gui_sketch_drag_state_get_to_x ( drag_state );
179 0 : const int32_t to_y = gui_sketch_drag_state_get_to_y ( drag_state );
180 0 : gui_sketch_overlay_private_draw_arrow( this_, from_x, from_y, to_x, to_y, cr );
181 : }
182 : else /* ! gui_sketch_drag_state_is_dragging() */
183 : {
184 0 : if ( NULL != card_under_mouse )
185 : {
186 0 : const bool draw_arrow
187 : = (( highlighted_object_table == DATA_TABLE_CLASSIFIER )
188 0 : ||( highlighted_object_table == DATA_TABLE_FEATURE )
189 0 : ||( highlighted_object_table == DATA_TABLE_DIAGRAMELEMENT ));
190 :
191 0 : const data_diagram_t *diag = gui_sketch_card_get_diagram_const ( card_under_mouse );
192 0 : const data_diagram_type_t diag_type = data_diagram_get_diagram_type( diag );
193 0 : const bool draw_2d_diagram
194 : = (( diag_type != DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM )
195 0 : && ( diag_type != DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM )
196 0 : && ( diag_type != DATA_DIAGRAM_TYPE_LIST ));
197 :
198 : /* draw grid */
199 0 : if (( ! draw_arrow )&&( draw_2d_diagram ))
200 : {
201 : /* draw grid line crossings */
202 0 : gui_sketch_overlay_private_draw_grid( this_, card_under_mouse, cr );
203 :
204 : /* draw snap-to-grid indicator */
205 0 : const int32_t to_x = gui_sketch_drag_state_get_to_x ( drag_state );
206 0 : const int32_t to_y = gui_sketch_drag_state_get_to_y ( drag_state );
207 0 : const gui_sketch_snap_state_t snapped = gui_sketch_card_is_pos_on_grid( card_under_mouse, to_x, to_y );
208 0 : gui_sketch_overlay_private_draw_snap_indicator( this_, card_under_mouse, snapped, to_x, to_y, cr );
209 : }
210 :
211 : /* get coordinates */
212 0 : const int32_t x = gui_sketch_drag_state_get_to_x ( drag_state );
213 0 : const int32_t y = gui_sketch_drag_state_get_to_y ( drag_state );
214 0 : gui_sketch_overlay_private_draw_create_icon( this_, x, y, draw_arrow, cr );
215 : }
216 : }
217 :
218 0 : U8_TRACE_END();
219 0 : }
220 :
221 0 : void gui_sketch_overlay_private_draw_arrow( gui_sketch_overlay_t *this_,
222 : int32_t from_x,
223 : int32_t from_y,
224 : int32_t to_x,
225 : int32_t to_y,
226 : cairo_t *cr )
227 : {
228 0 : U8_TRACE_BEGIN();
229 0 : assert( NULL != cr );
230 :
231 0 : cairo_set_source_rgba( cr,
232 : (*this_).overlay_std_red,
233 : (*this_).overlay_std_green,
234 : (*this_).overlay_std_blue,
235 : (*this_).overlay_std_alpha
236 : );
237 0 : cairo_move_to ( cr, from_x, from_y );
238 0 : cairo_line_to ( cr, to_x, to_y );
239 0 : cairo_stroke (cr);
240 :
241 : /* draw the arrow tip */
242 : int clock_direction; /* the gdk coordinate system if bottom up - and out clock is also mirrored! */
243 0 : const int32_t x_dist = to_x - from_x;
244 0 : const int32_t y_dist = to_y - from_y;
245 0 : if ( x_dist == 0 )
246 : {
247 0 : clock_direction = ( y_dist < 0 ) ? 6 : 0;
248 : }
249 : else
250 : {
251 0 : int32_t y_x_deci_ratio = ( y_dist * 10 ) / x_dist;
252 0 : if ( y_x_deci_ratio < 3 /* = 0.26 = tan(15 deg) */ )
253 : {
254 0 : if ( y_x_deci_ratio < -10 /* = -1.00 = tan(-45 deg) */ )
255 : {
256 0 : if ( y_x_deci_ratio < -37 /* = -3.73 = tan(-75 deg) */ )
257 : {
258 0 : clock_direction = 6;
259 : }
260 : else
261 : {
262 0 : clock_direction = 5;
263 : }
264 : }
265 : else
266 : {
267 0 : if ( y_x_deci_ratio < -2 /* = -0.26 = tan(-15 deg) */ )
268 : {
269 0 : clock_direction = 4;
270 : }
271 : else
272 : {
273 0 : clock_direction = 3;
274 : }
275 : }
276 : }
277 : else
278 : {
279 0 : if ( y_x_deci_ratio < 10 /* = 1.00 = tan(45 deg) */ )
280 : {
281 0 : clock_direction = 2;
282 : }
283 : else
284 : {
285 0 : if ( y_x_deci_ratio < 38 /* = 3.73 = tan(75 deg) */ )
286 : {
287 0 : clock_direction = 1;
288 : }
289 : else
290 : {
291 0 : clock_direction = 0;
292 : }
293 : }
294 : }
295 0 : if ( x_dist < 0 )
296 : {
297 0 : clock_direction = (clock_direction+6)%12;
298 : }
299 : }
300 : const static int32_t DX[12][2]={{-6,+6},{-9, 0},{-11,-4},{-9,-9},{-4,-11},{ 0,-9},{+6,-6},{+9, 0},{+11,+4},{+9,+9},{+4,+11},{ 0,+9}};
301 : const static int32_t DY[12][2]={{-9,-9},{-4,-11},{ 0,-9},{+6,-6},{+9, 0},{+11,+4},{+9,+9},{+4,+11},{ 0,+9},{+6,-6},{-9, 0},{-11,-4}};
302 0 : cairo_move_to ( cr, to_x + DX[clock_direction][0], to_y + DY[clock_direction][0] );
303 0 : cairo_line_to ( cr, to_x, to_y );
304 0 : cairo_line_to ( cr, to_x + DX[clock_direction][1], to_y + DY[clock_direction][1] );
305 0 : cairo_stroke (cr);
306 :
307 0 : U8_TRACE_END();
308 0 : }
309 :
310 0 : void gui_sketch_overlay_private_draw_create_icon( gui_sketch_overlay_t *this_,
311 : int32_t x,
312 : int32_t y,
313 : bool with_arrow_option,
314 : cairo_t *cr )
315 : {
316 0 : U8_TRACE_BEGIN();
317 0 : assert( NULL != cr );
318 :
319 0 : cairo_set_source_rgba( cr,
320 : (*this_).overlay_std_red,
321 : (*this_).overlay_std_green,
322 : (*this_).overlay_std_blue,
323 : (*this_).overlay_std_alpha
324 : );
325 : static const int32_t ICON_UNIT = 2;
326 : static const int32_t DIST = 12;
327 :
328 : /* star */
329 0 : const int32_t star_center_x = x+(with_arrow_option?-2:1)*ICON_UNIT;
330 0 : const int32_t star_center_y = y-DIST-6*ICON_UNIT;
331 0 : cairo_move_to ( cr, star_center_x, star_center_y-2*ICON_UNIT );
332 0 : cairo_line_to ( cr, star_center_x, star_center_y+2*ICON_UNIT );
333 0 : cairo_move_to ( cr, star_center_x-2*ICON_UNIT, star_center_y-1*ICON_UNIT );
334 0 : cairo_line_to ( cr, star_center_x+2*ICON_UNIT, star_center_y+1*ICON_UNIT );
335 0 : cairo_move_to ( cr, star_center_x-2*ICON_UNIT, star_center_y+1*ICON_UNIT );
336 0 : cairo_line_to ( cr, star_center_x+2*ICON_UNIT, star_center_y-1*ICON_UNIT );
337 :
338 0 : if ( with_arrow_option )
339 : {
340 : /* small box */
341 0 : cairo_move_to ( cr, x-4*ICON_UNIT, y-DIST-6*ICON_UNIT );
342 0 : cairo_line_to ( cr, x-8*ICON_UNIT, y-DIST-6*ICON_UNIT );
343 0 : cairo_line_to ( cr, x-8*ICON_UNIT, y-DIST-2*ICON_UNIT );
344 0 : cairo_line_to ( cr, x-2*ICON_UNIT, y-DIST-2*ICON_UNIT );
345 :
346 : /* arrow */
347 0 : cairo_move_to ( cr, x+2*ICON_UNIT, y-DIST-0*ICON_UNIT );
348 0 : cairo_line_to ( cr, x+8*ICON_UNIT, y-DIST-6*ICON_UNIT );
349 0 : cairo_line_to ( cr, x+5*ICON_UNIT, y-DIST-5*ICON_UNIT );
350 0 : cairo_move_to ( cr, x+8*ICON_UNIT, y-DIST-6*ICON_UNIT );
351 0 : cairo_line_to ( cr, x+7*ICON_UNIT, y-DIST-3*ICON_UNIT );
352 : }
353 : else
354 : {
355 : /* big box */
356 0 : cairo_move_to ( cr, x-1*ICON_UNIT, y-DIST-6*ICON_UNIT );
357 0 : cairo_line_to ( cr, x-8*ICON_UNIT, y-DIST-6*ICON_UNIT );
358 0 : cairo_line_to ( cr, x-8*ICON_UNIT, y-DIST+3*ICON_UNIT );
359 0 : cairo_line_to ( cr, x+1*ICON_UNIT, y-DIST+3*ICON_UNIT );
360 0 : cairo_line_to ( cr, x+1*ICON_UNIT, y-DIST-2*ICON_UNIT );
361 : }
362 :
363 0 : cairo_stroke (cr);
364 :
365 0 : U8_TRACE_END();
366 0 : }
367 :
368 0 : void gui_sketch_overlay_private_draw_grid( gui_sketch_overlay_t *this_,
369 : const gui_sketch_card_t *card_under_mouse,
370 : cairo_t *cr )
371 : {
372 0 : U8_TRACE_BEGIN();
373 0 : assert( NULL != card_under_mouse );
374 0 : assert( NULL != cr );
375 :
376 0 : cairo_set_source_rgba( cr,
377 : (*this_).overlay_std_red,
378 : (*this_).overlay_std_green,
379 : (*this_).overlay_std_blue,
380 : (*this_).overlay_std_alpha
381 : );
382 :
383 : /* draw grid */
384 : shape_int_rectangle_t bounds;
385 : uint32_t x_count;
386 : uint32_t y_count;
387 0 : gui_sketch_card_get_grid_area( card_under_mouse, &bounds, &x_count, &y_count );
388 0 : assert( x_count >= 2 );
389 0 : assert( y_count >= 2 );
390 0 : const int32_t left = shape_int_rectangle_get_left(&bounds);
391 0 : const int32_t top = shape_int_rectangle_get_top(&bounds);
392 0 : const int32_t width = shape_int_rectangle_get_width(&bounds);
393 0 : const int32_t height = shape_int_rectangle_get_height(&bounds);
394 0 : for ( uint32_t x_idx = 1; (x_idx+1) < x_count; x_idx ++ )
395 : {
396 0 : for ( uint32_t y_idx = 1; (y_idx+1) < y_count; y_idx ++ )
397 : {
398 0 : const int32_t x = left + (( width * x_idx )/( x_count-1 ));
399 0 : const int32_t y = top + (( height * y_idx )/( y_count-1 ));
400 : static const int32_t HALF_LINE = 16;
401 0 : cairo_rectangle ( cr, x, y-HALF_LINE, 1, 2*HALF_LINE );
402 0 : cairo_fill (cr);
403 0 : cairo_rectangle ( cr, x-HALF_LINE, y, 2*HALF_LINE, 1 );
404 0 : cairo_fill (cr);
405 : }
406 : }
407 :
408 0 : U8_TRACE_END();
409 0 : }
410 :
411 0 : void gui_sketch_overlay_private_draw_snap_indicator( gui_sketch_overlay_t *this_,
412 : const gui_sketch_card_t *card_under_mouse,
413 : gui_sketch_snap_state_t snapped,
414 : int32_t x,
415 : int32_t y,
416 : cairo_t *cr )
417 : {
418 0 : U8_TRACE_BEGIN();
419 0 : assert( NULL != card_under_mouse );
420 0 : assert( NULL != cr );
421 :
422 0 : cairo_set_source_rgba( cr,
423 : (*this_).overlay_std_red,
424 : (*this_).overlay_std_green,
425 : (*this_).overlay_std_blue,
426 : (*this_).overlay_std_alpha
427 : );
428 :
429 : /* draw marker that position snapped to grid */
430 0 : const shape_int_rectangle_t bounds = gui_sketch_card_get_bounds( card_under_mouse );
431 0 : const int32_t left = shape_int_rectangle_get_left(&bounds);
432 0 : const int32_t top = shape_int_rectangle_get_top(&bounds);
433 0 : const int32_t width = shape_int_rectangle_get_width(&bounds);
434 0 : const int32_t height = shape_int_rectangle_get_height(&bounds);
435 0 : if ( ( snapped & GUI_SKETCH_SNAP_STATE_X ) == GUI_SKETCH_SNAP_STATE_X )
436 : {
437 0 : cairo_rectangle ( cr, x-2, top, 1, height );
438 0 : cairo_fill (cr);
439 0 : cairo_rectangle ( cr, x+2, top, 1, height );
440 0 : cairo_fill (cr);
441 : }
442 0 : if ( ( snapped & GUI_SKETCH_SNAP_STATE_Y ) == GUI_SKETCH_SNAP_STATE_Y )
443 : {
444 0 : cairo_rectangle ( cr, left, y-2, width, 1 );
445 0 : cairo_fill (cr);
446 0 : cairo_rectangle ( cr, left, y+2, width, 1 );
447 0 : cairo_fill (cr);
448 : }
449 :
450 0 : U8_TRACE_END();
451 0 : }
452 :
453 :
454 : /*
455 : Copyright 2017-2024 Andreas Warnke
456 :
457 : Licensed under the Apache License, Version 2.0 (the "License");
458 : you may not use this file except in compliance with the License.
459 : You may obtain a copy of the License at
460 :
461 : http://www.apache.org/licenses/LICENSE-2.0
462 :
463 : Unless required by applicable law or agreed to in writing, software
464 : distributed under the License is distributed on an "AS IS" BASIS,
465 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
466 : See the License for the specific language governing permissions and
467 : limitations under the License.
468 : */
|