Line data Source code
1 : /* File: gui_sketch_card_painter.c; Copyright and License: see below */
2 :
3 : #include "sketch/gui_sketch_card_painter.h"
4 : #include "u8/u8_trace.h"
5 : #include <gtk/gtk.h>
6 : #include <assert.h>
7 :
8 0 : void gui_sketch_card_painter_init( gui_sketch_card_painter_t *this_ )
9 : {
10 0 : U8_TRACE_BEGIN();
11 :
12 0 : gui_sketch_style_init( &((*this_).sketch_style) );
13 :
14 0 : U8_TRACE_END();
15 0 : }
16 :
17 0 : void gui_sketch_card_painter_destroy( gui_sketch_card_painter_t *this_ )
18 : {
19 0 : U8_TRACE_BEGIN();
20 :
21 0 : gui_sketch_style_destroy( &((*this_).sketch_style) );
22 :
23 0 : U8_TRACE_END();
24 0 : }
25 :
26 0 : void gui_sketch_card_painter_draw_overlay( gui_sketch_card_painter_t *this_,
27 : gui_tool_t selected_tool,
28 : const gui_sketch_drag_state_t *drag_state,
29 : const gui_sketch_card_t *card_under_mouse,
30 : gui_marked_set_t *marked_objects,
31 : cairo_t *cr )
32 : {
33 0 : U8_TRACE_BEGIN();
34 0 : assert( NULL != drag_state );
35 0 : assert( NULL != cr );
36 :
37 0 : switch ( selected_tool )
38 : {
39 0 : case GUI_TOOL_NAVIGATE:
40 : {
41 : }
42 0 : break;
43 :
44 0 : case GUI_TOOL_EDIT:
45 : {
46 0 : gui_sketch_card_painter_private_draw_edit_mode( this_, drag_state, card_under_mouse, cr );
47 : }
48 0 : break;
49 :
50 0 : case GUI_TOOL_CREATE:
51 : {
52 0 : const data_id_t highlighted = gui_marked_set_get_highlighted( marked_objects );
53 0 : const layout_subelement_kind_t highlighted_kind = gui_marked_set_get_highlighted_kind( marked_objects );
54 0 : gui_sketch_card_painter_private_draw_create_mode( this_,
55 : drag_state,
56 : card_under_mouse,
57 : data_id_get_table(&highlighted),
58 : highlighted_kind,
59 : cr
60 : );
61 : }
62 0 : break;
63 :
64 0 : case GUI_TOOL_SEARCH:
65 : {
66 : }
67 0 : break;
68 :
69 0 : default:
70 : {
71 0 : U8_LOG_ERROR("selected_tool is out of range");
72 : }
73 0 : break;
74 : }
75 :
76 0 : U8_TRACE_END();
77 0 : }
78 :
79 :
80 0 : void gui_sketch_card_painter_private_draw_edit_mode( gui_sketch_card_painter_t *this_,
81 : const gui_sketch_drag_state_t *drag_state,
82 : const gui_sketch_card_t *card_under_mouse,
83 : cairo_t *cr )
84 : {
85 0 : U8_TRACE_BEGIN();
86 0 : assert( NULL != drag_state );
87 0 : assert( NULL != cr );
88 :
89 0 : if ( gui_sketch_drag_state_is_dragging ( drag_state ) )
90 : {
91 : const data_full_id_t *const dragged_object
92 0 : = gui_sketch_drag_state_get_dragged_object_const( drag_state );
93 0 : const data_id_t *const dragged_primary = data_full_id_get_primary_id_const( dragged_object );
94 0 : const bool dragging_classifier = ( DATA_TABLE_DIAGRAMELEMENT == data_id_get_table( dragged_primary ) );
95 :
96 0 : if ( NULL != card_under_mouse )
97 : {
98 0 : const data_diagram_t *diag = gui_sketch_card_get_diagram_const ( card_under_mouse );
99 0 : const data_diagram_type_t diag_type = data_diagram_get_diagram_type( diag );
100 0 : const bool draw_2d_diagram
101 : = (( diag_type != DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM )
102 0 : && ( diag_type != DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM )
103 0 : && ( diag_type != DATA_DIAGRAM_TYPE_LIST ));
104 :
105 0 : if ( draw_2d_diagram && dragging_classifier )
106 : {
107 : /* draw grid line crossings */
108 0 : gui_sketch_card_painter_private_draw_grid( this_, card_under_mouse, cr );
109 :
110 : /* draw new grid lines that visualize the order of classifiers */
111 0 : const int32_t to_x = gui_sketch_drag_state_get_to_x ( drag_state );
112 0 : const int32_t to_y = gui_sketch_drag_state_get_to_y ( drag_state );
113 0 : gui_sketch_card_painter_private_visualize_order( this_, card_under_mouse, to_x, to_y, cr );
114 : }
115 : }
116 : }
117 :
118 0 : U8_TRACE_END();
119 0 : }
120 :
121 0 : void gui_sketch_card_painter_private_draw_create_mode( gui_sketch_card_painter_t *this_,
122 : const gui_sketch_drag_state_t *drag_state,
123 : const gui_sketch_card_t *card_under_mouse,
124 : data_table_t highlighted_table,
125 : layout_subelement_kind_t highlighted_kind,
126 : cairo_t *cr )
127 : {
128 0 : U8_TRACE_BEGIN();
129 0 : assert( NULL != drag_state );
130 0 : assert( NULL != cr );
131 :
132 0 : if ( gui_sketch_drag_state_is_dragging ( drag_state ) )
133 : {
134 : /* draw a line */
135 0 : const int32_t from_x = gui_sketch_drag_state_get_from_x ( drag_state );
136 0 : const int32_t from_y = gui_sketch_drag_state_get_from_y ( drag_state );
137 0 : const int32_t to_x = gui_sketch_drag_state_get_to_x ( drag_state );
138 0 : const int32_t to_y = gui_sketch_drag_state_get_to_y ( drag_state );
139 0 : gui_sketch_card_painter_private_draw_arrow( this_, from_x, from_y, to_x, to_y, cr );
140 : }
141 : else /* ! gui_sketch_drag_state_is_dragging() */
142 : {
143 0 : if ( NULL != card_under_mouse )
144 : {
145 0 : const bool draw_new_classifier
146 0 : = (( highlighted_table == DATA_TABLE_CLASSIFIER )&&( highlighted_kind == LAYOUT_SUBELEMENT_KIND_SPACE ))
147 0 : || (( highlighted_table == DATA_TABLE_DIAGRAMELEMENT )&&( highlighted_kind == LAYOUT_SUBELEMENT_KIND_SPACE ))
148 0 : || (( highlighted_table == DATA_TABLE_DIAGRAM )&&( highlighted_kind == LAYOUT_SUBELEMENT_KIND_SPACE ));
149 0 : const bool draw_new_feature
150 0 : = (( highlighted_table == DATA_TABLE_CLASSIFIER )&&( highlighted_kind == LAYOUT_SUBELEMENT_KIND_OUTLINE ))
151 0 : || (( highlighted_table == DATA_TABLE_DIAGRAMELEMENT )&&( highlighted_kind == LAYOUT_SUBELEMENT_KIND_OUTLINE ));
152 0 : const bool draw_new_relationship
153 0 : = (( highlighted_table == DATA_TABLE_CLASSIFIER )&&( highlighted_kind != LAYOUT_SUBELEMENT_KIND_SPACE ))
154 0 : || (( highlighted_table == DATA_TABLE_DIAGRAMELEMENT )&&( highlighted_kind != LAYOUT_SUBELEMENT_KIND_SPACE ))
155 0 : || ( highlighted_table == DATA_TABLE_FEATURE );
156 :
157 0 : const data_diagram_t *diag = gui_sketch_card_get_diagram_const ( card_under_mouse );
158 0 : const data_diagram_type_t diag_type = data_diagram_get_diagram_type( diag );
159 0 : const bool draw_2d_diagram
160 : = (( diag_type != DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM )
161 0 : && ( diag_type != DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM )
162 0 : && ( diag_type != DATA_DIAGRAM_TYPE_LIST ));
163 :
164 : /* get coordinates */
165 0 : const int32_t to_x = gui_sketch_drag_state_get_to_x ( drag_state );
166 0 : const int32_t to_y = gui_sketch_drag_state_get_to_y ( drag_state );
167 :
168 : /* draw grid */
169 0 : if (( draw_new_classifier )&&( draw_2d_diagram ))
170 : {
171 : /* draw grid line crossings */
172 0 : gui_sketch_card_painter_private_draw_grid( this_, card_under_mouse, cr );
173 :
174 : /* draw new grid lines that visualize the order of classifiers */
175 0 : gui_sketch_card_painter_private_visualize_order( this_, card_under_mouse, to_x, to_y, cr );
176 : }
177 :
178 : /* draw boxes and arrow icons */
179 0 : if ( draw_new_classifier )
180 : {
181 0 : gui_sketch_card_painter_private_draw_new_classifier( this_, to_x, to_y, cr );
182 : }
183 0 : if ( draw_new_feature )
184 : {
185 0 : gui_sketch_card_painter_private_draw_new_feature( this_, to_x, to_y, cr );
186 : }
187 0 : if ( draw_new_relationship )
188 : {
189 0 : gui_sketch_card_painter_private_draw_new_relationship( this_, to_x, to_y, cr );
190 : }
191 : }
192 : }
193 :
194 0 : U8_TRACE_END();
195 0 : }
196 :
197 0 : void gui_sketch_card_painter_private_draw_arrow( gui_sketch_card_painter_t *this_,
198 : int32_t from_x,
199 : int32_t from_y,
200 : int32_t to_x,
201 : int32_t to_y,
202 : cairo_t *cr )
203 : {
204 0 : U8_TRACE_BEGIN();
205 0 : assert( NULL != cr );
206 :
207 0 : const GdkRGBA high_color = gui_sketch_style_get_highlight_color( &((*this_).sketch_style) );
208 0 : cairo_set_source_rgba( cr, high_color.red, high_color.green, high_color.blue, high_color.alpha );
209 0 : cairo_move_to ( cr, from_x, from_y );
210 0 : cairo_line_to ( cr, to_x, to_y );
211 0 : cairo_stroke (cr);
212 :
213 : /* draw the arrow tip */
214 : int clock_direction; /* the gdk coordinate system if bottom up - and out clock is also mirrored! */
215 0 : const int32_t x_dist = to_x - from_x;
216 0 : const int32_t y_dist = to_y - from_y;
217 0 : if ( x_dist == 0 )
218 : {
219 0 : clock_direction = ( y_dist < 0 ) ? 6 : 0;
220 : }
221 : else
222 : {
223 0 : int32_t y_x_deci_ratio = ( y_dist * 10 ) / x_dist;
224 0 : if ( y_x_deci_ratio < 3 /* = 0.26 = tan(15 deg) */ )
225 : {
226 0 : if ( y_x_deci_ratio < -10 /* = -1.00 = tan(-45 deg) */ )
227 : {
228 0 : if ( y_x_deci_ratio < -37 /* = -3.73 = tan(-75 deg) */ )
229 : {
230 0 : clock_direction = 6;
231 : }
232 : else
233 : {
234 0 : clock_direction = 5;
235 : }
236 : }
237 : else
238 : {
239 0 : if ( y_x_deci_ratio < -2 /* = -0.26 = tan(-15 deg) */ )
240 : {
241 0 : clock_direction = 4;
242 : }
243 : else
244 : {
245 0 : clock_direction = 3;
246 : }
247 : }
248 : }
249 : else
250 : {
251 0 : if ( y_x_deci_ratio < 10 /* = 1.00 = tan(45 deg) */ )
252 : {
253 0 : clock_direction = 2;
254 : }
255 : else
256 : {
257 0 : if ( y_x_deci_ratio < 38 /* = 3.73 = tan(75 deg) */ )
258 : {
259 0 : clock_direction = 1;
260 : }
261 : else
262 : {
263 0 : clock_direction = 0;
264 : }
265 : }
266 : }
267 0 : if ( x_dist < 0 )
268 : {
269 0 : clock_direction = (clock_direction+6)%12;
270 : }
271 : }
272 : 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}};
273 : 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}};
274 0 : cairo_move_to ( cr, to_x + DX[clock_direction][0], to_y + DY[clock_direction][0] );
275 0 : cairo_line_to ( cr, to_x, to_y );
276 0 : cairo_line_to ( cr, to_x + DX[clock_direction][1], to_y + DY[clock_direction][1] );
277 0 : cairo_stroke (cr);
278 :
279 0 : U8_TRACE_END();
280 0 : }
281 :
282 0 : void gui_sketch_card_painter_private_draw_new_classifier( gui_sketch_card_painter_t *this_,
283 : int32_t x,
284 : int32_t y,
285 : cairo_t *cr )
286 : {
287 0 : U8_TRACE_BEGIN();
288 0 : assert( NULL != cr );
289 :
290 0 : const GdkRGBA high_color = gui_sketch_style_get_highlight_color( &((*this_).sketch_style) );
291 0 : cairo_set_source_rgba( cr, high_color.red, high_color.green, high_color.blue, high_color.alpha );
292 : static const int32_t ICON_UNIT = 2;
293 : static const int32_t DIST = 12;
294 :
295 : /* star */
296 0 : const int32_t star_center_x = x+(1)*ICON_UNIT;
297 0 : const int32_t star_center_y = y-DIST-6*ICON_UNIT;
298 0 : cairo_move_to ( cr, star_center_x, star_center_y-2*ICON_UNIT );
299 0 : cairo_line_to ( cr, star_center_x, star_center_y+2*ICON_UNIT );
300 0 : cairo_move_to ( cr, star_center_x-2*ICON_UNIT, star_center_y-1*ICON_UNIT );
301 0 : cairo_line_to ( cr, star_center_x+2*ICON_UNIT, star_center_y+1*ICON_UNIT );
302 0 : cairo_move_to ( cr, star_center_x-2*ICON_UNIT, star_center_y+1*ICON_UNIT );
303 0 : cairo_line_to ( cr, star_center_x+2*ICON_UNIT, star_center_y-1*ICON_UNIT );
304 :
305 : /* big box */
306 0 : cairo_move_to ( cr, x-1*ICON_UNIT, y-DIST-6*ICON_UNIT );
307 0 : cairo_line_to ( cr, x-8*ICON_UNIT, y-DIST-6*ICON_UNIT );
308 0 : cairo_line_to ( cr, x-8*ICON_UNIT, y-DIST+3*ICON_UNIT );
309 0 : cairo_line_to ( cr, x+1*ICON_UNIT, y-DIST+3*ICON_UNIT );
310 0 : cairo_line_to ( cr, x+1*ICON_UNIT, y-DIST-2*ICON_UNIT );
311 :
312 0 : cairo_stroke (cr);
313 :
314 0 : U8_TRACE_END();
315 0 : }
316 :
317 0 : void gui_sketch_card_painter_private_draw_new_feature( gui_sketch_card_painter_t *this_,
318 : int32_t x,
319 : int32_t y,
320 : cairo_t *cr )
321 : {
322 0 : U8_TRACE_BEGIN();
323 0 : assert( NULL != cr );
324 :
325 0 : const GdkRGBA high_color = gui_sketch_style_get_highlight_color( &((*this_).sketch_style) );
326 0 : cairo_set_source_rgba( cr, high_color.red, high_color.green, high_color.blue, high_color.alpha );
327 : static const int32_t ICON_UNIT = 2;
328 : static const int32_t DIST = 12;
329 :
330 : /* star */
331 0 : const int32_t star_center_x = x+(-2)*ICON_UNIT;
332 0 : const int32_t star_center_y = y-DIST-6*ICON_UNIT;
333 0 : cairo_move_to ( cr, star_center_x, star_center_y-2*ICON_UNIT );
334 0 : cairo_line_to ( cr, star_center_x, star_center_y+2*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 0 : cairo_move_to ( cr, star_center_x-2*ICON_UNIT, star_center_y+1*ICON_UNIT );
338 0 : cairo_line_to ( cr, star_center_x+2*ICON_UNIT, star_center_y-1*ICON_UNIT );
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 0 : cairo_stroke (cr);
347 :
348 0 : U8_TRACE_END();
349 0 : }
350 :
351 0 : void gui_sketch_card_painter_private_draw_new_relationship( gui_sketch_card_painter_t *this_,
352 : int32_t x,
353 : int32_t y,
354 : cairo_t *cr )
355 : {
356 0 : U8_TRACE_BEGIN();
357 0 : assert( NULL != cr );
358 :
359 0 : const GdkRGBA high_color = gui_sketch_style_get_highlight_color( &((*this_).sketch_style) );
360 0 : cairo_set_source_rgba( cr, high_color.red, high_color.green, high_color.blue, high_color.alpha );
361 : static const int32_t ICON_UNIT = 2;
362 : static const int32_t DIST = 12;
363 :
364 : /* arrow */
365 0 : cairo_move_to ( cr, x+2*ICON_UNIT, y-DIST-0*ICON_UNIT );
366 0 : cairo_line_to ( cr, x+8*ICON_UNIT, y-DIST-6*ICON_UNIT );
367 0 : cairo_line_to ( cr, x+5*ICON_UNIT, y-DIST-5*ICON_UNIT );
368 0 : cairo_move_to ( cr, x+8*ICON_UNIT, y-DIST-6*ICON_UNIT );
369 0 : cairo_line_to ( cr, x+7*ICON_UNIT, y-DIST-3*ICON_UNIT );
370 :
371 0 : cairo_stroke (cr);
372 :
373 0 : U8_TRACE_END();
374 0 : }
375 :
376 0 : void gui_sketch_card_painter_private_draw_grid( gui_sketch_card_painter_t *this_,
377 : const gui_sketch_card_t *card_under_mouse,
378 : cairo_t *cr )
379 : {
380 0 : U8_TRACE_BEGIN();
381 0 : assert( NULL != card_under_mouse );
382 0 : assert( NULL != cr );
383 :
384 0 : const GdkRGBA high_color = gui_sketch_style_get_highlight_color( &((*this_).sketch_style) );
385 0 : cairo_set_source_rgba( cr, high_color.red, high_color.green, high_color.blue, high_color.alpha );
386 :
387 : /* draw grid */
388 : shape_int_rectangle_t bounds;
389 : uint32_t x_count;
390 : uint32_t y_count;
391 0 : gui_sketch_card_get_grid_area( card_under_mouse, &bounds, &x_count, &y_count );
392 0 : assert( x_count >= 2 );
393 0 : assert( y_count >= 2 );
394 0 : const int32_t left = shape_int_rectangle_get_left(&bounds);
395 0 : const int32_t top = shape_int_rectangle_get_top(&bounds);
396 0 : const int32_t width = shape_int_rectangle_get_width(&bounds);
397 0 : const int32_t height = shape_int_rectangle_get_height(&bounds);
398 0 : for ( uint32_t x_idx = 1; (x_idx+1) < x_count; x_idx ++ )
399 : {
400 0 : for ( uint32_t y_idx = 1; (y_idx+1) < y_count; y_idx ++ )
401 : {
402 0 : const int32_t x = left + (( width * x_idx )/( x_count-1 ));
403 0 : const int32_t y = top + (( height * y_idx )/( y_count-1 ));
404 : static const int32_t HALF_LINE = 16;
405 0 : cairo_rectangle ( cr, x, y-HALF_LINE, 1, 2*HALF_LINE );
406 0 : cairo_fill (cr);
407 0 : cairo_rectangle ( cr, x-HALF_LINE, y, 2*HALF_LINE, 1 );
408 0 : cairo_fill (cr);
409 : }
410 : }
411 :
412 0 : U8_TRACE_END();
413 0 : }
414 :
415 0 : void gui_sketch_card_painter_private_visualize_order( gui_sketch_card_painter_t *this_,
416 : const gui_sketch_card_t *card_under_mouse,
417 : int32_t x,
418 : int32_t y,
419 : cairo_t *cr )
420 : {
421 0 : U8_TRACE_BEGIN();
422 0 : assert( NULL != card_under_mouse );
423 0 : assert( NULL != cr );
424 :
425 : /* fetch input data: subwidget */
426 0 : const shape_int_rectangle_t bounds = gui_sketch_card_get_bounds( card_under_mouse );
427 0 : const int32_t left = shape_int_rectangle_get_left(&bounds);
428 0 : const int32_t top = shape_int_rectangle_get_top(&bounds);
429 0 : const int32_t right = shape_int_rectangle_get_right(&bounds);
430 0 : const int32_t bottom = shape_int_rectangle_get_bottom(&bounds);
431 :
432 : /* fetch input data: grid */
433 0 : const geometry_grid_t *const grid = gui_sketch_card_get_grid_const( card_under_mouse);
434 0 : const geometry_grid_kind_t grid_kind = geometry_grid_get_kind( grid );
435 0 : const double snap_interval = 5.0;
436 0 : const geometry_non_linear_scale_t *const x_scale = geometry_grid_get_x_scale_const( grid );
437 0 : const int32_t order_at_x = geometry_non_linear_scale_get_order( x_scale, (double) x, snap_interval );
438 0 : const geometry_non_linear_scale_t *const y_scale = geometry_grid_get_y_scale_const( grid );
439 0 : const int32_t order_at_y = geometry_non_linear_scale_get_order( y_scale, (double) y, snap_interval );
440 :
441 : /* define own distances */
442 0 : const double gap = 3.0;
443 0 : const double curve_space = 3.0 * gap;
444 :
445 : /* fetch input data: visible set */
446 0 : const layout_visible_set_t *const layout_data = gui_sketch_card_get_visible_set( card_under_mouse );
447 0 : const uint32_t classifiers = layout_visible_set_get_visible_classifier_count( layout_data );
448 :
449 : /* to draw x, follow y from top to bottom */
450 0 : if (( grid_kind == GEOMETRY_GRID_KIND_X )||( grid_kind == GEOMETRY_GRID_KIND_XY ))
451 : {
452 : /* order visible set by top y coordinates of classifiers */
453 : universal_array_index_sorter_t sorted;
454 0 : universal_array_index_sorter_init( &sorted );
455 0 : for ( uint32_t idx = 0; idx < classifiers; idx ++ )
456 : {
457 : const layout_visible_classifier_t *const classifier
458 0 : = layout_visible_set_get_visible_classifier_const( layout_data, idx );
459 :
460 0 : const geometry_rectangle_t *const envelope = layout_visible_classifier_get_envelope_box_const( classifier );
461 0 : const int64_t weight = geometry_rectangle_get_top( envelope );
462 0 : const u8_error_t insert_error = universal_array_index_sorter_insert( &sorted, idx, weight );
463 0 : if ( U8_ERROR_NONE != insert_error )
464 : {
465 0 : U8_LOG_WARNING( "not all rectangles are considered for the top-to-bottom line" );
466 : }
467 : }
468 :
469 : /* process rectangles top to bottom */
470 : /* local variables represent 3 points: */
471 : /* current_pos_x / current_pos_y : The position where the already drawn line ends */
472 : /* planned_pos_x / planned_pos_y : The position that would be the next unless the next loop finds an earlier position */
473 : /* draw_to_pos_x / draw_to_pos_y : While drawing, this is a temporary value storing the next current_pos position */
474 0 : double current_pos_x = x;
475 0 : double current_pos_y = top;
476 0 : double planned_pos_x = x;
477 0 : double planned_pos_y = top; /* the planned next y - may be superseded by the next classifier */
478 0 : cairo_move_to( cr, x, top );
479 0 : const uint32_t count_sorted = universal_array_index_sorter_get_count( &sorted );
480 0 : for ( uint32_t idx_of_idx = 0; idx_of_idx < count_sorted; idx_of_idx ++ )
481 : {
482 0 : const uint32_t idx = universal_array_index_sorter_get_array_index( &sorted, idx_of_idx );
483 : const layout_visible_classifier_t *const classifier
484 0 : = layout_visible_set_get_visible_classifier_const( layout_data, idx );
485 :
486 : /* skip classifiers which contain others, these are not positioned according to their order value */
487 0 : const uint32_t children = layout_visible_set_count_descendants( layout_data, classifier );
488 0 : if ( children == 0 )
489 : {
490 0 : const data_visible_classifier_t *const vis_data = layout_visible_classifier_get_data_const( classifier );
491 0 : const data_classifier_t *const c_data = data_visible_classifier_get_classifier_const( vis_data );
492 0 : const int32_t c_x_order = data_classifier_get_x_order( c_data );
493 0 : const geometry_rectangle_t *const envelope = layout_visible_classifier_get_envelope_box_const( classifier );
494 0 : const double envelope_left = geometry_rectangle_get_left( envelope );
495 0 : const double envelope_right = geometry_rectangle_get_right( envelope );
496 0 : const double envelope_top = geometry_rectangle_get_top( envelope );
497 0 : const double envelope_bottom = geometry_rectangle_get_bottom( envelope );
498 : /* if line passes through the classifier, center on symbol, not on envelope */
499 0 : const geometry_rectangle_t *const symbol = layout_visible_classifier_get_symbol_box_const( classifier );
500 0 : const double symbol_center_x = geometry_rectangle_get_center_x( symbol );
501 :
502 0 : const bool pass_through_center_x = ( c_x_order == order_at_x );
503 0 : const bool pass_on_left = ( c_x_order > order_at_x ) && ( envelope_left < x );
504 0 : const bool pass_on_right = ( c_x_order < order_at_x ) && ( envelope_right > x );
505 0 : const bool ignored = !( pass_through_center_x || pass_on_left || pass_on_right );
506 0 : const double draw_to_pos_y = envelope_top - gap;
507 0 : double draw_to_pos_x = x;
508 0 : if ( pass_through_center_x )
509 : {
510 0 : draw_to_pos_x = symbol_center_x;
511 : }
512 0 : if ( pass_on_left )
513 : {
514 0 : draw_to_pos_x = envelope_left - gap;
515 : }
516 0 : if ( pass_on_right )
517 : {
518 0 : draw_to_pos_x = envelope_right + gap;
519 : }
520 0 : if ( ! ignored )
521 : {
522 : /* if planned_pos_x not at x and enough space to draw */
523 : /* 1) a return to x and 2) a comeback to new draw_to_pos_x */
524 0 : if ( (( planned_pos_x < ( x - 0.001 ) )||( planned_pos_x > ( x + 0.001 ) ))
525 0 : && ( planned_pos_y + ( 2 * curve_space ) < draw_to_pos_y ) )
526 : {
527 0 : cairo_line_to( cr, current_pos_x, planned_pos_y );
528 0 : cairo_curve_to( cr,
529 : current_pos_x,
530 : planned_pos_y + curve_space,
531 : x,
532 : planned_pos_y,
533 : x,
534 : planned_pos_y + curve_space
535 : );
536 0 : current_pos_x = x;
537 0 : current_pos_y = planned_pos_y + curve_space;
538 : }
539 :
540 : /* if there is enough space to draw a line before drawing a curve to draw_to_pos_x */
541 0 : if ( ( current_pos_y + curve_space ) < draw_to_pos_y )
542 : {
543 0 : cairo_line_to( cr, current_pos_x, draw_to_pos_y - curve_space );
544 0 : current_pos_y = draw_to_pos_y - curve_space;
545 : }
546 :
547 : /* draw begin of current pass-by */
548 0 : cairo_curve_to( cr,
549 : current_pos_x,
550 : draw_to_pos_y,
551 : draw_to_pos_x,
552 : current_pos_y,
553 : draw_to_pos_x,
554 : draw_to_pos_y
555 : );
556 : /* update variables for next loop */
557 0 : current_pos_x = draw_to_pos_x;
558 0 : current_pos_y = draw_to_pos_y;
559 0 : planned_pos_x = current_pos_x;
560 0 : planned_pos_y = envelope_bottom + gap;
561 : }
562 : }
563 : }
564 : /* draw end of last pass-by (if any) */
565 0 : if ( (( planned_pos_x < ( x - 0.001 ) )||( planned_pos_x > ( x + 0.001 ) ))
566 0 : && ( planned_pos_y + ( 1 * curve_space ) < bottom ) )
567 : {
568 0 : cairo_line_to( cr, current_pos_x, planned_pos_y );
569 0 : cairo_curve_to( cr,
570 : current_pos_x,
571 : planned_pos_y + curve_space,
572 : x,
573 : planned_pos_y,
574 : x,
575 : planned_pos_y + curve_space
576 : );
577 0 : current_pos_x = x;
578 0 : current_pos_y = planned_pos_y + curve_space;
579 : }
580 : /* draw to end point and stroke the drawn path */
581 0 : cairo_line_to( cr, current_pos_x, bottom );
582 : {
583 : double dashes[2];
584 0 : dashes[0] = 2.0 * gap; /* on segment */
585 0 : dashes[1] = 4.0 * gap; /* off segment */
586 0 : cairo_set_dash ( cr, dashes, 2, 0.0 );
587 : }
588 0 : cairo_stroke( cr );
589 0 : cairo_set_dash( cr, NULL, 0, 0.0 );
590 : }
591 :
592 : /* to draw y, follow x from left to right */
593 0 : if (( grid_kind == GEOMETRY_GRID_KIND_Y )||( grid_kind == GEOMETRY_GRID_KIND_XY ))
594 : {
595 : /* order visible set by left x coordinates of classifiers */
596 : universal_array_index_sorter_t sorted;
597 0 : universal_array_index_sorter_init( &sorted );
598 0 : for ( uint32_t idx = 0; idx < classifiers; idx ++ )
599 : {
600 : const layout_visible_classifier_t *const classifier
601 0 : = layout_visible_set_get_visible_classifier_const( layout_data, idx );
602 :
603 0 : const geometry_rectangle_t *const envelope = layout_visible_classifier_get_envelope_box_const( classifier );
604 0 : const int64_t weight = geometry_rectangle_get_left( envelope );
605 0 : const u8_error_t insert_error = universal_array_index_sorter_insert( &sorted, idx, weight );
606 0 : if ( U8_ERROR_NONE != insert_error )
607 : {
608 0 : U8_LOG_WARNING( "not all rectangles are considered for the left-to-right line" );
609 : }
610 : }
611 :
612 : /* process rectangles left to right */
613 : /* local variables represent 3 points: */
614 : /* current_pos_x / current_pos_y : The position where the already drawn line ends */
615 : /* planned_pos_x / planned_pos_y : The position that would be the next unless the next loop finds an earlier position */
616 : /* draw_to_pos_x / draw_to_pos_y : While drawing, this is a temporary value storing the next current_pos position */
617 0 : double current_pos_x = left;
618 0 : double current_pos_y = y;
619 0 : double planned_pos_x = left; /* the planned next x - may be superseded by the next classifier */
620 0 : double planned_pos_y = y;
621 0 : cairo_move_to( cr, left, y );
622 0 : const uint32_t count_sorted = universal_array_index_sorter_get_count( &sorted );
623 0 : for ( uint32_t idx_of_idx = 0; idx_of_idx < count_sorted; idx_of_idx ++ )
624 : {
625 0 : const uint32_t idx = universal_array_index_sorter_get_array_index( &sorted, idx_of_idx );
626 : const layout_visible_classifier_t *const classifier
627 0 : = layout_visible_set_get_visible_classifier_const( layout_data, idx );
628 :
629 : /* skip classifiers which contain others, these are not positioned according to their order value */
630 0 : const uint32_t children = layout_visible_set_count_descendants( layout_data, classifier );
631 0 : if ( children == 0 )
632 : {
633 0 : const data_visible_classifier_t *const vis_data = layout_visible_classifier_get_data_const( classifier );
634 0 : const data_classifier_t *const c_data = data_visible_classifier_get_classifier_const( vis_data );
635 0 : const int32_t c_y_order = data_classifier_get_y_order( c_data );
636 0 : const geometry_rectangle_t *const envelope = layout_visible_classifier_get_envelope_box_const( classifier );
637 0 : const double envelope_top = geometry_rectangle_get_top( envelope );
638 0 : const double envelope_bottom = geometry_rectangle_get_bottom( envelope );
639 0 : const double envelope_left = geometry_rectangle_get_left( envelope );
640 0 : const double envelope_right = geometry_rectangle_get_right( envelope );
641 : /* if line passes through the classifier, center on symbol, not on envelope */
642 0 : const geometry_rectangle_t *const symbol = layout_visible_classifier_get_symbol_box_const( classifier );
643 0 : const double symbol_center_y = geometry_rectangle_get_center_y( symbol );
644 :
645 0 : const bool pass_through_center_y = ( c_y_order == order_at_y );
646 0 : const bool pass_on_top = ( c_y_order > order_at_y ) && ( envelope_top < y );
647 0 : const bool pass_on_bottom = ( c_y_order < order_at_y ) && ( envelope_bottom > y );
648 0 : const bool ignored = !( pass_through_center_y || pass_on_top || pass_on_bottom );
649 0 : const double draw_to_pos_x = envelope_left - gap;
650 0 : double draw_to_pos_y = y;
651 0 : if ( pass_through_center_y )
652 : {
653 0 : draw_to_pos_y = symbol_center_y;
654 : }
655 0 : if ( pass_on_top )
656 : {
657 0 : draw_to_pos_y = envelope_top - gap;
658 : }
659 0 : if ( pass_on_bottom )
660 : {
661 0 : draw_to_pos_y = envelope_bottom + gap;
662 : }
663 0 : if ( ! ignored )
664 : {
665 : /* if planned_pos_y not at y and enough space to draw */
666 : /* 1) a return to y and 2) a comeback to new draw_to_pos_y */
667 0 : if ( (( planned_pos_y < ( y - 0.001 ) )||( planned_pos_y > ( y + 0.001 ) ))
668 0 : && ( planned_pos_x + ( 2 * curve_space ) < draw_to_pos_x ) )
669 : {
670 0 : cairo_line_to( cr, planned_pos_x, current_pos_y );
671 0 : cairo_curve_to( cr,
672 : planned_pos_x + curve_space,
673 : current_pos_y,
674 : planned_pos_x,
675 : y,
676 : planned_pos_x + curve_space,
677 : y
678 : );
679 0 : current_pos_x = planned_pos_x + curve_space;
680 0 : current_pos_y = y;
681 : }
682 :
683 : /* if there is enough space to draw a line before drawing a curve to draw_to_pos_x */
684 0 : if ( ( current_pos_x + curve_space ) < draw_to_pos_x )
685 : {
686 0 : cairo_line_to( cr, draw_to_pos_x - curve_space, current_pos_y );
687 0 : current_pos_x = draw_to_pos_x - curve_space;
688 : }
689 :
690 : /* draw begin of current pass-by */
691 0 : cairo_curve_to( cr,
692 : draw_to_pos_x,
693 : current_pos_y,
694 : current_pos_x,
695 : draw_to_pos_y,
696 : draw_to_pos_x,
697 : draw_to_pos_y
698 : );
699 : /* update variables for next loop */
700 0 : current_pos_x = draw_to_pos_x;
701 0 : current_pos_y = draw_to_pos_y;
702 0 : planned_pos_x = envelope_right + gap;
703 0 : planned_pos_y = current_pos_y;
704 : }
705 : }
706 : }
707 : /* draw end of last pass-by (if any) */
708 0 : if ( (( planned_pos_y < ( y - 0.001 ) )||( planned_pos_y > ( y + 0.001 ) ))
709 0 : && ( planned_pos_x + ( 1 * curve_space ) < right ) )
710 : {
711 0 : cairo_line_to( cr, planned_pos_x, current_pos_y );
712 0 : cairo_curve_to( cr,
713 : planned_pos_x + curve_space,
714 : current_pos_y,
715 : planned_pos_x,
716 : y,
717 : planned_pos_x + curve_space,
718 : y
719 : );
720 0 : current_pos_x = planned_pos_x + curve_space;
721 0 : current_pos_y = y;
722 : }
723 : /* draw to end point and stroke the drawn path */
724 0 : cairo_line_to( cr, right, current_pos_y );
725 : {
726 : double dashes[2];
727 0 : dashes[0] = 2.0 * gap; /* on segment */
728 0 : dashes[1] = 4.0 * gap; /* off segment */
729 0 : cairo_set_dash ( cr, dashes, 2, 0.0 );
730 : }
731 0 : cairo_stroke( cr );
732 0 : cairo_set_dash( cr, NULL, 0, 0.0 );
733 : }
734 :
735 0 : U8_TRACE_END();
736 0 : }
737 :
738 0 : void gui_sketch_card_painter_private_draw_element_space( const gui_sketch_card_painter_t *this_,
739 : const layout_subelement_id_t *subelement,
740 : const layout_visible_set_t *layouted_set,
741 : cairo_t *cr )
742 : {
743 0 : assert( NULL != subelement );
744 0 : assert( NULL != layouted_set );
745 0 : assert( NULL != cr );
746 0 : const layout_diagram_t *const layout_diag = layout_visible_set_get_diagram_const( layouted_set );
747 :
748 : geometry_rectangle_t highlight;
749 0 : geometry_rectangle_init_empty( &highlight );
750 : data_id_t search_id;
751 0 : data_id_copy( &search_id, data_full_id_get_primary_id_const( layout_subelement_id_get_id_const( subelement ) ) );
752 0 : const layout_subelement_kind_t kind = layout_subelement_id_get_kind( subelement );
753 :
754 : /* check diagram */
755 0 : const data_diagram_t *const diag_data = layout_diagram_get_data_const( layout_diag );
756 0 : const data_id_t diag_id = data_diagram_get_data_id( diag_data );
757 0 : if ( data_id_equals( &search_id, &diag_id ) )
758 : {
759 0 : switch ( kind )
760 : {
761 0 : case LAYOUT_SUBELEMENT_KIND_LABEL:
762 : {
763 0 : geometry_rectangle_replace( &highlight, layout_diagram_get_label_box_const( layout_diag ) );
764 0 : geometry_rectangle_expand_4dir( &highlight, 4.0 /* delta_width */, 4.0 /* delta_height */ );
765 0 : gui_sketch_card_painter_private_draw_rect( this_, &highlight, cr );
766 : }
767 0 : break;
768 :
769 0 : case LAYOUT_SUBELEMENT_KIND_OUTLINE:
770 : {
771 : geometry_rectangle_t empty_space;
772 0 : geometry_rectangle_replace( &highlight, layout_diagram_get_bounds_const( layout_diag ) );
773 0 : geometry_rectangle_copy( &empty_space, layout_diagram_get_draw_area_const( layout_diag ) ); /* no highlight in space */
774 0 : gui_sketch_card_painter_private_draw_border( this_, &highlight, &empty_space, cr );
775 : }
776 0 : break;
777 :
778 0 : default:
779 : case LAYOUT_SUBELEMENT_KIND_SPACE:
780 : {
781 0 : geometry_rectangle_replace( &highlight, layout_diagram_get_draw_area_const( layout_diag ) );
782 0 : gui_sketch_card_painter_private_draw_rect( this_, &highlight, cr );
783 : }
784 0 : break;
785 : }
786 : }
787 :
788 : /* iterate over all classifiers */
789 0 : const uint32_t c_count = layout_visible_set_get_visible_classifier_count( layouted_set );
790 0 : for ( uint32_t c_index = 0; c_index < c_count; c_index ++ )
791 : {
792 : const layout_visible_classifier_t *const visible_classifier
793 0 : = layout_visible_set_get_visible_classifier_const ( layouted_set, c_index );
794 0 : const data_diagramelement_t *diagele = layout_visible_classifier_get_diagramelement_const( visible_classifier );
795 0 : const data_id_t diagele_id = data_diagramelement_get_data_id( diagele );
796 0 : if ( data_id_equals( &search_id, &diagele_id ) )
797 : {
798 0 : switch ( kind )
799 : {
800 0 : case LAYOUT_SUBELEMENT_KIND_LABEL:
801 : {
802 0 : geometry_rectangle_replace( &highlight, layout_visible_classifier_get_label_box_const( visible_classifier ) );
803 0 : geometry_rectangle_expand_4dir( &highlight, 4.0 /* delta_width */, 4.0 /* delta_height */ );
804 0 : gui_sketch_card_painter_private_draw_rect( this_, &highlight, cr );
805 : }
806 0 : break;
807 :
808 0 : case LAYOUT_SUBELEMENT_KIND_OUTLINE:
809 : {
810 : geometry_rectangle_t empty_space;
811 0 : geometry_rectangle_replace( &highlight, layout_visible_classifier_get_symbol_box_const( visible_classifier ) );
812 0 : geometry_rectangle_copy( &empty_space, layout_visible_classifier_get_space_const( visible_classifier ) ); /* no highlight in space */
813 0 : gui_sketch_card_painter_private_draw_border( this_, &highlight, &empty_space, cr );
814 : }
815 0 : break;
816 :
817 0 : default:
818 : case LAYOUT_SUBELEMENT_KIND_SPACE:
819 : {
820 0 : geometry_rectangle_replace( &highlight, layout_visible_classifier_get_space_const( visible_classifier ) );
821 0 : gui_sketch_card_painter_private_draw_rect( this_, &highlight, cr );
822 : }
823 0 : break;
824 : }
825 : }
826 : }
827 :
828 : /* check all contained features */
829 0 : const uint32_t f_count = layout_visible_set_get_feature_count( layouted_set );
830 0 : for ( uint32_t f_index = 0; f_index < f_count; f_index ++ )
831 : {
832 : const layout_feature_t *const the_feature
833 0 : = layout_visible_set_get_feature_const ( layouted_set, f_index );
834 0 : const data_feature_t *feature = layout_feature_get_data_const( the_feature );
835 0 : const data_id_t feature_id = data_feature_get_data_id( feature );
836 0 : if ( data_id_equals( &search_id, &feature_id ) )
837 : {
838 0 : switch ( kind )
839 : {
840 0 : case LAYOUT_SUBELEMENT_KIND_LABEL:
841 : {
842 0 : geometry_rectangle_replace( &highlight, layout_feature_get_label_box_const( the_feature ) );
843 0 : geometry_rectangle_expand_4dir( &highlight, 4.0 /* delta_width */, 4.0 /* delta_height */ );
844 0 : gui_sketch_card_painter_private_draw_rect( this_, &highlight, cr );
845 : }
846 0 : break;
847 :
848 0 : default:
849 : case LAYOUT_SUBELEMENT_KIND_OUTLINE:
850 : {
851 0 : geometry_rectangle_replace( &highlight, layout_feature_get_symbol_box_const( the_feature ) );
852 0 : geometry_rectangle_expand_4dir( &highlight, 4.0 /* delta_width */, 4.0 /* delta_height */ );
853 0 : gui_sketch_card_painter_private_draw_rect( this_, &highlight, cr );
854 : }
855 0 : break;
856 : }
857 : }
858 : }
859 :
860 0 : const uint32_t count_relations = layout_visible_set_get_relationship_count ( layouted_set );
861 0 : for ( uint32_t rel_index = 0; rel_index < count_relations; rel_index ++ )
862 : {
863 : const layout_relationship_t *const the_relationship
864 0 : = layout_visible_set_get_relationship_const( layouted_set, rel_index );
865 0 : const data_relationship_t *const relationship = layout_relationship_get_data_const( the_relationship );
866 0 : const data_id_t relationship_id = data_relationship_get_data_id( relationship );
867 0 : if ( data_id_equals( &search_id, &relationship_id ) )
868 : {
869 0 : switch ( kind )
870 : {
871 0 : case LAYOUT_SUBELEMENT_KIND_LABEL:
872 : {
873 0 : geometry_rectangle_replace( &highlight, layout_relationship_get_label_box_const( the_relationship ) );
874 0 : geometry_rectangle_expand_4dir( &highlight, 4.0 /* delta_width */, 4.0 /* delta_height */ );
875 0 : gui_sketch_card_painter_private_draw_rect( this_, &highlight, cr );
876 : }
877 0 : break;
878 :
879 0 : default:
880 : case LAYOUT_SUBELEMENT_KIND_OUTLINE:
881 : {
882 : const geometry_connector_t *const relationship_shape
883 0 : = layout_relationship_get_shape_const( the_relationship );
884 : {
885 : geometry_rectangle_t segment_src;
886 0 : segment_src = geometry_connector_get_segment_bounds( relationship_shape,
887 : GEOMETRY_CONNECTOR_SEGMENT_SOURCE
888 : );
889 0 : geometry_rectangle_expand_4dir( &segment_src, 6.0 /* delta_width */, 6.0 /* delta_height */ );
890 0 : gui_sketch_card_painter_private_draw_rect( this_, &segment_src, cr );
891 : }
892 : {
893 : geometry_rectangle_t segment_dst;
894 0 : segment_dst = geometry_connector_get_segment_bounds( relationship_shape,
895 : GEOMETRY_CONNECTOR_SEGMENT_DESTINATION
896 : );
897 0 : geometry_rectangle_expand_4dir( &segment_dst, 6.0 /* delta_width */, 6.0 /* delta_height */ );
898 0 : gui_sketch_card_painter_private_draw_rect( this_, &segment_dst, cr );
899 : }
900 : {
901 : geometry_rectangle_t segment_main;
902 0 : segment_main = geometry_connector_get_segment_bounds( relationship_shape,
903 : GEOMETRY_CONNECTOR_SEGMENT_MAIN
904 : );
905 0 : geometry_rectangle_expand_4dir( &segment_main, 6.0 /* delta_width */, 6.0 /* delta_height */ );
906 0 : gui_sketch_card_painter_private_draw_rect( this_, &segment_main, cr );
907 : }
908 : }
909 0 : break;
910 : }
911 : }
912 : }
913 0 : }
914 :
915 0 : void gui_sketch_card_painter_draw_paper( gui_sketch_card_painter_t *this_,
916 : gui_tool_t selected_tool,
917 : const gui_sketch_drag_state_t *drag_state,
918 : const gui_sketch_card_t *card,
919 : cairo_t *cr )
920 : {
921 0 : U8_TRACE_BEGIN();
922 0 : assert( NULL != drag_state );
923 0 : assert( NULL != card );
924 0 : assert( NULL != cr );
925 :
926 0 : if ( gui_sketch_card_is_visible(card) )
927 : {
928 0 : const bool create_tool = ( selected_tool == GUI_TOOL_CREATE );
929 :
930 0 : shape_int_rectangle_t bounds = gui_sketch_card_get_bounds( card );
931 0 : const int32_t left = shape_int_rectangle_get_left( &bounds );
932 0 : const int32_t top = shape_int_rectangle_get_top( &bounds );
933 0 : const uint32_t width = shape_int_rectangle_get_width( &bounds );
934 0 : const uint32_t height = shape_int_rectangle_get_height( &bounds );
935 :
936 : /* draw paper */
937 0 : if ( create_tool )
938 : {
939 : static const double GRAY_R = 0.875;
940 : static const double GRAY_G = 0.875;
941 : static const double GRAY_B = 0.875;
942 : static const double GRAY_A = 1.0;
943 0 : cairo_set_source_rgba( cr, GRAY_R, GRAY_G, GRAY_B, GRAY_A );
944 : }
945 : else
946 : {
947 : static const double WHITE_R = 1.0;
948 : static const double WHITE_G = 1.0;
949 : static const double WHITE_B = 1.0;
950 : static const double WHITE_A = 1.0;
951 0 : cairo_set_source_rgba( cr, WHITE_R, WHITE_G, WHITE_B, WHITE_A );
952 : }
953 0 : cairo_rectangle ( cr, left, top, width, height );
954 0 : cairo_fill (cr);
955 :
956 0 : const layout_visible_set_t *const layout = gui_sketch_card_get_visible_set( card );
957 0 : if ( layout_visible_set_is_valid( layout ) && create_tool )
958 : {
959 0 : const int32_t mouse_x = gui_sketch_drag_state_get_to_x( drag_state );
960 0 : const int32_t mouse_y = gui_sketch_drag_state_get_to_y( drag_state );
961 :
962 : const layout_subelement_id_t subelement_to_highlight
963 0 : = gui_sketch_card_get_element_at_pos( card, mouse_x, mouse_y, !create_tool /* filter_lifelines */ );
964 :
965 0 : gui_sketch_card_painter_private_draw_element_space( this_, &subelement_to_highlight, layout, cr );
966 : }
967 : }
968 :
969 0 : U8_TRACE_END();
970 0 : }
971 :
972 :
973 : /*
974 : Copyright 2017-2024 Andreas Warnke
975 :
976 : Licensed under the Apache License, Version 2.0 (the "License");
977 : you may not use this file except in compliance with the License.
978 : You may obtain a copy of the License at
979 :
980 : http://www.apache.org/licenses/LICENSE-2.0
981 :
982 : Unless required by applicable law or agreed to in writing, software
983 : distributed under the License is distributed on an "AS IS" BASIS,
984 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
985 : See the License for the specific language governing permissions and
986 : limitations under the License.
987 : */
|