12 #include <yui/Libyui_config.h>
13 #include "ygtksteps.h"
18 #define CURRENT_MARK_ANIMATION_TIME 250
19 #define CURRENT_MARK_ANIMATION_OFFSET 3
20 #define CURRENT_MARK_FRAMES_NB (CURRENT_MARK_ANIMATION_OFFSET*2)
22 G_DEFINE_TYPE (
YGtkSteps, ygtk_steps, GTK_TYPE_BOX)
24 static void ygtk_steps_init (
YGtkSteps *steps)
26 gtk_box_set_spacing (GTK_BOX (steps), 8);
27 gtk_orientable_set_orientation (GTK_ORIENTABLE (steps), GTK_ORIENTATION_VERTICAL);
28 gtk_container_set_border_width (GTK_CONTAINER (steps), 4);
30 const gchar *check =
"\u2714", *current =
"\u25b6", *todo =
"\u26ab";
31 if (gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL)
33 PangoContext *context = gtk_widget_get_pango_context (GTK_WIDGET (steps));
34 steps->check_mark_layout = pango_layout_new (context);
35 steps->current_mark_layout = pango_layout_new (context);
36 steps->todo_mark_layout = pango_layout_new (context);
37 pango_layout_set_text (steps->check_mark_layout, check, -1);
38 pango_layout_set_text (steps->current_mark_layout, current, -1);
39 pango_layout_set_text (steps->todo_mark_layout, todo, -1);
40 steps->current_mark_timeout_id = steps->current_mark_frame = 0;
43 static void ygtk_steps_destroy (GtkWidget *widget)
46 if (steps->current_mark_timeout_id) {
47 g_source_remove (steps->current_mark_timeout_id);
48 steps->current_mark_timeout_id = 0;
50 if (steps->check_mark_layout)
51 g_object_unref (steps->check_mark_layout);
52 steps->check_mark_layout = NULL;
53 if (steps->current_mark_layout)
54 g_object_unref (steps->current_mark_layout);
55 if (steps->todo_mark_layout)
56 g_object_unref (steps->todo_mark_layout);
57 steps->todo_mark_layout = NULL;
59 GTK_WIDGET_CLASS (ygtk_steps_parent_class)->destroy(widget);
62 static void ygtk_step_update_layout (
YGtkSteps *steps, gint step)
65 gboolean bold = steps->current_step == step;
66 GList *children = gtk_container_get_children (GTK_CONTAINER (steps));
67 GtkWidget *label = (GtkWidget *) g_list_nth_data (children, step);
68 if (g_object_get_data (G_OBJECT (label),
"is-header"))
71 PangoAttrList *attrbs = pango_attr_list_new();
72 pango_attr_list_insert (attrbs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
73 gtk_label_set_attributes (GTK_LABEL (label), attrbs);
74 pango_attr_list_unref (attrbs);
75 atk_object_set_description (gtk_widget_get_accessible (label), _(
"Current step"));
78 gtk_label_set_attributes (GTK_LABEL (label), NULL);
79 atk_object_set_description (gtk_widget_get_accessible (label),
"");
81 g_list_free (children);
84 static gboolean ygtk_steps_draw (GtkWidget *widget, cairo_t *cr)
86 GTK_WIDGET_CLASS (ygtk_steps_parent_class)->draw(widget, cr);
89 gboolean reverse = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
90 GList *children = gtk_container_get_children (GTK_CONTAINER (widget)), *i;
92 cairo_set_source_rgb (cr, 0, 0, 0);
94 for (i = children; i; i = i->next, n++) {
95 GtkWidget *label = i->data;
97 gtk_widget_get_allocation(label, &alloc);
99 if (g_object_get_data (G_OBJECT (label),
"is-header"))
102 if (n < steps->current_step)
103 layout = steps->check_mark_layout;
104 else if (n == steps->current_step)
105 layout = steps->current_mark_layout;
107 layout = steps->todo_mark_layout;
108 int x = alloc.x, y = alloc.y;
111 pango_layout_get_pixel_extents (layout, NULL, &rect);
112 x += alloc.width - rect.width - 4;
116 if (n == steps->current_step) {
118 if (steps->current_mark_frame < CURRENT_MARK_FRAMES_NB/2)
119 offset = steps->current_mark_frame * CURRENT_MARK_ANIMATION_OFFSET;
121 offset = (CURRENT_MARK_FRAMES_NB - steps->current_mark_frame) *
122 CURRENT_MARK_ANIMATION_OFFSET;
123 x += offset * (reverse ? 1 : -1);
126 cairo_move_to (cr, x, y);
127 pango_cairo_show_layout (cr, layout);
129 g_list_free (children);
133 GtkWidget* ygtk_steps_new (
void)
135 return g_object_new (YGTK_TYPE_STEPS, NULL);
138 gint ygtk_steps_append (
YGtkSteps *steps,
const gchar *text)
140 GtkWidget *label = gtk_label_new (text);
141 GdkRGBA black = { 0.0, 0.0, 0.0, 1.0 };
142 gtk_widget_override_color (label, GTK_STATE_NORMAL, &black);
144 # if GTK_CHECK_VERSION (3, 14, 0)
145 gtk_widget_set_halign (label, GTK_ALIGN_START);
146 gtk_widget_set_valign (label, GTK_ALIGN_START);
148 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
152 pango_layout_get_pixel_size (steps->check_mark_layout, &mark_width, NULL);
154 # if GTK_CHECK_VERSION (3, 14, 0)
155 gtk_widget_set_margin_start (label, mark_width+12);
156 gtk_widget_set_margin_end (label, mark_width+12);
157 gtk_widget_set_margin_top (label, 0);
158 gtk_widget_set_margin_bottom (label, 0);
160 gtk_misc_set_padding (GTK_MISC (label), mark_width+12, 0);
163 gtk_widget_show (label);
164 gtk_box_pack_start (GTK_BOX (steps), label, FALSE, TRUE, 0);
165 return ygtk_steps_total (steps)-1;
168 void ygtk_steps_append_heading (
YGtkSteps *steps,
const gchar *heading)
170 GtkWidget *label = gtk_label_new (heading);
171 GdkRGBA black = { 0.0, 0.0, 0.0, 1.0 };
172 gtk_widget_override_color (label, GTK_STATE_NORMAL, &black);
173 g_object_set_data (G_OBJECT (label),
"is-header", GINT_TO_POINTER (1));
175 # if GTK_CHECK_VERSION (3, 14, 0)
176 gtk_widget_set_halign (label, GTK_ALIGN_START);
177 gtk_widget_set_valign (label, GTK_ALIGN_START);
179 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
182 PangoAttrList *attrbs = pango_attr_list_new();
183 pango_attr_list_insert (attrbs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
184 pango_attr_list_insert (attrbs, pango_attr_scale_new (PANGO_SCALE_LARGE));
185 gtk_label_set_attributes (GTK_LABEL (label), attrbs);
186 pango_attr_list_unref (attrbs);
188 gtk_widget_show (label);
189 gtk_box_pack_start (GTK_BOX (steps), label, FALSE, TRUE, 6);
192 static gboolean current_mark_animation_cb (
void *steps_ptr)
197 gtk_widget_queue_draw (GTK_WIDGET (steps));
199 if (++steps->current_mark_frame == CURRENT_MARK_FRAMES_NB) {
200 steps->current_mark_frame = 0;
206 void ygtk_steps_set_current (
YGtkSteps *steps, gint step)
208 gint old_step = steps->current_step;
209 steps->current_step = step;
212 if (old_step != step) {
213 ygtk_step_update_layout (steps, old_step);
214 ygtk_step_update_layout (steps, step);
217 if (step != -1 && step != old_step) {
218 steps->current_mark_frame = 0;
219 steps->current_mark_timeout_id = g_timeout_add
220 (CURRENT_MARK_ANIMATION_TIME / CURRENT_MARK_FRAMES_NB,
221 current_mark_animation_cb, steps);
227 GList *children = gtk_container_get_children (GTK_CONTAINER (steps));
228 int steps_nb = g_list_length (children);
229 g_list_free (children);
233 const gchar *ygtk_steps_get_nth_label (
YGtkSteps *steps, gint n)
235 if (n < 0)
return NULL;
237 GList *children = gtk_container_get_children (GTK_CONTAINER (steps));
238 step = g_list_nth_data (children, n);
239 g_list_free (children);
241 return gtk_label_get_text (GTK_LABEL (step));
247 GList *children = gtk_container_get_children (GTK_CONTAINER (steps)), *i;
248 for (i = children; i; i = i->next)
249 gtk_container_remove (GTK_CONTAINER (steps), (GtkWidget *) i->data);
250 g_list_free (children);
255 ygtk_steps_parent_class = g_type_class_peek_parent (klass);
257 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass);
258 widget_class->draw = ygtk_steps_draw;
259 widget_class->destroy = ygtk_steps_destroy;