[gtk/prop-list] wip: Add GtkDropDown
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/prop-list] wip: Add GtkDropDown
- Date: Mon, 9 Dec 2019 17:31:40 +0000 (UTC)
commit 1213f61e02ad6ba46c4c4ca83b70d3fb3cb8aada
Author: Matthias Clasen <mclasen redhat com>
Date: Sun Dec 8 20:22:06 2019 -0500
wip: Add GtkDropDown
This is a simple drop down control using list models.
gtk/gtk.h | 1 +
gtk/gtkdropdown.c | 492 ++++++++++++++++++++++++++++++++++++++++++++++++++
gtk/gtkdropdown.h | 57 ++++++
gtk/meson.build | 2 +
gtk/ui/gtkdropdown.ui | 64 +++++++
tests/meson.build | 1 +
tests/testdropdown.c | 89 +++++++++
7 files changed, 706 insertions(+)
---
diff --git a/gtk/gtk.h b/gtk/gtk.h
index 096fdbca70..78f971db05 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -101,6 +101,7 @@
#include <gtk/gtkdragdest.h>
#include <gtk/gtkdragsource.h>
#include <gtk/gtkdrawingarea.h>
+#include <gtk/gtkdropdown.h>
#include <gtk/gtkeditable.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkentrybuffer.h>
diff --git a/gtk/gtkdropdown.c b/gtk/gtkdropdown.c
new file mode 100644
index 0000000000..3d8529c3a2
--- /dev/null
+++ b/gtk/gtkdropdown.c
@@ -0,0 +1,492 @@
+/*
+ * Copyright © 2019 Red Hat, Inc.
+ *
+ * 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.1 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
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#include "config.h"
+
+#include "gtkdropdown.h"
+
+#include "gtkintl.h"
+#include "gtklistview.h"
+#include "gtklistitemfactory.h"
+#include "gtklistitemwidgetprivate.h"
+#include "gtkpopover.h"
+#include "gtkprivate.h"
+#include "gtksingleselection.h"
+#include "gtknoselection.h"
+#include "gtkselectionmodel.h"
+#include "gtkstylecontext.h"
+#include "gtkiconprivate.h"
+#include "gtkwidgetprivate.h"
+#include "gtknative.h"
+#include "gtktogglebutton.h"
+#include "gtkstack.h"
+
+
+struct _GtkDropDown
+{
+ GtkWidget parent_instance;
+
+ GtkListItemFactory *factory;
+ GListModel *model;
+ GListModel *selection;
+ GListModel *popup_selection;
+
+ GtkWidget *popup;
+ GtkWidget *button;
+
+ GtkWidget *popup_list;
+ GtkWidget *button_stack;
+ GtkWidget *button_item;
+ GtkWidget *button_placeholder;
+
+ guint selected;
+};
+
+struct _GtkDropDownClass
+{
+ GtkDropDownClass parent_class;
+};
+
+enum
+{
+ PROP_0,
+ PROP_FACTORY,
+ PROP_MODEL,
+ PROP_SELECTED,
+
+ N_PROPS
+};
+
+G_DEFINE_TYPE (GtkDropDown, gtk_drop_down, GTK_TYPE_WIDGET)
+
+static GParamSpec *properties[N_PROPS] = { NULL, };
+
+static void
+button_toggled (GtkWidget *widget,
+ gpointer data)
+{
+ GtkDropDown *self = data;
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
+ gtk_popover_popup (GTK_POPOVER (self->popup));
+ else
+ gtk_popover_popdown (GTK_POPOVER (self->popup));
+}
+
+static void
+popover_closed (GtkPopover *popover,
+ gpointer data)
+{
+ GtkDropDown *self = data;
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->button), FALSE);
+}
+
+static void
+row_activated (GtkListView *listview,
+ guint position,
+ gpointer data)
+{
+ GtkDropDown *self = data;
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->button), FALSE);
+ gtk_popover_popdown (GTK_POPOVER (self->popup));
+
+ gtk_drop_down_set_selected (self, gtk_single_selection_get_selected (GTK_SINGLE_SELECTION
(self->popup_selection)));
+}
+
+static void
+selection_changed (GtkSelectionModel *selection,
+ guint position,
+ guint n_items,
+ gpointer data)
+{
+ GtkDropDown *self = data;
+ guint selected;
+ gpointer item;
+
+ selected = gtk_single_selection_get_selected (GTK_SINGLE_SELECTION (self->selection));
+ item = gtk_single_selection_get_selected_item (GTK_SINGLE_SELECTION (self->selection));
+
+ if (selected == GTK_INVALID_LIST_POSITION)
+ {
+ gtk_stack_set_visible_child_name (GTK_STACK (self->button_stack), "empty");
+ }
+ else
+ {
+ gtk_stack_set_visible_child_name (GTK_STACK (self->button_stack), "item");
+ gtk_list_item_widget_update (GTK_LIST_ITEM_WIDGET (self->button_item), selected, item, FALSE);
+ }
+
+ gtk_single_selection_set_selected (GTK_SINGLE_SELECTION (self->popup_selection), selected);
+}
+
+static void
+gtk_drop_down_dispose (GObject *object)
+{
+ GtkDropDown *self = GTK_DROP_DOWN (object);
+
+ g_clear_pointer (&self->popup, gtk_widget_unparent);
+ g_clear_pointer (&self->button, gtk_widget_unparent);
+
+ g_clear_object (&self->model);
+ if (self->selection)
+ g_signal_handlers_disconnect_by_func (self->selection, selection_changed, self);
+ g_clear_object (&self->selection);
+ g_clear_object (&self->popup_selection);
+
+ G_OBJECT_CLASS (gtk_drop_down_parent_class)->dispose (object);
+}
+
+static void
+gtk_drop_down_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkDropDown *self = GTK_DROP_DOWN (object);
+
+ switch (property_id)
+ {
+ case PROP_FACTORY:
+ g_value_set_object (value, self->factory);
+ break;
+
+ case PROP_MODEL:
+ g_value_set_object (value, self->model);
+ break;
+
+ case PROP_SELECTED:
+ g_value_set_uint (value, gtk_drop_down_get_selected (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_drop_down_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkDropDown *self = GTK_DROP_DOWN (object);
+
+ switch (property_id)
+ {
+ case PROP_FACTORY:
+ gtk_drop_down_set_factory (self, g_value_get_object (value));
+ break;
+
+ case PROP_MODEL:
+ gtk_drop_down_set_model (self, g_value_get_object (value));
+ break;
+
+ case PROP_SELECTED:
+ gtk_drop_down_set_selected (self, g_value_get_uint (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_drop_down_measure (GtkWidget *widget,
+ GtkOrientation orientation,
+ int size,
+ int *minimum,
+ int *natural,
+ int *minimum_baseline,
+ int *natural_baseline)
+{
+ GtkDropDown *self = GTK_DROP_DOWN (widget);
+
+ gtk_widget_measure (self->button,
+ orientation,
+ size,
+ minimum, natural,
+ minimum_baseline, natural_baseline);
+}
+
+static void
+gtk_drop_down_size_allocate (GtkWidget *widget,
+ int width,
+ int height,
+ int baseline)
+{
+ GtkDropDown *self = GTK_DROP_DOWN (widget);
+
+ gtk_widget_size_allocate (self->button, &(GtkAllocation) { 0, 0, width, height }, baseline);
+
+ gtk_native_check_resize (GTK_NATIVE (self->popup));
+}
+
+
+static void
+gtk_drop_down_class_init (GtkDropDownClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->dispose = gtk_drop_down_dispose;
+ gobject_class->get_property = gtk_drop_down_get_property;
+ gobject_class->set_property = gtk_drop_down_set_property;
+
+ widget_class->measure = gtk_drop_down_measure;
+ widget_class->size_allocate = gtk_drop_down_size_allocate;
+
+ /**
+ * GtkDropDown:factory:
+ *
+ * Factory for populating list items
+ */
+ properties[PROP_FACTORY] =
+ g_param_spec_object ("factory",
+ P_("Factory"),
+ P_("Factory for populating list items"),
+ GTK_TYPE_LIST_ITEM_FACTORY,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkDropDown:model:
+ *
+ * Model for the items displayed
+ */
+ properties[PROP_MODEL] =
+ g_param_spec_object ("model",
+ P_("Model"),
+ P_("Model for the items displayed"),
+ G_TYPE_LIST_MODEL,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_SELECTED] =
+ g_param_spec_uint ("selected",
+ P_("Selected"),
+ P_("Position of the selected item"),
+ 0, G_MAXUINT, GTK_INVALID_LIST_POSITION,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (gobject_class, N_PROPS, properties);
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/ui/gtkdropdown.ui");
+ gtk_widget_class_bind_template_child (widget_class, GtkDropDown, button);
+ gtk_widget_class_bind_template_child (widget_class, GtkDropDown, button_stack);
+ gtk_widget_class_bind_template_child (widget_class, GtkDropDown, button_item);
+ gtk_widget_class_bind_template_child (widget_class, GtkDropDown, popup);
+ gtk_widget_class_bind_template_child (widget_class, GtkDropDown, popup_list);
+ gtk_widget_class_bind_template_callback (widget_class, row_activated);
+
+ gtk_widget_class_bind_template_callback (widget_class, button_toggled);
+ gtk_widget_class_bind_template_callback (widget_class, popover_closed);
+
+ gtk_widget_class_set_css_name (widget_class, I_("combobox"));
+}
+
+static void
+gtk_drop_down_init (GtkDropDown *self)
+{
+ g_type_ensure (GTK_TYPE_ICON);
+ g_type_ensure (GTK_TYPE_LIST_ITEM_WIDGET);
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ self->selected = GTK_INVALID_LIST_POSITION;
+}
+
+/**
+ * gtk_drop_down_new:
+ *
+ * Creates a new empty #GtkDropDown.
+ *
+ * You most likely want to call gtk_drop_down_set_factory() to
+ * set up a way to map its items to widgets and gtk_drop_down_set_model()
+ * to set a model to provide items next.
+ *
+ * Returns: a new #GtkDropDown
+ **/
+GtkWidget *
+gtk_drop_down_new (void)
+{
+ return g_object_new (GTK_TYPE_DROP_DOWN, NULL);
+}
+
+/**
+ * gtk_drop_down_new_with_factory:
+ * @factory: (transfer full): The factory to populate items with
+ *
+ * Creates a new #GtkDropDown that uses the given @factory for
+ * mapping items to widgets.
+ *
+ * You most likely want to call gtk_drop_down_set_model() to set
+ * a model next.
+ *
+ * Returns: a new #GtkDropDown using the given @factory
+ **/
+GtkWidget *
+gtk_drop_down_new_with_factory (GtkListItemFactory *factory)
+{
+ GtkWidget *result;
+
+ g_return_val_if_fail (GTK_IS_LIST_ITEM_FACTORY (factory), NULL);
+
+ result = g_object_new (GTK_TYPE_DROP_DOWN,
+ "factory", factory,
+ NULL);
+
+ g_object_unref (factory);
+
+ return result;
+}
+
+/**
+ * gtk_drop_down_get_model:
+ * @self: a #GtkDropDown
+ *
+ * Gets the model that's currently used to read the items displayed.
+ *
+ * Returns: (nullable) (transfer none): The model in use
+ **/
+GListModel *
+gtk_drop_down_get_model (GtkDropDown *self)
+{
+ g_return_val_if_fail (GTK_IS_DROP_DOWN (self), NULL);
+
+ return self->model;
+}
+
+/**
+ * gtk_drop_down_set_model:
+ * @self: a #GtkDropDown
+ * @model: (allow-none) (transfer none): the model to use or %NULL for none
+ *
+ * Sets the #GListModel to use.
+ */
+void
+gtk_drop_down_set_model (GtkDropDown *self,
+ GListModel *model)
+{
+ g_return_if_fail (GTK_IS_DROP_DOWN (self));
+ g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
+
+ if (!g_set_object (&self->model, model))
+ return;
+
+ if (model == NULL)
+ {
+ gtk_list_view_set_model (GTK_LIST_VIEW (self->popup_list), NULL);
+
+ if (self->selection)
+ g_signal_handlers_disconnect_by_func (self->selection, selection_changed, self);
+
+ g_clear_object (&self->selection);
+ g_clear_object (&self->popup_selection);
+ }
+ else
+ {
+ GListModel *selection;
+
+ selection = G_LIST_MODEL (gtk_single_selection_new (model));
+ g_set_object (&self->popup_selection, selection);
+ gtk_list_view_set_model (GTK_LIST_VIEW (self->popup_list), selection);
+ g_object_unref (selection);
+
+ if (GTK_IS_SINGLE_SELECTION (model))
+ selection = g_object_ref (model);
+ else
+ selection = G_LIST_MODEL (gtk_single_selection_new (model));
+ g_set_object (&self->selection, selection);
+ g_object_unref (selection);
+
+ g_signal_connect (self->selection, "selection-changed", G_CALLBACK (selection_changed), self);
+ gtk_single_selection_set_selected (GTK_SINGLE_SELECTION (self->selection), self->selected);
+ }
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
+}
+
+/**
+ * gtk_drop_down_get_factory:
+ * @self: a #GtkDropDown
+ *
+ * Gets the factory that's currently used to populate list items.
+ *
+ * Returns: (nullable) (transfer none): The factory in use
+ **/
+GtkListItemFactory *
+gtk_drop_down_get_factory (GtkDropDown *self)
+{
+ g_return_val_if_fail (GTK_IS_DROP_DOWN (self), NULL);
+
+ return self->factory;
+}
+
+/**
+ * gtk_drop_down_set_factory:
+ * @self: a #GtkDropDown
+ * @factory: (allow-none) (transfer none): the factory to use or %NULL for none
+ *
+ * Sets the #GtkListItemFactory to use for populating list items.
+ **/
+void
+gtk_drop_down_set_factory (GtkDropDown *self,
+ GtkListItemFactory *factory)
+{
+ g_return_if_fail (GTK_IS_DROP_DOWN (self));
+ g_return_if_fail (factory == NULL || GTK_LIST_ITEM_FACTORY (factory));
+
+ if (!g_set_object (&self->factory, factory))
+ return;
+
+ gtk_list_view_set_factory (GTK_LIST_VIEW (self->popup_list), factory);
+ gtk_list_item_widget_set_factory (GTK_LIST_ITEM_WIDGET (self->button_item), factory);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FACTORY]);
+}
+
+void
+gtk_drop_down_set_selected (GtkDropDown *self,
+ guint position)
+{
+ g_return_if_fail (GTK_IS_DROP_DOWN (self));
+
+ if (self->selection == NULL)
+ return;
+
+ if (gtk_single_selection_get_selected (GTK_SINGLE_SELECTION (self->selection)) == position)
+ return;
+
+ gtk_single_selection_set_selected (GTK_SINGLE_SELECTION (self->selection), position);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED]);
+}
+
+guint
+gtk_drop_down_get_selected (GtkDropDown *self)
+{
+ g_return_val_if_fail (GTK_IS_DROP_DOWN (self), GTK_INVALID_LIST_POSITION);
+
+ if (self->selection == NULL)
+ return GTK_INVALID_LIST_POSITION;
+
+ return gtk_single_selection_get_selected (GTK_SINGLE_SELECTION (self->selection));
+}
diff --git a/gtk/gtkdropdown.h b/gtk/gtkdropdown.h
new file mode 100644
index 0000000000..107b5b1b45
--- /dev/null
+++ b/gtk/gtkdropdown.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright © 2018 Red Hat, Inc.
+ *
+ * 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.1 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
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen
+ */
+
+#ifndef __GTK_DROP_DOWN_H__
+#define __GTK_DROP_DOWN_H__
+
+#include <gtk/gtkwidget.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_DROP_DOWN (gtk_drop_down_get_type ())
+
+GDK_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (GtkDropDown, gtk_drop_down, GTK, DROP_DOWN, GtkWidget)
+
+GDK_AVAILABLE_IN_ALL
+GtkWidget * gtk_drop_down_new (void);
+GDK_AVAILABLE_IN_ALL
+GtkWidget * gtk_drop_down_new_with_factory (GtkListItemFactory *factory);
+
+GDK_AVAILABLE_IN_ALL
+GListModel * gtk_drop_down_get_model (GtkDropDown *self);
+GDK_AVAILABLE_IN_ALL
+void gtk_drop_down_set_model (GtkDropDown *self,
+ GListModel *model);
+GDK_AVAILABLE_IN_ALL
+void gtk_drop_down_set_factory (GtkDropDown *self,
+ GtkListItemFactory *factory);
+GDK_AVAILABLE_IN_ALL
+GtkListItemFactory *
+ gtk_drop_down_get_factory (GtkDropDown *self);
+
+GDK_AVAILABLE_IN_ALL
+void gtk_drop_down_set_selected (GtkDropDown *self,
+ guint position);
+GDK_AVAILABLE_IN_ALL
+guint gtk_drop_down_get_selected (GtkDropDown *self);
+
+G_END_DECLS
+
+#endif /* __GTK_DROP_DOWN_H__ */
diff --git a/gtk/meson.build b/gtk/meson.build
index d0160c857d..d546efbc50 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -229,6 +229,7 @@ gtk_public_sources = files([
'gtkdragdest.c',
'gtkdragsource.c',
'gtkdrawingarea.c',
+ 'gtkdropdown.c',
'gtkeditable.c',
'gtkemojichooser.c',
'gtkemojicompletion.c',
@@ -520,6 +521,7 @@ gtk_public_headers = files([
'gtkdragdest.h',
'gtkdragsource.h',
'gtkdrawingarea.h',
+ 'gtkdropdown.h',
'gtkeditable.h',
'gtkentry.h',
'gtkentrybuffer.h',
diff --git a/gtk/ui/gtkdropdown.ui b/gtk/ui/gtkdropdown.ui
new file mode 100644
index 0000000000..d3754203fb
--- /dev/null
+++ b/gtk/ui/gtkdropdown.ui
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface domain="gtk40">
+ <template class="GtkDropDown" parent="GtkWidget">
+ <child>
+ <object class="GtkToggleButton" id="button">
+ <signal name="toggled" handler="button_toggled"/>
+ <child>
+ <object class="GtkBox">
+ <child>
+ <object class="GtkStack" id="button_stack">
+ <property name="hhomogeneous">0</property>
+ <child>
+ <object class="GtkStackPage">
+ <property name="name">empty</property>
+ <property name="child">
+ <object class="GtkLabel">
+ <property name="label" translatable="yes">(None)</property>
+ <property name="xalign">0</property>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStackPage">
+ <property name="name">item</property>
+ <property name="child">
+ <object class="GtkListItemWidget" id="button_item"/>
+ </property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkIcon">
+ <property name="css-name">arrow</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+ <object class="GtkPopover" id="popup">
+ <signal name="closed" handler="popover_closed"/>
+ <property name="relative-to">GtkDropDown</property>
+ <property name="has-arrow">0</property>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">never</property>
+ <child>
+ <object class="GtkListView" id="popup_list">
+ <signal name="activate" handler="row_activated"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/tests/meson.build b/tests/meson.build
index 2be5d96dae..479ae8db9b 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -1,5 +1,6 @@
gtk_tests = [
# testname, optional extra sources
+ ['testdropdown'],
['rendernode'],
['rendernode-create-tests'],
['overlayscroll'],
diff --git a/tests/testdropdown.c b/tests/testdropdown.c
new file mode 100644
index 0000000000..98ca331b57
--- /dev/null
+++ b/tests/testdropdown.c
@@ -0,0 +1,89 @@
+/* simple.c
+ * Copyright (C) 2017 Red Hat, Inc
+ * Author: Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <gtk/gtk.h>
+
+static void
+setup_item (GtkSignalListItemFactory *self,
+ GtkListItem *list_item,
+ gpointer data)
+{
+ GtkWidget *label;
+
+ label = gtk_label_new (NULL);
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ gtk_list_item_set_child (list_item, label);
+}
+
+static void
+bind_item (GtkSignalListItemFactory *factory,
+ GtkListItem *list_item)
+{
+ gpointer item;
+ GtkWidget *label;
+
+ item = gtk_list_item_get_item (list_item);
+ label = gtk_list_item_get_child (list_item);
+
+ gtk_label_set_label (GTK_LABEL (label), pango_font_family_get_name (PANGO_FONT_FAMILY (item)));
+}
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *window, *button, *box, *spin;
+ GtkListItemFactory *factory;
+ GListModel *model;
+
+ gtk_init ();
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), "hello world");
+ gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
+ g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+ box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+
+ button = gtk_drop_down_new ();
+ g_object_set (button, "margin", 10, NULL);
+
+ factory = gtk_signal_list_item_factory_new ();
+ g_signal_connect (factory, "setup", G_CALLBACK (setup_item), NULL);
+ g_signal_connect (factory, "bind", G_CALLBACK (bind_item), NULL);
+ gtk_drop_down_set_factory (GTK_DROP_DOWN (button), factory);
+ g_object_unref (factory);
+
+ model = G_LIST_MODEL (pango_cairo_font_map_get_default ());
+ gtk_drop_down_set_model (GTK_DROP_DOWN (button), model);
+ gtk_drop_down_set_selected (GTK_DROP_DOWN (button), 0);
+
+ gtk_container_add (GTK_CONTAINER (window), box);
+ gtk_container_add (GTK_CONTAINER (box), button);
+
+ spin = gtk_spin_button_new_with_range (-1, g_list_model_get_n_items (G_LIST_MODEL (model)), 1);
+ g_object_set (spin, "margin", 10, NULL);
+ g_object_bind_property (button, "selected", spin, "value", G_BINDING_SYNC_CREATE |
G_BINDING_BIDIRECTIONAL);
+ gtk_container_add (GTK_CONTAINER (box), spin);
+
+ g_object_unref (model);
+
+ gtk_widget_show (window);
+
+ gtk_main ();
+
+ return 0;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]