diff options
author | Cosimo Cecchi <cosimoc@gnome.org> | 2012-05-29 17:00:33 -0400 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2012-07-10 22:41:12 -0400 |
commit | 126a2308ca467744178d4be3309403f6899de987 (patch) | |
tree | 66a321f37f4874f89b57772044662bb9cd195cb7 | |
parent | f7683b05b1c29ecc715715b95b2011a895917cf4 (diff) | |
download | gtk+-126a2308ca467744178d4be3309403f6899de987.tar.gz |
level-bar: introduce GtkLevelBar
Similar to CcStrengthBar from gnome-control-center, but more generic and
with thorough CSS styling support.
https://bugzilla.gnome.org/show_bug.cgi?id=677892
-rw-r--r-- | docs/reference/gtk/gtk-docs.sgml | 1 | ||||
-rw-r--r-- | docs/reference/gtk/gtk3-sections.txt | 31 | ||||
-rw-r--r-- | docs/reference/gtk/gtk3.types.in | 1 | ||||
-rw-r--r-- | docs/reference/gtk/objects_grouped.sgml | 1 | ||||
-rw-r--r-- | gtk/Makefile.am | 2 | ||||
-rw-r--r-- | gtk/gtk.h | 1 | ||||
-rw-r--r-- | gtk/gtk.symbols | 15 | ||||
-rw-r--r-- | gtk/gtkenums.h | 14 | ||||
-rw-r--r-- | gtk/gtklevelbar.c | 1216 | ||||
-rw-r--r-- | gtk/gtklevelbar.h | 111 | ||||
-rw-r--r-- | gtk/gtkstylecontext.h | 10 |
11 files changed, 1403 insertions, 0 deletions
diff --git a/docs/reference/gtk/gtk-docs.sgml b/docs/reference/gtk/gtk-docs.sgml index b5de514f85..6eca4d0dce 100644 --- a/docs/reference/gtk/gtk-docs.sgml +++ b/docs/reference/gtk/gtk-docs.sgml @@ -102,6 +102,7 @@ <xi:include href="xml/gtklabel.xml" /> <xi:include href="xml/gtkprogressbar.xml" /> <xi:include href="xml/gtkstatusbar.xml" /> + <xi:include href="xml/gtklevelbar.xml" /> <xi:include href="xml/gtkinfobar.xml" /> <xi:include href="xml/gtkstatusicon.xml" /> <xi:include href="xml/gtkspinner.xml" /> diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt index 979e86a0ea..08cf91f16f 100644 --- a/docs/reference/gtk/gtk3-sections.txt +++ b/docs/reference/gtk/gtk3-sections.txt @@ -3248,6 +3248,35 @@ gtk_status_icon_get_type </SECTION> <SECTION> +<FILE>gtklevelbar</FILE> +<TITLE>GtkLevelBar</TITLE> +GtkLevelBar +gtk_level_bar_new +gtk_level_bar_new_for_interval +gtk_level_bar_set_mode +gtk_level_bar_get_mode +gtk_level_bar_set_value +gtk_level_bar_get_value +gtk_level_bar_set_min_value +gtk_level_bar_get_min_value +gtk_level_bar_set_max_value +gtk_level_bar_get_max_value +gtk_level_bar_add_offset_value +gtk_level_bar_remove_offset_value +gtk_level_bar_get_offset_value +<SUBSECTION Standard> +GTK_LEVEL_BAR +GTK_IS_LEVEL_BAR +GTK_TYPE_LEVEL_BAR +GTK_LEVEL_BAR_CLASS +GTK_IS_LEVEL_BAR_CLASS +GTK_LEVEL_BAR_GET_CLASS +<SUBSECTION Private> +GtkLevelBarPrivate +gtk_level_bar_get_type +</SECTION> + +<SECTION> <FILE>gtktable</FILE> <TITLE>GtkTable</TITLE> GtkTable @@ -5721,6 +5750,7 @@ GTK_STYLE_CLASS_RIGHT GTK_STYLE_CLASS_LINKED GTK_STYLE_CLASS_ARROW GTK_STYLE_CLASS_OSD +GTK_STYLE_CLASS_LEVEL_BAR GTK_STYLE_REGION_COLUMN GTK_STYLE_REGION_COLUMN_HEADER GTK_STYLE_REGION_ROW @@ -6232,6 +6262,7 @@ GtkExpanderStyle GtkIMPreeditStyle GtkIMStatusStyle GtkJustification +GtkLevelBarMode GtkMovementStep GtkOrientation GtkPackType diff --git a/docs/reference/gtk/gtk3.types.in b/docs/reference/gtk/gtk3.types.in index 5b9b3bd015..bdcebf1ad0 100644 --- a/docs/reference/gtk/gtk3.types.in +++ b/docs/reference/gtk/gtk3.types.in @@ -155,6 +155,7 @@ gtk_spinner_get_type gtk_statusbar_get_type gtk_status_icon_get_type gtk_switch_get_type +gtk_level_bar_get_type gtk_style_get_type gtk_style_context_get_type gtk_style_provider_get_type diff --git a/docs/reference/gtk/objects_grouped.sgml b/docs/reference/gtk/objects_grouped.sgml index 78dc95bf9f..56bfd953da 100644 --- a/docs/reference/gtk/objects_grouped.sgml +++ b/docs/reference/gtk/objects_grouped.sgml @@ -90,6 +90,7 @@ <link linkend="GtkCalendar">GtkCalendar</link> <link linkend="GtkProgressBar">GtkProgressBar</link> <link linkend="GtkStatusbar">GtkStatusbar</link> + <link linkend="GtkStrengthBar">GtkStrengthBar</link> <link linkend="GtkHRuler">GtkHRuler</link> <link linkend="GtkVRuler">GtkVRuler</link> <link linkend="GtkHScrollbar">GtkHScrollbar</link> diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 4f4cda03bf..41c61b86d1 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -265,6 +265,7 @@ gtk_public_h_sources = \ gtkinvisible.h \ gtklabel.h \ gtklayout.h \ + gtklevelbar.h \ gtklinkbutton.h \ gtkliststore.h \ gtklockbutton.h \ @@ -729,6 +730,7 @@ gtk_base_c_sources = \ gtkkeyhash.c \ gtklabel.c \ gtklayout.c \ + gtklevelbar.c \ gtklinkbutton.c \ gtkliststore.c \ gtklockbutton.c \ @@ -122,6 +122,7 @@ #include <gtk/gtkinvisible.h> #include <gtk/gtklabel.h> #include <gtk/gtklayout.h> +#include <gtk/gtklevelbar.h> #include <gtk/gtklinkbutton.h> #include <gtk/gtkliststore.h> #include <gtk/gtklockbutton.h> diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index 8b6f90232e..82f6f6f2a5 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -2566,6 +2566,21 @@ gtk_switch_get_active gtk_switch_get_type gtk_switch_new gtk_switch_set_active +gtk_level_bar_get_type +gtk_level_bar_new +gtk_level_bar_new_for_interval +gtk_level_bar_set_mode +gtk_level_bar_get_mode +gtk_level_bar_set_value +gtk_level_bar_get_value +gtk_level_bar_set_min_value +gtk_level_bar_get_min_value +gtk_level_bar_set_max_value +gtk_level_bar_get_max_value +gtk_level_bar_add_offset_value +gtk_level_bar_remove_offset_value +gtk_level_bar_get_offset_value +gtk_level_bar_mode_get_type gtk_style_apply_default_background gtk_style_attach gtk_style_context_add_class diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h index e409d79c7e..5f647a2887 100644 --- a/gtk/gtkenums.h +++ b/gtk/gtkenums.h @@ -932,6 +932,20 @@ typedef enum { GTK_BORDER_STYLE_RIDGE } GtkBorderStyle; +/** + * GtkLevelBarMode: + * @GTK_LEVEL_BAR_MODE_CONTINUOUS: the bar has a continuous mode + * @GTK_LEVEL_BAR_MODE_DISCRETE: the bar has a discrete mode + * + * Describes how #GtkLevelBar contents should be rendered. + * Note that this enumeration could be extended with additional modes + * in the future. + */ +typedef enum { + GTK_LEVEL_BAR_MODE_CONTINUOUS, + GTK_LEVEL_BAR_MODE_DISCRETE +} GtkLevelBarMode; + G_END_DECLS diff --git a/gtk/gtklevelbar.c b/gtk/gtklevelbar.c new file mode 100644 index 0000000000..4a371042e5 --- /dev/null +++ b/gtk/gtklevelbar.c @@ -0,0 +1,1216 @@ +/* GTK - The GIMP Toolkit + * Copyright © 2012 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/>. + * + * Author: Cosimo Cecchi <cosimoc@gnome.org> + * + */ + +/** + * SECTION:gtklevelbar + * @Title: GtkLevelBar + * @Short_description: A bar that can used as a level indicator + * + * The #GtkLevelBar is a bar widget that can be used + * as a level indicator. Typical use cases are displaying the level + * of a password, or showing the charge level of a battery. + * + * Use #gtk_level_bar_set_value to set the current value, and + * #gtk_level_bar_add_offset_value to set the value offsets at which + * the bar will be considered in a different state. GTK will add two offsets + * by default on the level bar: #GTK_LEVEL_BAR_OFFSET_LOW and + * #GTK_LEVEL_BAR_OFFSET_HIGH, with values 0.25 and 0.75 respectively. + * + * The default interval of values is between zero and one, but it's possible to + * modify the interval using #gtk_level_bar_set_min_value and + * #gtk_level_bar_set_max_value. The value will be always drawn in proportion to + * the admissible interval, i.e. a value of 15 with a specified interval between + * 10 and 20 is equivalent to a value of 0.5 with an interval between 0 and 1. + * When #GTK_LEVEL_BAR_MODE_DISCRETE is used, the bar level is rendered + * as a finite and number of separated blocks instead of a single one. The number + * of blocks that will be rendered is equal to the number of units specified by + * the admissible interval. + * For instance, to build a bar rendered with five blocks, it's sufficient to + * set the minimum value to 0 and the maximum value to 5 after changing the indicator + * mode to discrete. + * + * Since: 3.6 + */ +#include "config.h" + +#include "gtkbuildable.h" +#include "gtkintl.h" +#include "gtkorientableprivate.h" +#include "gtklevelbar.h" +#include "gtkmarshalers.h" +#include "gtkstylecontext.h" +#include "gtktypebuiltins.h" +#include "gtkwidget.h" + +#include <math.h> +#include <stdlib.h> + +#define DEFAULT_BLOCK_SIZE 3 + +/* these don't make sense outside of GtkLevelBar, so we don't add + * global defines */ +#define STYLE_CLASS_INDICATOR_CONTINUOUS "indicator-continuous" +#define STYLE_CLASS_INDICATOR_DISCRETE "indicator-discrete" +#define STYLE_CLASS_FILL_BLOCK "fill-block" +#define STYLE_CLASS_EMPTY_FILL_BLOCK "empty-fill-block" + +static void gtk_level_bar_buildable_init (GtkBuildableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (GtkLevelBar, gtk_level_bar, GTK_TYPE_WIDGET, + G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL) + G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, + gtk_level_bar_buildable_init)) + +enum { + PROP_VALUE = 1, + PROP_MIN_VALUE, + PROP_MAX_VALUE, + PROP_MODE, + LAST_PROPERTY, + PROP_ORIENTATION /* overridden */ +}; + +enum { + SIGNAL_OFFSET_CHANGED, + NUM_SIGNALS +}; + +static GParamSpec *properties[LAST_PROPERTY] = { NULL, }; +static guint signals[NUM_SIGNALS] = { 0, }; + +typedef struct { + gchar *name; + gdouble value; +} GtkLevelBarOffset; + +struct _GtkLevelBarPrivate { + GtkOrientation orientation; + + gdouble min_value; + gdouble max_value; + gdouble cur_value; + + GList *offsets; + + GtkLevelBarMode bar_mode; +}; + +static void gtk_level_bar_set_value_internal (GtkLevelBar *self, + gdouble value); + +static GtkLevelBarOffset * +gtk_level_bar_offset_new (const gchar *name, + gdouble value) +{ + GtkLevelBarOffset *offset = g_slice_new0 (GtkLevelBarOffset); + + offset->name = g_strdup (name); + offset->value = value; + + return offset; +} + +static void +gtk_level_bar_offset_free (GtkLevelBarOffset *offset) +{ + g_free (offset->name); + g_slice_free (GtkLevelBarOffset, offset); +} + +static gint +offset_find_func (gconstpointer data, + gconstpointer user_data) +{ + const GtkLevelBarOffset *offset = data; + const gchar *name = user_data; + + return g_strcmp0 (name, offset->name); +} + +static gint +offset_sort_func (gconstpointer a, + gconstpointer b) +{ + const GtkLevelBarOffset *offset_a = a; + const GtkLevelBarOffset *offset_b = b; + + return (offset_a->value > offset_b->value); +} + +static gboolean +gtk_level_bar_ensure_offset (GtkLevelBar *self, + const gchar *name, + gdouble value) +{ + GList *existing; + GtkLevelBarOffset *offset = NULL; + + existing = g_list_find_custom (self->priv->offsets, name, offset_find_func); + if (existing) + offset = existing->data; + + if (offset && (offset->value == value)) + return FALSE; + + if (offset) + { + gtk_level_bar_offset_free (offset); + self->priv->offsets = g_list_delete_link (self->priv->offsets, existing); + } + + offset = gtk_level_bar_offset_new (name, value); + self->priv->offsets = g_list_insert_sorted (self->priv->offsets, offset, offset_sort_func); + + return TRUE; +} + +static gboolean +gtk_level_bar_value_in_interval (GtkLevelBar *self, + gdouble value) +{ + return ((value >= self->priv->min_value) && + (value <= self->priv->max_value)); +} + +static void +gtk_level_bar_get_min_block_size (GtkLevelBar *self, + gint *block_width, + gint *block_height) +{ + GtkWidget *widget = GTK_WIDGET (self); + GtkStyleContext *context = gtk_widget_get_style_context (widget); + GtkStateFlags flags = gtk_widget_get_state_flags (widget); + GtkBorder border, tmp, tmp2; + gint min_width, min_height; + + gtk_style_context_save (context); + gtk_style_context_add_class (context, STYLE_CLASS_FILL_BLOCK); + gtk_style_context_get_border (context, flags, &border); + gtk_style_context_get_padding (context, flags, &tmp); + gtk_style_context_get_margin (context, flags, &tmp2); + gtk_style_context_restore (context); + + gtk_style_context_get_style (context, + "min-block-width", &min_width, + "min-block-height", &min_height, + NULL); + + border.top += tmp.top; + border.right += tmp.right; + border.bottom += tmp.bottom; + border.left += tmp.left; + + border.top += tmp2.top; + border.right += tmp2.right; + border.bottom += tmp2.bottom; + border.left += tmp2.left; + + if (block_width) + *block_width = MAX (border.left + border.right, min_width); + if (block_height) + *block_height = MAX (border.top + border.bottom, min_height); +} + +static gint +gtk_level_bar_get_num_blocks (GtkLevelBar *self) +{ + if (self->priv->bar_mode == GTK_LEVEL_BAR_MODE_CONTINUOUS) + return 1; + else if (self->priv->bar_mode == GTK_LEVEL_BAR_MODE_DISCRETE) + return MAX (1, (gint) (round (self->priv->max_value) - round (self->priv->min_value))); + + return 0; +} + +static void +gtk_level_bar_get_borders (GtkLevelBar *self, + GtkBorder *borders_out) +{ + GtkWidget *widget = GTK_WIDGET (self); + GtkStyleContext *context = gtk_widget_get_style_context (widget); + GtkStateFlags flags = gtk_widget_get_state_flags (widget); + GtkBorder border, tmp; + + gtk_style_context_save (context); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_TROUGH); + gtk_style_context_get_border (context, flags, &border); + gtk_style_context_get_padding (context, flags, &tmp); + gtk_style_context_restore (context); + + border.top += tmp.top; + border.right += tmp.right; + border.bottom += tmp.bottom; + border.left += tmp.left; + + if (borders_out) + *borders_out = border; +} + +static void +gtk_level_bar_draw_fill_continuous (GtkLevelBar *self, + cairo_t *cr, + cairo_rectangle_int_t *fill_area) +{ + GtkWidget *widget = GTK_WIDGET (self); + GtkStyleContext *context = gtk_widget_get_style_context (widget); + GtkStateFlags flags = gtk_widget_get_state_flags (widget); + cairo_rectangle_int_t base_area, block_area; + GtkBorder block_margin; + gdouble fill_percentage; + + gtk_style_context_save (context); + gtk_style_context_add_class (context, STYLE_CLASS_FILL_BLOCK); + gtk_style_context_get_margin (context, flags, &block_margin); + + /* render the empty (unfilled) part */ + base_area = *fill_area; + base_area.x += block_margin.left; + base_area.y += block_margin.top; + base_area.width -= block_margin.left + block_margin.right; + base_area.height -= block_margin.top + block_margin.bottom; + + gtk_style_context_add_class (context, STYLE_CLASS_EMPTY_FILL_BLOCK); + + gtk_render_background (context, cr, base_area.x, base_area.y, + base_area.width, base_area.height); + gtk_render_frame (context, cr, base_area.x, base_area.y, + base_area.width, base_area.height); + + /* now render the filled part on top of it */ + block_area = base_area; + + fill_percentage = (self->priv->cur_value - self->priv->min_value) / + (self->priv->max_value - self->priv->min_value); + + if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) + block_area.width = (gint) floor (block_area.width * fill_percentage); + else + block_area.height = (gint) floor (block_area.height * fill_percentage); + + gtk_style_context_remove_class (context, STYLE_CLASS_EMPTY_FILL_BLOCK); + + gtk_render_background (context, cr, block_area.x, block_area.y, + block_area.width, block_area.height); + gtk_render_frame (context, cr, block_area.x, block_area.y, + block_area.width, block_area.height); + + gtk_style_context_restore (context); +} + +static void +gtk_level_bar_draw_fill_discrete (GtkLevelBar *self, + cairo_t *cr, + cairo_rectangle_int_t *fill_area) +{ + GtkWidget *widget = GTK_WIDGET (self); + GtkStyleContext *context = gtk_widget_get_style_context (widget); + GtkStateFlags flags = gtk_widget_get_state_flags (widget); + gint num_blocks, num_filled, idx; + gint block_width, block_height; + gint block_draw_width, block_draw_height; + GtkBorder block_margin; + cairo_rectangle_int_t block_area; + + gtk_level_bar_get_min_block_size (self, &block_width, &block_height); + + block_area = *fill_area; + num_blocks = gtk_level_bar_get_num_blocks (self); + num_filled = (gint) round (self->priv->cur_value) - (gint) round (self->priv->min_value); + + if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) + block_width = MAX (block_width, (gint) floor (block_area.width / num_blocks)); + else + block_height = MAX (block_height, (gint) floor (block_area.height / num_blocks)); + + gtk_style_context_save (context); + gtk_style_context_add_class (context, STYLE_CLASS_FILL_BLOCK); + gtk_style_context_get_margin (context, flags, &block_margin); + + block_draw_width = block_width - block_margin.left - block_margin.right; + block_draw_height = block_height - block_margin.top - block_margin.bottom; + + if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + block_draw_height = MAX (block_draw_height, block_area.height - block_margin.top - block_margin.bottom); + block_area.y += block_margin.top; + } + else + { + block_draw_width = MAX (block_draw_width, block_area.width - block_margin.left - block_margin.right); + block_area.x += block_margin.left; + } + + for (idx = 0; idx < num_blocks; idx++) + { + if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) + block_area.x += block_margin.left; + else + block_area.y += block_margin.top; + + if (idx > num_filled - 1) + gtk_style_context_add_class (context, STYLE_CLASS_EMPTY_FILL_BLOCK); + + gtk_render_background (context, cr, + block_area.x, block_area.y, + block_draw_width, block_draw_height); + gtk_render_frame (context, cr, + block_area.x, block_area.y, + block_draw_width, block_draw_height); + + if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) + block_area.x += block_draw_width + block_margin.right; + else + block_area.y += block_draw_height + block_margin.bottom; + } + + gtk_style_context_restore (context); +} + +static void +gtk_level_bar_draw_fill (GtkLevelBar *self, + cairo_t *cr) +{ + GtkWidget *widget = GTK_WIDGET (self); + GtkBorder trough_borders; + cairo_rectangle_int_t fill_area; + + gtk_level_bar_get_borders (self, &trough_borders); + + fill_area.x = trough_borders.left; + fill_area.y = trough_borders.top; + fill_area.width = gtk_widget_get_allocated_width (widget) - + trough_borders.left - trough_borders.right; + fill_area.height = gtk_widget_get_allocated_height (widget) - + trough_borders.top - trough_borders.bottom; + + if (self->priv->bar_mode == GTK_LEVEL_BAR_MODE_CONTINUOUS) + gtk_level_bar_draw_fill_continuous (self, cr, &fill_area); + else if (self->priv->bar_mode == GTK_LEVEL_BAR_MODE_DISCRETE) + gtk_level_bar_draw_fill_discrete (self, cr, &fill_area); +} + +static gboolean +gtk_level_bar_draw (GtkWidget *widget, + cairo_t *cr) +{ + GtkLevelBar *self = GTK_LEVEL_BAR (widget); + GtkStyleContext *context = gtk_widget_get_style_context (widget); + gint width, height; + + width = gtk_widget_get_allocated_width (widget); + height = gtk_widget_get_allocated_height (widget); + + gtk_style_context_save (context); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_TROUGH); + + gtk_render_background (context, cr, 0, 0, width, height); + gtk_render_frame (context, cr, 0, 0, width, height); + + gtk_style_context_restore (context); + + gtk_level_bar_draw_fill (self, cr); + + return FALSE; +} + +static void +gtk_level_bar_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + GtkLevelBar *self = GTK_LEVEL_BAR (widget); + GtkBorder borders; + gint num_blocks; + gint width, block_width; + + num_blocks = gtk_level_bar_get_num_blocks (self); + gtk_level_bar_get_min_block_size (self, &block_width, NULL); + + gtk_level_bar_get_borders (self, &borders); + width = borders.left + borders.right; + + if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) + width += num_blocks * block_width; + else + width += block_width; + + if (minimum) + *minimum = width; + if (natural) + *natural = width; +} + +static void +gtk_level_bar_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + GtkLevelBar *self = GTK_LEVEL_BAR (widget); + GtkBorder borders; + gint num_blocks; + gint height, block_height; + + num_blocks = gtk_level_bar_get_num_blocks (self); + gtk_level_bar_get_min_block_size (self, NULL, &block_height); + + gtk_level_bar_get_borders (self, &borders); + height = borders.top + borders.bottom; + + if (self->priv->orientation == GTK_ORIENTATION_VERTICAL) + height += num_blocks * block_height; + else + height += block_height; + + if (minimum) + *minimum = height; + if (natural) + *natural = height; +} + +static void +gtk_level_bar_update_mode_style_classes (GtkLevelBar *self) +{ + GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET (self)); + + if (self->priv->bar_mode == GTK_LEVEL_BAR_MODE_CONTINUOUS) + { + gtk_style_context_remove_class (context, STYLE_CLASS_INDICATOR_DISCRETE); + gtk_style_context_add_class (context, STYLE_CLASS_INDICATOR_CONTINUOUS); + } + else if (self->priv->bar_mode == GTK_LEVEL_BAR_MODE_DISCRETE) + { + gtk_style_context_remove_class (context, STYLE_CLASS_INDICATOR_CONTINUOUS); + gtk_style_context_add_class (context, STYLE_CLASS_INDICATOR_DISCRETE); + } +} + +static void +gtk_level_bar_update_level_style_classes (GtkLevelBar *self) +{ + GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET (self)); + gdouble value = gtk_level_bar_get_value (self); + gchar *offset_style_class, *value_class = NULL; + GtkLevelBarOffset *offset, *prev_offset; + GList *l; + + for (l = self->priv->offsets; l != NULL; l = l->next) + { + offset = l->data; + + offset_style_class = g_strconcat ("level-", offset->name, NULL); + gtk_style_context_remove_class (context, offset_style_class); + + /* find the right offset for our style class */ + if (((l->prev == NULL) && (value < offset->value)) || + ((l->next == NULL) && (value > offset->value))) + { + value_class = offset_style_class; + } + else if ((l->next != NULL) && (l->prev != NULL)) + { + prev_offset = l->prev->data; + if ((prev_offset->value <= value) && (value < offset->value)) + value_class = offset_style_class; + } + else + { + g_free (offset_style_class); + } + } + + if (value_class != NULL) + { + gtk_style_context_add_class (context, value_class); + g_free (value_class); + } +} + +static void +gtk_level_bar_ensure_offsets_in_range (GtkLevelBar *self) +{ + GtkLevelBarOffset *offset; + GList *l = self->priv->offsets; + + while (l != NULL) + { + offset = l->data; + l = l->next; + + if (offset->value < self->priv->min_value) + gtk_level_bar_ensure_offset (self, offset->name, self->priv->min_value); + else if (offset->value > self->priv->max_value) + gtk_level_bar_ensure_offset (self, offset->name, self->priv->max_value); + } +} + +#define OFFSETS_ELEMENT "offsets" +#define OFFSET_ELEMENT "offset" +#define OFFSET_NAME "name" +#define OFFSET_VALUE "value" + +typedef struct { + GtkLevelBar *self; + GList *offsets; +} OffsetsParserData; + +static void +offset_start_element (GMarkupParseContext *context, + const gchar *element_name, + const gchar **names, + const gchar **values, + gpointer user_data, + GError **error) +{ + OffsetsParserData *parser_data = user_data; + const gchar *name = NULL; + const gchar *value_str = NULL; + GtkLevelBarOffset *offset; + gint idx; + + if (strcmp (element_name, OFFSET_ELEMENT) == 0) + { + for (idx = 0; names[idx] != NULL; idx++) + { + if (strcmp (names[idx], OFFSET_NAME) == 0) + name = values[idx]; + else if (strcmp (names[idx], OFFSET_VALUE) == 0) + value_str = values[idx]; + } + + if (name && value_str) + { + offset = gtk_level_bar_offset_new (name, strtof (value_str, NULL)); + parser_data->offsets = g_list_prepend (parser_data->offsets, offset); + } + } + else if (strcmp (element_name, OFFSETS_ELEMENT) == 0) + { + return; + } + else + { + g_warning ("Unsupported type tag for GtkLevelBar: %s\n", + element_name); + } +} + +static const GMarkupParser offset_parser = +{ + offset_start_element +}; + +static gboolean +gtk_level_bar_buildable_custom_tag_start (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *tagname, + GMarkupParser *parser, + gpointer *data) +{ + OffsetsParserData *parser_data; + + if (child) + return FALSE; + + if (strcmp (tagname, OFFSETS_ELEMENT) != 0) + return FALSE; + + parser_data = g_slice_new0 (OffsetsParserData); + parser_data->self = GTK_LEVEL_BAR (buildable); + parser_data->offsets = NULL; + + *parser = offset_parser; + *data = parser_data; + + return TRUE; +} + +static void +gtk_level_bar_buildable_custom_finished (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *tagname, + gpointer user_data) +{ + OffsetsParserData *parser_data; + GtkLevelBar *self; + GtkLevelBarOffset *offset; + GList *l; + + if (strcmp (tagname, OFFSETS_ELEMENT) != 0) + return; + + parser_data = user_data; + self = parser_data->self; + + for (l = parser_data->offsets; l != NULL; l = l->next) + { + offset = l->data; + gtk_level_bar_add_offset_value (self, offset->name, offset->value); + } + + g_list_free_full (parser_data->offsets, (GDestroyNotify) gtk_level_bar_offset_free); + g_slice_free (OffsetsParserData, parser_data); +} + +static void +gtk_level_bar_buildable_init (GtkBuildableIface *iface) +{ + iface->custom_tag_start = gtk_level_bar_buildable_custom_tag_start; + iface->custom_finished = gtk_level_bar_buildable_custom_finished; +} + +static void +gtk_level_bar_set_orientation (GtkLevelBar *self, + GtkOrientation orientation) +{ + if (self->priv->orientation != orientation) + { + self->priv->orientation = orientation; + _gtk_orientable_set_style_classes (GTK_ORIENTABLE (self)); + + gtk_widget_queue_resize (GTK_WIDGET (self)); + } +} + +static void +gtk_level_bar_get_property (GObject *obj, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GtkLevelBar *self = GTK_LEVEL_BAR (obj); + + switch (property_id) + { + case PROP_VALUE: + g_value_set_double (value, gtk_level_bar_get_value (self)); + break; + case PROP_MIN_VALUE: + g_value_set_double (value, gtk_level_bar_get_min_value (self)); + break; + case PROP_MAX_VALUE: + g_value_set_double (value, gtk_level_bar_get_max_value (self)); + break; + case PROP_MODE: + g_value_set_enum (value, gtk_level_bar_get_mode (self)); + break; + case PROP_ORIENTATION: + g_value_set_enum (value, self->priv->orientation); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec); + break; + } +} + +static void +gtk_level_bar_set_property (GObject *obj, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkLevelBar *self = GTK_LEVEL_BAR (obj); + + switch (property_id) + { + case PROP_VALUE: + gtk_level_bar_set_value (self, g_value_get_double (value)); + break; + case PROP_MIN_VALUE: + gtk_level_bar_set_min_value (self, g_value_get_double (value)); + break; + case PROP_MAX_VALUE: + gtk_level_bar_set_max_value (self, g_value_get_double (value)); + break; + case PROP_MODE: + gtk_level_bar_set_mode (self, g_value_get_enum (value)); + break; + case PROP_ORIENTATION: + gtk_level_bar_set_orientation (self, g_value_get_enum (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec); + break; + } +} + +static void +gtk_level_bar_finalize (GObject *obj) +{ + GtkLevelBar *self = GTK_LEVEL_BAR (obj); + + g_list_free_full (self->priv->offsets, (GDestroyNotify) gtk_level_bar_offset_free); + + G_OBJECT_CLASS (gtk_level_bar_parent_class)->finalize (obj); +} + +static void +gtk_level_bar_class_init (GtkLevelBarClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass); + + oclass->get_property = gtk_level_bar_get_property; + oclass->set_property = gtk_level_bar_set_property; + oclass->finalize = gtk_level_bar_finalize; + + wclass->draw = gtk_level_bar_draw; + wclass->get_preferred_width = gtk_level_bar_get_preferred_width; + wclass->get_preferred_height = gtk_level_bar_get_preferred_height; + + g_object_class_override_property (oclass, PROP_ORIENTATION, "orientation"); + + signals[SIGNAL_OFFSET_CHANGED] = + g_signal_new ("offset-changed", + GTK_TYPE_LEVEL_BAR, + G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED, + G_STRUCT_OFFSET (GtkLevelBarClass, offset_changed), + NULL, NULL, + _gtk_marshal_VOID__STRING, + G_TYPE_NONE, + 1, G_TYPE_STRING); + + /** + * GtkLevelBar:value: + * + * The #GtkLevelBar:value property determines the currently + * filled value of the level bar. + * + * Since: 3.6 + */ + properties[PROP_VALUE] = + g_param_spec_double ("value", + P_("Currently filled value level"), + P_("Currently filled value level of the level bar"), + 0.0, G_MAXDOUBLE, 0.0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + /** + * GtkLevelBar:min-value: + * + * The #GtkLevelBar:min-value property determines the minimum value of + * the interval that can be displayed by the bar. + * + * Since: 3.6 + */ + properties[PROP_MIN_VALUE] = + g_param_spec_double ("min-value", + P_("Minimum value level for the bar"), + P_("Minimum value level that can be displayed by the bar"), + 0.0, G_MAXDOUBLE, 0.0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + /** + * GtkLevelBar:max-value: + * + * The #GtkLevelBar:max-value property determaxes the maximum value of + * the interval that can be displayed by the bar. + * + * Since: 3.6 + */ + properties[PROP_MAX_VALUE] = + g_param_spec_double ("max-value", + P_("Maximum value level for the bar"), + P_("Maximum value level that can be displayed by the bar"), + 0.0, G_MAXDOUBLE, 1.0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + /** + * GtkLevelBar:bar-mode: + * + * The #GtkLevelBar:bar-mode property determines the way #GtkLevelBar + * interprets the value properties to draw the level fill area. + * Specifically, when the value is #GTK_LEVEL_BAR_MODE_CONTINUOUS, + * #GtkLevelBar will draw a single block representing the current value in + * that area; when the value is #GTK_LEVEL_BAR_MODE_DISCRETE, + * the widget will draw a succession of separate blocks filling the + * draw area, with the number of blocks being equal to the units separating + * the integral roundings of #GtkLevelBar:min-value and #GtkLevelBar:max-value. + * + * Since: 3.6 + */ + properties[PROP_MODE] = + g_param_spec_enum ("mode", + P_("The mode of the value indicator"), + P_("The mode of the value indicator displayed by the bar"), + GTK_TYPE_LEVEL_BAR_MODE, + GTK_LEVEL_BAR_MODE_CONTINUOUS, + G_PARAM_READWRITE); + + gtk_widget_class_install_style_property + (wclass, g_param_spec_int ("min-block-height", + P_("Minimum height for filling blocks"), + P_("Minimum height for blocks that fill the bar"), + 1, G_MAXINT, DEFAULT_BLOCK_SIZE, + G_PARAM_READWRITE)); + gtk_widget_class_install_style_property + (wclass, g_param_spec_int ("min-block-width", + P_("Minimum width for filling blocks"), + P_("Minimum width for blocks that fill the bar"), + 1, G_MAXINT, DEFAULT_BLOCK_SIZE, + G_PARAM_READWRITE)); + + g_type_class_add_private (klass, sizeof (GtkLevelBarPrivate)); + g_object_class_install_properties (oclass, LAST_PROPERTY, properties); +} + +static void +gtk_level_bar_init (GtkLevelBar *self) +{ + GtkStyleContext *context; + + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTK_TYPE_LEVEL_BAR, GtkLevelBarPrivate); + + context = gtk_widget_get_style_context (GTK_WIDGET (self)); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEVEL_BAR); + + self->priv->cur_value = 0.0; + self->priv->min_value = 0.0; + self->priv->max_value = 1.0; + + gtk_level_bar_ensure_offset (self, GTK_LEVEL_BAR_OFFSET_LOW, 0.25); + gtk_level_bar_ensure_offset (self, GTK_LEVEL_BAR_OFFSET_HIGH, 0.75); + gtk_level_bar_update_level_style_classes (self); + + self->priv->bar_mode = GTK_LEVEL_BAR_MODE_CONTINUOUS; + gtk_level_bar_update_mode_style_classes (self); + + /* set initial orientation and style classes */ + self->priv->orientation = GTK_ORIENTATION_HORIZONTAL; + _gtk_orientable_set_style_classes (GTK_ORIENTABLE (self)); + + gtk_widget_set_has_window (GTK_WIDGET (self), FALSE); +} + +/** + * gtk_level_bar_new: + * + * Creates a new #GtkLevelBar. + * + * Returns: a #GtkLevelBar. + * + * Since: 3.6 + */ +GtkWidget * +gtk_level_bar_new (void) +{ + return g_object_new (GTK_TYPE_LEVEL_BAR, NULL); +} + +/** + * gtk_level_bar_new_for_interval: + * @min_value: a positive value + * @max_value: a positive value + * + * Utility constructor that creates a new #GtkLevelBar for the specified + * interval. + * + * Returns: a #GtkLevelBar + * + * Since: 3.6 + */ +GtkWidget * +gtk_level_bar_new_for_interval (gdouble min_value, + gdouble max_value) +{ + return g_object_new (GTK_TYPE_LEVEL_BAR, + "min-value", min_value, + "max-value", max_value, + NULL); +} + +/** + * gtk_level_bar_get_min_value: + * @self: a #GtkLevelBar + * + * Returns the value of the #GtkLevelBar:min-value property. + * + * Returns: a positive value + * + * Since: 3.6 + */ +gdouble +gtk_level_bar_get_min_value (GtkLevelBar *self) +{ + g_return_val_if_fail (GTK_IS_LEVEL_BAR (self), 0.0); + + return self->priv->min_value; +} + +/** + * gtk_level_bar_get_max_value: + * @self: a #GtkLevelBar + * + * Returns the value of the #GtkLevelBar:max-value property. + * + * Returns: a positive value + * + * Since: 3.6 + */ +gdouble +gtk_level_bar_get_max_value (GtkLevelBar *self) +{ + g_return_val_if_fail (GTK_IS_LEVEL_BAR (self), 0.0); + + return self->priv->max_value; +} + +/** + * gtk_level_bar_get_value: + * @self: a #GtkLevelBar + * + * Returns the value of the #GtkLevelBar:value property. + * + * Returns: a value in the interval between + * #GtkLevelBar:min-value and #GtkLevelBar:max-value + * + * Since: 3.6 + */ +gdouble +gtk_level_bar_get_value (GtkLevelBar *self) +{ + g_return_val_if_fail (GTK_IS_LEVEL_BAR (self), 0.0); + + return self->priv->cur_value; +} + +static void +gtk_level_bar_set_value_internal (GtkLevelBar *self, + gdouble value) +{ + self->priv->cur_value = value; + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VALUE]); + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + +/** + * gtk_level_bar_set_min_value: + * @self: a #GtkLevelBar + * @value: a positive value + * + * Sets the value of the #GtkLevelBar:min-value property. + * + * Since: 3.6 + */ +void +gtk_level_bar_set_min_value (GtkLevelBar *self, + gdouble value) +{ + g_return_if_fail (GTK_IS_LEVEL_BAR (self)); + g_return_if_fail (value >= 0.0); + + if (value != self->priv->min_value) + { + self->priv->min_value = value; + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MIN_VALUE]); + + if (self->priv->min_value > self->priv->cur_value) + gtk_level_bar_set_value_internal (self, self->priv->min_value); + + gtk_level_bar_update_level_style_classes (self); + } +} + +/** + * gtk_level_bar_set_max_value: + * @self: a #GtkLevelBar + * @value: a positive value + * + * Sets the value of the #GtkLevelBar:max-value property. + * + * Since: 3.6 + */ +void +gtk_level_bar_set_max_value (GtkLevelBar *self, + gdouble value) +{ + g_return_if_fail (GTK_IS_LEVEL_BAR (self)); + g_return_if_fail (value >= 0.0); + + if (value != self->priv->max_value) + { + self->priv->max_value = value; + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MAX_VALUE]); + + if (self->priv->max_value < self->priv->cur_value) + gtk_level_bar_set_value_internal (self, self->priv->max_value); + + gtk_level_bar_ensure_offsets_in_range (self); + gtk_level_bar_update_level_style_classes (self); + } +} + +/** + * gtk_level_bar_set_value: + * @self: a #GtkLevelBar + * @value: a value in the interval between + * #GtkLevelBar:min-value and #GtkLevelBar:max-value + * + * Sets the value of the #GtkLevelBar:value property. + * + * Since: 3.6 + */ +void +gtk_level_bar_set_value (GtkLevelBar *self, + gdouble value) +{ + g_return_if_fail (GTK_IS_LEVEL_BAR (self)); + + if (value != self->priv->cur_value) + { + gtk_level_bar_set_value_internal (self, value); + gtk_level_bar_update_level_style_classes (self); + } +} + +/** + * gtk_level_bar_get_mode: + * @self: a #GtkLevelBar + * + * Returns the value of the #GtkLevelBar:bar-mode property + * + * Returns: a #GtkLevelBarMode + * + * Since: 3.6 + */ +GtkLevelBarMode +gtk_level_bar_get_mode (GtkLevelBar *self) +{ + g_return_val_if_fail (GTK_IS_LEVEL_BAR (self), 0); + + return self->priv->bar_mode; +} + +/** + * gtk_level_bar_set_mode: + * @self: a #GtkLevelBar + * @mode: a #GtkLevelBarMode + * + * Sets the value of the #GtkLevelBar:bar-mode property + * + * Since: 3.6 + */ +void +gtk_level_bar_set_mode (GtkLevelBar *self, + GtkLevelBarMode mode) +{ + g_return_if_fail (GTK_IS_LEVEL_BAR (self)); + + if (self->priv->bar_mode != mode) + { + self->priv->bar_mode = mode; + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODE]); + + gtk_level_bar_update_mode_style_classes (self); + gtk_widget_queue_resize (GTK_WIDGET (self)); + } +} + +/** + * gtk_level_bar_remove_offset_value: + * @self: a #GtkLevelBar + * @name: (allow-none): the name of an offset in the bar + * + * Removes an offset marker previously added with + * gtk_level_bar_add_offset_value(). + * + * Since: 3.6 + */ +void +gtk_level_bar_remove_offset_value (GtkLevelBar *self, + const gchar *name) +{ + GList *existing; + + g_return_if_fail (GTK_IS_LEVEL_BAR (self)); + + existing = g_list_find_custom (self->priv->offsets, name, offset_find_func); + if (existing) + { + gtk_level_bar_offset_free (existing->data); + self->priv->offsets = g_list_delete_link (self->priv->offsets, existing); + + gtk_level_bar_update_level_style_classes (self); + } +} + +/** + * gtk_level_bar_add_offset_value: + * @self: a #GtkLevelBar + * @name: the name of the new offset + * @value: the value for the new offset + * + * Adds a new offset marker on @self at the position specified by @value. + * When the bar value is in the interval topped by @value (or between @value + * and #GtkLevelBar:max-value in case the offset is the last one on the bar) + * a style class named <literal>level-</literal>@name will be applied + * when rendering the level bar fill. + * If another offset marker named @name exists, its value will be + * replaced by @value. + * + * Since: 3.6 + */ +void +gtk_level_bar_add_offset_value (GtkLevelBar *self, + const gchar *name, + gdouble value) +{ + GQuark name_quark; + + g_return_if_fail (GTK_IS_LEVEL_BAR (self)); + g_return_if_fail (gtk_level_bar_value_in_interval (self, value)); + + if (!gtk_level_bar_ensure_offset (self, name, value)) + return; + + gtk_level_bar_update_level_style_classes (self); + name_quark = g_quark_from_string (name); + g_signal_emit (self, signals[SIGNAL_OFFSET_CHANGED], name_quark, name); +} + +/** + * gtk_level_bar_get_offset_value: + * @self: a #GtkLevelBar + * @name: (allow-none): the name of an offset in the bar + * + * Returns the value specified for the offset marker @name in @self, or + * zero if it's not found. + * + * Returns: a value in the interval between + * #GtkLevelBar:min-value and #GtkLevelBar:max-value, or zero. + * + * Since: 3.6 + */ +gdouble +gtk_level_bar_get_offset_value (GtkLevelBar *self, + const gchar *name) +{ + GList *existing; + GtkLevelBarOffset *offset = NULL; + + g_return_val_if_fail (GTK_IS_LEVEL_BAR (self), 0.0); + + existing = g_list_find_custom (self->priv->offsets, name, offset_find_func); + if (existing) + offset = existing->data; + + if (offset) + return offset->value; + + return 0.0; +} diff --git a/gtk/gtklevelbar.h b/gtk/gtklevelbar.h new file mode 100644 index 0000000000..5fcfa687ec --- /dev/null +++ b/gtk/gtklevelbar.h @@ -0,0 +1,111 @@ +/* GTK - The GIMP Toolkit + * Copyright © 2012 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/>. + * + * Author: Cosimo Cecchi <cosimoc@gnome.org> + * + */ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only <gtk/gtk.h> can be included directly." +#endif + +#ifndef __GTK_LEVEL_BAR_H__ +#define __GTK_LEVEL_BAR_H__ + +#include <gtk/gtkwidget.h> + +G_BEGIN_DECLS + +#define GTK_TYPE_LEVEL_BAR (gtk_level_bar_get_type ()) +#define GTK_LEVEL_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_LEVEL_BAR, GtkLevelBar)) +#define GTK_LEVEL_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_LEVEL_BAR, GtkLevelBarClass)) +#define GTK_IS_LEVEL_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_LEVEL_BAR)) +#define GTK_IS_LEVEL_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_LEVEL_BAR)) +#define GTK_LEVEL_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_LEVEL_BAR, GtkLevelBarClass)) + +#define GTK_LEVEL_BAR_OFFSET_LOW "low" +#define GTK_LEVEL_BAR_OFFSET_HIGH "high" + +typedef struct _GtkLevelBarClass GtkLevelBarClass; +typedef struct _GtkLevelBar GtkLevelBar; +typedef struct _GtkLevelBarPrivate GtkLevelBarPrivate; + +struct _GtkLevelBar { + /*< private >*/ + GtkWidget parent; + + GtkLevelBarPrivate *priv; +}; + +struct _GtkLevelBarClass { + /*< private >*/ + GtkWidgetClass parent_class; + + void (* offset_changed) (GtkLevelBar *self, + const gchar *name); + + /* padding for future class expansion */ + gpointer padding[16]; +}; + +GDK_AVAILABLE_IN_3_6 +GType gtk_level_bar_get_type (void) G_GNUC_CONST; + +GDK_AVAILABLE_IN_3_6 +GtkWidget *gtk_level_bar_new (void); + +GDK_AVAILABLE_IN_3_6 +GtkWidget *gtk_level_bar_new_for_interval (gdouble min_value, + gdouble max_value); + +GDK_AVAILABLE_IN_3_6 +void gtk_level_bar_set_mode (GtkLevelBar *self, + GtkLevelBarMode mode); +GDK_AVAILABLE_IN_3_6 +GtkLevelBarMode gtk_level_bar_get_mode (GtkLevelBar *self); + +GDK_AVAILABLE_IN_3_6 +void gtk_level_bar_set_value (GtkLevelBar *self, + gdouble value); +GDK_AVAILABLE_IN_3_6 +gdouble gtk_level_bar_get_value (GtkLevelBar *self); + +GDK_AVAILABLE_IN_3_6 +void gtk_level_bar_set_min_value (GtkLevelBar *self, + gdouble value); +GDK_AVAILABLE_IN_3_6 +gdouble gtk_level_bar_get_min_value (GtkLevelBar *self); + +GDK_AVAILABLE_IN_3_6 +void gtk_level_bar_set_max_value (GtkLevelBar *self, + gdouble value); +GDK_AVAILABLE_IN_3_6 +gdouble gtk_level_bar_get_max_value (GtkLevelBar *self); + +GDK_AVAILABLE_IN_3_6 +void gtk_level_bar_add_offset_value (GtkLevelBar *self, + const gchar *name, + gdouble value); +GDK_AVAILABLE_IN_3_6 +void gtk_level_bar_remove_offset_value (GtkLevelBar *self, + const gchar *name); +GDK_AVAILABLE_IN_3_6 +gdouble gtk_level_bar_get_offset_value (GtkLevelBar *self, + const gchar *name); + +G_END_DECLS + +#endif /* __GTK_LEVEL_BAR_H__ */ diff --git a/gtk/gtkstylecontext.h b/gtk/gtkstylecontext.h index 4975862f79..456b5a1026 100644 --- a/gtk/gtkstylecontext.h +++ b/gtk/gtkstylecontext.h @@ -691,6 +691,16 @@ struct _GtkStyleContextClass */ #define GTK_STYLE_CLASS_OSD "osd" +/** + * GTK_STYLE_CLASS_LEVEL_BAR: + * + * A CSS class used when rendering a level indicator, such + * as a battery charge level, or a password strength. + * + * This is used by #GtkLevelBar. + */ +#define GTK_STYLE_CLASS_LEVEL_BAR "level-bar" + /* Predefined set of widget regions */ /** |