Compare commits

...

16 Commits

Author SHA1 Message Date
Matthias Clasen
5471365b07 option list: Underline matches
When using search in an option list, show matches in the list.

This commit is just a proof-of-concept, it needs more work to
be utf8-safe.
2015-02-10 06:57:48 -05:00
Matthias Clasen
8e7088342d Fix annotations
The function gtk_label_set_attributes() is also used to
unset attributes, by passing %NULL. Reflect that in the
argument annotations.
2015-02-08 21:02:57 +01:00
Matthias Clasen
77263b925c Factor out hit testing
Factor out hit testing into a separate function.
This will be useful in the following commits.
2015-02-08 21:02:57 +01:00
Matthias Clasen
9fdbb14db5 Fix up docs a bit 2015-01-07 00:22:58 -05:00
Matthias Clasen
7169eee75d Split GtkCombo up into two widgets
Split GtkCombo up into GtkOptionButton and GtkOptionList. The
latter is just the list widget, which can be used standalone.
Add new tests in testoptionlist to demonstrate this.
2015-01-07 00:15:37 -05:00
Matthias Clasen
abae79f170 Implement multi-selection
Add a selection-mode property to GtkCombo, and implement
suitable behaviors. This requires the selected property
to change to an array, instead of a single ID. At the
same time change the terminology from 'active' to 'selected'.
2015-01-07 00:14:53 -05:00
Matthias Clasen
d76873ca23 Add a getter for the item text
This can be used to check for the presence of items as well.
2015-01-07 00:12:19 -05:00
Matthias Clasen
515f6d14e8 Allow changing the 'Custom Entry' label 2015-01-07 00:12:04 -05:00
Matthias Clasen
d4a0807ced Some API changes
Split out setting of sort keys and group keys from gtk_combo_add_item,
and rename the placeholder property to placeholder-text.
2015-01-07 00:12:04 -05:00
Matthias Clasen
1673f92dae Make 'show more' rows same height
This fixes a cosmetic issue with those rows.
2015-01-07 00:12:04 -05:00
Matthias Clasen
e292343440 Properly manage list separators
If we never unset separators, the stick around at the top of the
list during filtering.
2015-01-06 09:21:48 -05:00
Matthias Clasen
a60ad04b03 Update combo test for new API 2014-12-27 01:03:03 -05:00
Matthias Clasen
8a91e0b987 Support grouping in the new combo box 2014-12-27 01:03:02 -05:00
Matthias Clasen
23887ca9d3 Document GtkCombo
Add documentation for GtkCombo.
2014-12-27 01:01:21 -05:00
Matthias Clasen
4cf965625c Add a test for the new combo box
Add a some simple test app for GtkCombo.
2014-12-27 01:01:21 -05:00
Matthias Clasen
2662457ab4 A new combo box
Add a new, simple combo box. The feature set of this is similar
to GtkComboBoxText, but it is using a popover and supports search.

https://raw.githubusercontent.com/gnome-design-team/gnome-mockups/master/theming/widgets/combobox-replacements.png
2014-12-27 01:01:20 -05:00
21 changed files with 3353 additions and 5 deletions

View File

@@ -193,6 +193,8 @@
<xi:include href="xml/gtkradiotoolbutton.xml" />
<xi:include href="xml/gtkpopover.xml" />
<xi:include href="xml/gtkpopovermenu.xml" />
<xi:include href="xml/gtkoptionlist.xml" />
<xi:include href="xml/gtkoptionbutton.xml" />
</chapter>
<chapter id="SelectorWidgets">

View File

@@ -977,6 +977,59 @@ GtkComboBoxTextPrivate
gtk_combo_box_text_get_type
</SECTION>
<SECTION>
<FILE>gtkoptionlist</FILE>
<TITLE>GtkOptionList</TITLE>
GtkOptionList
gtk_option_list_new
gtk_option_list_add_item
gtk_option_list_remove_item
gtk_option_list_item_get_text
gtk_option_list_item_set_sort_key
gtk_option_list_item_set_group_key
gtk_option_list_add_group
gtk_option_list_get_selected_items
gtk_option_list_select_item
gtk_option_list_unselect_item
gtk_option_list_get_allow_custom
gtk_option_list_set_allow_custom
gtk_option_list_get_custom_text
gtk_option_list_set_custom_text
gtk_option_list_handle_key_event
<SUBSECTION Standard>
GTK_TYPE_OPTION_LIST
GTK_OPTION_LIST
GTK_IS_OPTION_LIST
GTK_OPTION_LIST_CLASS
GTK_IS_OPTION_LIST_CLASS
GTK_OPTION_LIST_GET_CLASS
<SUBSECTION Private>
gtk_option_list_get_type
</SECTION>
<SECTION>
<FILE>gtkoptionbutton</FILE>
<TITLE>GtkOptionButton</TITLE>
GtkOptionButton
gtk_option_button_new
gtk_option_button_get_option_list
gtk_option_button_get_placeholder_text
gtk_option_button_set_placeholder_text
<SUBSECTION Standard>
GTK_TYPE_OPTION_BUTTON
GTK_OPTION_BUTTON
GTK_IS_OPTION_BUTTON
GTK_OPTION_BUTTON_CLASS
GTK_IS_OPTION_BUTTON_CLASS
GTK_OPTION_BUTTON_GET_CLASS
<SUBSECTION Private>
gtk_option_button_get_type
</SECTION>
<SECTION>
<FILE>gtkcontainer</FILE>
<TITLE>GtkContainer</TITLE>

View File

@@ -131,6 +131,8 @@ gtk_mount_operation_get_type
gtk_notebook_get_type
gtk_numerable_icon_get_type
gtk_offscreen_window_get_type
gtk_option_button_get_type
gtk_option_list_get_type
gtk_orientable_get_type
gtk_overlay_get_type
gtk_page_setup_get_type

View File

@@ -228,6 +228,8 @@ gtk_public_h_sources = \
gtkmountoperation.h \
gtknotebook.h \
gtkoffscreenwindow.h \
gtkoptionbutton.h \
gtkoptionlist.h \
gtkorientable.h \
gtkoverlay.h \
gtkpagesetup.h \
@@ -724,6 +726,8 @@ gtk_base_c_sources = \
gtkmountoperation.c \
gtknotebook.c \
gtkoffscreenwindow.c \
gtkoptionbutton.c \
gtkoptionlist.c \
gtkorientable.c \
gtkoverlay.c \
gtkpagesetup.c \
@@ -1047,7 +1051,10 @@ templates = \
ui/gtkassistant.ui \
ui/gtkcolorchooserdialog.ui \
ui/gtkcoloreditor.ui \
ui/gtkdialog.ui \
ui/gtkoptionlist.ui \
ui/gtkoptionlistrow.ui \
ui/gtkoptionlisttab.ui \
ui/gtkdialog.ui \
ui/gtkfilechooserbutton.ui \
ui/gtkfilechooserwidget.ui \
ui/gtkfilechooserdialog.ui \
@@ -1056,7 +1063,8 @@ templates = \
ui/gtkfontchooserwidget.ui \
ui/gtkinfobar.ui \
ui/gtklockbutton.ui \
ui/gtkmessagedialog.ui \
ui/gtkmessagedialog.ui \
ui/gtkoptionbutton.ui \
ui/gtkpagesetupunixdialog.ui \
ui/gtkpathbar.ui \
ui/gtkprintunixdialog.ui \

View File

@@ -146,6 +146,8 @@
#include <gtk/gtkmountoperation.h>
#include <gtk/gtknotebook.h>
#include <gtk/gtkoffscreenwindow.h>
#include <gtk/gtkoptionbutton.h>
#include <gtk/gtkoptionlist.h>
#include <gtk/gtkorientable.h>
#include <gtk/gtkoverlay.h>
#include <gtk/gtkpagesetup.h>

View File

@@ -2232,10 +2232,10 @@ gtk_label_set_text (GtkLabel *label,
/**
* gtk_label_set_attributes:
* @label: a #GtkLabel
* @attrs: a #PangoAttrList
*
* @attrs: (allow-none): a #PangoAttrList, or %NULL
*
* Sets a #PangoAttrList; the attributes in the list are applied to the
* label text.
* label text.
*
* The attributes set with this function will be applied
* and merged with any other attributes previously effected by way

284
gtk/gtkoptionbutton.c Normal file
View File

@@ -0,0 +1,284 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2015 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 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/>.
*/
#include "config.h"
#include <string.h>
#include "gtkoptionbutton.h"
#include "gtkoptionlist.h"
#include "gtktogglebutton.h"
#include "gtkbox.h"
#include "gtklabel.h"
#include "gtkintl.h"
#include "gtkprivate.h"
enum {
PROP_PLACEHOLDER_TEXT = 1
};
struct _GtkOptionButton
{
GtkBin parent;
GtkWidget *label;
GtkWidget *popover;
GtkWidget *list;
gchar *placeholder_text;
};
struct _GtkOptionButtonClass
{
GtkBinClass parent_class;
};
G_DEFINE_TYPE (GtkOptionButton, gtk_option_button, GTK_TYPE_BIN)
static void
gtk_option_button_init (GtkOptionButton *combo)
{
gtk_widget_init_template (GTK_WIDGET (combo));
}
static void
gtk_option_button_finalize (GObject *object)
{
GtkOptionButton *button = GTK_OPTION_BUTTON (object);
g_free (button->placeholder_text);
G_OBJECT_CLASS (gtk_option_button_parent_class)->finalize (object);
}
static void
gtk_option_button_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkOptionButton *button = (GtkOptionButton *)object;
switch (prop_id)
{
case PROP_PLACEHOLDER_TEXT:
gtk_option_button_set_placeholder_text (button, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_option_button_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkOptionButton *button = (GtkOptionButton *)object;
switch (prop_id)
{
case PROP_PLACEHOLDER_TEXT:
g_value_set_string (value, gtk_option_button_get_placeholder_text (button));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static gboolean popover_key_press (GtkWidget *widget,
GdkEvent *event,
GtkOptionButton *button);
static gboolean button_key_press (GtkWidget *widget,
GdkEvent *event,
GtkOptionButton *button);
static void selected_changed (GObject *list,
GParamSpec *pspec,
GtkOptionButton *button);
static void
gtk_option_button_class_init (GtkOptionButtonClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->finalize = gtk_option_button_finalize;
object_class->set_property = gtk_option_button_set_property;
object_class->get_property = gtk_option_button_get_property;
/**
* GtkOptionButton:placeholder-text:
*
* The text that is displayed if no item is selected.
*/
g_object_class_install_property (object_class,
PROP_PLACEHOLDER_TEXT,
g_param_spec_string ("placeholder-text",
P_("Placeholder text"),
P_("Text to show when no item is selected"),
NULL,
GTK_PARAM_READWRITE));
gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/ui/gtkoptionbutton.ui");
gtk_widget_class_bind_template_child (widget_class, GtkOptionButton, label);
gtk_widget_class_bind_template_child (widget_class, GtkOptionButton, popover);
gtk_widget_class_bind_template_child_internal (widget_class, GtkOptionButton, list);
gtk_widget_class_bind_template_callback (widget_class, popover_key_press);
gtk_widget_class_bind_template_callback (widget_class, button_key_press);
gtk_widget_class_bind_template_callback (widget_class, selected_changed);
}
/***/
static gboolean
popover_key_press (GtkWidget *widget,
GdkEvent *event,
GtkOptionButton *button)
{
return gtk_option_list_handle_key_event (GTK_OPTION_LIST (button->list), event);
}
static gboolean
button_key_press (GtkWidget *widget,
GdkEvent *event,
GtkOptionButton *button)
{
gboolean handled;
handled = gtk_option_list_handle_key_event (GTK_OPTION_LIST (button->list), event);
if (handled == GDK_EVENT_STOP)
gtk_widget_show (button->popover);
return handled;
}
static void
selected_changed (GObject *list,
GParamSpec *pspec,
GtkOptionButton *button)
{
const gchar **selected;
selected = gtk_option_list_get_selected_items (GTK_OPTION_LIST (button->list));
if (selected[0] == NULL)
{
gtk_label_set_text (GTK_LABEL (button->label), button->placeholder_text);
}
else
{
GString *str;
const gchar *text;
gint i;
str = g_string_new ("");
for (i = 0; selected[i]; i++)
{
if (i > 0)
g_string_append (str, ", ");
text = gtk_option_list_item_get_text (GTK_OPTION_LIST (button->list), selected[i]);
g_string_append (str, text);
}
gtk_label_set_text (GTK_LABEL (button->label), str->str);
g_string_free (str, TRUE);
}
}
/***/
/**
* gtk_option_button_new:
*
* Creates a new #GtkOptionButton.
*
* Returns: A new #GtkOptionButton
*
* Since: 3.16
*/
GtkWidget *
gtk_option_button_new (void)
{
return g_object_new (GTK_TYPE_OPTION_BUTTON, NULL);
}
GtkWidget *
gtk_option_button_get_option_list (GtkOptionButton *button)
{
g_return_val_if_fail (GTK_IS_OPTION_BUTTON (button), NULL);
return button->list;
}
/**
* gtk_option_button_set_placeholder_text:
* @button: a #GtkOptionButton
* @text: the placeholder text to use
*
* Sets the placeholder text that is displayed in the button
* if no item is currently selected.
*
* Since: 3.16
*/
void
gtk_option_button_set_placeholder_text (GtkOptionButton *button,
const gchar *text)
{
g_return_if_fail (GTK_IS_OPTION_BUTTON (button));
g_return_if_fail (text != NULL);
g_free (button->placeholder_text);
button->placeholder_text = g_strdup (text);
if (button->label != NULL && button->list != NULL)
{
const gchar **selected;
selected = gtk_option_list_get_selected_items (GTK_OPTION_LIST (button->list));
if (selected[0] == NULL)
gtk_label_set_text (GTK_LABEL (button->label), button->placeholder_text);
}
g_object_notify (G_OBJECT (button), "placeholder-text");
}
/**
* gtk_option_button_get_placeholder_text:
* @button: a #GtkOptionButton
*
* Gets the placeholder text that is displayed in the combo
* if no item is currently selected.
*
* Returns: (transfer none): the placeholder text
*
* Since: 3.16
*/
const gchar *
gtk_option_button_get_placeholder_text (GtkOptionButton *button)
{
g_return_val_if_fail (GTK_IS_OPTION_BUTTON (button), NULL);
return button->placeholder_text;
}

58
gtk/gtkoptionbutton.h Normal file
View File

@@ -0,0 +1,58 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2015 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/>.
*/
#ifndef __GTK_OPTION_BUTTON_H__
#define __GTK_OPTION_BUTTON_H__
#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkwidget.h>
G_BEGIN_DECLS
#define GTK_TYPE_OPTION_BUTTON (gtk_option_button_get_type ())
#define GTK_OPTION_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_OPTION_BUTTON, GtkOptionButton))
#define GTK_OPTION_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_OPTION_BUTTON, GtkOptionButtonClass))
#define GTK_IS_OPTION_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_OPTION_BUTTON))
#define GTK_IS_OPTION_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_OPTION_BUTTON))
#define GTK_OPTION_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_OPTION_BUTTON, GtkOptionButtonClass))
typedef struct _GtkOptionButton GtkOptionButton;
typedef struct _GtkOptionButtonClass GtkOptionButtonClass;
GDK_AVAILABLE_IN_3_16
GType gtk_option_button_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_16
GtkWidget * gtk_option_button_new (void);
GDK_AVAILABLE_IN_3_16
GtkWidget * gtk_option_button_get_option_list (GtkOptionButton *button);
GDK_AVAILABLE_IN_3_16
void gtk_option_button_set_placeholder_text (GtkOptionButton *button,
const gchar *text);
GDK_AVAILABLE_IN_3_16
const gchar * gtk_option_button_get_placeholder_text (GtkOptionButton *button);
G_END_DECLS
#endif /* __GTK_OPTION_BUTTON_H__ */

2054
gtk/gtkoptionlist.c Normal file

File diff suppressed because it is too large Load Diff

107
gtk/gtkoptionlist.h Normal file
View File

@@ -0,0 +1,107 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2014 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/>.
*/
#ifndef __GTK_OPTION_LIST_H__
#define __GTK_OPTION_LIST_H__
#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkwidget.h>
G_BEGIN_DECLS
#define GTK_TYPE_OPTION_LIST (gtk_option_list_get_type ())
#define GTK_OPTION_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_OPTION_LIST, GtkOptionList))
#define GTK_OPTION_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_OPTION_LIST, GtkOptionListClass))
#define GTK_IS_OPTION_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_OPTION_LIST))
#define GTK_IS_OPTION_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_OPTION_LIST))
#define GTK_OPTION_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_OPTION_LIST, GtkOptionListClass))
typedef struct _GtkOptionList GtkOptionList;
typedef struct _GtkOptionListClass GtkOptionListClass;
GDK_AVAILABLE_IN_3_16
GType gtk_option_list_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_16
GtkWidget * gtk_option_list_new (void);
GDK_AVAILABLE_IN_3_16
const gchar ** gtk_option_list_get_selected_items (GtkOptionList *list);
GDK_AVAILABLE_IN_3_16
void gtk_option_list_select_item (GtkOptionList *list,
const gchar *id);
GDK_AVAILABLE_IN_3_16
void gtk_option_list_unselect_item (GtkOptionList *list,
const gchar *id);
GDK_AVAILABLE_IN_3_16
void gtk_option_list_add_item (GtkOptionList *list,
const gchar *id,
const gchar *text);
GDK_AVAILABLE_IN_3_16
void gtk_option_list_remove_item (GtkOptionList *list,
const gchar *id);
GDK_AVAILABLE_IN_3_16
const gchar * gtk_option_list_item_get_text (GtkOptionList *list,
const gchar *id);
GDK_AVAILABLE_IN_3_16
void gtk_option_list_item_set_sort_key (GtkOptionList *list,
const gchar *id,
const gchar *sort);
GDK_AVAILABLE_IN_3_16
void gtk_option_list_item_set_group_key (GtkOptionList *list,
const gchar *id,
const gchar *group);
GDK_AVAILABLE_IN_3_16
void gtk_option_list_add_group (GtkOptionList *list,
const gchar *group,
const gchar *text,
const gchar *sort);
GDK_AVAILABLE_IN_3_16
void gtk_option_list_set_allow_custom (GtkOptionList *list,
gboolean allow);
GDK_AVAILABLE_IN_3_16
gboolean gtk_option_list_get_allow_custom (GtkOptionList *list);
GDK_AVAILABLE_IN_3_16
void gtk_option_list_set_custom_text (GtkOptionList *list,
const gchar *text);
GDK_AVAILABLE_IN_3_16
const gchar * gtk_option_list_get_custom_text (GtkOptionList *list);
GDK_AVAILABLE_IN_3_16
void gtk_option_list_set_selection_mode (GtkOptionList *list,
GtkSelectionMode mode);
GDK_AVAILABLE_IN_3_16
GtkSelectionMode gtk_option_list_get_selection_mode (GtkOptionList *list);
GDK_AVAILABLE_IN_3_16
gboolean gtk_option_list_handle_key_event (GtkOptionList *list,
GdkEvent *event);
G_END_DECLS
#endif /* __GTK_OPTION_LIST_H__ */

57
gtk/ui/gtkoptionbutton.ui Normal file
View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="gtk30">
<!-- interface-requires gtk+ 3.10 -->
<template class="GtkOptionButton" parent="GtkBin">
<child>
<object class="GtkToggleButton" id="button">
<property name="visible">True</property>
<signal name="key-press-event" handler="button_key_press"/>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child type="center">
<object class="GtkLabel" id="label">
<property name="visible">True</property>
<property name="ellipsize">end</property>
</object>
</child>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="icon-name">pan-down-symbolic</property>
<property name="icon-size">1</property>
</object>
<packing>
<property name="pack-type">end</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</template>
<object class="GtkPopover" id="popover">
<property name="relative-to">button</property>
<property name="position">bottom</property>
<property name="modal">True</property>
<property name="visible" bind-source="button" bind-property="active" bind-flags="bidirectional"/>
<signal name="key-press-event" handler="popover_key_press"/>
<child>
<object class="GtkOptionList" id="list">
<property name="visible">True</property>
<signal name="notify::selected" handler="selected_changed"/>
</object>
</child>
</object>
<object class="GtkSizeGroup">
<property name="mode">horizontal</property>
<widgets>
<widget name="button"/>
<widget name="list"/>
</widgets>
</object>
</interface>

View File

155
gtk/ui/gtkoptionlist.ui Normal file
View File

@@ -0,0 +1,155 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="gtk30">
<!-- interface-requires gtk+ 3.10 -->
<template class="GtkOptionList" parent="GtkBin">
<property name="custom-text" translatable="yes">Custom Entry</property>
<signal name="unmap" handler="reset" swapped="yes"/>
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="vhomogeneous">False</property>
<property name="transition-type">slide-left-right</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="margin">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkRevealer" id="search_revealer">
<property name="transition-type">slide-down</property>
<child>
<object class="GtkSearchEntry" id="search_entry">
<property name="visible">True</property>
<property name="width-chars">15</property>
<property name="max-width-chars">15</property>
<signal name="search-changed" handler="search_changed"/>
<signal name="grab-focus" handler="search_focus_grabbed" after="yes"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolled_window">
<property name="visible">True</property>
<property name="shadow-type">in</property>
<property name="hscrollbar-policy">never</property>
<property name="vscrollbar-policy">never</property>
<child>
<object class="GtkListBox" id="list">
<property name="visible">True</property>
<property name="selection-mode">none</property>
<property name="width-request">100</property>
<signal name="row-activated" handler="list_row_activated"/>
<child type="placeholder">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="margin">6</property>
<property name="label" translatable="yes">No match</property>
</object>
</child>
<child>
<object class="GtkListBoxRow" id="show_more">
<property name="no-show-all">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="margin">6</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="icon-name">view-more-symbolic</property>
<property name="icon-size">1</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkOptionListRow" id="add_custom">
<property name="no-show-all">True</property>
<property name="group">custom</property>
<property name="text" bind-source="GtkOptionList" bind-property="custom-text" bind-flags="sync-create"/>
<property name="visible" bind-source="GtkOptionList" bind-property="allow-custom" bind-flags="sync-create"/>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="name">list</property>
</packing>
</child>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="margin">10</property>
<child>
<object class="GtkListBox" id="custom">
<property name="visible">True</property>
<property name="selection-mode">none</property>
<property name="width-request">100</property>
<signal name="row-activated" handler="list_row_activated"/>
<child>
<object class="GtkOptionListRow" id="back_to_list">
<property name="group">list</property>
<property name="text" bind-source="GtkOptionList" bind-property="custom-text" bind-flags="sync-create"/>
<property name="inverted">True</property>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="visible">True</property>
<property name="activatable">False</property>
<child>
<object class="GtkEntry" id="custom_entry">
<property name="visible">True</property>
<property name="margin">6</property>
<signal name="activate" handler="custom_entry_done"/>
<signal name="notify::text" handler="custom_entry_changed"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="visible">True</property>
<property name="activatable">False</property>
<child>
<object class="GtkButton" id="custom_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="margin">6</property>
<property name="label" translatable="yes">Done</property>
<signal name="clicked" handler="custom_entry_done"/>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="name">custom</property>
</packing>
</child>
</object>
</child>
</template>
<object class="GtkSizeGroup">
<property name="mode">horizontal</property>
<property name="ignore-hidden">False</property>
<widgets>
<widget name="search_entry"/>
<widget name="scrolled_window"/>
</widgets>
</object>
<object class="GtkSizeGroup">
<property name="mode">vertical</property>
<property name="ignore-hidden">False</property>
<widgets>
<widget name="show_more"/>
<widget name="add_custom"/>
</widgets>
</object>
</interface>

View File

@@ -0,0 +1,3 @@
N_("Custom Entry");
N_("No match");
N_("Done");

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="gtk30">
<!-- interface-requires gtk+ 3.10 -->
<template class="GtkOptionListRow" parent="GtkListBoxRow">
<property name="visible">True</property>
<child>
<object class="GtkBox" id="box">
<property name="visible">True</property>
<property name="orientation">horizontal</property>
<property name="margin">6</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel" id="label">
<property name="visible">True</property>
<property name="label" bind-source="GtkOptionListRow" bind-property="text"/>
</object>
</child>
<child>
<object class="GtkImage" id="check">
<property name="no-show-all">True</property>
<property name="icon-name">object-select-symbolic</property>
<property name="icon-size">1</property>
<property name="visible" bind-source="GtkOptionListRow" bind-property="active"/>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="gtk30">
<!-- interface-requires gtk+ 3.10 -->
<object class="GtkFrame" id="tab">
<property name="visible">True</property>
<property name="margin">10</property>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="hscrollbar-policy">never</property>
<property name="vscrollbar-policy">never</property>
<child>
<object class="GtkListBox" id="list">
<property name="visible">True</property>
<property name="selection-mode">none</property>
<child>
<object class="GtkOptionListRow" id="header">
<property name="group">list</property>
<property name="inverted">True</property>
</object>
</child>
<child>
<object class="GtkListBoxRow" id="show_more">
<property name="no-show-all">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="margin">6</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="icon-name">view-more-symbolic</property>
<property name="icon-size">1</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<object class="GtkSizeGroup">
<property name="mode">vertical</property>
<property name="ignore-hidden">False</property>
<widgets>
<widget name="header"/>
<widget name="show_more"/>
</widgets>
</object>
</interface>

View File

View File

@@ -340,6 +340,9 @@ gtk/ui/gtkapplication-quartz.ui.h
gtk/ui/gtkassistant.ui.h
gtk/ui/gtkcolorchooserdialog.ui.h
gtk/ui/gtkcoloreditor.ui.h
gtk/ui/gtkoptionlist.ui.h
gtk/ui/gtkoptionlistrow.ui.h
gtk/ui/gtkoptionlisttab.ui.h
gtk/ui/gtkdialog.ui.h
gtk/ui/gtkfilechooserbutton.ui.h
gtk/ui/gtkfilechooserdialog.ui.h
@@ -350,6 +353,7 @@ gtk/ui/gtkfontchooserwidget.ui.h
gtk/ui/gtkinfobar.ui.h
gtk/ui/gtklockbutton.ui.h
gtk/ui/gtkmessagedialog.ui.h
gtk/ui/gtkoptionbutton.ui.h
gtk/ui/gtkpagesetupunixdialog.ui.h
gtk/ui/gtkpathbar.ui.h
gtk/ui/gtkprintunixdialog.ui.h

View File

@@ -97,6 +97,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \
testnouiprint \
testoffscreen \
testoffscreenwindow \
testoptionlist \
testorientable \
testoverlay \
testoverlaystyleclass \
@@ -239,6 +240,7 @@ testnouiprint_DEPENDENCIES = $(TEST_DEPS)
testnumerableicon_DEPENDENCIES = $(TEST_DEPS)
testoffscreen_DEPENDENCIES = $(TEST_DEPS)
testoffscreenwindow_DEPENDENCIES = $(TEST_DEPS)
testoptionlist_DEPENDENCIES = $(TEST_DEPS)
testappchooser_DEPENDENCIES = $(TEST_DEPS)
testappchooserbutton_DEPENDENCIES = $(TEST_DEPS)
testorientable_DEPENDENCIES = $(TEST_DEPS)

478
tests/testoptionlist.c Normal file
View File

@@ -0,0 +1,478 @@
#include <gtk/gtk.h>
static void
add_one (GtkButton *button, gpointer data)
{
static gint count = 3;
gchar *text;
gchar *sort;
gchar *id;
count++;
id = g_strdup_printf ("%d", count);
text = g_strdup_printf ("Value %d", count);
sort = g_strdup_printf ("Value %03d", count);
gtk_option_list_add_item (GTK_OPTION_LIST (data), id, text);
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (data), id, sort);
gtk_option_list_select_item (GTK_OPTION_LIST (data), id);
g_free (id);
g_free (text);
g_free (sort);
}
static void
remove_selected (GtkButton *button, gpointer data)
{
const gchar **ids;
ids = gtk_option_list_get_selected_items (GTK_OPTION_LIST (data));
if (ids[0] != NULL)
gtk_option_list_remove_item (GTK_OPTION_LIST (data), ids[0]);
}
static void
select_a (GtkButton *button, gpointer data)
{
gtk_option_list_select_item (GTK_OPTION_LIST (data), "1");
}
static void
unselect_a (GtkButton *button, gpointer data)
{
gtk_option_list_unselect_item (GTK_OPTION_LIST (data), "1");
}
const gchar data[] =
"<interface>"
" <object class='GtkOptionButton' id='button'>"
" <property name='visible'>True</property>"
" <property name='halign'>center</property>"
" <property name='placeholder-text'>None</property>"
" <child internal-child='list'>"
" <object class='GtkOptionList'>"
" <property name='custom-text'>Other</property>"
" <property name='selection-mode'>multiple</property>"
" <property name='selected'>1</property>"
" <items>"
" <item translatable='yes' id='1' sort='Value 001'>Value 1</item>"
" <item translatable='yes' id='2' sort='Value 002'>Value 2</item>"
" <item translatable='yes' id='3' sort='Value 003'>Value 3</item>"
" <item translatable='yes' id='4' sort='Value 004' group='1'>Value 4</item>"
" <item translatable='yes' id='5' sort='Value 005' group='1'>Value 5</item>"
" </items>"
" <groups>"
" <group id='1' translatable='yes'>Group 1</group>"
" </groups>"
" </object>"
" </child>"
" </object>"
"</interface>";
static gboolean
selected_to_bool (GBinding *binding,
const GValue *from_value,
GValue *to_value,
gpointer data)
{
const gchar * const *ids;
ids = g_value_get_boxed (from_value);
g_value_set_boolean (to_value, ids[0] != NULL);
return TRUE;
}
static gboolean
selected_to_string (GBinding *binding,
const GValue *from_value,
GValue *to_value,
gpointer data)
{
gchar **ids;
gchar *text;
ids = g_value_get_boxed (from_value);
text = g_strjoinv (", ", ids);
g_value_set_string (to_value, text);
g_free (text);
return TRUE;
}
static gboolean
selected_to_text (GBinding *binding,
const GValue *from_value,
GValue *to_value,
gpointer data)
{
const gchar * const *ids;
GString *str;
gint i;
str = g_string_new ("");
ids = g_value_get_boxed (from_value);
for (i = 0; ids[i]; i++)
{
const gchar *text;
if (i > 0)
g_string_append (str, ", ");
text = gtk_option_list_item_get_text (GTK_OPTION_LIST (g_binding_get_source (binding)), ids[i]);
g_string_append (str, text);
}
g_value_set_string (to_value, str->str);
g_string_free (str, TRUE);
return TRUE;
}
static void
list_header_func (GtkListBoxRow *row,
GtkListBoxRow *before,
gpointer data)
{
if (before != NULL)
{
if (gtk_list_box_row_get_header (row) == NULL)
gtk_list_box_row_set_header (row, gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
}
}
static void
selected_changed (GObject *olist,
GParamSpec *pspec,
gpointer data)
{
GtkWidget *label = data;
const gchar **ids;
gchar *text;
ids = gtk_option_list_get_selected_items (GTK_OPTION_LIST (olist));
text = g_strdup_printf ("Row 2: %s", gtk_option_list_item_get_text (GTK_OPTION_LIST (olist), ids[0]));
gtk_label_set_label (GTK_LABEL (label), text);
g_free (text);
}
static void
row_activated (GtkListBox *list,
GtkListBoxRow *row,
gpointer data)
{
GtkWidget *popover = data;
if (GTK_WIDGET (row) == gtk_popover_get_relative_to (GTK_POPOVER (popover)))
gtk_widget_show (popover);
}
static gboolean
row_key_press (GtkWidget *row,
GdkEvent *event,
gpointer data)
{
if (gtk_option_list_handle_key_event (GTK_OPTION_LIST (data), event) == GDK_EVENT_STOP)
{
gtk_widget_show (gtk_widget_get_parent (GTK_WIDGET (data)));
return GDK_EVENT_STOP;
}
return GDK_EVENT_PROPAGATE;
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *hbox;
GtkWidget *box;
GtkWidget *box2;
GtkWidget *button;
GtkWidget *olist;
GtkWidget *label;
GtkWidget *frame;
GtkWidget *list;
GtkWidget *row;
GtkWidget *popover;
GtkBuilder *builder;
gtk_init (NULL, NULL);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 400, 600);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
g_object_set (hbox, "margin", 10, NULL);
gtk_container_add (GTK_CONTAINER (window), hbox);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
gtk_container_add (GTK_CONTAINER (hbox), box);
label = gtk_label_new ("Simple");
gtk_widget_set_margin_start (label, 10);
gtk_container_add (GTK_CONTAINER (box), label);
button = gtk_option_button_new ();
gtk_widget_set_halign (button, GTK_ALIGN_CENTER);
gtk_container_add (GTK_CONTAINER (box), button);
gtk_option_button_set_placeholder_text (GTK_OPTION_BUTTON (button), "None");
olist = gtk_option_button_get_option_list (GTK_OPTION_BUTTON (button));
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "1", "Value 1");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "2", "Value 2");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "3", "Value 3");
gtk_option_list_select_item (GTK_OPTION_LIST (olist), "1");
gtk_container_add (GTK_CONTAINER (box), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
label = gtk_label_new ("With search and collapsing");
gtk_widget_set_margin_start (label, 10);
gtk_container_add (GTK_CONTAINER (box), label);
button = gtk_option_button_new ();
gtk_widget_set_halign (button, GTK_ALIGN_CENTER);
gtk_container_add (GTK_CONTAINER (box), button);
gtk_option_button_set_placeholder_text (GTK_OPTION_BUTTON (button), "None");
olist = gtk_option_button_get_option_list (GTK_OPTION_BUTTON (button));
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "1", "Value 1");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "2", "Value 2");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "3", "Value 3");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "4", "Value 4");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "5", "Value 5");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "6", "Value 6");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "7", "Value 7");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "8", "Value 8");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "9", "Value 9");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "10", "Value 10");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "11", "Value 11");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "1", "Value 01");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "2", "Value 02");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "3", "Value 03");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "4", "Value 04");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "5", "Value 05");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "6", "Value 06");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "7", "Value 07");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "8", "Value 08");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "9", "Value 09");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "10", "Value 10");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "11", "Value 11");
gtk_option_list_select_item (GTK_OPTION_LIST (olist), "1");
gtk_container_add (GTK_CONTAINER (box), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
label = gtk_label_new ("With free-form text");
gtk_widget_set_margin_start (label, 10);
gtk_container_add (GTK_CONTAINER (box), label);
olist = gtk_option_button_new ();
gtk_widget_set_halign (olist, GTK_ALIGN_CENTER);
gtk_container_add (GTK_CONTAINER (box), olist);
olist = gtk_option_button_get_option_list (GTK_OPTION_BUTTON (olist));
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "1", "Value 1");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "2", "Value 2");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "3", "Value 3");
gtk_option_list_set_allow_custom (GTK_OPTION_LIST (olist), TRUE);
gtk_option_list_select_item (GTK_OPTION_LIST (olist), "1");
gtk_container_add (GTK_CONTAINER (box), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
label = gtk_label_new ("With grouping");
gtk_widget_set_margin_start (label, 10);
gtk_container_add (GTK_CONTAINER (box), label);
olist = gtk_option_button_new ();
gtk_widget_set_halign (olist, GTK_ALIGN_CENTER);
gtk_container_add (GTK_CONTAINER (box), olist);
olist = gtk_option_button_get_option_list (GTK_OPTION_BUTTON (olist));
gtk_option_list_add_group (GTK_OPTION_LIST (olist), "Group 3", "G 3", "Group 3");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "1", "Value 1");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "2", "Value 2");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "3", "Value 3");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "4", "Value 4");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "5", "Value 5");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "6", "Value 6");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "7", "Value 7");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "8", "Value 8");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "9", "Value 9");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "10", "Value 10");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "11", "Value 11");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "12", "Value 12");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "13", "Value 13");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "14", "Value 14");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "15", "Value 15");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "16", "Value 16");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "17", "Value 17");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "18", "Value 18");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "1", "Value 01");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "2", "Value 02");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "3", "Value 03");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "4", "Value 04");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "5", "Value 05");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "6", "Value 06");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "7", "Value 07");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "8", "Value 08");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "9", "Value 09");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "10", "Value 10");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "11", "Value 11");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "12", "Value 12");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "13", "Value 13");
gtk_option_list_item_set_sort_key (GTK_OPTION_LIST (olist), "14", "Value 14");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "1", "Group 1");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "2", "Group 1");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "3", "Group 1");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "4", "Group 1");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "5", "Group 2");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "6", "Group 2");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "7", "Group 2");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "8", "Group 2");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "9", "Group 3");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "10", "Group 3");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "11", "Group 3");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "12", "Group 3");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "13", "Group 3");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "14", "Group 3");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "15", "Group 3");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "16", "Group 3");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "17", "Group 3");
gtk_option_list_item_set_group_key (GTK_OPTION_LIST (olist), "18", "Group 3");
gtk_option_list_select_item (GTK_OPTION_LIST (olist), "7");
button = gtk_button_new_with_label ("Remove selected");
gtk_widget_set_halign (button, GTK_ALIGN_CENTER);
g_signal_connect (button, "clicked", G_CALLBACK (remove_selected), olist);
gtk_container_add (GTK_CONTAINER (box), button);
g_object_bind_property_full (olist, "selected",
button, "sensitive",
G_BINDING_SYNC_CREATE,
selected_to_bool, NULL, NULL, NULL);
gtk_container_add (GTK_CONTAINER (box), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
label = gtk_label_new ("Builder");
gtk_widget_set_margin_start (label, 10);
gtk_container_add (GTK_CONTAINER (box), label);
builder = gtk_builder_new_from_string (data, -1);
button = (GtkWidget *)gtk_builder_get_object (builder, "button");
gtk_widget_set_halign (button, GTK_ALIGN_CENTER);
gtk_container_add (GTK_CONTAINER (box), button);
olist = gtk_option_button_get_option_list (GTK_OPTION_BUTTON (button));
g_object_unref (builder);
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_widget_set_halign (box2, GTK_ALIGN_CENTER);
gtk_container_add (GTK_CONTAINER (box), box2);
button = gtk_button_new_with_label ("Add value");
g_signal_connect (button, "clicked", G_CALLBACK (add_one), olist);
gtk_container_add (GTK_CONTAINER (box2), button);
button = gtk_button_new_with_label ("Select 1");
g_signal_connect (button, "clicked", G_CALLBACK (select_a), olist);
gtk_container_add (GTK_CONTAINER (box2), button);
button = gtk_button_new_with_label ("Unselect 1");
g_signal_connect (button, "clicked", G_CALLBACK (unselect_a), olist);
gtk_container_add (GTK_CONTAINER (box2), button);
button = gtk_button_new_with_label ("Remove selected");
g_signal_connect (button, "clicked", G_CALLBACK (remove_selected), olist);
gtk_container_add (GTK_CONTAINER (box2), button);
g_object_bind_property_full (olist, "selected",
button, "sensitive",
G_BINDING_SYNC_CREATE,
selected_to_bool, NULL, NULL, NULL);
button = gtk_check_button_new_with_label ("Allow custom");
gtk_widget_set_halign (button, GTK_ALIGN_CENTER);
g_object_bind_property (button, "active",
olist, "allow-custom",
0);
gtk_container_add (GTK_CONTAINER (box), button);
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_widget_set_halign (box2, GTK_ALIGN_CENTER);
gtk_container_add (GTK_CONTAINER (box), box2);
label = gtk_label_new ("Active:");
gtk_container_add (GTK_CONTAINER (box2), label);
label = gtk_label_new ("");
gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
g_object_bind_property_full (olist, "selected",
label, "label",
G_BINDING_SYNC_CREATE,
selected_to_string, NULL, NULL, NULL);
gtk_container_add (GTK_CONTAINER (box2), label);
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_widget_set_halign (box2, GTK_ALIGN_CENTER);
gtk_container_add (GTK_CONTAINER (box), box2);
label = gtk_label_new ("Label:");
gtk_container_add (GTK_CONTAINER (box2), label);
label = gtk_label_new ("");
gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
g_object_bind_property_full (olist, "selected",
label, "label",
G_BINDING_SYNC_CREATE,
selected_to_text, NULL, NULL, NULL);
gtk_container_add (GTK_CONTAINER (box2), label);
gtk_container_add (GTK_CONTAINER (hbox), gtk_separator_new (GTK_ORIENTATION_VERTICAL));
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
gtk_container_add (GTK_CONTAINER (hbox), box);
label = gtk_label_new ("Embedded");
gtk_widget_set_margin_start (label, 10);
gtk_container_add (GTK_CONTAINER (box), label);
olist = gtk_option_list_new ();
gtk_widget_set_halign (olist, GTK_ALIGN_CENTER);
gtk_container_add (GTK_CONTAINER (box), olist);
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "1", "Value 1");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "2", "Value 2");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "3", "Value 3");
gtk_option_list_set_allow_custom (GTK_OPTION_LIST (olist), TRUE);
gtk_option_list_select_item (GTK_OPTION_LIST (olist), "1");
gtk_container_add (GTK_CONTAINER (box), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
label = gtk_label_new ("On a list");
gtk_widget_set_margin_start (label, 10);
gtk_container_add (GTK_CONTAINER (box), label);
frame = gtk_frame_new (NULL);
gtk_container_add (GTK_CONTAINER (box), frame);
list = gtk_list_box_new ();
gtk_list_box_set_selection_mode (GTK_LIST_BOX (list), GTK_SELECTION_NONE);
gtk_container_add (GTK_CONTAINER (frame), list);
gtk_list_box_set_header_func (GTK_LIST_BOX (list), list_header_func, NULL, NULL);
label = gtk_label_new ("Row 1");
gtk_widget_set_halign (label, GTK_ALIGN_START);
g_object_set (label, "margin", 10, NULL);
gtk_container_add (GTK_CONTAINER (list), label);
row = gtk_widget_get_parent (label);
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
label = gtk_label_new ("Row 2");
gtk_widget_set_halign (label, GTK_ALIGN_START);
g_object_set (label, "margin", 10, NULL);
gtk_container_add (GTK_CONTAINER (list), label);
row = gtk_widget_get_parent (label);
olist = gtk_option_list_new ();
gtk_widget_set_halign (olist, GTK_ALIGN_CENTER);
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "1", "Value 1");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "2", "Value 2");
gtk_option_list_add_item (GTK_OPTION_LIST (olist), "3", "Value 3");
gtk_widget_show (olist);
popover = gtk_popover_new (row);
gtk_container_add (GTK_CONTAINER (popover), olist);
g_signal_connect (olist, "notify::selected", G_CALLBACK (selected_changed), label);
g_signal_connect (list, "row-activated", G_CALLBACK (row_activated), popover);
g_signal_connect (row, "key-press-event", G_CALLBACK (row_key_press), olist);
label = gtk_label_new ("Row 3");
gtk_widget_set_halign (label, GTK_ALIGN_START);
g_object_set (label, "margin", 10, NULL);
gtk_container_add (GTK_CONTAINER (list), label);
row = gtk_widget_get_parent (label);
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}