From 72bebbd9dc7d59f69e23442b6c5b5526feb2a1a9 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Fri, 1 Mar 2019 15:57:19 +0100 Subject: Drawn a preview of blocks to collapse in graph view. --- src/gtkext/blockbar.ui | 4 +- src/gtkext/graph/cluster.c | 70 +++++++++++++++++- src/gtkext/graph/cluster.h | 3 + src/gtkext/gtkbufferdisplay-int.h | 2 + src/gtkext/gtkbufferdisplay.c | 62 ++++++++++++++++ src/gtkext/gtkgraphdisplay.c | 150 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 289 insertions(+), 2 deletions(-) diff --git a/src/gtkext/blockbar.ui b/src/gtkext/blockbar.ui index b8f07cd..9659aec 100644 --- a/src/gtkext/blockbar.ui +++ b/src/gtkext/blockbar.ui @@ -36,7 +36,7 @@ - + True True False @@ -44,7 +44,9 @@ Collapse the block with all its dominated blocks 0.59999999999999998 none + + diff --git a/src/gtkext/graph/cluster.c b/src/gtkext/graph/cluster.c index 7872000..8220bfe 100644 --- a/src/gtkext/graph/cluster.c +++ b/src/gtkext/graph/cluster.c @@ -264,6 +264,8 @@ static void set_y_for_graph_rank(const graph_rank_t *, gint *); /* Détermine les ordonnées de tous les liens en place. */ static void compute_loop_link_with_graph_rank(const graph_rank_t *, const GtkAllocation *); +/* Recherche le groupe de blocs avec un composant comme chef. */ +static GGraphCluster *find_cluster_by_widget_in_graph_rank(const graph_rank_t *, GtkWidget *); /* -------------------------- DEFINITION D'UN CHEF DE FILE -------------------------- */ @@ -1776,7 +1778,7 @@ static void set_y_for_graph_rank(const graph_rank_t *grank, gint *base) static void compute_loop_link_with_graph_rank(const graph_rank_t *grank, const GtkAllocation *needed) { - size_t i; /* Boucle de parcours #1 */ + size_t i; /* Boucle de parcours */ for (i = 0; i < grank->count; i++) g_graph_cluster_compute_link_y_positions(grank->clusters[i]); @@ -1786,6 +1788,34 @@ static void compute_loop_link_with_graph_rank(const graph_rank_t *grank, const G } +/****************************************************************************** +* * +* Paramètres : grank = ensemble de blocs de même rang à analyser. * +* widget = composant graphique à retrouver. * +* * +* Description : Recherche le groupe de blocs avec un composant comme chef. * +* * +* Retour : Groupe trouvé ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GGraphCluster *find_cluster_by_widget_in_graph_rank(const graph_rank_t *grank, GtkWidget *widget) +{ + GGraphCluster *result; /* Trouvaille à retourner */ + size_t i; /* Boucle de parcours */ + + result = NULL; + + for (i = 0; i < grank->count && result == NULL; i++) + result = g_graph_cluster_find_by_widget(grank->clusters[i], widget); + + return result; + +} + + /* ---------------------------------------------------------------------------------- */ /* DEFINITION D'UN CHEF DE FILE */ @@ -3361,6 +3391,44 @@ static void g_graph_cluster_resolve_links(const GGraphCluster *cluster) } +/****************************************************************************** +* * +* Paramètres : cluster = graphique de blocs à analyser. * +* widget = composant graphique à retrouver. * +* * +* Description : Recherche le groupe de blocs avec un composant comme chef. * +* * +* Retour : Groupe trouvé ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GGraphCluster *g_graph_cluster_find_by_widget(GGraphCluster *cluster, GtkWidget *widget) +{ + GGraphCluster *result; /* Trouvaille à retourner */ + size_t i; /* Boucle de parcours */ + + if (cluster->display == widget) + { + result = cluster; + g_object_ref(G_OBJECT(result)); + } + + else + { + result = NULL; + + for (i = 0; i < cluster->ranks_count && result == NULL; i++) + result = find_cluster_by_widget_in_graph_rank(&cluster->ranks[i], widget); + + } + + return result; + +} + + /* ---------------------------------------------------------------------------------- */ /* CALCUL DE REPARTITION DE BLOCS */ diff --git a/src/gtkext/graph/cluster.h b/src/gtkext/graph/cluster.h index 00c6d82..2a48b25 100644 --- a/src/gtkext/graph/cluster.h +++ b/src/gtkext/graph/cluster.h @@ -64,6 +64,9 @@ GtkWidget *g_graph_cluster_get_widget(GGraphCluster *); /* Dispose chaque noeud sur la surface de destination donnée. */ void g_graph_cluster_place(GGraphCluster *, GtkGraphDisplay *); +/* Recherche le groupe de blocs avec un composant comme chef. */ +GGraphCluster *g_graph_cluster_find_by_widget(GGraphCluster *, GtkWidget *); + /* ------------------------- CALCUL DE REPARTITION DE BLOCS ------------------------- */ diff --git a/src/gtkext/gtkbufferdisplay-int.h b/src/gtkext/gtkbufferdisplay-int.h index b4b64d0..1d98332 100644 --- a/src/gtkext/gtkbufferdisplay-int.h +++ b/src/gtkext/gtkbufferdisplay-int.h @@ -65,6 +65,8 @@ struct _GtkBufferDisplayClass void (* reach_limit) (GtkBufferDisplay *, GdkScrollDirection); + void (* prepare_collapsing) (GtkBufferDisplay *, gboolean); + }; diff --git a/src/gtkext/gtkbufferdisplay.c b/src/gtkext/gtkbufferdisplay.c index 5ad808f..0794dd4 100644 --- a/src/gtkext/gtkbufferdisplay.c +++ b/src/gtkext/gtkbufferdisplay.c @@ -120,6 +120,12 @@ static gboolean on_block_bar_enter_notify(GtkWidget *, GdkEventCrossing *, GtkBu /* Accompagne la fin du survol d'un élément de barre d'outils. */ static gboolean on_block_bar_leave_notify(GtkWidget *, GdkEventCrossing *, GtkBufferDisplay *); +/* Accompagne le début du survol du bouton de compression. */ +static gboolean on_block_bar_collapsing_enter(GtkWidget *, GdkEventCrossing *, GtkBufferDisplay *); + +/* Accompagne la fin du survol du bouton de compression. */ +static gboolean on_block_bar_collapsing_leave(GtkWidget *, GdkEventCrossing *, GtkBufferDisplay *); + /* ---------------------------------------------------------------------------------- */ @@ -184,6 +190,14 @@ static void gtk_buffer_display_class_init(GtkBufferDisplayClass *class) g_cclosure_marshal_VOID__ENUM, G_TYPE_NONE, 1, GTK_TYPE_SCROLL_TYPE); + g_signal_new("prepare-collapsing", + GTK_TYPE_BUFFER_DISPLAY, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GtkBufferDisplayClass, prepare_collapsing), + NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + } @@ -1257,6 +1271,8 @@ void gtk_buffer_display_add_block_bar(GtkBufferDisplay *display) gtk_builder_add_callback_symbols(display->builder, "on_block_bar_enter_notify", G_CALLBACK(on_block_bar_enter_notify), "on_block_bar_leave_notify", G_CALLBACK(on_block_bar_leave_notify), + "on_block_bar_collapsing_enter", G_CALLBACK(on_block_bar_collapsing_enter), + "on_block_bar_collapsing_leave", G_CALLBACK(on_block_bar_collapsing_leave), NULL); gtk_builder_connect_signals(display->builder, display); @@ -1339,3 +1355,49 @@ static gboolean on_block_bar_leave_notify(GtkWidget *widget, GdkEventCrossing *e return FALSE; } + + +/****************************************************************************** +* * +* Paramètres : widget = composant graphique concerné par l'opération. * +* event = informations liées à l'événement. * +* display = panneau d'affichage impliqué par l'action. * +* * +* Description : Accompagne le début du survol du bouton de compression. * +* * +* Retour : FALSE pour poursuivre la propagation de l'événement. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static gboolean on_block_bar_collapsing_enter(GtkWidget *widget, GdkEventCrossing *event, GtkBufferDisplay *display) +{ + g_signal_emit_by_name(display, "prepare-collapsing", FALSE); + + return FALSE; + +} + + +/****************************************************************************** +* * +* Paramètres : widget = composant graphique concerné par l'opération. * +* event = informations liées à l'événement. * +* display = panneau d'affichage impliqué par l'action. * +* * +* Description : Accompagne la fin du survol du bouton de compression. * +* * +* Retour : FALSE pour poursuivre la propagation de l'événement. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static gboolean on_block_bar_collapsing_leave(GtkWidget *widget, GdkEventCrossing *event, GtkBufferDisplay *display) +{ + g_signal_emit_by_name(display, "prepare-collapsing", TRUE); + + return FALSE; + +} diff --git a/src/gtkext/gtkgraphdisplay.c b/src/gtkext/gtkgraphdisplay.c index 72519a2..fb89b2e 100644 --- a/src/gtkext/gtkgraphdisplay.c +++ b/src/gtkext/gtkgraphdisplay.c @@ -25,6 +25,7 @@ #include +#include #include @@ -55,6 +56,8 @@ struct _GtkGraphDisplay segcnt_list *highlighted; /* Segments mis en évidence */ GGraphCluster *cluster; /* Disposition en graphique */ + GtkAllocation collapsing_area; /* Aire à compresser */ + bool may_collapsing; /* Validité de cette aire */ GGraphEdge **edges; /* Liens entre les noeuds */ size_t edges_count; /* Quantité de ces liens */ @@ -82,6 +85,9 @@ struct _GtkGraphDisplayClass /* Marges en bordure de graphique */ #define GRAPH_MARGIN 23 +/* Taille du cadrillage pour l'aperçu des compressions */ +#define COLLAPSING_GRID_SIZE 4 + /* Initialise la classe générique des graphiques de code. */ static void gtk_graph_display_class_init(GtkGraphDisplayClass *); @@ -149,6 +155,9 @@ static void gtk_graph_display_changed_highlights(GtkBlockDisplay *, GtkGraphDisp /* Notifie une incapacité de déplacement au sein d'un noeud. */ static void gtk_graph_display_reach_caret_limit(GtkBufferDisplay *, GdkScrollDirection, GtkGraphDisplay *); +/* Prend note de la proximité d'une compression de blocs. */ +static void gtk_graph_display_prepare_collasping(GtkBufferDisplay *, gboolean, GtkGraphDisplay *); + /* Détermine le type du composant d'affichage en graphique. */ @@ -457,6 +466,93 @@ static void gtk_graph_display_adjust_scroll_value(GtkGraphDisplay *display, GtkA static gboolean gtk_graph_display_draw(GtkWidget *widget, cairo_t *cr, GtkGraphDisplay *display) { size_t i; /* Boucle de parcours */ + cairo_surface_t *pat_image; /* Fond du futur pinceau */ + cairo_t *pat_cr; /* Pinceau pour le pinceau */ + cairo_pattern_t *pattern; /* Patron de remplissage */ + double degrees; /* Conversion en degrés */ + + /* Eventuel fond pour la zone de compression */ + + if (display->may_collapsing) + { + /* Préparation du pinceau */ + + pat_image = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + 2 * COLLAPSING_GRID_SIZE, 2 * COLLAPSING_GRID_SIZE); + + pat_cr = cairo_create(pat_image); + + cairo_set_source_rgba(pat_cr, 1.0, 1.0, 1.0, 0.05); + + cairo_rectangle(pat_cr, + 0, 0, + COLLAPSING_GRID_SIZE, COLLAPSING_GRID_SIZE); + + cairo_fill(pat_cr); + + cairo_rectangle(pat_cr, + COLLAPSING_GRID_SIZE, COLLAPSING_GRID_SIZE, + COLLAPSING_GRID_SIZE, COLLAPSING_GRID_SIZE); + + cairo_fill(pat_cr); + + pattern = cairo_pattern_create_for_surface(pat_image); + cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); + + + /* Dessin de la zone */ + + degrees = M_PI / 180.0; + + cairo_arc(cr, + display->collapsing_area.x + BORDER_CORNER_RADIUS, + display->collapsing_area.y + BORDER_CORNER_RADIUS, + BORDER_CORNER_RADIUS, 180 * degrees, 270 * degrees); + + cairo_line_to(cr, + display->collapsing_area.x + display->collapsing_area.width - BORDER_CORNER_RADIUS, + display->collapsing_area.y); + + cairo_arc(cr, + display->collapsing_area.x + display->collapsing_area.width - BORDER_CORNER_RADIUS, + display->collapsing_area.y + BORDER_CORNER_RADIUS, + BORDER_CORNER_RADIUS, 270 * degrees, 360 * degrees); + + cairo_line_to(cr, + display->collapsing_area.x + display->collapsing_area.width, + display->collapsing_area.y + display->collapsing_area.height - BORDER_CORNER_RADIUS); + + cairo_arc(cr, + display->collapsing_area.x + display->collapsing_area.width - BORDER_CORNER_RADIUS, + display->collapsing_area.y + display->collapsing_area.height - BORDER_CORNER_RADIUS, + BORDER_CORNER_RADIUS, 0 * degrees, 90 * degrees); + + cairo_line_to(cr, + display->collapsing_area.x + BORDER_CORNER_RADIUS, + display->collapsing_area.y + display->collapsing_area.height); + + cairo_arc(cr, + display->collapsing_area.x + BORDER_CORNER_RADIUS, + display->collapsing_area.y + display->collapsing_area.height - BORDER_CORNER_RADIUS, + BORDER_CORNER_RADIUS, 90 * degrees, 180 * degrees); + + cairo_close_path(cr); + + cairo_set_source(cr, pattern); + + cairo_fill(cr); + + /* Sortie propre */ + + cairo_pattern_destroy(pattern); + + cairo_destroy(pat_cr); + + cairo_surface_destroy(pat_image); + + } + + /* Dessin des ombres */ void draw_shadow(GtkWidget *child, gpointer unused) { @@ -1098,6 +1194,7 @@ GtkWidget *gtk_graph_display_new(void) void gtk_graph_display_put(GtkGraphDisplay *display, GtkWidget *widget, const GtkAllocation *alloc) { g_signal_connect(widget, "reach-limit", G_CALLBACK(gtk_graph_display_reach_caret_limit), display); + g_signal_connect(widget, "prepare-collapsing", G_CALLBACK(gtk_graph_display_prepare_collasping), display); g_signal_connect(widget, "highlight-changed", G_CALLBACK(gtk_graph_display_changed_highlights), display); gtk_fixed_put(GTK_FIXED(display->support), widget, GRAPH_MARGIN + alloc->x, GRAPH_MARGIN + alloc->y); @@ -1180,6 +1277,8 @@ static void gtk_graph_display_reset(GtkGraphDisplay *display, bool dispose) display->cluster = NULL; } + display->may_collapsing = false; + for (i = 0; i < display->edges_count; i++) g_object_unref(G_OBJECT(display->edges[i])); @@ -1422,3 +1521,54 @@ static void gtk_graph_display_reach_caret_limit(GtkBufferDisplay *node, GdkScrol /* TODO : scrolling... */ #endif } + + +/****************************************************************************** +* * +* Paramètres : node = composant d'affichage impliqué dans la procédure. * +* done = indique si la préparation est à jeter. * +* display = support graphique de tous les noeuds. * +* * +* Description : Prend note de la proximité d'une compression de blocs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void gtk_graph_display_prepare_collasping(GtkBufferDisplay *node, gboolean done, GtkGraphDisplay *display) +{ + GGraphCluster *cluster; /* Ensemble à priori concerné */ + + if (!done) + { + cluster = g_graph_cluster_find_by_widget(display->cluster, GTK_WIDGET(node)); + + if (cluster == NULL) + done = TRUE; + + else + { + g_graph_cluster_compute_needed_alloc(cluster, &display->collapsing_area); + g_object_unref(G_OBJECT(cluster)); + + display->collapsing_area.x += GRAPH_MARGIN; + display->collapsing_area.y += GRAPH_MARGIN; + + assert(BORDER_CORNER_RADIUS < GRAPH_MARGIN); + + display->collapsing_area.x -= BORDER_CORNER_RADIUS; + display->collapsing_area.y -= BORDER_CORNER_RADIUS; + display->collapsing_area.width += 2 * BORDER_CORNER_RADIUS; + display->collapsing_area.height += 2 * BORDER_CORNER_RADIUS; + + } + + } + + display->may_collapsing = !done; + + gtk_widget_queue_draw(GTK_WIDGET(display)); + +} -- cgit v0.11.2-87-g4458