mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-18 17:30:10 +00:00
GtkContainer: Support focus chain in GtkBuilder
This adds support for a <focus-chain> element which can be used to specify a custom focus order for the children of a container. https://bugzilla.gnome.org/show_bug.cgi?id=582799
This commit is contained in:
parent
6d3c61856b
commit
aa3020a39e
@ -221,21 +221,33 @@
|
|||||||
* a <packing> element for children, which can contain multiple <property>
|
* a <packing> element for children, which can contain multiple <property>
|
||||||
* elements that specify child properties for the child.
|
* elements that specify child properties for the child.
|
||||||
*
|
*
|
||||||
* An example of child properties in UI definitions:
|
* Since 2.16, child properties can also be marked as translatable using
|
||||||
|
* the same “translatable”, “comments” and “context” attributes that are used
|
||||||
|
* for regular properties.
|
||||||
|
*
|
||||||
|
* Since 3.16, containers can have a <focus-chain> element containing multiple
|
||||||
|
* <widget> elements, one for each child that should be added to the focus
|
||||||
|
* chain. The ”name” attribute gives the id of the widget.
|
||||||
|
*
|
||||||
|
* An example of these properties in UI definitions:
|
||||||
* |[
|
* |[
|
||||||
* <object class="GtkVBox">
|
* <object class="GtkBox">
|
||||||
* <child>
|
* <child>
|
||||||
* <object class="GtkLabel"/>
|
* <object class="GtkEntry" id="entry1"/>
|
||||||
* <packing>
|
* <packing>
|
||||||
* <property name="pack-type">start</property>
|
* <property name="pack-type">start</property>
|
||||||
* </packing>
|
* </packing>
|
||||||
* </child>
|
* </child>
|
||||||
|
* <child>
|
||||||
|
* <object class="GtkEntry" id="entry2"/>
|
||||||
|
* </child>
|
||||||
|
* <focus-chain>
|
||||||
|
* <widget name="entry1"/>
|
||||||
|
* <widget name="entry2"/>
|
||||||
|
* </focus-chain>
|
||||||
* </object>
|
* </object>
|
||||||
* ]|
|
* ]|
|
||||||
*
|
*
|
||||||
* Since 2.16, child properties can also be marked as translatable using
|
|
||||||
* the same “translatable”, “comments” and “context” attributes that are used
|
|
||||||
* for regular properties.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -353,6 +365,11 @@ static void gtk_container_buildable_custom_tag_end (GtkBuildable *buildable,
|
|||||||
GObject *child,
|
GObject *child,
|
||||||
const gchar *tagname,
|
const gchar *tagname,
|
||||||
gpointer *data);
|
gpointer *data);
|
||||||
|
static void gtk_container_buildable_custom_finished (GtkBuildable *buildable,
|
||||||
|
GtkBuilder *builder,
|
||||||
|
GObject *child,
|
||||||
|
const gchar *tagname,
|
||||||
|
gpointer data);
|
||||||
|
|
||||||
static gboolean gtk_container_should_propagate_draw (GtkContainer *container,
|
static gboolean gtk_container_should_propagate_draw (GtkContainer *container,
|
||||||
GtkWidget *child,
|
GtkWidget *child,
|
||||||
@ -557,6 +574,7 @@ gtk_container_buildable_init (GtkBuildableIface *iface)
|
|||||||
iface->add_child = gtk_container_buildable_add_child;
|
iface->add_child = gtk_container_buildable_add_child;
|
||||||
iface->custom_tag_start = gtk_container_buildable_custom_tag_start;
|
iface->custom_tag_start = gtk_container_buildable_custom_tag_start;
|
||||||
iface->custom_tag_end = gtk_container_buildable_custom_tag_end;
|
iface->custom_tag_end = gtk_container_buildable_custom_tag_end;
|
||||||
|
iface->custom_finished = gtk_container_buildable_custom_finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -727,6 +745,46 @@ static const GMarkupParser attributes_parser =
|
|||||||
attributes_text_element,
|
attributes_text_element,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GSList *items;
|
||||||
|
GObject *object;
|
||||||
|
} FocusChainData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
focus_chain_start_element (GMarkupParseContext *context,
|
||||||
|
const gchar *element_name,
|
||||||
|
const gchar **names,
|
||||||
|
const gchar **values,
|
||||||
|
gpointer user_data,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
FocusChainData *data = (FocusChainData*)user_data;
|
||||||
|
|
||||||
|
if (strcmp (element_name, "widget") == 0)
|
||||||
|
{
|
||||||
|
for (i = 0; names[i]; i++)
|
||||||
|
{
|
||||||
|
if (strcmp (names[i], "name") == 0)
|
||||||
|
data->items = g_slist_prepend (data->items, g_strdup (values[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp (element_name, "focus-chain") == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_warning ("Unsupported type tag for GtkContainer %s\n", element_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const GMarkupParser focus_chain_parser =
|
||||||
|
{
|
||||||
|
focus_chain_start_element
|
||||||
|
};
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gtk_container_buildable_custom_tag_start (GtkBuildable *buildable,
|
gtk_container_buildable_custom_tag_start (GtkBuildable *buildable,
|
||||||
GtkBuilder *builder,
|
GtkBuilder *builder,
|
||||||
@ -735,14 +793,14 @@ gtk_container_buildable_custom_tag_start (GtkBuildable *buildable,
|
|||||||
GMarkupParser *parser,
|
GMarkupParser *parser,
|
||||||
gpointer *data)
|
gpointer *data)
|
||||||
{
|
{
|
||||||
PackingPropertiesData *parser_data;
|
|
||||||
|
|
||||||
if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
|
if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
|
||||||
tagname, parser, data))
|
tagname, parser, data))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
if (child && strcmp (tagname, "packing") == 0)
|
if (child && strcmp (tagname, "packing") == 0)
|
||||||
{
|
{
|
||||||
|
PackingPropertiesData *parser_data;
|
||||||
|
|
||||||
parser_data = g_slice_new0 (PackingPropertiesData);
|
parser_data = g_slice_new0 (PackingPropertiesData);
|
||||||
parser_data->string = g_string_new ("");
|
parser_data->string = g_string_new ("");
|
||||||
parser_data->builder = builder;
|
parser_data->builder = builder;
|
||||||
@ -754,6 +812,17 @@ gtk_container_buildable_custom_tag_start (GtkBuildable *buildable,
|
|||||||
*data = parser_data;
|
*data = parser_data;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
else if (!child && strcmp (tagname, "focus-chain") == 0)
|
||||||
|
{
|
||||||
|
FocusChainData *parser_data;
|
||||||
|
parser_data = g_slice_new0 (FocusChainData);
|
||||||
|
parser_data->items = NULL;
|
||||||
|
parser_data->object = G_OBJECT (buildable);
|
||||||
|
|
||||||
|
*parser = focus_chain_parser;
|
||||||
|
*data = parser_data;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -778,6 +847,48 @@ gtk_container_buildable_custom_tag_end (GtkBuildable *buildable,
|
|||||||
child, tagname, data);
|
child, tagname, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_container_buildable_custom_finished (GtkBuildable *buildable,
|
||||||
|
GtkBuilder *builder,
|
||||||
|
GObject *child,
|
||||||
|
const gchar *tagname,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
if (strcmp (tagname, "focus-chain") == 0)
|
||||||
|
{
|
||||||
|
FocusChainData *parser_data = (FocusChainData*)data;
|
||||||
|
GSList *l;
|
||||||
|
GList *chain;
|
||||||
|
GObject *object;
|
||||||
|
|
||||||
|
chain = NULL;
|
||||||
|
for (l = parser_data->items; l; l = l->next)
|
||||||
|
{
|
||||||
|
object = gtk_builder_get_object (builder, l->data);
|
||||||
|
if (!object)
|
||||||
|
{
|
||||||
|
g_warning ("Unknown object %s specified in focus-chain for %s",
|
||||||
|
(const gchar*)l->data,
|
||||||
|
gtk_buildable_get_name (GTK_BUILDABLE (parser_data->object)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
chain = g_list_prepend (chain, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_container_set_focus_chain (GTK_CONTAINER (parser_data->object), chain);
|
||||||
|
g_list_free (chain);
|
||||||
|
|
||||||
|
g_slist_free_full (parser_data->items, g_free);
|
||||||
|
g_slice_free (FocusChainData, parser_data);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent_buildable_iface->custom_finished)
|
||||||
|
parent_buildable_iface->custom_finished (buildable, builder,
|
||||||
|
child, tagname, data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gtk_container_child_type:
|
* gtk_container_child_type:
|
||||||
* @container: a #GtkContainer
|
* @container: a #GtkContainer
|
||||||
|
Loading…
Reference in New Issue
Block a user