summaryrefslogtreecommitdiff
path: root/src/gtkext
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2019-03-01 14:57:19 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2019-03-01 14:57:19 (GMT)
commit72bebbd9dc7d59f69e23442b6c5b5526feb2a1a9 (patch)
tree94506e5bce1f511a3704a7f7d505ceb91432b23d /src/gtkext
parent1dae3be2d0860b601d780583365ea7827a6a1be6 (diff)
Drawn a preview of blocks to collapse in graph view.
Diffstat (limited to 'src/gtkext')
-rw-r--r--src/gtkext/blockbar.ui4
-rw-r--r--src/gtkext/graph/cluster.c70
-rw-r--r--src/gtkext/graph/cluster.h3
-rw-r--r--src/gtkext/gtkbufferdisplay-int.h2
-rw-r--r--src/gtkext/gtkbufferdisplay.c62
-rw-r--r--src/gtkext/gtkgraphdisplay.c150
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 @@
</packing>
</child>
<child>
- <object class="GtkButton">
+ <object class="GtkButton" id="collapse">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="focus_on_click">False</property>
@@ -44,7 +44,9 @@
<property name="tooltip_text" translatable="yes">Collapse the block with all its dominated blocks</property>
<property name="opacity">0.59999999999999998</property>
<property name="relief">none</property>
+ <signal name="enter-notify-event" handler="on_block_bar_collapsing_enter" swapped="no"/>
<signal name="enter-notify-event" handler="on_block_bar_enter_notify" swapped="no"/>
+ <signal name="leave-notify-event" handler="on_block_bar_collapsing_leave" swapped="no"/>
<signal name="leave-notify-event" handler="on_block_bar_leave_notify" swapped="no"/>
<child>
<object class="GtkImage">
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 <assert.h>
+#include <math.h>
#include <i18n.h>
@@ -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));
+
+}