LCOV - code coverage report
Current view: top level - gui/source/sketch - gui_sketch_card_painter.c (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.64.2_covts Lines: 0.0 % 455 0
Test Date: 2025-06-21 07:03:58 Functions: 0.0 % 10 0

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

Generated by: LCOV version 2.0-1