testnotebookdnd.c 11 KB
Newer Older
1
/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2
/*
Cody Russell's avatar
Cody Russell committed
3
 * GTK - The GIMP Toolkit
Matthias Clasen's avatar
Matthias Clasen committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright (C) 2006  Carlos Garnacho Parro <carlosg@gnome.org>
 *
 * All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
19
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Matthias Clasen's avatar
Matthias Clasen committed
20 21 22
 */
#include <gtk/gtk.h>

23 24
static gpointer GROUP_A = "GROUP_A";
static gpointer GROUP_B = "GROUP_B";
Matthias Clasen's avatar
Matthias Clasen committed
25 26

gchar *tabs1 [] = {
27 28 29 30
  "aaaaaaaaaa",
  "bbbbbbbbbb",
  "cccccccccc",
  "dddddddddd",
Matthias Clasen's avatar
Matthias Clasen committed
31 32 33 34 35 36 37 38
  NULL
};

gchar *tabs2 [] = {
  "1",
  "2",
  "3",
  "4",
39
  "55555",
Matthias Clasen's avatar
Matthias Clasen committed
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
  NULL
};

gchar *tabs3 [] = {
  "foo",
  "bar",
  NULL
};

gchar *tabs4 [] = {
  "beer",
  "water",
  "lemonade",
  "coffee",
  "tea",
  NULL
};

58 59 60 61
static const GtkTargetEntry button_targets[] = {
  { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
};

Matthias Clasen's avatar
Matthias Clasen committed
62 63
static GtkNotebook*
window_creation_function (GtkNotebook *source_notebook,
64 65 66 67
                          GtkWidget   *child,
                          gint         x,
                          gint         y,
                          gpointer     data)
Matthias Clasen's avatar
Matthias Clasen committed
68 69 70 71 72
{
  GtkWidget *window, *notebook;

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  notebook = gtk_notebook_new ();
73 74
  g_signal_connect (notebook, "create-window",
                    G_CALLBACK (window_creation_function), NULL);
Matthias Clasen's avatar
Matthias Clasen committed
75

76
  gtk_notebook_set_group_name (GTK_NOTEBOOK (notebook),
77
                               gtk_notebook_get_group_name (source_notebook));
Matthias Clasen's avatar
Matthias Clasen committed
78 79 80 81 82 83 84 85 86 87 88

  gtk_container_add (GTK_CONTAINER (window), notebook);

  gtk_window_set_default_size (GTK_WINDOW (window), 300, 300);
  gtk_window_move (GTK_WINDOW (window), x, y);
  gtk_widget_show_all (window);

  return GTK_NOTEBOOK (notebook);
}

static void
89
on_page_reordered (GtkNotebook *notebook, GtkWidget *child, guint page_num, gpointer data)
Matthias Clasen's avatar
Matthias Clasen committed
90
{
91
  g_print ("page %d reordered\n", page_num);
Matthias Clasen's avatar
Matthias Clasen committed
92 93
}

94 95
static void
on_notebook_drag_begin (GtkWidget      *widget,
96 97
                        GdkDragContext *context,
                        gpointer        data)
98 99 100 101 102 103
{
  GdkPixbuf *pixbuf;
  guint page_num;

  page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (widget));

Matthias Clasen's avatar
Matthias Clasen committed
104 105
  if (page_num > 2)
    {
106 107 108 109 110 111 112 113 114 115
      GtkIconTheme *icon_theme;
      int width;

      icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
      gtk_icon_size_lookup (GTK_ICON_SIZE_DND, &width, NULL);
      pixbuf = gtk_icon_theme_load_icon (icon_theme,
                                         (page_num % 2) ? "help-browser" : "process-stop",
                                         width,
                                         GTK_ICON_LOOKUP_GENERIC_FALLBACK,
                                         NULL);
116

Matthias Clasen's avatar
Matthias Clasen committed
117 118 119
      gtk_drag_set_icon_pixbuf (context, pixbuf, 0, 0);
      g_object_unref (pixbuf);
    }
120 121
}

122 123 124 125 126 127 128 129 130 131 132 133 134 135
static gboolean
remove_in_idle (gpointer data)
{
  GtkWidget *child = data;
  GtkWidget *parent = gtk_widget_get_parent (child);
  GtkWidget *tab_label;

  tab_label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (parent), child);
  g_print ("Removing tab: %s\n", gtk_label_get_text (GTK_LABEL (tab_label)));
  gtk_container_remove (GTK_CONTAINER (parent), child);

  return G_SOURCE_REMOVE;
}

136 137
static void
on_button_drag_data_received (GtkWidget        *widget,
138 139 140 141 142 143 144
                              GdkDragContext   *context,
                              gint              x,
                              gint              y,
                              GtkSelectionData *data,
                              guint             info,
                              guint             time,
                              gpointer          user_data)
145 146 147
{
  GtkWidget **child;

148
  child = (void*) gtk_selection_data_get_data (data);
149

150
  g_idle_add (remove_in_idle, *child);
151 152
}

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
static void
action_clicked_cb (GtkWidget *button,
                   GtkWidget *notebook)
{
  GtkWidget *page, *title;

  page = gtk_entry_new ();
  gtk_entry_set_text (GTK_ENTRY (page), "Addition");
  gtk_widget_show (page);

  title = gtk_label_new ("Addition");

  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, title);
  gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), page, TRUE);
  gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook), page, TRUE);
}

Matthias Clasen's avatar
Matthias Clasen committed
170 171
static GtkWidget*
create_notebook (gchar           **labels,
172 173
                 const gchar      *group,
                 GtkPositionType   pos)
Matthias Clasen's avatar
Matthias Clasen committed
174
{
175
  GtkWidget *notebook, *title, *page, *action_widget;
Matthias Clasen's avatar
Matthias Clasen committed
176 177

  notebook = gtk_notebook_new ();
178 179
  gtk_widget_set_vexpand (notebook, TRUE);
  gtk_widget_set_hexpand (notebook, TRUE);
180 181 182 183 184 185

  action_widget = gtk_button_new_from_icon_name ("list-add-symbolic", GTK_ICON_SIZE_BUTTON);
  g_signal_connect (action_widget, "clicked", G_CALLBACK (action_clicked_cb), notebook);
  gtk_widget_show (action_widget);
  gtk_notebook_set_action_widget (GTK_NOTEBOOK (notebook), action_widget, GTK_PACK_END);

186 187
  g_signal_connect (notebook, "create-window",
                    G_CALLBACK (window_creation_function), NULL);
Matthias Clasen's avatar
Matthias Clasen committed
188 189 190 191

  gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), pos);
  gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
  gtk_container_set_border_width (GTK_CONTAINER (notebook), 6);
192
  gtk_notebook_set_group_name (GTK_NOTEBOOK (notebook), group);
Matthias Clasen's avatar
Matthias Clasen committed
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207

  while (*labels)
    {
      page = gtk_entry_new ();
      gtk_entry_set_text (GTK_ENTRY (page), *labels);

      title = gtk_label_new (*labels);

      gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, title);
      gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), page, TRUE);
      gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook), page, TRUE);

      labels++;
    }

208
  g_signal_connect (GTK_NOTEBOOK (notebook), "page-reordered",
209
                    G_CALLBACK (on_page_reordered), NULL);
210
  g_signal_connect_after (G_OBJECT (notebook), "drag-begin",
211
                          G_CALLBACK (on_notebook_drag_begin), NULL);
Matthias Clasen's avatar
Matthias Clasen committed
212 213 214
  return notebook;
}

215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
static GtkWidget*
create_notebook_non_dragable_content (gchar           **labels,
                                      const gchar      *group,
                                      GtkPositionType   pos)
{
  GtkWidget *notebook, *title, *page, *action_widget;

  notebook = gtk_notebook_new ();
  gtk_widget_set_vexpand (notebook, TRUE);
  gtk_widget_set_hexpand (notebook, TRUE);

  action_widget = gtk_button_new_from_icon_name ("list-add-symbolic", GTK_ICON_SIZE_BUTTON);
  g_signal_connect (action_widget, "clicked", G_CALLBACK (action_clicked_cb), notebook);
  gtk_widget_show (action_widget);
  gtk_notebook_set_action_widget (GTK_NOTEBOOK (notebook), action_widget, GTK_PACK_END);

  g_signal_connect (notebook, "create-window",
                    G_CALLBACK (window_creation_function), NULL);

  gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), pos);
  gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
  gtk_container_set_border_width (GTK_CONTAINER (notebook), 6);
  gtk_notebook_set_group_name (GTK_NOTEBOOK (notebook), group);

  while (*labels)
    {
      GtkWidget *button;
      button = gtk_button_new_with_label (*labels);
      /* Use GtkListBox since it bubbles up motion notify event, which can
       * experience more issues than GtkBox. */
      page = gtk_list_box_new ();
      gtk_container_add (GTK_CONTAINER (page), button);

      title = gtk_label_new (*labels);

      gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, title);
      gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), page, TRUE);
      gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook), page, TRUE);

      labels++;
    }

  g_signal_connect (GTK_NOTEBOOK (notebook), "page-reordered",
                    G_CALLBACK (on_page_reordered), NULL);
  g_signal_connect_after (G_OBJECT (notebook), "drag-begin",
                          G_CALLBACK (on_notebook_drag_begin), NULL);
  return notebook;
}

264 265
static GtkWidget*
create_notebook_with_notebooks (gchar           **labels,
266 267
                                const gchar      *group,
                                GtkPositionType   pos)
268 269 270 271 272
{
  GtkWidget *notebook, *title, *page;
  gint count = 0;

  notebook = gtk_notebook_new ();
273 274
  g_signal_connect (notebook, "create-window",
                    G_CALLBACK (window_creation_function), NULL);
275 276 277 278

  gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), pos);
  gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
  gtk_container_set_border_width (GTK_CONTAINER (notebook), 6);
279
  gtk_notebook_set_group_name (GTK_NOTEBOOK (notebook), group);
280 281 282

  while (*labels)
    {
283
      page = create_notebook (labels, group, pos);
284
      gtk_notebook_popup_enable (GTK_NOTEBOOK (page));
285

286 287 288 289 290 291 292 293 294 295 296
      title = gtk_label_new (*labels);

      gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, title);
      gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), page, TRUE);
      gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook), page, TRUE);

      count++;
      labels++;
    }

  g_signal_connect (GTK_NOTEBOOK (notebook), "page-reordered",
297
                    G_CALLBACK (on_page_reordered), NULL);
298
  g_signal_connect_after (G_OBJECT (notebook), "drag-begin",
299
                          G_CALLBACK (on_notebook_drag_begin), NULL);
300 301 302
  return notebook;
}

303 304 305 306 307
static GtkWidget*
create_trash_button (void)
{
  GtkWidget *button;

308
  button = gtk_button_new_with_mnemonic ("_Delete");
309 310

  gtk_drag_dest_set (button,
311 312 313 314
                     GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
                     button_targets,
                     G_N_ELEMENTS (button_targets),
                     GDK_ACTION_MOVE);
315 316

  g_signal_connect_after (G_OBJECT (button), "drag-data-received",
317
                          G_CALLBACK (on_button_drag_data_received), NULL);
318 319 320
  return button;
}

Matthias Clasen's avatar
Matthias Clasen committed
321 322 323
gint
main (gint argc, gchar *argv[])
{
324
  GtkWidget *window, *grid;
Matthias Clasen's avatar
Matthias Clasen committed
325 326 327 328

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
329
  grid = gtk_grid_new ();
Matthias Clasen's avatar
Matthias Clasen committed
330

331
  gtk_grid_attach (GTK_GRID (grid),
332
                   create_notebook_non_dragable_content (tabs1, GROUP_A, GTK_POS_TOP),
333
                   0, 0, 1, 1);
Matthias Clasen's avatar
Matthias Clasen committed
334

335 336 337
  gtk_grid_attach (GTK_GRID (grid),
                   create_notebook (tabs2, GROUP_B, GTK_POS_BOTTOM),
                   0, 1, 1, 1);
Matthias Clasen's avatar
Matthias Clasen committed
338

339 340 341
  gtk_grid_attach (GTK_GRID (grid),
                   create_notebook (tabs3, GROUP_B, GTK_POS_LEFT),
                   1, 0, 1, 1);
Matthias Clasen's avatar
Matthias Clasen committed
342

343 344 345
  gtk_grid_attach (GTK_GRID (grid),
                   create_notebook_with_notebooks (tabs4, GROUP_A, GTK_POS_RIGHT),
                   1, 1, 1, 1);
Matthias Clasen's avatar
Matthias Clasen committed
346

347 348 349
  gtk_grid_attach (GTK_GRID (grid),
                   create_trash_button (),
                   1, 2, 1, 1);
350

351
  gtk_container_add (GTK_CONTAINER (window), grid);
Matthias Clasen's avatar
Matthias Clasen committed
352 353 354 355 356 357 358
  gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
  gtk_widget_show_all (window);

  gtk_main ();

  return 0;
}