[libadwaita/wip/exalm/tabs: 6/6] demo: Add a AdwTabView/AdwTabBar example




commit e62d7e23d98ca58a09309594c04e6b6f26c3cf93
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Sun Sep 13 02:28:19 2020 +0500

    demo: Add a AdwTabView/AdwTabBar example

 examples/adw-demo-window.c                         |  13 +
 examples/adw-demo-window.ui                        |  20 +
 examples/adw-tab-view-demo-window.c                | 539 +++++++++++++++++++++
 examples/adw-tab-view-demo-window.h                |  15 +
 examples/adw-tab-view-demo-window.ui               | 124 +++++
 examples/adwaita-demo.gresources.xml               |   5 +
 .../icons/scalable/actions/tab-new-symbolic.svg    |   1 +
 .../scalable/actions/widget-tab-view-symbolic.svg  |   1 +
 .../scalable/status/tab-audio-muted-symbolic.svg   |  86 ++++
 .../scalable/status/tab-audio-playing-symbolic.svg |   1 +
 examples/meson.build                               |   1 +
 11 files changed, 806 insertions(+)
---
diff --git a/examples/adw-demo-window.c b/examples/adw-demo-window.c
index d368b17..d0b6d62 100644
--- a/examples/adw-demo-window.c
+++ b/examples/adw-demo-window.c
@@ -2,6 +2,7 @@
 
 #include <glib/gi18n.h>
 #include "adw-flap-demo-window.h"
+#include "adw-tab-view-demo-window.h"
 #include "adw-view-switcher-demo-window.h"
 
 struct _AdwDemoWindow
@@ -399,6 +400,17 @@ flap_demo_clicked_cb (GtkButton     *btn,
   gtk_window_present (GTK_WINDOW (window));
 }
 
+static void
+tab_view_demo_clicked_cb (GtkButton     *btn,
+                          AdwDemoWindow *self)
+{
+  AdwTabViewDemoWindow *window = adw_tab_view_demo_window_new ();
+
+  adw_tab_view_demo_window_prepopulate (window);
+
+  gtk_window_present (GTK_WINDOW (window));
+}
+
 static void
 adw_demo_window_class_init (AdwDemoWindowClass *klass)
 {
@@ -441,6 +453,7 @@ adw_demo_window_class_init (AdwDemoWindowClass *klass)
   gtk_widget_class_bind_template_callback (widget_class, avatar_file_chooser_clicked_cb);
   gtk_widget_class_bind_template_callback (widget_class, avatar_save_to_file_cb);
   gtk_widget_class_bind_template_callback (widget_class, flap_demo_clicked_cb);
+  gtk_widget_class_bind_template_callback (widget_class, tab_view_demo_clicked_cb);
 }
 
 static void
diff --git a/examples/adw-demo-window.ui b/examples/adw-demo-window.ui
index 97697fe..db5bd50 100644
--- a/examples/adw-demo-window.ui
+++ b/examples/adw-demo-window.ui
@@ -837,6 +837,26 @@
                         </property>
                       </object>
                     </child>
+                    <child>
+                      <object class="GtkStackPage">
+                        <property name="name">tab-view</property>
+                        <property name="title" translatable="yes">Tab View</property>
+                        <property name="child">
+                          <object class="AdwStatusPage">
+                            <property name="icon-name">widget-tab-view-symbolic</property>
+                            <property name="title" translatable="yes">Tab View</property>
+                            <property name="description" translatable="yes">A modern tab widget.</property>
+                            <property name="child">
+                              <object class="GtkButton">
+                                <property name="label" translatable="yes">Run the demo</property>
+                                <property name="halign">center</property>
+                                <signal name="clicked" handler="tab_view_demo_clicked_cb" swapped="no"/>
+                              </object>
+                            </property>
+                          </object>
+                        </property>
+                      </object>
+                    </child>
                   </object>
                 </child>
               </object>
diff --git a/examples/adw-tab-view-demo-window.c b/examples/adw-tab-view-demo-window.c
new file mode 100644
index 0000000..2de60b7
--- /dev/null
+++ b/examples/adw-tab-view-demo-window.c
@@ -0,0 +1,539 @@
+#include "adw-tab-view-demo-window.h"
+
+#include <glib/gi18n.h>
+
+struct _AdwTabViewDemoWindow
+{
+  AdwWindow parent_instance;
+  AdwTabView *view;
+  AdwTabBar *tab_bar;
+
+  GActionMap *tab_action_group;
+
+  AdwTabPage *menu_page;
+};
+
+G_DEFINE_TYPE (AdwTabViewDemoWindow, adw_tab_view_demo_window, ADW_TYPE_WINDOW)
+
+char **icon_names = NULL;
+gsize n_icon_names = 0;
+
+static void
+init_icon_names (GtkIconTheme *theme)
+{
+  if (icon_names)
+    return;
+
+  icon_names = gtk_icon_theme_get_icon_names (theme);
+  n_icon_names = g_strv_length (icon_names);
+}
+
+static GIcon *
+get_random_icon (AdwTabViewDemoWindow *self)
+{
+  GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (self));
+  GtkIconTheme *theme = gtk_icon_theme_get_for_display (display);
+  int index;
+
+  init_icon_names (theme);
+
+  index = g_random_int_range (0, n_icon_names);
+
+  return g_themed_icon_new (icon_names[index]);
+}
+
+static void
+window_new (GSimpleAction *action,
+            GVariant      *parameter,
+            gpointer       user_data)
+{
+  AdwTabViewDemoWindow *window = adw_tab_view_demo_window_new ();
+
+  adw_tab_view_demo_window_prepopulate (window);
+
+  gtk_window_present (GTK_WINDOW (window));
+}
+
+static gboolean
+text_to_tooltip (GBinding     *binding,
+                 const GValue *input,
+                 GValue       *output,
+                 gpointer      user_data)
+{
+  const char *title = g_value_get_string (input);
+  char *tooltip = g_markup_printf_escaped (_("An elaborate tooltip for <b>%s</b>"), title);
+
+  g_value_take_string (output, tooltip);
+
+  return TRUE;
+}
+
+static AdwTabPage *
+add_page (AdwTabViewDemoWindow *self,
+          AdwTabPage           *parent,
+          const char           *title,
+          GIcon                *icon)
+{
+  GtkWidget *content;
+  AdwTabPage *page;
+
+  content = g_object_new (GTK_TYPE_ENTRY,
+                          "text", title,
+                          "halign", GTK_ALIGN_CENTER,
+                          "valign", GTK_ALIGN_CENTER,
+                          NULL);
+
+  page = adw_tab_view_add_page (self->view, GTK_WIDGET (content), parent);
+
+  g_object_bind_property (content, "text",
+                          page, "title",
+                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+  g_object_bind_property_full (content, "text",
+                               page, "tooltip",
+                               G_BINDING_SYNC_CREATE,
+                               text_to_tooltip, NULL,
+                               NULL, NULL);
+
+  adw_tab_page_set_icon (page, icon);
+  adw_tab_page_set_indicator_activatable (page, TRUE);
+
+  return page;
+}
+
+static void
+tab_new (GSimpleAction *action,
+         GVariant      *parameter,
+         gpointer       user_data)
+{
+  AdwTabViewDemoWindow *self = ADW_TAB_VIEW_DEMO_WINDOW (user_data);
+  g_autofree char *title = NULL;
+  AdwTabPage *page;
+  GtkWidget *content;
+  GIcon *icon;
+  static int next_page = 1;
+
+  title = g_strdup_printf (_("Tab %d"), next_page);
+  icon = get_random_icon (self);
+
+  page = add_page (self, NULL, title, icon);
+  content = adw_tab_page_get_child (page);
+
+  adw_tab_view_set_selected_page (self->view, page);
+
+  gtk_widget_grab_focus (content);
+
+  next_page++;
+}
+
+static AdwTabPage *
+get_current_page (AdwTabViewDemoWindow *self)
+{
+  if (self->menu_page)
+    return self->menu_page;
+
+  return adw_tab_view_get_selected_page (self->view);
+}
+
+static void
+tab_pin (GSimpleAction *action,
+         GVariant      *parameter,
+         gpointer       user_data)
+{
+  AdwTabViewDemoWindow *self = ADW_TAB_VIEW_DEMO_WINDOW (user_data);
+
+  adw_tab_view_set_page_pinned (self->view, get_current_page (self), TRUE);
+}
+
+static void
+tab_unpin (GSimpleAction *action,
+           GVariant      *parameter,
+           gpointer       user_data)
+{
+  AdwTabViewDemoWindow *self = ADW_TAB_VIEW_DEMO_WINDOW (user_data);
+
+  adw_tab_view_set_page_pinned (self->view, get_current_page (self), FALSE);
+}
+
+static void
+tab_close (GSimpleAction *action,
+           GVariant      *parameter,
+           gpointer       user_data)
+{
+  AdwTabViewDemoWindow *self = ADW_TAB_VIEW_DEMO_WINDOW (user_data);
+
+  adw_tab_view_close_page (self->view, get_current_page (self));
+}
+
+static void
+tab_close_other (GSimpleAction *action,
+                 GVariant      *parameter,
+                 gpointer       user_data)
+{
+  AdwTabViewDemoWindow *self = ADW_TAB_VIEW_DEMO_WINDOW (user_data);
+
+  adw_tab_view_close_other_pages (self->view, get_current_page (self));
+}
+
+static void
+tab_close_before (GSimpleAction *action,
+                  GVariant      *parameter,
+                  gpointer       user_data)
+{
+  AdwTabViewDemoWindow *self = ADW_TAB_VIEW_DEMO_WINDOW (user_data);
+
+  adw_tab_view_close_pages_before (self->view, get_current_page (self));
+}
+
+static void
+tab_close_after (GSimpleAction *action,
+                 GVariant      *parameter,
+                 gpointer       user_data)
+{
+  AdwTabViewDemoWindow *self = ADW_TAB_VIEW_DEMO_WINDOW (user_data);
+
+  adw_tab_view_close_pages_after (self->view, get_current_page (self));
+}
+
+static void
+tab_move_to_new_window (GSimpleAction *action,
+                        GVariant      *parameter,
+                        gpointer       user_data)
+{
+  AdwTabViewDemoWindow *self = ADW_TAB_VIEW_DEMO_WINDOW (user_data);
+
+  AdwTabViewDemoWindow *window = adw_tab_view_demo_window_new ();
+
+  adw_tab_view_transfer_page (self->view,
+                              self->menu_page,
+                              window->view,
+                              0);
+
+  gtk_window_present (GTK_WINDOW (window));
+}
+
+static void
+tab_change_needs_attention (GSimpleAction *action,
+                            GVariant      *parameter,
+                            gpointer       user_data)
+{
+  AdwTabViewDemoWindow *self = ADW_TAB_VIEW_DEMO_WINDOW (user_data);
+  gboolean need_attention = g_variant_get_boolean (parameter);
+
+  adw_tab_page_set_needs_attention (get_current_page (self), need_attention);
+  g_simple_action_set_state (action, g_variant_new_boolean (need_attention));
+}
+
+static void
+tab_change_loading (GSimpleAction *action,
+                    GVariant      *parameter,
+                    gpointer       user_data)
+{
+  AdwTabViewDemoWindow *self = ADW_TAB_VIEW_DEMO_WINDOW (user_data);
+  gboolean loading = g_variant_get_boolean (parameter);
+
+  adw_tab_page_set_loading (get_current_page (self), loading);
+  g_simple_action_set_state (action, g_variant_new_boolean (loading));
+}
+
+static GIcon *
+get_indicator_icon (AdwTabPage *page)
+{
+  gboolean muted;
+
+  muted = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (page),
+                                              "adw-tab-view-demo-muted"));
+
+  if (muted)
+    return g_themed_icon_new ("tab-audio-muted-symbolic");
+  else
+    return g_themed_icon_new ("tab-audio-playing-symbolic");
+}
+
+static void
+tab_change_indicator (GSimpleAction *action,
+                      GVariant      *parameter,
+                      gpointer       user_data)
+{
+  AdwTabViewDemoWindow *self = ADW_TAB_VIEW_DEMO_WINDOW (user_data);
+  gboolean indicator = g_variant_get_boolean (parameter);
+  g_autoptr (GIcon) icon = NULL;
+
+  if (indicator)
+    icon = get_indicator_icon (get_current_page (self));
+
+  adw_tab_page_set_indicator_icon (get_current_page (self), icon);
+  g_simple_action_set_state (action, g_variant_new_boolean (indicator));
+}
+
+static void
+tab_change_icon (GSimpleAction *action,
+                 GVariant      *parameter,
+                 gpointer       user_data)
+{
+  AdwTabViewDemoWindow *self = ADW_TAB_VIEW_DEMO_WINDOW (user_data);
+  gboolean enable_icon = g_variant_get_boolean (parameter);
+
+  if (enable_icon) {
+    g_autoptr (GIcon) icon = get_random_icon (self);
+
+    adw_tab_page_set_icon (get_current_page (self), icon);
+  } else {
+    adw_tab_page_set_icon (get_current_page (self), NULL);
+  }
+
+  g_simple_action_set_state (action, g_variant_new_boolean (enable_icon));
+}
+
+static void
+tab_refresh_icon (GSimpleAction *action,
+                  GVariant      *parameter,
+                  gpointer       user_data)
+{
+  AdwTabViewDemoWindow *self = ADW_TAB_VIEW_DEMO_WINDOW (user_data);
+  g_autoptr (GIcon) icon = get_random_icon (self);
+
+  adw_tab_page_set_icon (get_current_page (self), icon);
+}
+
+static void
+tab_duplicate (GSimpleAction *action,
+               GVariant      *parameter,
+               gpointer       user_data)
+{
+  AdwTabViewDemoWindow *self = ADW_TAB_VIEW_DEMO_WINDOW (user_data);
+  AdwTabPage *parent = get_current_page (self);
+  AdwTabPage *page;
+
+  page = add_page (self, parent,
+                   adw_tab_page_get_title (parent),
+                   adw_tab_page_get_icon (parent));
+
+  adw_tab_page_set_indicator_icon (page, adw_tab_page_get_indicator_icon (parent));
+  adw_tab_page_set_loading (page, adw_tab_page_get_loading (parent));
+  adw_tab_page_set_needs_attention (page, adw_tab_page_get_needs_attention (parent));
+
+  g_object_set_data (G_OBJECT (page),
+                     "adw-tab-view-demo-muted",
+                     g_object_get_data (G_OBJECT (parent),
+                                        "adw-tab-view-demo-muted"));
+
+  adw_tab_view_set_selected_page (self->view, page);
+}
+
+static GActionEntry action_entries[] = {
+  { "window-new", window_new },
+  { "tab-new", tab_new },
+};
+
+static GActionEntry tab_action_entries[] = {
+  { "pin", tab_pin },
+  { "unpin", tab_unpin },
+  { "close", tab_close },
+  { "close-other", tab_close_other },
+  { "close-before", tab_close_before },
+  { "close-after", tab_close_after },
+  { "move-to-new-window", tab_move_to_new_window },
+  { "needs-attention", NULL, NULL, "false", tab_change_needs_attention },
+  { "loading", NULL, NULL, "false", tab_change_loading },
+  { "indicator", NULL, NULL, "false", tab_change_indicator },
+  { "icon", NULL, NULL, "false", tab_change_icon },
+  { "refresh-icon", tab_refresh_icon },
+  { "duplicate", tab_duplicate },
+};
+
+static inline void
+set_tab_action_enabled (AdwTabViewDemoWindow *self,
+                        const char           *name,
+                        gboolean              enabled)
+{
+  GAction *action = g_action_map_lookup_action (self->tab_action_group, name);
+
+  g_assert (G_IS_SIMPLE_ACTION (action));
+
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+                               enabled);
+}
+
+static inline void
+set_tab_action_state (AdwTabViewDemoWindow *self,
+                      const char           *name,
+                      gboolean              state)
+{
+  GAction *action = g_action_map_lookup_action (self->tab_action_group, name);
+
+  g_assert (G_IS_SIMPLE_ACTION (action));
+
+  g_simple_action_set_state (G_SIMPLE_ACTION (action),
+                             g_variant_new_boolean (state));
+}
+
+static void
+page_detached_cb (AdwTabViewDemoWindow *self,
+                  AdwTabPage           *page)
+{
+  if (!adw_tab_view_get_n_pages (self->view))
+    gtk_window_close (GTK_WINDOW (self));
+}
+
+static void
+setup_menu_cb (AdwTabViewDemoWindow *self,
+               AdwTabPage           *page,
+               AdwTabView           *view)
+{
+  AdwTabPage *prev = NULL;
+  gboolean can_close_before = TRUE, can_close_after = TRUE;
+  gboolean pinned = FALSE, prev_pinned;
+  gboolean has_icon = FALSE;
+  guint n_pages, pos;
+
+  self->menu_page = page;
+
+  n_pages = adw_tab_view_get_n_pages (self->view);
+
+  if (page) {
+    pos = adw_tab_view_get_page_position (self->view, page);
+
+    if (pos > 0)
+      prev = adw_tab_view_get_nth_page (self->view, pos - 1);
+
+    pinned = adw_tab_page_get_pinned (page);
+    prev_pinned = prev && adw_tab_page_get_pinned (prev);
+
+    can_close_before = !pinned && prev && !prev_pinned;
+    can_close_after = pos < n_pages - 1;
+
+    has_icon = adw_tab_page_get_icon (page) != NULL;
+  }
+
+  set_tab_action_enabled (self, "pin", !page || !pinned);
+  set_tab_action_enabled (self, "unpin", !page || pinned);
+  set_tab_action_enabled (self, "close", !page || !pinned);
+  set_tab_action_enabled (self, "close-before", can_close_before);
+  set_tab_action_enabled (self, "close-after", can_close_after);
+  set_tab_action_enabled (self, "close-other", can_close_before || can_close_after);
+  set_tab_action_enabled (self, "move-to-new-window", !page || (!pinned && n_pages > 1));
+  set_tab_action_enabled (self, "refresh-icon", has_icon);
+
+  if (page) {
+    set_tab_action_state (self, "icon", has_icon);
+    set_tab_action_state (self, "loading", adw_tab_page_get_loading (page));
+    set_tab_action_state (self, "needs-attention", adw_tab_page_get_needs_attention (page));
+    set_tab_action_state (self, "indicator", adw_tab_page_get_indicator_icon (page) != NULL);
+  }
+}
+
+static AdwTabView *
+create_window_cb (AdwTabViewDemoWindow *self)
+{
+  AdwTabViewDemoWindow *window = adw_tab_view_demo_window_new ();
+
+  gtk_window_present (GTK_WINDOW (window));
+
+  return window->view;
+}
+
+static void
+indicator_activated_cb (AdwTabViewDemoWindow *self,
+                        AdwTabPage           *page)
+{
+  g_autoptr (GIcon) icon = NULL;
+  gboolean muted;
+
+  muted = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (page),
+                                              "adw-tab-view-demo-muted"));
+
+  g_object_set_data (G_OBJECT (page),
+                     "adw-tab-view-demo-muted",
+                     GINT_TO_POINTER (!muted));
+
+  icon = get_indicator_icon (page);
+
+  adw_tab_page_set_indicator_icon (page, icon);
+}
+
+static gboolean
+extra_drag_drop_cb (AdwTabViewDemoWindow *self,
+                    AdwTabPage           *page,
+                    GValue               *value)
+{
+  adw_tab_page_set_title (page,  g_value_get_string (value));
+
+  return GDK_EVENT_STOP;
+}
+
+static void
+adw_tab_view_demo_window_dispose (GObject *object)
+{
+  AdwTabViewDemoWindow *self = ADW_TAB_VIEW_DEMO_WINDOW (object);
+
+  g_clear_object (&self->tab_action_group);
+
+  G_OBJECT_CLASS (adw_tab_view_demo_window_parent_class)->dispose (object);
+}
+
+static void
+adw_tab_view_demo_window_class_init (AdwTabViewDemoWindowClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->dispose = adw_tab_view_demo_window_dispose;
+
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/Adwaita/Demo/ui/adw-tab-view-demo-window.ui");
+  gtk_widget_class_bind_template_child (widget_class, AdwTabViewDemoWindow, view);
+  gtk_widget_class_bind_template_child (widget_class, AdwTabViewDemoWindow, tab_bar);
+  gtk_widget_class_bind_template_callback (widget_class, page_detached_cb);
+  gtk_widget_class_bind_template_callback (widget_class, setup_menu_cb);
+  gtk_widget_class_bind_template_callback (widget_class, create_window_cb);
+  gtk_widget_class_bind_template_callback (widget_class, indicator_activated_cb);
+  gtk_widget_class_bind_template_callback (widget_class, extra_drag_drop_cb);
+
+  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_t, GDK_CONTROL_MASK, "win.tab-new", NULL);
+  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_n, GDK_CONTROL_MASK, "win.window-new", NULL);
+  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_w, GDK_CONTROL_MASK, "tab.close", NULL);
+}
+
+static void
+adw_tab_view_demo_window_init (AdwTabViewDemoWindow *self)
+{
+  GActionMap *action_map;
+
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  action_map = G_ACTION_MAP (g_simple_action_group_new ());
+  g_action_map_add_action_entries (action_map,
+                                   action_entries,
+                                   G_N_ELEMENTS (action_entries),
+                                   self);
+  gtk_widget_insert_action_group (GTK_WIDGET (self),
+                                  "win",
+                                  G_ACTION_GROUP (action_map));
+
+  self->tab_action_group = G_ACTION_MAP (g_simple_action_group_new ());
+  g_action_map_add_action_entries (self->tab_action_group,
+                                   tab_action_entries,
+                                   G_N_ELEMENTS (tab_action_entries),
+                                   self);
+
+  gtk_widget_insert_action_group (GTK_WIDGET (self),
+                                  "tab",
+                                  G_ACTION_GROUP (self->tab_action_group));
+
+  adw_tab_bar_setup_extra_drop_target (self->tab_bar,
+                                       GDK_ACTION_COPY,
+                                       (GType[1]) { G_TYPE_STRING }, 1);
+}
+
+AdwTabViewDemoWindow *
+adw_tab_view_demo_window_new (void)
+{
+  return g_object_new (ADW_TYPE_TAB_VIEW_DEMO_WINDOW, NULL);
+}
+
+void
+adw_tab_view_demo_window_prepopulate (AdwTabViewDemoWindow *self)
+{
+  tab_new (NULL, NULL, self);
+  tab_new (NULL, NULL, self);
+  tab_new (NULL, NULL, self);
+}
diff --git a/examples/adw-tab-view-demo-window.h b/examples/adw-tab-view-demo-window.h
new file mode 100644
index 0000000..6261436
--- /dev/null
+++ b/examples/adw-tab-view-demo-window.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <adwaita.h>
+
+G_BEGIN_DECLS
+
+#define ADW_TYPE_TAB_VIEW_DEMO_WINDOW (adw_tab_view_demo_window_get_type())
+
+G_DECLARE_FINAL_TYPE (AdwTabViewDemoWindow, adw_tab_view_demo_window, ADW, TAB_VIEW_DEMO_WINDOW, AdwWindow)
+
+AdwTabViewDemoWindow *adw_tab_view_demo_window_new (void);
+
+void adw_tab_view_demo_window_prepopulate (AdwTabViewDemoWindow *self);
+
+G_END_DECLS
diff --git a/examples/adw-tab-view-demo-window.ui b/examples/adw-tab-view-demo-window.ui
new file mode 100644
index 0000000..1da1777
--- /dev/null
+++ b/examples/adw-tab-view-demo-window.ui
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk" version="4.0"/>
+  <requires lib="libadwaita" version="1.0"/>
+  <template class="AdwTabViewDemoWindow" parent="AdwWindow">
+    <property name="title" translatable="yes">Tab View Demo</property>
+    <property name="default-width">800</property>
+    <property name="default-height">600</property>
+    <child>
+      <object class="GtkBox">
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkHeaderBar">
+            <child type="start">
+              <object class="GtkButton">
+                <property name="action-name">win.tab-new</property>
+                <property name="icon-name">tab-new-symbolic</property>
+              </object>
+            </child>
+            <child type="end">
+              <object class="GtkMenuButton">
+                <property name="menu-model">primary_menu</property>
+                <property name="icon-name">open-menu-symbolic</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="AdwTabBar" id="tab_bar">
+            <property name="view">view</property>
+            <signal name="extra-drag-drop" handler="extra_drag_drop_cb" swapped="true"/>
+          </object>
+        </child>
+        <child>
+          <object class="AdwTabView" id="view">
+            <property name="vexpand">True</property>
+            <property name="menu-model">tab_menu</property>
+            <property name="shortcut-widget">AdwTabViewDemoWindow</property>
+            <signal name="page-detached" handler="page_detached_cb" swapped="true"/>
+            <signal name="setup-menu" handler="setup_menu_cb" swapped="true"/>
+            <signal name="create-window" handler="create_window_cb" swapped="true"/>
+            <signal name="indicator-activated" handler="indicator_activated_cb" swapped="true"/>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+  <menu id="primary_menu">
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">_New Window</attribute>
+        <attribute name="action">win.window-new</attribute>
+      </item>
+    </section>
+  </menu>
+  <menu id="tab_menu">
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">_Move to New Window</attribute>
+        <attribute name="action">tab.move-to-new-window</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">D_uplicate</attribute>
+        <attribute name="action">tab.duplicate</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">P_in Tab</attribute>
+        <attribute name="action">tab.pin</attribute>
+        <attribute name="hidden-when">action-disabled</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Unp_in Tab</attribute>
+        <attribute name="action">tab.unpin</attribute>
+        <attribute name="hidden-when">action-disabled</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">Icon</attribute>
+        <attribute name="action">tab.icon</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">R_efresh Icon</attribute>
+        <attribute name="action">tab.refresh-icon</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">Loa_ding</attribute>
+        <attribute name="action">tab.loading</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Needs _Attention</attribute>
+        <attribute name="action">tab.needs-attention</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Indicator</attribute>
+        <attribute name="action">tab.indicator</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">Close _Other Tabs</attribute>
+        <attribute name="action">tab.close-other</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes" comments="Translators: “Close Tabs to the _Right” if 
you’re translating for a language that reads from right to left">Close Tabs to the _Left</attribute>
+        <attribute name="action">tab.close-before</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes" comments="Translators: “Close Tabs to the _Left” if 
you’re translating for a language that reads from right to left">Close Tabs to the _Right</attribute>
+        <attribute name="action">tab.close-after</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">_Close</attribute>
+        <attribute name="action">tab.close</attribute>
+      </item>
+    </section>
+  </menu>
+</interface>
diff --git a/examples/adwaita-demo.gresources.xml b/examples/adwaita-demo.gresources.xml
index 67a48ba..6caaa70 100644
--- a/examples/adwaita-demo.gresources.xml
+++ b/examples/adwaita-demo.gresources.xml
@@ -18,6 +18,7 @@
     <file preprocess="xml-stripblanks">icons/scalable/actions/row-forbidden-symbolic.svg</file>
     <file preprocess="xml-stripblanks">icons/scalable/actions/row-preferences-symbolic.svg</file>
     <file preprocess="xml-stripblanks">icons/scalable/actions/row-shutdown-symbolic.svg</file>
+    <file preprocess="xml-stripblanks">icons/scalable/actions/tab-new-symbolic.svg</file>
     <file preprocess="xml-stripblanks">icons/scalable/actions/view-sidebar-start-symbolic.svg</file>
     <file preprocess="xml-stripblanks">icons/scalable/actions/view-sidebar-start-symbolic-rtl.svg</file>
     <file preprocess="xml-stripblanks">icons/scalable/actions/view-sidebar-end-symbolic.svg</file>
@@ -28,15 +29,19 @@
     <file preprocess="xml-stripblanks">icons/scalable/actions/widget-leaflet-symbolic.svg</file>
     <file preprocess="xml-stripblanks">icons/scalable/actions/widget-list-symbolic.svg</file>
     <file preprocess="xml-stripblanks">icons/scalable/actions/widget-search-symbolic.svg</file>
+    <file preprocess="xml-stripblanks">icons/scalable/actions/widget-tab-view-symbolic.svg</file>
     <file preprocess="xml-stripblanks">icons/scalable/actions/widget-view-switcher-symbolic.svg</file>
     <file preprocess="xml-stripblanks">icons/scalable/actions/widget-window-symbolic.svg</file>
     <file preprocess="xml-stripblanks">icons/scalable/status/dark-mode-symbolic.svg</file>
     <file preprocess="xml-stripblanks">icons/scalable/status/light-mode-symbolic.svg</file>
+    <file preprocess="xml-stripblanks">icons/scalable/status/tab-audio-playing-symbolic.svg</file>
+    <file preprocess="xml-stripblanks">icons/scalable/status/tab-audio-muted-symbolic.svg</file>
   </gresource>
   <gresource prefix="/org/gnome/Adwaita/Demo/ui">
     <file preprocess="xml-stripblanks">adw-demo-preferences-window.ui</file>
     <file preprocess="xml-stripblanks">adw-demo-window.ui</file>
     <file preprocess="xml-stripblanks">adw-flap-demo-window.ui</file>
+    <file preprocess="xml-stripblanks">adw-tab-view-demo-window.ui</file>
     <file preprocess="xml-stripblanks">adw-view-switcher-demo-window.ui</file>
     <file compressed="true">style.css</file>
   </gresource>
diff --git a/examples/icons/scalable/actions/tab-new-symbolic.svg 
b/examples/icons/scalable/actions/tab-new-symbolic.svg
new file mode 100644
index 0000000..f1f4ebb
--- /dev/null
+++ b/examples/icons/scalable/actions/tab-new-symbolic.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg"; width="16.009" height="16"><g fill="#2e3436"><path d="M4.003 
1s-.709-.014-1.447.355C1.817 1.725 1.003 2.667 1.003 4v9h-1l-.004 2h.004l3 
.01V15h13v-2h-1V4s.014-.709-.355-1.447C14.278 1.814 13.336 1 12.003 1zm0 2h8c.667 0 
.725.186.855.447.131.262.145.553.145.553v9h-10V4c0-.667.186-.725.447-.855.262-.131.553-.145.553-.145z" 
style="line-height:normal;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000;text-transform:none;text-orientation:mixed;shape-padding:0;isolation:auto;mix-blend-mode:normal"
 color="#000" font-weight="400" font-family="sans-serif" overflow="visible"/><path d="M7.009 
5v2h-2v2h2v2h2V9h2V7h-2V5z"/></g></svg>
\ No newline at end of file
diff --git a/examples/icons/scalable/actions/widget-tab-view-symbolic.svg 
b/examples/icons/scalable/actions/widget-tab-view-symbolic.svg
new file mode 100644
index 0000000..38230bb
--- /dev/null
+++ b/examples/icons/scalable/actions/widget-tab-view-symbolic.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg"; width="16.009" height="16"><g fill="#2e3436"><path d="M4.003 
1s-.709-.014-1.447.355C1.817 1.725 1.003 2.667 1.003 4v9h-1l-.004 2h.004l3 
.01V15h13v-2h-1V4s.014-.709-.355-1.447C14.278 1.814 13.336 1 12.003 1zm0 2h8c.667 0 
.725.186.855.447.131.262.145.553.145.553v9h-10V4c0-.667.186-.725.447-.855.262-.131.553-.145.553-.145z" 
style="line-height:normal;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000;text-transform:none;text-orientation:mixed;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"
 color="#000" font-weight="400" font-family="sans-serif" overflow="visible"/><path d="M7.009 
5v2h-2v2h2v2h2V9h2V7h-2V5z"/></g></svg>
\ No newline at end of file
diff --git a/examples/icons/scalable/status/tab-audio-muted-symbolic.svg 
b/examples/icons/scalable/status/tab-audio-muted-symbolic.svg
new file mode 100644
index 0000000..e838a7b
--- /dev/null
+++ b/examples/icons/scalable/status/tab-audio-muted-symbolic.svg
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="15.999999"
+   height="15.999999"
+   viewBox="0 0 4.233333 4.2333332"
+   version="1.1"
+   id="svg59656"
+   inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
+   sodipodi:docname="sound-muted-symbolic.svg">
+  <defs
+     id="defs59650" />
+  <sodipodi:namedview
+     inkscape:snap-midpoints="true"
+     inkscape:snap-smooth-nodes="true"
+     inkscape:snap-intersection-paths="true"
+     inkscape:object-paths="true"
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="4.7332096"
+     inkscape:cx="72.365677"
+     inkscape:cy="-5.9069288"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     inkscape:document-rotation="0"
+     showgrid="true"
+     units="px"
+     inkscape:window-width="1920"
+     inkscape:window-height="1016"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1">
+    <inkscape:grid
+       type="xygrid"
+       id="grid59669"
+       originx="-414.0729"
+       originy="-67.204172" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata59653">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-414.07291,-67.20417)">
+    <g
+       style="fill:#241f31"
+       transform="matrix(0.26458333,0,0,0.26458333,414.07293,67.204165)"
+       fill="#474747"
+       id="g16">
+      <path
+         transform="translate(-7.5590552e-5,1.8897638e-5)"
+         d="M 7.453125 2 L 4.5214844 4.9609375 L 8 8.4394531 L 8 2 L 7.453125 2 z M 11 3 L 11 5 C 11.607 
5.789 12 6.76 12 8 C 12 9.241 11.607 10.22 11 11 L 11 11.439453 L 12.287109 12.726562 C 13.34008 11.684021 14 
9.952001 14 8 C 14 5.834 13.261 3.98 12 3 L 11 3 z M 2 5 L 2 11 L 4.484375 11 L 7.5253906 14 L 8 14 L 8 
10.5625 L 2.4375 5 L 2 5 z M 9 5 L 9 9.4394531 L 10.226562 10.666016 C 10.734406 9.9178051 11 9.0952939 11 8 
C 11 6.743 10.688 5.784 10 5 L 9 5 z "
+         style="marker:none;fill:#241f31"
+         id="path10" />
+    </g>
+    <path
+       id="path60"
+       d="m 417.90147,71.336914 0.28098,-0.280987 -3.70443,-3.703902 -0.28072,0.280723 z"
+       
style="fill:#241f31;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
 />
+    <g
+       style="fill:#2ec27e"
+       transform="translate(-5.8208332)"
+       id="g72" />
+  </g>
+</svg>
diff --git a/examples/icons/scalable/status/tab-audio-playing-symbolic.svg 
b/examples/icons/scalable/status/tab-audio-playing-symbolic.svg
new file mode 100644
index 0000000..0a64157
--- /dev/null
+++ b/examples/icons/scalable/status/tab-audio-playing-symbolic.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg"; width="16" height="16"><g fill="#474747"><path d="M2 
5h2.484l2.97-3H8v12h-.475l-3.04-3H2z" style="marker:none" color="#bebebe" overflow="visible"/><path d="M14 
8c0-2.166-.739-4.02-2-5h-1v2c.607.789 1 1.76 1 3 0 1.241-.393 2.22-1 3v2h1c1.223-.995 2-2.873 2-5z" 
style="marker:none" color="#000" overflow="visible"/><path d="M11 8c0-1.257-.312-2.216-1-3H9v6h1c.672-.837 
1-1.742 1-3z" 
style="line-height:normal;-inkscape-font-specification:Sans;text-indent:0;text-align:start;text-decoration-line:none;text-transform:none;marker:none"
 color="#000" font-weight="400" font-family="Sans" overflow="visible"/></g></svg>
\ No newline at end of file
diff --git a/examples/meson.build b/examples/meson.build
index 86b0cfb..798b23c 100644
--- a/examples/meson.build
+++ b/examples/meson.build
@@ -13,6 +13,7 @@ adwaita_demo_sources = [
   'adw-demo-preferences-window.c',
   'adw-demo-window.c',
   'adw-flap-demo-window.c',
+  'adw-tab-view-demo-window.c',
   'adw-view-switcher-demo-window.c',
   libadwaita_generated_headers,
 ]


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]