]> Pileus Git - ~andy/gtk/blob - examples/list/list.c
Fixes #136082 and #135265, patch by Morten Welinder.
[~andy/gtk] / examples / list / list.c
1
2 #include <config.h>
3 #include <gtk/gtk.h>
4 #include <stdio.h>
5
6 /* This is our data identification string to store
7  * data in list items
8  */
9 const gchar *list_item_data_key="list_item_data";
10
11
12 /* prototypes for signal handler that we are going to connect
13  * to the List widget
14  */
15 static void  sigh_print_selection( GtkWidget *gtklist,
16                                    gpointer   func_data);
17
18 static void  sigh_button_event( GtkWidget      *gtklist,
19                                 GdkEventButton *event,
20                                 GtkWidget      *frame );
21
22
23 /* Main function to set up the user interface */
24
25 gint main( int    argc,
26            gchar *argv[] )
27 {                                  
28     GtkWidget *separator;
29     GtkWidget *window;
30     GtkWidget *vbox;
31     GtkWidget *scrolled_window;
32     GtkWidget *frame;
33     GtkWidget *gtklist;
34     GtkWidget *button;
35     GtkWidget *list_item;
36     GList *dlist;
37     guint i;
38     gchar buffer[64];
39     
40     
41     /* Initialize GTK (and subsequently GDK) */
42
43     gtk_init (&argc, &argv);
44     
45     
46     /* Create a window to put all the widgets in
47      * connect gtk_main_quit() to the "destroy" event of
48      * the window to handle window manager close-window-events
49      */
50     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
51     gtk_window_set_title (GTK_WINDOW (window), "GtkList Example");
52     g_signal_connect (G_OBJECT (window), "destroy",
53                       G_CALLBACK (gtk_main_quit),
54                       NULL);
55     
56     
57     /* Inside the window we need a box to arrange the widgets
58      * vertically */
59     vbox=gtk_vbox_new (FALSE, 5);
60     gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
61     gtk_container_add (GTK_CONTAINER (window), vbox);
62     gtk_widget_show (vbox);
63     
64     /* This is the scrolled window to put the List widget inside */
65     scrolled_window = gtk_scrolled_window_new (NULL, NULL);
66     gtk_widget_set_size_request (scrolled_window, 250, 150);
67     gtk_container_add (GTK_CONTAINER (vbox), scrolled_window);
68     gtk_widget_show (scrolled_window);
69     
70     /* Create thekList widget.
71      * Connect the sigh_print_selection() signal handler
72      * function to the "selection_changed" signal of the List
73      * to print out the selected items each time the selection
74      * has changed */
75     gtklist=gtk_list_new ();
76     gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window),
77                                            gtklist);
78     gtk_widget_show (gtklist);
79     g_signal_connect (G_OBJECT (gtklist), "selection_changed",
80                       G_CALLBACK (sigh_print_selection),
81                       NULL);
82     
83     /* We create a "Prison" to put a list item in ;) */
84     frame=gtk_frame_new ("Prison");
85     gtk_widget_set_size_request (frame, 200, 50);
86     gtk_container_set_border_width (GTK_CONTAINER (frame), 5);
87     gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
88     gtk_container_add (GTK_CONTAINER (vbox), frame);
89     gtk_widget_show (frame);
90     
91     /* Connect the sigh_button_event() signal handler to the List
92      * which will handle the "arresting" of list items
93      */
94     g_signal_connect (G_OBJECT (gtklist), "button_release_event",
95                       G_CALLBACK (sigh_button_event),
96                       frame);
97     
98     /* Create a separator */
99     separator=gtk_hseparator_new ();
100     gtk_container_add (GTK_CONTAINER (vbox), separator);
101     gtk_widget_show (separator);
102     
103     /* Finally create a button and connect its "clicked" signal
104      * to the destruction of the window */
105     button=gtk_button_new_with_label ("Close");
106     gtk_container_add (GTK_CONTAINER (vbox), button);
107     gtk_widget_show (button);
108     g_signal_connect_swapped (G_OBJECT (button), "clicked",
109                               G_CALLBACK (gtk_widget_destroy),
110                               window);
111     
112     
113     /* Now we create 5 list items, each having its own
114      * label and add them to the List using gtk_container_add()
115      * Also we query the text string from the label and
116      * associate it with the list_item_data_key for each list item
117      */
118     for (i = 0; i < 5; i++) {
119         GtkWidget       *label;
120         gchar           *string;
121         
122         sprintf(buffer, "ListItemContainer with Label #%d", i);
123         label=gtk_label_new (buffer);
124         list_item=gtk_list_item_new ();
125         gtk_container_add (GTK_CONTAINER (list_item), label);
126         gtk_widget_show (label);
127         gtk_container_add (GTK_CONTAINER (gtklist), list_item);
128         gtk_widget_show (list_item);
129         gtk_label_get (GTK_LABEL (label), &string);
130         g_object_set_data (G_OBJECT (list_item), list_item_data_key, string);
131     }
132     /* Here, we are creating another 5 labels, this time
133      * we use gtk_list_item_new_with_label() for the creation
134      * we can't query the text string from the label because
135      * we don't have the labels pointer and therefore
136      * we just associate the list_item_data_key of each
137      * list item with the same text string.
138      * For adding of the list items we put them all into a doubly
139      * linked list (GList), and then add them by a single call to
140      * gtk_list_append_items().
141      * Because we use g_list_prepend() to put the items into the
142      * doubly linked list, their order will be descending (instead
143      * of ascending when using g_list_append())
144      */
145     dlist = NULL;
146     for (; i < 10; i++) {
147         sprintf(buffer, "List Item with Label %d", i);
148         list_item = gtk_list_item_new_with_label (buffer);
149         dlist = g_list_prepend (dlist, list_item);
150         gtk_widget_show (list_item);
151         g_object_set_data (G_OBJECT (list_item),
152                            list_item_data_key,
153                            "ListItem with integrated Label");
154     }
155     gtk_list_append_items (GTK_LIST (gtklist), dlist);
156     
157     /* Finally we want to see the window, don't we? ;) */
158     gtk_widget_show (window);
159     
160     /* Fire up the main event loop of gtk */
161     gtk_main ();
162     
163     /* We get here after gtk_main_quit() has been called which
164      * happens if the main window gets destroyed
165      */
166     return 0;
167 }
168
169 /* This is the signal handler that got connected to button
170  * press/release events of the List
171  */
172 void sigh_button_event( GtkWidget      *gtklist,
173                         GdkEventButton *event,
174                         GtkWidget      *frame )
175 {
176     /* We only do something if the third (rightmost mouse button
177      * was released
178      */
179     if (event->type == GDK_BUTTON_RELEASE &&
180         event->button == 3) {
181         GList           *dlist, *free_list;
182         GtkWidget       *new_prisoner;
183         
184         /* Fetch the currently selected list item which
185          * will be our next prisoner ;)
186          */
187         dlist = GTK_LIST (gtklist)->selection;
188         if (dlist)
189                 new_prisoner = GTK_WIDGET (dlist->data);
190         else
191                 new_prisoner = NULL;
192         
193         /* Look for already imprisoned list items, we
194          * will put them back into the list.
195          * Remember to free the doubly linked list that
196          * gtk_container_children() returns
197          */
198         dlist = gtk_container_children (GTK_CONTAINER (frame));
199         free_list = dlist;
200         while (dlist) {
201             GtkWidget       *list_item;
202             
203             list_item = dlist->data;
204             
205             gtk_widget_reparent (list_item, gtklist);
206             
207             dlist = dlist->next;
208         }
209         g_list_free (free_list);
210         
211         /* If we have a new prisoner, remove him from the
212          * List and put him into the frame "Prison".
213          * We need to unselect the item first.
214          */
215         if (new_prisoner) {
216             GList   static_dlist;
217             
218             static_dlist.data = new_prisoner;
219             static_dlist.next = NULL;
220             static_dlist.prev = NULL;
221             
222             gtk_list_unselect_child (GTK_LIST (gtklist),
223                                      new_prisoner);
224             gtk_widget_reparent (new_prisoner, frame);
225         }
226     }
227 }
228
229 /* This is the signal handler that gets called if List
230  * emits the "selection_changed" signal
231  */
232 void sigh_print_selection( GtkWidget *gtklist,
233                            gpointer   func_data )
234 {
235     GList   *dlist;
236     
237     /* Fetch the doubly linked list of selected items
238      * of the List, remember to treat this as read-only!
239      */
240     dlist = GTK_LIST (gtklist)->selection;
241     
242     /* If there are no selected items there is nothing more
243      * to do than just telling the user so
244      */
245     if (!dlist) {
246         g_print ("Selection cleared\n");
247         return;
248     }
249     /* Ok, we got a selection and so we print it
250      */
251     g_print ("The selection is a ");
252     
253     /* Get the list item from the doubly linked list
254      * and then query the data associated with list_item_data_key.
255      * We then just print it */
256     while (dlist) {
257         const gchar *item_data_string;
258         
259         item_data_string = g_object_get_data (G_OBJECT (dlist->data),
260                                               list_item_data_key);
261         g_print("%s ", item_data_string);
262         
263         dlist = dlist->next;
264     }
265     g_print ("\n");
266 }