forked from AuroraMiddleware/gtk
Support scale marks in builder markup
This commit is contained in:
parent
6e51533ec3
commit
dc8f36e254
4
NEWS
4
NEWS
@ -1,6 +1,10 @@
|
||||
Overview of Changes from GTK+ 2.16.x to 2.17.0
|
||||
==============================================
|
||||
|
||||
* GtkBuilder:
|
||||
- Scale marks can now be specified in builder markup
|
||||
- GtkAssistant action widgets can be added in builder markup
|
||||
|
||||
* Changes that are relevant for theme authors
|
||||
- GtkEntry now has a ::invisible-char style property that allows
|
||||
themes to set the preferred invisible character
|
||||
|
@ -229,7 +229,8 @@ respective objects, see
|
||||
<link linkend="GtkUIManager-BUILDER-UI">GtkUIManager</link>,
|
||||
<link linkend="GtkActionGroup-BUILDER-UI">GtkActionGroup</link>.
|
||||
<link linkend="GtkMenuItem-BUILDER-UI">GtkMenuItem</link>,
|
||||
<link linkend="GtkAssistant-BUILDER-UI">GtkAssistant</link>.
|
||||
<link linkend="GtkAssistant-BUILDER-UI">GtkAssistant</link>,
|
||||
<link linkend="GtkScale-BUILDER-UI">GtkScale</link>.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
|
@ -7,18 +7,28 @@ Base class for GtkHScale and GtkVScale
|
||||
<!-- ##### SECTION Long_Description ##### -->
|
||||
<para>
|
||||
A #GtkScale is a slider control used to select a numeric value.
|
||||
To use it, you'll probably want to investigate the methods on
|
||||
To use it, you'll probably want to investigate the methods on
|
||||
its base class, #GtkRange, in addition to the methods for #GtkScale itself.
|
||||
To set the value of a scale, you would normally use gtk_range_set_value().
|
||||
To detect changes to the value, you would normally use the "value_changed"
|
||||
To set the value of a scale, you would normally use gtk_range_set_value().
|
||||
To detect changes to the value, you would normally use the "value_changed"
|
||||
signal.
|
||||
</para>
|
||||
<para>
|
||||
The #GtkScale widget is an abstract class, used only for deriving the
|
||||
subclasses #GtkHScale and #GtkVScale. To create a scale widget,
|
||||
subclasses #GtkHScale and #GtkVScale. To create a scale widget,
|
||||
call gtk_hscale_new_with_range() or gtk_vscale_new_with_range().
|
||||
</para>
|
||||
|
||||
<refsect2 id="GtkScale-BUILDER-UI"><title>GtkScale as GtkBuildable</title>
|
||||
<para>
|
||||
GtkScale supports a custom <marks> element, which
|
||||
can contain multiple <mark> elements. The "value" and "position"
|
||||
attributes have the same meaning as gtk_scale_add_mark() parameters of the
|
||||
same name. If the element is not empty, its content is taken as the markup
|
||||
to show at the mark. It can be translated with the usual "translatable and
|
||||
"context" attributes.
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION See_Also ##### -->
|
||||
<para>
|
||||
|
||||
@ -39,9 +49,9 @@ the accessor functions.
|
||||
|
||||
</para>
|
||||
|
||||
@scale:
|
||||
@value:
|
||||
@Returns:
|
||||
@scale:
|
||||
@value:
|
||||
@Returns:
|
||||
|
||||
<!-- ##### ARG GtkScale:digits ##### -->
|
||||
<para>
|
||||
|
256
gtk/gtkscale.c
256
gtk/gtkscale.c
@ -38,6 +38,8 @@
|
||||
#include "gtkbindings.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkbuildable.h"
|
||||
#include "gtkbuilderprivate.h"
|
||||
#include "gtkalias.h"
|
||||
|
||||
|
||||
@ -56,7 +58,7 @@ typedef struct _GtkScaleMark GtkScaleMark;
|
||||
struct _GtkScaleMark
|
||||
{
|
||||
gdouble value;
|
||||
const gchar *markup;
|
||||
gchar *markup;
|
||||
GtkPositionType position;
|
||||
};
|
||||
|
||||
@ -110,8 +112,24 @@ static gboolean gtk_scale_expose (GtkWidget *widget,
|
||||
static void gtk_scale_real_get_layout_offsets (GtkScale *scale,
|
||||
gint *x,
|
||||
gint *y);
|
||||
static void gtk_scale_buildable_interface_init (GtkBuildableIface *iface);
|
||||
static gboolean gtk_scale_buildable_custom_tag_start (GtkBuildable *buildable,
|
||||
GtkBuilder *builder,
|
||||
GObject *child,
|
||||
const gchar *tagname,
|
||||
GMarkupParser *parser,
|
||||
gpointer *data);
|
||||
static void gtk_scale_buildable_custom_finished (GtkBuildable *buildable,
|
||||
GtkBuilder *builder,
|
||||
GObject *child,
|
||||
const gchar *tagname,
|
||||
gpointer user_data);
|
||||
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkScale, gtk_scale, GTK_TYPE_RANGE,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
|
||||
gtk_scale_buildable_interface_init))
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE (GtkScale, gtk_scale, GTK_TYPE_RANGE)
|
||||
|
||||
static gboolean
|
||||
single_string_accumulator (GSignalInvocationHint *ihint,
|
||||
@ -1355,6 +1373,240 @@ gtk_scale_add_mark (GtkScale *scale,
|
||||
gtk_widget_queue_resize (GTK_WIDGET (scale));
|
||||
}
|
||||
|
||||
static GtkBuildableIface *parent_buildable_iface;
|
||||
|
||||
static void
|
||||
gtk_scale_buildable_interface_init (GtkBuildableIface *iface)
|
||||
{
|
||||
parent_buildable_iface = g_type_interface_peek_parent (iface);
|
||||
iface->custom_tag_start = gtk_scale_buildable_custom_tag_start;
|
||||
iface->custom_finished = gtk_scale_buildable_custom_finished;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GtkScale *scale;
|
||||
GtkBuilder *builder;
|
||||
GSList *marks;
|
||||
} MarksSubparserData;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gdouble value;
|
||||
GtkPositionType position;
|
||||
GString *markup;
|
||||
gchar *context;
|
||||
gboolean translatable;
|
||||
} MarkData;
|
||||
|
||||
static void
|
||||
mark_data_free (MarkData *data)
|
||||
{
|
||||
g_string_free (data->markup, TRUE);
|
||||
g_free (data->context);
|
||||
g_slice_free (MarkData, data);
|
||||
}
|
||||
|
||||
static void
|
||||
marks_start_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
const gchar **names,
|
||||
const gchar **values,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
MarksSubparserData *parser_data = (MarksSubparserData*)user_data;
|
||||
guint i;
|
||||
gint line_number, char_number;
|
||||
|
||||
if (strcmp (element_name, "marks") == 0)
|
||||
;
|
||||
else if (strcmp (element_name, "mark") == 0)
|
||||
{
|
||||
gdouble value;
|
||||
gboolean has_value = FALSE;
|
||||
GtkPositionType position = GTK_POS_BOTTOM;
|
||||
const gchar *msg_context = NULL;
|
||||
gboolean translatable = FALSE;
|
||||
MarkData *mark;
|
||||
|
||||
for (i = 0; names[i]; i++)
|
||||
{
|
||||
if (strcmp (names[i], "translatable") == 0)
|
||||
{
|
||||
if (!_gtk_builder_boolean_from_string (values[i], &translatable, error))
|
||||
return;
|
||||
}
|
||||
else if (strcmp (names[i], "comments") == 0)
|
||||
{
|
||||
/* do nothing, comments are for translators */
|
||||
}
|
||||
else if (strcmp (names[i], "context") == 0)
|
||||
msg_context = values[i];
|
||||
else if (strcmp (names[i], "value") == 0)
|
||||
{
|
||||
GValue gvalue = { 0, };
|
||||
|
||||
if (!gtk_builder_value_from_string_type (parser_data->builder, G_TYPE_DOUBLE, values[i], &gvalue, error))
|
||||
return;
|
||||
|
||||
value = g_value_get_double (&gvalue);
|
||||
has_value = TRUE;
|
||||
}
|
||||
else if (strcmp (names[i], "position") == 0)
|
||||
{
|
||||
GValue gvalue = { 0, };
|
||||
|
||||
if (!gtk_builder_value_from_string_type (parser_data->builder, GTK_TYPE_POSITION_TYPE, values[i], &gvalue, error))
|
||||
return;
|
||||
|
||||
position = g_value_get_enum (&gvalue);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_markup_parse_context_get_position (context,
|
||||
&line_number,
|
||||
&char_number);
|
||||
g_set_error (error,
|
||||
GTK_BUILDER_ERROR,
|
||||
GTK_BUILDER_ERROR_INVALID_ATTRIBUTE,
|
||||
"%s:%d:%d '%s' is not a valid attribute of <%s>",
|
||||
"<input>",
|
||||
line_number, char_number, names[i], "mark");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_value)
|
||||
{
|
||||
g_markup_parse_context_get_position (context,
|
||||
&line_number,
|
||||
&char_number);
|
||||
g_set_error (error,
|
||||
GTK_BUILDER_ERROR,
|
||||
GTK_BUILDER_ERROR_MISSING_ATTRIBUTE,
|
||||
"%s:%d:%d <%s> requires attribute \"%s\"",
|
||||
"<input>",
|
||||
line_number, char_number, "mark",
|
||||
"value");
|
||||
return;
|
||||
}
|
||||
|
||||
mark = g_slice_new (MarkData);
|
||||
mark->value = value;
|
||||
mark->position = position;
|
||||
mark->markup = g_string_new ("");
|
||||
mark->context = g_strdup (msg_context);
|
||||
mark->translatable = translatable;
|
||||
|
||||
parser_data->marks = g_slist_prepend (parser_data->marks, mark);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_markup_parse_context_get_position (context,
|
||||
&line_number,
|
||||
&char_number);
|
||||
g_set_error (error,
|
||||
GTK_BUILDER_ERROR,
|
||||
GTK_BUILDER_ERROR_MISSING_ATTRIBUTE,
|
||||
"%s:%d:%d unsupported tag for GtkScale: \"%s\"",
|
||||
"<input>",
|
||||
line_number, char_number, element_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
marks_text (GMarkupParseContext *context,
|
||||
const gchar *text,
|
||||
gsize text_len,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
MarksSubparserData *data = (MarksSubparserData*)user_data;
|
||||
|
||||
if (strcmp (g_markup_parse_context_get_element (context), "mark") == 0)
|
||||
{
|
||||
MarkData *mark = data->marks->data;
|
||||
|
||||
g_string_append_len (mark->markup, text, text_len);
|
||||
}
|
||||
}
|
||||
|
||||
static const GMarkupParser marks_parser =
|
||||
{
|
||||
marks_start_element,
|
||||
NULL,
|
||||
marks_text,
|
||||
};
|
||||
|
||||
|
||||
static gboolean
|
||||
gtk_scale_buildable_custom_tag_start (GtkBuildable *buildable,
|
||||
GtkBuilder *builder,
|
||||
GObject *child,
|
||||
const gchar *tagname,
|
||||
GMarkupParser *parser,
|
||||
gpointer *data)
|
||||
{
|
||||
MarksSubparserData *parser_data;
|
||||
|
||||
if (child)
|
||||
return FALSE;
|
||||
|
||||
if (strcmp (tagname, "marks") == 0)
|
||||
{
|
||||
parser_data = g_slice_new0 (MarksSubparserData);
|
||||
parser_data->scale = GTK_SCALE (buildable);
|
||||
parser_data->marks = NULL;
|
||||
|
||||
*parser = marks_parser;
|
||||
*data = parser_data;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return parent_buildable_iface->custom_tag_start (buildable, builder, child,
|
||||
tagname, parser, data);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_scale_buildable_custom_finished (GtkBuildable *buildable,
|
||||
GtkBuilder *builder,
|
||||
GObject *child,
|
||||
const gchar *tagname,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkScale *scale = GTK_SCALE (buildable);
|
||||
MarksSubparserData *marks_data;
|
||||
GtkWidget *toplevel;
|
||||
|
||||
if (strcmp (tagname, "marks") == 0)
|
||||
{
|
||||
GSList *m;
|
||||
gchar *markup;
|
||||
|
||||
marks_data = (MarksSubparserData *)user_data;
|
||||
|
||||
for (m = marks_data->marks; m; m = m->next)
|
||||
{
|
||||
MarkData *mdata = m->data;
|
||||
|
||||
if (mdata->translatable && mdata->markup->len)
|
||||
markup = _gtk_builder_parser_translate (gtk_builder_get_translation_domain (builder),
|
||||
mdata->context,
|
||||
mdata->markup->str);
|
||||
else
|
||||
markup = mdata->markup->str;
|
||||
|
||||
gtk_scale_add_mark (scale, mdata->value, mdata->position, markup);
|
||||
|
||||
mark_data_free (mdata);
|
||||
}
|
||||
|
||||
g_slist_free (marks_data->marks);
|
||||
g_slice_free (MarksSubparserData, marks_data);
|
||||
}
|
||||
}
|
||||
|
||||
#define __GTK_SCALE_C__
|
||||
#include "gtkaliasdef.c"
|
||||
|
Loading…
Reference in New Issue
Block a user