From cffbe4839da452af215f05dfb7cc6c9304c1285e Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Thu, 20 Dec 2018 23:12:28 +0100 Subject: Kept the current location when switching views. --- src/glibext/gbufferview.c | 9 +++---- src/glibext/linesegment.c | 53 ++++++++++++++++++++++++++++++++++++++- src/glibext/linesegment.h | 6 +++++ src/gtkext/graph/cluster.c | 25 +++++++++++++++++++ src/gtkext/graph/cluster.h | 3 +++ src/gtkext/gtkbufferdisplay.c | 56 +++++++++++++++++++++++++++++++++++++++++ src/gtkext/gtkbufferdisplay.h | 3 +++ src/gtkext/gtkdisplaypanel.c | 31 +++++++++++++++++++++-- src/gtkext/gtkdisplaypanel.h | 4 +++ src/gtkext/gtkgraphdisplay.c | 58 ++++++++++++++++++++++++++++++++++++++++--- src/gui/menus/view.c | 57 +++++++++++++++++++++++++++++++++++++++--- 11 files changed, 290 insertions(+), 15 deletions(-) diff --git a/src/glibext/gbufferview.c b/src/glibext/gbufferview.c index f5adc9d..2239d23 100644 --- a/src/glibext/gbufferview.c +++ b/src/glibext/gbufferview.c @@ -36,7 +36,6 @@ struct _GBufferView GBufferCache *cache; /* Tampon du contenu visualisé */ segcnt_list *highlighted; /* Segments mis en évidence */ - bool external; /* Note l'origine de la liste */ bool unrestricted; /* Validité des informations */ GLineCursor *start; /* Première ligne intégrée */ @@ -189,8 +188,7 @@ static void g_buffer_view_dispose(GBufferView *view) static void g_buffer_view_finalize(GBufferView *view) { - if (!view->external) - exit_segment_content_list(view->highlighted); + unref_segment_content_list(view->highlighted); G_OBJECT_CLASS(g_buffer_view_parent_class)->finalize(G_OBJECT(view)); @@ -223,12 +221,13 @@ GBufferView *g_buffer_view_new(GBufferCache *cache, segcnt_list *highlighted) g_signal_connect(cache, "size-changed", G_CALLBACK(on_buffer_cache_size_changed), result); if (highlighted != NULL) + { + ref_segment_content_list(highlighted); result->highlighted = highlighted; + } else result->highlighted = init_segment_content_list(); - result->external = (highlighted != NULL); - return result; } diff --git a/src/glibext/linesegment.c b/src/glibext/linesegment.c index 557dff2..15fde78 100644 --- a/src/glibext/linesegment.c +++ b/src/glibext/linesegment.c @@ -148,6 +148,8 @@ struct _segcnt_list fnv64_t *hashes; /* Empreinte pour comparaisons */ size_t count; /* Nommbre de ces empreintes */ + unsigned int ref_count; /* Compteur de références */ + }; @@ -970,7 +972,12 @@ segcnt_list *init_segment_content_list(void) { segcnt_list *result; /* Structure à retourner */ - result = (segcnt_list *)calloc(1, sizeof(segcnt_list)); + result = malloc(sizeof(segcnt_list)); + + result->hashes = NULL; + result->count = 0; + + result->ref_count = 1; return result; @@ -991,6 +998,8 @@ segcnt_list *init_segment_content_list(void) void exit_segment_content_list(segcnt_list *list) { + assert(list->ref_count == 0); + reset_segment_content_list(list); free(list); @@ -1000,6 +1009,48 @@ void exit_segment_content_list(segcnt_list *list) /****************************************************************************** * * +* Paramètres : list = ensemble de références de contenus à traiter. * +* * +* Description : Incrémente le nombre d'utilisation de la liste de contenus. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void ref_segment_content_list(segcnt_list *list) +{ + assert(list->ref_count > 0); + + list->ref_count++; + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble de références de contenus à traiter. * +* * +* Description : Décrémente le nombre d'utilisation de la liste de contenus. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void unref_segment_content_list(segcnt_list *list) +{ + assert(list->ref_count > 0); + + list->ref_count--; + +} + + +/****************************************************************************** +* * * Paramètres : list = ensemble de références de contenus à manipuler. * * * * Description : Vide, si besoin est, une liste de contenus de segments. * diff --git a/src/glibext/linesegment.h b/src/glibext/linesegment.h index c6deb38..9723a80 100644 --- a/src/glibext/linesegment.h +++ b/src/glibext/linesegment.h @@ -191,6 +191,12 @@ segcnt_list *init_segment_content_list(void); /* Libère la mémoire occupée par une liste de contenus. */ void exit_segment_content_list(segcnt_list *); +/* Incrémente le nombre d'utilisation de la liste de contenus. */ +void ref_segment_content_list(segcnt_list *); + +/* Décrémente le nombre d'utilisation de la liste de contenus. */ +void unref_segment_content_list(segcnt_list *); + /* Vide, si besoin est, une liste de contenus de segments. */ bool reset_segment_content_list(segcnt_list *); diff --git a/src/gtkext/graph/cluster.c b/src/gtkext/graph/cluster.c index 9bbfb34..17af9ce 100644 --- a/src/gtkext/graph/cluster.c +++ b/src/gtkext/graph/cluster.c @@ -790,6 +790,31 @@ void g_graph_cluster_compute_needed_alloc(const GGraphCluster *cluster, GtkAlloc /****************************************************************************** * * +* Paramètres : cluster = encapsulation à consulter. * +* * +* Description : Fournit le composant graphique principal du groupe. * +* * +* Retour : Composant graphique principal utilisé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GtkWidget *g_graph_cluster_get_widget(GGraphCluster *cluster) +{ + GtkWidget *result; + + result = cluster->display; + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : cluster = encapsulation à traiter. * * display = support de destination finale. * * * diff --git a/src/gtkext/graph/cluster.h b/src/gtkext/graph/cluster.h index fbf2d10..11ce66e 100644 --- a/src/gtkext/graph/cluster.h +++ b/src/gtkext/graph/cluster.h @@ -56,6 +56,9 @@ GGraphCluster *g_graph_cluster_new(GCodeBlock *, segcnt_list *, GLoadedBinary *) /* Détermine l'emplacement requis d'un ensemble de blocs. */ void g_graph_cluster_compute_needed_alloc(const GGraphCluster *, GtkAllocation *); +/* Fournit le composant graphique principal du groupe. */ +GtkWidget *g_graph_cluster_get_widget(GGraphCluster *); + /* Dispose chaque noeud sur la surface de destination donnée. */ void g_graph_cluster_place(GGraphCluster *, GtkGraphDisplay *); diff --git a/src/gtkext/gtkbufferdisplay.c b/src/gtkext/gtkbufferdisplay.c index 1989b1c..a748cf2 100644 --- a/src/gtkext/gtkbufferdisplay.c +++ b/src/gtkext/gtkbufferdisplay.c @@ -212,6 +212,12 @@ static void gtk_buffer_display_init(GtkBufferDisplay *display) static void gtk_buffer_display_dispose(GtkBufferDisplay *display) { + if (display->caret_timer != 0) + { + g_source_remove(display->caret_timer); + display->caret_timer = 0; + } + g_clear_object(&display->view); g_clear_object(&display->cursor); @@ -814,6 +820,56 @@ GBufferView *gtk_buffer_display_get_view(const GtkBufferDisplay *display) /****************************************************************************** * * +* Paramètres : display = composant GTK à consulter. * +* cursor = définition générique d'une localisation à l'écran. * +* * +* Description : Détermine si une position est comprise dans l'affichage. * +* * +* Retour : true si le composant comprend bien la localisation fournie. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool gtk_buffer_display_contains_cursor(const GtkBufferDisplay *display, const GLineCursor *cursor) +{ + bool result; /* Bilan à retourner */ + GLineCursor *start; /* Position initiale du tampon */ + GLineCursor *end; /* Position finale du tampon */ + int status; /* Bilan d'une comparaison */ + + g_buffer_view_get_restrictions(display->view, &start, &end); + + if (start == NULL && end == NULL) + result = NULL; + + else + { + status = g_line_cursor_compare(start, cursor); + + if (status > 0) + result = false; + + else + { + status = g_line_cursor_compare(cursor, end); + + result = (status < 0); + + } + + g_object_unref(G_OBJECT(start)); + g_object_unref(G_OBJECT(end)); + + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : display = composant GTK à manipuler. * * x = abscisse proposée pour le nouvel emplacement. * * y = ordonnée proposée pour le nouvel emplacement. * diff --git a/src/gtkext/gtkbufferdisplay.h b/src/gtkext/gtkbufferdisplay.h index dc2e4ff..73fbbde 100644 --- a/src/gtkext/gtkbufferdisplay.h +++ b/src/gtkext/gtkbufferdisplay.h @@ -59,6 +59,9 @@ GBufferView *gtk_buffer_display_get_view(const GtkBufferDisplay *); /* ------------------------------ ANIMATION DU CURSEUR ------------------------------ */ +/* Détermine si une position est comprise dans l'affichage. */ +bool gtk_buffer_display_contains_cursor(const GtkBufferDisplay *, const GLineCursor *); + /* Déplace le curseur à un emplacement en extrémité. */ bool gtk_buffer_display_move_caret_to(GtkBufferDisplay *, bool, gint *); diff --git a/src/gtkext/gtkdisplaypanel.c b/src/gtkext/gtkdisplaypanel.c index 3623ced..93e47e7 100644 --- a/src/gtkext/gtkdisplaypanel.c +++ b/src/gtkext/gtkdisplaypanel.c @@ -887,6 +887,33 @@ const vmpa2t *gtk_display_panel_get_caret_location(const GtkDisplayPanel *panel) /****************************************************************************** * * +* Paramètres : panel = composant GTK à consulter. * +* cursor = emplacement à présenter à l'écran. * +* x = position horizontale au sein du composant. [OUT] * +* y = position verticale au sein du composant. [OUT] * +* tweak = adaptation finale à effectuer. * +* * +* Description : Indique la position d'affichage d'un emplacement donné. * +* * +* Retour : true si l'adresse fait partie du composant, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool gtk_display_panel_get_cursor_coordinates(const GtkDisplayPanel *panel, const GLineCursor *cursor, gint *x, gint *y, ScrollPositionTweak tweak) +{ + bool result; /* Bilan à remonter */ + + result = GTK_DISPLAY_PANEL_GET_CLASS(panel)->get_coordinates(panel, cursor, x, y, tweak); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : panel = composant GTK à consulter. * * * * Description : Fournit l'élément actif lié à la position courante. * @@ -1182,7 +1209,7 @@ static void gtk_display_panel_scroll_to_cursor(GtkDisplayPanel *panel, const GLi GTK_DISPLAY_PANEL_GET_CLASS(panel)->define(panel, addr); */ - if (GTK_DISPLAY_PANEL_GET_CLASS(panel)->get_coordinates(panel, cursor, &x, &y, tweak)) + if (gtk_display_panel_get_cursor_coordinates(panel, cursor, &x, &y, tweak)) { viewport = gtk_widget_get_parent(GTK_WIDGET(panel)); @@ -1216,7 +1243,7 @@ static void gtk_display_panel_scroll_to_cursor(GtkDisplayPanel *panel, const GLi /* Déplacement du curseur */ - if (move && GTK_DISPLAY_PANEL_GET_CLASS(panel)->get_coordinates(panel, cursor, &x, &y, SPT_RAW)) + if (move && gtk_display_panel_get_cursor_coordinates(panel, cursor, &x, &y, SPT_RAW)) GTK_DISPLAY_PANEL_GET_CLASS(panel)->move_caret_to(panel, x, y); } diff --git a/src/gtkext/gtkdisplaypanel.h b/src/gtkext/gtkdisplaypanel.h index 51648df..6baac64 100644 --- a/src/gtkext/gtkdisplaypanel.h +++ b/src/gtkext/gtkdisplaypanel.h @@ -30,6 +30,7 @@ #include "../arch/vmpa.h" +#include "../glibext/gloadedpanel.h" @@ -63,6 +64,9 @@ void gtk_display_panel_set_code_display(GtkDisplayPanel *, bool); /* Indique la position courante du curseur. */ const vmpa2t *gtk_display_panel_get_caret_location(const GtkDisplayPanel *); +/* Indique la position d'affichage d'un emplacement donné. */ +bool gtk_display_panel_get_cursor_coordinates(const GtkDisplayPanel *, const GLineCursor *, gint *, gint *, ScrollPositionTweak); + /* Fournit l'élément actif lié à la position courante. */ GObject *gtk_display_panel_get_active_object(const GtkDisplayPanel *); diff --git a/src/gtkext/gtkgraphdisplay.c b/src/gtkext/gtkgraphdisplay.c index 955f540..6187677 100644 --- a/src/gtkext/gtkgraphdisplay.c +++ b/src/gtkext/gtkgraphdisplay.c @@ -637,6 +637,7 @@ static void gtk_graph_display_define_main_address(GtkGraphDisplay *display, cons gint right; /* Abscisse du coin droit */ gint bottom; /* Ordonnée du coin inférieur */ GtkAllocation allocation; /* Espace alloué au panneau */ + GtkWidget *child; /* Composant sélectionné */ if (display->routine == NULL) need_update = true; @@ -694,6 +695,16 @@ static void gtk_graph_display_define_main_address(GtkGraphDisplay *display, cons gtk_graph_display_update_support_margins(display, &allocation); + /** + * Première sélection... + */ + + child = g_graph_cluster_get_widget(display->cluster); + + gtk_container_set_focus_child(GTK_CONTAINER(display->support), child); + + g_object_unref(G_OBJECT(child)); + ggddma_bad_type: g_object_unref(G_OBJECT(symbol)); @@ -746,9 +757,42 @@ static const vmpa2t *gtk_graph_display_get_caret_location(const GtkGraphDisplay static bool gtk_graph_display_get_cursor_coordinates(const GtkGraphDisplay *display, const GLineCursor *cursor, gint *x, gint *y, ScrollPositionTweak tweak) { - /* TODO */ + bool result; /* Bilan final à retourner */ + GList *children; /* Sous-composants à parcourir */ + GList *iter; /* Boucle de parcours */ + GtkWidget *child; /* Composant embarqué */ + GtkAllocation alloc; /* Emplacement réservé */ + + result = false; + + children = gtk_container_get_children(GTK_CONTAINER(display->support)); - return false; + for (iter = g_list_first(children); iter != NULL; iter = g_list_next(iter)) + { + child = GTK_WIDGET(iter->data); + + if (!GTK_IS_BUFFER_DISPLAY(child)) + continue; + + result = gtk_buffer_display_contains_cursor(GTK_BUFFER_DISPLAY(child), cursor); + + if (result) + { + result = gtk_display_panel_get_cursor_coordinates(GTK_DISPLAY_PANEL(child), cursor, x, y, tweak); + assert(result); + + gtk_widget_get_allocation(child, &alloc); + + *x += alloc.x; + *y += alloc.y; + break; + } + + } + + g_list_free(children); + + return result; } @@ -822,8 +866,14 @@ static bool gtk_graph_display_move_caret_to(GtkGraphDisplay *display, gint x, gi static GLineCursor *gtk_graph_display_get_cursor(const GtkGraphDisplay *display) { GLineCursor *result; /* Contenu à retourner */ + GtkWidget *child; /* Composant sélectionné */ + + child = gtk_container_get_focus_child(GTK_CONTAINER(display->support)); - result = NULL; + if (child != NULL) + result = g_loaded_panel_get_cursor(G_LOADED_PANEL(child)); + else + result = NULL; return result; @@ -1012,7 +1062,7 @@ static void gtk_graph_display_reset(GtkGraphDisplay *display, bool dispose) if (display->highlighted != NULL) { - exit_segment_content_list(display->highlighted); + unref_segment_content_list(display->highlighted); display->highlighted = NULL; } diff --git a/src/gui/menus/view.c b/src/gui/menus/view.c index 4591c0f..63b6371 100644 --- a/src/gui/menus/view.c +++ b/src/gui/menus/view.c @@ -58,6 +58,9 @@ static void mcb_view_switch_to_next_support(GtkRadioMenuItem *, gpointer); /* Réagit avec le menu "Affichage -> Basculer vers le précédent". */ static void mcb_view_switch_to_prev_support(GtkRadioMenuItem *, gpointer); +/* Accompagne la première allocation d'un panneau d'affichage. */ +static void handle_loaded_panel_first_allocation(GtkWidget *, GdkRectangle *, GLineCursor *); + /* Effectue la bascule d'un panneau de chargement à un autre. */ static void change_current_view_support(unsigned int); @@ -741,6 +744,32 @@ static void mcb_view_switch_to_prev_support(GtkRadioMenuItem *menuitem, gpointer /****************************************************************************** * * +* Paramètres : widget = composant graphique visé par la procédure. * +* alloc = emplacement accordé à ce composant. * +* cursor = emplacement transmis à présenter en premier lieu. * +* * +* Description : Accompagne la première allocation d'un panneau d'affichage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void handle_loaded_panel_first_allocation(GtkWidget *widget, GdkRectangle *alloc, GLineCursor *cursor) +{ + /* On ne réagit que la première fois */ + g_signal_handlers_disconnect_by_func(widget, G_CALLBACK(handle_loaded_panel_first_allocation), cursor); + + g_loaded_panel_scroll_to_cursor(G_LOADED_PANEL(widget), cursor, SPT_TOP, true); + + g_object_unref(G_OBJECT(cursor)); + +} + + +/****************************************************************************** +* * * Paramètres : wanted = indice de la vue désirée. * * * * Description : Effectue la bascule d'un panneau de chargement à un autre. * @@ -776,13 +805,35 @@ static void change_current_view_support(unsigned int wanted) cursor = g_loaded_panel_get_cursor(panel); + change_editor_items_current_view(new); + if (cursor != NULL) { g_loaded_panel_set_cursor(new, cursor); - g_object_unref(G_OBJECT(cursor)); - } - change_editor_items_current_view(new); + /** + * A ce stade, le nouveau composant d'affichage n'a pas encore connu son + * premier gtk_widget_size_allocate(). Cela viendra avec un événement ultérieur + * à celui déclenché pour ce menu. + * + * Dans les faits, cette situation est notable pour la vue en graphique : + * tous les blocs basiques chargés et intégrés dedans ont une position + * égale à -1 et une dimension d'un pixel. + * + * La recherche du bloc présent à une position donnée échoue donc dans la + * fonction gtk_graph_display_move_caret_to(), appelée in fine par + * g_loaded_panel_scroll_to_cursor(). + * + * Et au final, le curseur d'origine n'est pas transmis, et donc pas + * transmissible non plus par la suite. + * + * On se doit ainsi d'attendre l'attribution des emplacements avant de déplacer + * le curseur et de terminer de cet fait les opérations. + */ + + g_signal_connect(new, "size-allocate", G_CALLBACK(handle_loaded_panel_first_allocation), cursor); + + } g_object_unref(G_OBJECT(new)); -- cgit v0.11.2-87-g4458