Compare commits

...

19 Commits

Author SHA1 Message Date
Emmanuele Bassi
150c0cae9a docs: Add description for GtkOptionButton 2015-08-10 13:49:03 +01:00
Emmanuele Bassi
ded87c133d optionlist: Use g_clear_pointer()
Instead of setting to NULL after calling g_free().
2015-08-10 13:46:08 +01:00
Emmanuele Bassi
d3957af1cf docs: Fix the description of GtkOptionList
Drop references to unknown widgets, and clean up the description of the
class.
2015-08-10 13:44:56 +01:00
Emmanuele Bassi
87665ba380 Use 3.18 symbol annotations for GtkOptionButton and List
We missed the window for 3.16.
2015-08-10 13:09:59 +01:00
Matthias Clasen
7a8f7ed50f 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-08-10 12:51:33 +01:00
Matthias Clasen
4797f37ccd Factor out hit testing
Factor out hit testing into a separate function.
This will be useful in the following commits.
2015-08-10 12:51:33 +01:00
Matthias Clasen
892792a84c Fix up docs a bit 2015-08-10 12:51:33 +01:00
Matthias Clasen
b17c6a0f44 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-08-10 12:51:33 +01:00
Matthias Clasen
ec66d8e04e 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-08-10 12:49:25 +01:00
Matthias Clasen
4fe89fcb0d Add a getter for the item text
This can be used to check for the presence of items as well.
2015-08-10 12:49:25 +01:00
Matthias Clasen
fe94b58dc4 Allow changing the 'Custom Entry' label 2015-08-10 12:49:25 +01:00
Matthias Clasen
7d39962359 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-08-10 12:48:57 +01:00
Matthias Clasen
48014df4a1 Make 'show more' rows same height
This fixes a cosmetic issue with those rows.
2015-08-10 12:48:57 +01:00
Matthias Clasen
5ef70fe3ba Properly manage list separators
If we never unset separators, the stick around at the top of the
list during filtering.
2015-08-10 12:48:57 +01:00
Matthias Clasen
c4ddffb2de Update combo test for new API 2015-08-10 12:48:57 +01:00
Matthias Clasen
1f9f1e9a73 Support grouping in the new combo box 2015-08-10 12:48:57 +01:00
Matthias Clasen
11b36196d2 Document GtkCombo
Add documentation for GtkCombo.
2015-08-10 12:47:31 +01:00
Matthias Clasen
4b0c8fe722 Add a test for the new combo box
Add a some simple test app for GtkCombo.
2015-08-10 12:47:31 +01:00
Matthias Clasen
5106f16f9c 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
2015-08-10 12:47:31 +01:00
19 changed files with 3356 additions and 2 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

@@ -987,6 +987,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

@@ -230,6 +230,8 @@ gtk_public_h_sources = \
gtkmountoperation.h \
gtknotebook.h \
gtkoffscreenwindow.h \
gtkoptionbutton.h \
gtkoptionlist.h \
gtkorientable.h \
gtkoverlay.h \
gtkpagesetup.h \
@@ -751,6 +753,8 @@ gtk_base_c_sources = \
gtkmountoperation.c \
gtknotebook.c \
gtkoffscreenwindow.c \
gtkoptionbutton.c \
gtkoptionlist.c \
gtkorientable.c \
gtkoverlay.c \
gtkpagesetup.c \
@@ -1080,7 +1084,7 @@ templates = \
ui/gtkcolorchooserdialog.ui \
ui/gtkcoloreditor.ui \
ui/gtkcombobox.ui \
ui/gtkdialog.ui \
ui/gtkdialog.ui \
ui/gtkfilechooserbutton.ui \
ui/gtkfilechooserwidget.ui \
ui/gtkfilechooserdialog.ui \
@@ -1089,7 +1093,11 @@ templates = \
ui/gtkfontchooserwidget.ui \
ui/gtkinfobar.ui \
ui/gtklockbutton.ui \
ui/gtkmessagedialog.ui \
ui/gtkmessagedialog.ui \
ui/gtkoptionbutton.ui \
ui/gtkoptionlist.ui \
ui/gtkoptionlistrow.ui \
ui/gtkoptionlisttab.ui \
ui/gtkpagesetupunixdialog.ui \
ui/gtkpathbar.ui \
ui/gtkplacesview.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>

293
gtk/gtkoptionbutton.c Normal file
View File

@@ -0,0 +1,293 @@
/* 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"
/**
* SECTION:gtkoptionbutton
* @Short_description: A button widget tied to a GtkOptionList
* @Title: GtkOptionButton
* @See_also: #GtkOptionList
*
* GtkOptionButton is a button widget that can be used to show a
* #GtkOptionList as a pop over.
*/
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.18
*/
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.18
*/
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.18
*/
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_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_18
GType gtk_option_button_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_18
GtkWidget * gtk_option_button_new (void);
GDK_AVAILABLE_IN_3_18
GtkWidget * gtk_option_button_get_option_list (GtkOptionButton *button);
GDK_AVAILABLE_IN_3_18
void gtk_option_button_set_placeholder_text (GtkOptionButton *button,
const gchar *text);
GDK_AVAILABLE_IN_3_18
const gchar * gtk_option_button_get_placeholder_text (GtkOptionButton *button);
G_END_DECLS
#endif /* __GTK_OPTION_BUTTON_H__ */

2052
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_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_18
GType gtk_option_list_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_18
GtkWidget * gtk_option_list_new (void);
GDK_AVAILABLE_IN_3_18
const gchar ** gtk_option_list_get_selected_items (GtkOptionList *list);
GDK_AVAILABLE_IN_3_18
void gtk_option_list_select_item (GtkOptionList *list,
const gchar *id);
GDK_AVAILABLE_IN_3_18
void gtk_option_list_unselect_item (GtkOptionList *list,
const gchar *id);
GDK_AVAILABLE_IN_3_18
void gtk_option_list_add_item (GtkOptionList *list,
const gchar *id,
const gchar *text);
GDK_AVAILABLE_IN_3_18
void gtk_option_list_remove_item (GtkOptionList *list,
const gchar *id);
GDK_AVAILABLE_IN_3_18
const gchar * gtk_option_list_item_get_text (GtkOptionList *list,
const gchar *id);
GDK_AVAILABLE_IN_3_18
void gtk_option_list_item_set_sort_key (GtkOptionList *list,
const gchar *id,
const gchar *sort);
GDK_AVAILABLE_IN_3_18
void gtk_option_list_item_set_group_key (GtkOptionList *list,
const gchar *id,
const gchar *group);
GDK_AVAILABLE_IN_3_18
void gtk_option_list_add_group (GtkOptionList *list,
const gchar *group,
const gchar *text,
const gchar *sort);
GDK_AVAILABLE_IN_3_18
void gtk_option_list_set_allow_custom (GtkOptionList *list,
gboolean allow);
GDK_AVAILABLE_IN_3_18
gboolean gtk_option_list_get_allow_custom (GtkOptionList *list);
GDK_AVAILABLE_IN_3_18
void gtk_option_list_set_custom_text (GtkOptionList *list,
const gchar *text);
GDK_AVAILABLE_IN_3_18
const gchar * gtk_option_list_get_custom_text (GtkOptionList *list);
GDK_AVAILABLE_IN_3_18
void gtk_option_list_set_selection_mode (GtkOptionList *list,
GtkSelectionMode mode);
GDK_AVAILABLE_IN_3_18
GtkSelectionMode gtk_option_list_get_selection_mode (GtkOptionList *list);
GDK_AVAILABLE_IN_3_18
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,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

@@ -328,6 +328,9 @@ gtk/ui/gtkapplication-quartz.ui
gtk/ui/gtkassistant.ui
gtk/ui/gtkcolorchooserdialog.ui
gtk/ui/gtkcoloreditor.ui
gtk/ui/gtkcombo.ui
gtk/ui/gtkcomborow.ui
gtk/ui/gtkcombotab.ui
gtk/ui/gtkdialog.ui
gtk/ui/gtkfilechooserbutton.ui
gtk/ui/gtkfilechooserdialog.ui
@@ -338,6 +341,9 @@ gtk/ui/gtkfontchooserwidget.ui
gtk/ui/gtkinfobar.ui
gtk/ui/gtklockbutton.ui
gtk/ui/gtkmessagedialog.ui
gtk/ui/gtkoptionlist.ui
gtk/ui/gtkoptionlistrow.ui
gtk/ui/gtkoptionlisttab.ui
gtk/ui/gtkpagesetupunixdialog.ui
gtk/ui/gtkpathbar.ui
gtk/ui/gtkplacesviewrow.ui

View File

@@ -103,6 +103,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \
testnouiprint \
testoffscreen \
testoffscreenwindow \
testoptionlist \
testorientable \
testoverlay \
testoverlaystyleclass \
@@ -248,6 +249,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;
}