@@ -215,22 +215,35 @@ toolkitgroupview_dispose(GObject *object)
215215 Toolkitgroupview * kitgview = TOOLKITGROUPVIEW (object );
216216
217217 gtk_widget_dispose_template (GTK_WIDGET (kitgview ), TOOLKITGROUPVIEW_TYPE );
218- g_slist_free_full (g_steal_pointer (& kitgview -> page_names ), g_free );
218+ for (int i = 0 ; i < MAX_PAGE_DEPTH ; i ++ )
219+ VIPS_FREE (kitgview -> page_names [i ]);
219220
220221 G_OBJECT_CLASS (toolkitgroupview_parent_class )-> dispose (object );
221222}
222223
223- static GSList *
224- toolkitgroupview_parse_path ( char * path )
224+ static void
225+ toolkitgroupview_set_path ( Toolkitgroupview * kitgview , char * path )
225226{
226- GSList * page_names = NULL ;
227+ for (int i = 0 ; i < MAX_PAGE_DEPTH ; i ++ ) {
228+ VIPS_FREE (kitgview -> page_names [i ]);
229+ kitgview -> pinned [i ] = FALSE;
230+ }
231+ kitgview -> n_pages = 1 ;
232+ kitgview -> page_names [0 ] = g_strdup ("root" );
233+
234+ if (path ) {
235+ char * p ;
236+ char * q ;
227237
228- char * p ;
229- char * q ;
230- for (p = path ; (q = vips_break_token (p , ">" )); p = q )
231- page_names = g_slist_append (page_names , g_strdup (p ));
238+ kitgview -> n_pages = 0 ;
239+ for (p = path ; (q = vips_break_token (p , ">" )); p = q ) {
240+ VIPS_SETSTR (kitgview -> page_names [kitgview -> n_pages ], g_strdup (p ));
232241
233- return page_names ;
242+ if (kitgview -> n_pages >= MAX_PAGE_DEPTH - 1 )
243+ return ;
244+ kitgview -> n_pages += 1 ;
245+ }
246+ }
234247}
235248
236249static void
@@ -250,8 +263,7 @@ toolkitgroupview_set_property(GObject *object,
250263 case PROP_PATH :
251264 path = g_strdup (g_value_get_string (value ));
252265 if (strlen (path ) > 0 ) {
253- g_slist_free_full (g_steal_pointer (& kitgview -> page_names ), g_free );
254- kitgview -> page_names = toolkitgroupview_parse_path (path );
266+ toolkitgroupview_set_path (kitgview , path );
255267 kitgview -> search_mode = FALSE;
256268 vobject_refresh_queue (VOBJECT (kitgview ));
257269 }
@@ -264,8 +276,7 @@ toolkitgroupview_set_property(GObject *object,
264276 vobject_refresh_queue (VOBJECT (kitgview ));
265277 gtk_editable_set_text (GTK_EDITABLE (kitgview -> search_entry ),
266278 search_text );
267- gtk_string_filter_set_search (kitgview -> filter ,
268- search_text );
279+ gtk_string_filter_set_search (kitgview -> filter , search_text );
269280 }
270281 break ;
271282
@@ -276,16 +287,14 @@ toolkitgroupview_set_property(GObject *object,
276287}
277288
278289static char *
279- toolkitgroupview_print_path (GSList * page_names )
290+ toolkitgroupview_print_path (Toolkitgroupview * kitgview )
280291{
281292 GString * path = g_string_new ("" );
282293
283- for (GSList * p = page_names ; p ; p = p -> next ) {
284- const char * name = (const char * ) p -> data ;
285-
286- g_string_append (path , name );
287- if (p -> next )
294+ for (int i = 0 ; i < kitgview -> n_pages ; i ++ ) {
295+ if (i > 0 )
288296 g_string_append (path , ">" );
297+ g_string_append (path , kitgview -> page_names [i ]);
289298 }
290299
291300 return g_string_free_and_steal (path );
@@ -306,8 +315,7 @@ toolkitgroupview_get_property(GObject *object,
306315 if (kitgview -> search_mode )
307316 g_value_set_string (value , "" );
308317 else
309- g_value_take_string (value ,
310- toolkitgroupview_print_path (kitgview -> page_names ));
318+ g_value_take_string (value , toolkitgroupview_print_path (kitgview ));
311319 break ;
312320
313321 case PROP_SEARCH :
@@ -425,8 +433,27 @@ toolkitgroupview_build_node(Toolkitgroupview *kitgview, Node *parent)
425433 return G_LIST_MODEL (store );
426434}
427435
436+ // go back one, if we can
437+ static void
438+ toolkitgroupview_browse_back (Toolkitgroupview * kitgview )
439+ {
440+ if (kitgview -> n_pages > 1 ) {
441+ GtkWidget * last_page =
442+ gtk_stack_get_visible_child (GTK_STACK (kitgview -> stack ));
443+
444+ // display the second-last page
445+ gtk_stack_set_visible_child_name (GTK_STACK (kitgview -> stack ),
446+ kitgview -> page_names [kitgview -> n_pages - 2 ]);
447+
448+ // delete the last page
449+ gtk_stack_remove (GTK_STACK (kitgview -> stack ), last_page );
450+
451+ kitgview -> n_pages -= 1 ;
452+ }
453+ }
454+
428455static GtkWidget *
429- toolkitgroupview_build_browse_page (Toolkitgroupview * kitgview , Node * parent );
456+ toolkitgroupview_add_browse_page (Toolkitgroupview * kitgview , Node * parent );
430457
431458static void
432459toolkitgroupview_browse_clicked (GtkWidget * button ,
@@ -438,41 +465,27 @@ toolkitgroupview_browse_clicked(GtkWidget *button,
438465 GtkWidget * left = gtk_widget_get_first_child (box );
439466
440467 // click on "go back?"
441- if (gtk_widget_is_visible (left )) {
442- // remove the last item from the page_names list ... we know we are
443- // at least one deep in the menu
444- g_assert (kitgview -> page_names -> next );
445- char * last_name = (char * ) g_slist_last (kitgview -> page_names )-> data ;
446- kitgview -> page_names = g_slist_remove (kitgview -> page_names , last_name );
447- g_free (last_name );
448-
449- // get the (new) last name
450- const char * name =
451- (const char * ) g_slist_last (kitgview -> page_names )-> data ;
452- GtkWidget * last_page =
453- gtk_stack_get_visible_child (GTK_STACK (kitgview -> stack ));
454-
455- gtk_stack_set_visible_child_name (GTK_STACK (kitgview -> stack ), name );
456- gtk_stack_remove (GTK_STACK (kitgview -> stack ), last_page );
457- kitgview -> pin = NULL ;
458- }
468+ if (gtk_widget_is_visible (left ))
469+ toolkitgroupview_browse_back (kitgview );
459470 else {
460471 if (node -> kit ||
461- (node -> toolitem && node -> toolitem -> is_pullright )) {
462- // go right ... make sure we clear the pin widget first
463- if (kitgview -> pin )
464- gtk_check_button_set_active (GTK_CHECK_BUTTON (kitgview -> pin ),
465- FALSE);
466- kitgview -> pin = NULL ;
467- toolkitgroupview_build_browse_page (kitgview , node );
468- }
472+ (node -> toolitem && node -> toolitem -> is_pullright ))
473+ toolkitgroupview_add_browse_page (kitgview , node );
469474
470475 // activate after moving to the new page so listeners can get the new
471476 // page name
472477 toolkitgroupview_activate (kitgview , node -> toolitem , node -> tool );
473478 }
474479}
475480
481+ static void
482+ toolkitgroupview_pin_toggled (GtkCheckButton * self , gpointer user_data )
483+ {
484+ Toolkitgroupview * kitgview = TOOLKITGROUPVIEW (user_data );
485+
486+ kitgview -> pinned [kitgview -> n_pages - 1 ] ^= 1 ;
487+ }
488+
476489static void
477490toolkitgroupview_setup_browse_item (GtkListItemFactory * factory ,
478491 GtkListItem * item , Toolkitgroupview * kitgview )
@@ -507,6 +520,8 @@ toolkitgroupview_setup_browse_item(GtkListItemFactory *factory,
507520
508521 GtkWidget * pin = gtk_check_button_new ();
509522 set_tooltip (pin , "Pin menu in place" );
523+ g_signal_connect (pin , "toggled" ,
524+ G_CALLBACK (toolkitgroupview_pin_toggled ), kitgview );
510525 gtk_box_append (GTK_BOX (enclosing ), pin );
511526
512527 gtk_list_item_set_child (item , enclosing );
@@ -541,8 +556,7 @@ toolkitgroupview_bind_browse_item(GtkListItemFactory *factory,
541556 gtk_label_set_xalign (GTK_LABEL (label ), 0.5 );
542557 g_object_set_qdata (G_OBJECT (button ), node_quark , parent );
543558
544- // remember the widget so we can test and set the state
545- kitgview -> pin = pin ;
559+ // note the pin widget on the page
546560 }
547561 else {
548562 gtk_label_set_xalign (GTK_LABEL (label ), 0.0 );
@@ -583,20 +597,22 @@ toolkitgroupview_build_browse_list_view(Toolkitgroupview *kitgview, Node *this)
583597}
584598
585599static GtkWidget *
586- toolkitgroupview_build_browse_page (Toolkitgroupview * kitgview , Node * this )
600+ toolkitgroupview_add_browse_page (Toolkitgroupview * kitgview , Node * this )
587601{
588602 const char * name = node_get_name (this );
589603
590604#ifdef DEBUG
591- printf ("toolkitgroupview_build_browse_page : adding page %s\n" , name );
605+ printf ("toolkitgroupview_add_browse_page : adding page %s\n" , name );
592606#endif /*DEBUG*/
593607
594608 GtkWidget * scrolled_window = gtk_scrolled_window_new ();
595609 // no scrollbars ... they obstruct useful widgets
596610 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window ),
597611 GTK_POLICY_EXTERNAL , GTK_POLICY_EXTERNAL );
598612 gtk_stack_add_named (GTK_STACK (kitgview -> stack ), scrolled_window , name );
599- kitgview -> page_names = g_slist_append (kitgview -> page_names , g_strdup (name ));
613+ kitgview -> page_names [kitgview -> n_pages ] = g_strdup (name );
614+ kitgview -> pinned [kitgview -> n_pages ] = FALSE;
615+ kitgview -> n_pages += 1 ;
600616
601617 GtkWidget * list_view =
602618 toolkitgroupview_build_browse_list_view (kitgview , this );
@@ -618,17 +634,23 @@ toolkitgroupview_rebuild_browse(Toolkitgroupview *kitgview)
618634 g_assert (!kitgview -> list_view );
619635 g_assert (!kitgview -> filter );
620636
621- // take a copy of the old pages_names list and reset to the root
622- GSList * old_page_names = kitgview -> page_names ;
623- kitgview -> page_names = g_slist_append (NULL , g_strdup ("root" ));
624-
625637 // don't animate the browser rebuild process
626638 gboolean should_animate =
627639 widget_should_animate (GTK_WIDGET (kitgview -> stack ));
628640 g_object_set (gtk_widget_get_settings (GTK_WIDGET (kitgview -> stack )),
629641 "gtk-enable-animations" , FALSE,
630642 NULL );
631643
644+ // steal the old pages_names list and reset to the root
645+ char * old_page_names [MAX_PAGE_DEPTH ];
646+ int old_n_pages = kitgview -> n_pages ;
647+ for (int i = 0 ; i < old_n_pages ; i ++ ) {
648+ old_page_names [i ] = kitgview -> page_names [i ];
649+ kitgview -> page_names [i ] = NULL ;
650+ }
651+
652+ toolkitgroupview_set_path (kitgview , NULL );
653+
632654 // build and fill the root page in the root scrolled window
633655 kitgview -> list_view =
634656 toolkitgroupview_build_browse_list_view (kitgview , NULL );
@@ -639,20 +661,18 @@ toolkitgroupview_rebuild_browse(Toolkitgroupview *kitgview)
639661 G_LIST_MODEL (gtk_list_view_get_model (
640662 GTK_LIST_VIEW (kitgview -> list_view )));
641663
642- for (GSList * p = old_page_names -> next ; p ; p = p -> next ) {
643- char * name = (char * ) p -> data ;
644-
664+ for (int i = 0 ; i < old_n_pages ; i ++ ) {
645665 /* Is there an item on the page we've just made with the next name on
646666 * the page list?
647667 */
648668 Node * this = NULL ;
649- for (int i = 0 ; i < g_list_model_get_n_items (list_model ); i ++ ) {
650- Node * item = g_list_model_get_item (list_model , i );
669+ for (int j = 0 ; j < g_list_model_get_n_items (list_model ); j ++ ) {
670+ Node * item = g_list_model_get_item (list_model , j );
651671 const char * item_name = node_get_name (item );
652672
653673 // name can be NULL for eg separators
654674 if (item_name &&
655- g_str_equal (item_name , name )) {
675+ g_str_equal (item_name , old_page_names [ i ] )) {
656676 this = item ;
657677 break ;
658678 }
@@ -661,12 +681,13 @@ toolkitgroupview_rebuild_browse(Toolkitgroupview *kitgview)
661681 break ;
662682
663683 GtkWidget * list_view =
664- toolkitgroupview_build_browse_page (kitgview , this );
684+ toolkitgroupview_add_browse_page (kitgview , this );
665685 list_model = G_LIST_MODEL (gtk_list_view_get_model (
666686 GTK_LIST_VIEW (list_view )));
667687 }
668688
669- g_slist_free_full (g_steal_pointer (& old_page_names ), g_free );
689+ for (int i = 0 ; i < old_n_pages ; i ++ )
690+ VIPS_FREE (old_page_names [i ]);
670691
671692 g_object_set (gtk_widget_get_settings (GTK_WIDGET (kitgview -> stack )),
672693 "gtk-enable-animations" , should_animate ,
@@ -826,8 +847,7 @@ toolkitgroupview_rebuild_list(Toolkitgroupview *kitgview)
826847 gtk_scrolled_window_set_child (
827848 GTK_SCROLLED_WINDOW (kitgview -> scrolled_window ), kitgview -> list_view );
828849
829- // truncate the page_names list, since we're a flat view
830- g_slist_free_full (g_steal_pointer (& kitgview -> page_names -> next ), g_free );
850+ kitgview -> n_pages = 1 ;
831851}
832852
833853static void
@@ -839,8 +859,6 @@ toolkitgroupview_refresh(vObject *vobject)
839859 printf ("toolkitgroupview_refresh:\n" );
840860#endif /*DEBUG*/
841861
842- kitgview -> pin = NULL ;
843-
844862 // remove all stack pages except the first
845863 GtkWidget * stack = kitgview -> stack ;
846864 GtkWidget * root_page = gtk_widget_get_first_child (stack );
@@ -849,8 +867,6 @@ toolkitgroupview_refresh(vObject *vobject)
849867
850868 while ((child = gtk_widget_get_next_sibling (root_page )))
851869 gtk_stack_remove (GTK_STACK (stack ), child );
852-
853- kitgview -> pin = NULL ;
854870 }
855871 gtk_stack_set_visible_child (GTK_STACK (kitgview -> stack ), root_page );
856872
@@ -1018,8 +1034,7 @@ toolkitgroupview_init(Toolkitgroupview *kitgview)
10181034{
10191035 gtk_widget_init_template (GTK_WIDGET (kitgview ));
10201036
1021- kitgview -> page_names =
1022- g_slist_append (kitgview -> page_names , g_strdup ("root" ));
1037+ toolkitgroupview_set_path (kitgview , NULL );
10231038
10241039 GtkEntryBuffer * buffer =
10251040 gtk_entry_get_buffer (GTK_ENTRY (kitgview -> search_entry ));
@@ -1038,12 +1053,7 @@ toolkitgroupview_new(void)
10381053void
10391054toolkitgroupview_home (Toolkitgroupview * kitgview )
10401055{
1041- if (!kitgview -> pin ||
1042- !gtk_check_button_get_active (GTK_CHECK_BUTTON (kitgview -> pin ))) {
1043- // back to just the "root" page
1044- if (kitgview -> page_names )
1045- g_slist_free_full (g_steal_pointer (& kitgview -> page_names -> next ),
1046- g_free );
1047- vobject_refresh_queue (VOBJECT (kitgview ));
1048- }
1056+ while (kitgview -> n_pages > 1 &&
1057+ !kitgview -> pinned [kitgview -> n_pages - 1 ])
1058+ toolkitgroupview_browse_back (kitgview );
10491059}
0 commit comments