1 | /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */ |
2 | /* |
3 | * GTK - The GIMP Toolkit |
4 | * Copyright (C) 2006 Carlos Garnacho Parro <carlosg@gnome.org> |
5 | * |
6 | * All rights reserved. |
7 | * |
8 | * This library is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU Lesser General Public |
10 | * License as published by the Free Software Foundation; either |
11 | * version 2 of the License, or (at your option) any later version. |
12 | * |
13 | * This library is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * Lesser General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU Lesser General Public |
19 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
20 | */ |
21 | #include <gtk/gtk.h> |
22 | |
23 | static gconstpointer GROUP_A = "GROUP_A" ; |
24 | static gconstpointer GROUP_B = "GROUP_B" ; |
25 | |
26 | const char *tabs1 [] = { |
27 | "aaaaaaaaaa" , |
28 | "bbbbbbbbbb" , |
29 | "cccccccccc" , |
30 | "dddddddddd" , |
31 | NULL |
32 | }; |
33 | |
34 | const char *tabs2 [] = { |
35 | "1" , |
36 | "2" , |
37 | "3" , |
38 | "4" , |
39 | "55555" , |
40 | NULL |
41 | }; |
42 | |
43 | const char *tabs3 [] = { |
44 | "foo" , |
45 | "bar" , |
46 | NULL |
47 | }; |
48 | |
49 | const char *tabs4 [] = { |
50 | "beer" , |
51 | "water" , |
52 | "lemonade" , |
53 | "coffee" , |
54 | "tea" , |
55 | NULL |
56 | }; |
57 | |
58 | static GtkNotebook* |
59 | window_creation_function (GtkNotebook *source_notebook, |
60 | GtkWidget *child, |
61 | int x, |
62 | int y, |
63 | gpointer data) |
64 | { |
65 | GtkWidget *window, *notebook; |
66 | |
67 | window = gtk_window_new (); |
68 | notebook = gtk_notebook_new (); |
69 | g_signal_connect (notebook, "create-window" , |
70 | G_CALLBACK (window_creation_function), NULL); |
71 | |
72 | gtk_notebook_set_group_name (GTK_NOTEBOOK (notebook), |
73 | group_name: gtk_notebook_get_group_name (notebook: source_notebook)); |
74 | |
75 | gtk_window_set_child (GTK_WINDOW (window), child: notebook); |
76 | |
77 | gtk_window_set_default_size (GTK_WINDOW (window), width: 300, height: 300); |
78 | gtk_widget_show (widget: window); |
79 | |
80 | return GTK_NOTEBOOK (notebook); |
81 | } |
82 | |
83 | static void |
84 | on_page_reordered (GtkNotebook *notebook, GtkWidget *child, guint page_num, gpointer data) |
85 | { |
86 | g_print (format: "page %d reordered\n" , page_num); |
87 | } |
88 | |
89 | static gboolean |
90 | remove_in_idle (gpointer data) |
91 | { |
92 | GtkNotebookPage *page = data; |
93 | GtkWidget *child = gtk_notebook_page_get_child (page); |
94 | GtkWidget *parent = gtk_widget_get_ancestor (widget: child, GTK_TYPE_NOTEBOOK); |
95 | GtkWidget *tab_label; |
96 | |
97 | tab_label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (parent), child); |
98 | g_print (format: "Removing tab: %s\n" , gtk_label_get_text (GTK_LABEL (tab_label))); |
99 | gtk_box_remove (GTK_BOX (parent), child); |
100 | |
101 | return G_SOURCE_REMOVE; |
102 | } |
103 | |
104 | static gboolean |
105 | on_button_drag_drop (GtkDropTarget *dest, |
106 | const GValue *value, |
107 | double x, |
108 | double y, |
109 | gpointer user_data) |
110 | { |
111 | GtkNotebookPage *page; |
112 | |
113 | page = g_value_get_object (value); |
114 | g_idle_add (function: remove_in_idle, data: page); |
115 | |
116 | return TRUE; |
117 | } |
118 | |
119 | static void |
120 | action_clicked_cb (GtkWidget *button, |
121 | GtkWidget *notebook) |
122 | { |
123 | GtkWidget *page, *title; |
124 | |
125 | page = gtk_entry_new (); |
126 | gtk_editable_set_text (GTK_EDITABLE (page), text: "Addition" ); |
127 | |
128 | title = gtk_label_new (str: "Addition" ); |
129 | |
130 | gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child: page, tab_label: title); |
131 | gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), child: page, TRUE); |
132 | gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook), child: page, TRUE); |
133 | } |
134 | |
135 | static GtkWidget* |
136 | create_notebook (const char **labels, |
137 | const char *group, |
138 | GtkPositionType pos) |
139 | { |
140 | GtkWidget *notebook, *title, *page, *action_widget; |
141 | |
142 | notebook = gtk_notebook_new (); |
143 | gtk_widget_set_vexpand (widget: notebook, TRUE); |
144 | gtk_widget_set_hexpand (widget: notebook, TRUE); |
145 | |
146 | action_widget = gtk_button_new_from_icon_name (icon_name: "list-add-symbolic" ); |
147 | g_signal_connect (action_widget, "clicked" , G_CALLBACK (action_clicked_cb), notebook); |
148 | gtk_notebook_set_action_widget (GTK_NOTEBOOK (notebook), widget: action_widget, pack_type: GTK_PACK_END); |
149 | |
150 | g_signal_connect (notebook, "create-window" , |
151 | G_CALLBACK (window_creation_function), NULL); |
152 | |
153 | gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), pos); |
154 | gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE); |
155 | gtk_notebook_set_group_name (GTK_NOTEBOOK (notebook), group_name: group); |
156 | |
157 | while (*labels) |
158 | { |
159 | page = gtk_entry_new (); |
160 | gtk_editable_set_text (GTK_EDITABLE (page), text: *labels); |
161 | |
162 | title = gtk_label_new (str: *labels); |
163 | |
164 | gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child: page, tab_label: title); |
165 | gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), child: page, TRUE); |
166 | gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook), child: page, TRUE); |
167 | |
168 | labels++; |
169 | } |
170 | |
171 | g_signal_connect (GTK_NOTEBOOK (notebook), "page-reordered" , |
172 | G_CALLBACK (on_page_reordered), NULL); |
173 | return notebook; |
174 | } |
175 | |
176 | static GtkWidget* |
177 | create_notebook_non_dragable_content (const char **labels, |
178 | const char *group, |
179 | GtkPositionType pos) |
180 | { |
181 | GtkWidget *notebook, *title, *page, *action_widget; |
182 | |
183 | notebook = gtk_notebook_new (); |
184 | gtk_widget_set_vexpand (widget: notebook, TRUE); |
185 | gtk_widget_set_hexpand (widget: notebook, TRUE); |
186 | |
187 | action_widget = gtk_button_new_from_icon_name (icon_name: "list-add-symbolic" ); |
188 | g_signal_connect (action_widget, "clicked" , G_CALLBACK (action_clicked_cb), notebook); |
189 | gtk_notebook_set_action_widget (GTK_NOTEBOOK (notebook), widget: action_widget, pack_type: GTK_PACK_END); |
190 | |
191 | g_signal_connect (notebook, "create-window" , |
192 | G_CALLBACK (window_creation_function), NULL); |
193 | |
194 | gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), pos); |
195 | gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE); |
196 | gtk_notebook_set_group_name (GTK_NOTEBOOK (notebook), group_name: group); |
197 | |
198 | while (*labels) |
199 | { |
200 | GtkWidget *button; |
201 | button = gtk_button_new_with_label (label: "example content" ); |
202 | /* Use GtkListBox since it bubbles up motion notify event, which can |
203 | * experience more issues than GtkBox. */ |
204 | page = gtk_list_box_new (); |
205 | gtk_box_append (GTK_BOX (page), child: button); |
206 | |
207 | button = gtk_button_new_with_label (label: "row 2" ); |
208 | gtk_box_append (GTK_BOX (page), child: button); |
209 | |
210 | button = gtk_button_new_with_label (label: "third row" ); |
211 | gtk_box_append (GTK_BOX (page), child: button); |
212 | |
213 | title = gtk_label_new (str: *labels); |
214 | |
215 | gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child: page, tab_label: title); |
216 | gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), child: page, TRUE); |
217 | gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook), child: page, TRUE); |
218 | |
219 | labels++; |
220 | } |
221 | |
222 | g_signal_connect (GTK_NOTEBOOK (notebook), "page-reordered" , |
223 | G_CALLBACK (on_page_reordered), NULL); |
224 | return notebook; |
225 | } |
226 | |
227 | static GtkWidget* |
228 | create_notebook_with_notebooks (const char **labels, |
229 | const char *group, |
230 | GtkPositionType pos) |
231 | { |
232 | GtkWidget *notebook, *title, *page; |
233 | int count = 0; |
234 | |
235 | notebook = gtk_notebook_new (); |
236 | g_signal_connect (notebook, "create-window" , |
237 | G_CALLBACK (window_creation_function), NULL); |
238 | |
239 | gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), pos); |
240 | gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE); |
241 | gtk_notebook_set_group_name (GTK_NOTEBOOK (notebook), group_name: group); |
242 | |
243 | while (*labels) |
244 | { |
245 | page = create_notebook (labels, group, pos); |
246 | gtk_notebook_popup_enable (GTK_NOTEBOOK (page)); |
247 | |
248 | title = gtk_label_new (str: *labels); |
249 | |
250 | gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child: page, tab_label: title); |
251 | gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), child: page, TRUE); |
252 | gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook), child: page, TRUE); |
253 | |
254 | count++; |
255 | labels++; |
256 | } |
257 | |
258 | g_signal_connect (GTK_NOTEBOOK (notebook), "page-reordered" , |
259 | G_CALLBACK (on_page_reordered), NULL); |
260 | return notebook; |
261 | } |
262 | |
263 | static GtkWidget* |
264 | create_trash_button (void) |
265 | { |
266 | GtkWidget *button; |
267 | GtkDropTarget *dest; |
268 | |
269 | button = gtk_button_new_with_mnemonic (label: "_Delete" ); |
270 | |
271 | dest = gtk_drop_target_new (GTK_TYPE_NOTEBOOK_PAGE, actions: GDK_ACTION_MOVE); |
272 | g_signal_connect (dest, "drop" , G_CALLBACK (on_button_drag_drop), NULL); |
273 | gtk_widget_add_controller (widget: button, GTK_EVENT_CONTROLLER (dest)); |
274 | |
275 | return button; |
276 | } |
277 | |
278 | static void |
279 | quit_cb (GtkWidget *widget, |
280 | gpointer data) |
281 | { |
282 | gboolean *done = data; |
283 | |
284 | *done = TRUE; |
285 | |
286 | g_main_context_wakeup (NULL); |
287 | } |
288 | |
289 | int |
290 | main (int argc, char *argv[]) |
291 | { |
292 | GtkWidget *window, *grid; |
293 | gboolean done = FALSE; |
294 | |
295 | gtk_init (); |
296 | |
297 | window = gtk_window_new (); |
298 | grid = gtk_grid_new (); |
299 | |
300 | gtk_grid_attach (GTK_GRID (grid), |
301 | child: create_notebook_non_dragable_content (labels: tabs1, group: GROUP_A, pos: GTK_POS_TOP), |
302 | column: 0, row: 0, width: 1, height: 1); |
303 | |
304 | gtk_grid_attach (GTK_GRID (grid), |
305 | child: create_notebook (labels: tabs2, group: GROUP_B, pos: GTK_POS_BOTTOM), |
306 | column: 0, row: 1, width: 1, height: 1); |
307 | |
308 | gtk_grid_attach (GTK_GRID (grid), |
309 | child: create_notebook (labels: tabs3, group: GROUP_B, pos: GTK_POS_LEFT), |
310 | column: 1, row: 0, width: 1, height: 1); |
311 | |
312 | gtk_grid_attach (GTK_GRID (grid), |
313 | child: create_notebook_with_notebooks (labels: tabs4, group: GROUP_A, pos: GTK_POS_RIGHT), |
314 | column: 1, row: 1, width: 1, height: 1); |
315 | |
316 | gtk_grid_attach (GTK_GRID (grid), |
317 | child: create_trash_button (), |
318 | column: 1, row: 2, width: 1, height: 1); |
319 | |
320 | gtk_window_set_child (GTK_WINDOW (window), child: grid); |
321 | gtk_window_set_default_size (GTK_WINDOW (window), width: 400, height: 400); |
322 | |
323 | g_signal_connect (window, "destroy" , G_CALLBACK (quit_cb), &done); |
324 | |
325 | gtk_widget_show (widget: window); |
326 | |
327 | while (!done) |
328 | g_main_context_iteration (NULL, TRUE); |
329 | |
330 | return 0; |
331 | } |
332 | |