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_VBOX)
24 static
void ygtk_steps_init (
YGtkSteps *steps)
26 gtk_box_set_spacing (GTK_BOX (steps), 8);
27 gtk_container_set_border_width (GTK_CONTAINER (steps), 4);
29 const gchar *check =
"\u2714", *current =
"\u25b6", *todo =
"\u26ab";
30 if (gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL)
32 PangoContext *context = gtk_widget_get_pango_context (GTK_WIDGET (steps));
33 steps->check_mark_layout = pango_layout_new (context);
34 steps->current_mark_layout = pango_layout_new (context);
35 steps->todo_mark_layout = pango_layout_new (context);
36 pango_layout_set_text (steps->check_mark_layout, check, -1);
37 pango_layout_set_text (steps->current_mark_layout, current, -1);
38 pango_layout_set_text (steps->todo_mark_layout, todo, -1);
39 steps->current_mark_timeout_id = steps->current_mark_frame = 0;
42 static void ygtk_steps_destroy (GtkWidget *widget)
45 if (steps->current_mark_timeout_id) {
46 g_source_remove (steps->current_mark_timeout_id);
47 steps->current_mark_timeout_id = 0;
49 if (steps->check_mark_layout)
50 g_object_unref (steps->check_mark_layout);
51 steps->check_mark_layout = NULL;
52 if (steps->current_mark_layout)
53 g_object_unref (steps->current_mark_layout);
54 if (steps->todo_mark_layout)
55 g_object_unref (steps->todo_mark_layout);
56 steps->todo_mark_layout = NULL;
58 GTK_WIDGET_CLASS (ygtk_steps_parent_class)->destroy(widget);
61 static void ygtk_step_update_layout (
YGtkSteps *steps, gint step)
64 gboolean bold = steps->current_step == step;
65 GList *children = gtk_container_get_children (GTK_CONTAINER (steps));
66 GtkWidget *label = (GtkWidget *) g_list_nth_data (children, step);
67 if (g_object_get_data (G_OBJECT (label),
"is-header"))
70 PangoAttrList *attrbs = pango_attr_list_new();
71 pango_attr_list_insert (attrbs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
72 gtk_label_set_attributes (GTK_LABEL (label), attrbs);
73 pango_attr_list_unref (attrbs);
74 atk_object_set_description (gtk_widget_get_accessible (label), _(
"Current step"));
77 gtk_label_set_attributes (GTK_LABEL (label), NULL);
78 atk_object_set_description (gtk_widget_get_accessible (label),
"");
80 g_list_free (children);
83 static gboolean ygtk_steps_draw (GtkWidget *widget, cairo_t *cr)
85 GTK_WIDGET_CLASS (ygtk_steps_parent_class)->draw(widget, cr);
88 gboolean reverse = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
89 GList *children = gtk_container_get_children (GTK_CONTAINER (widget)), *i;
91 cairo_set_source_rgb (cr, 0, 0, 0);
93 for (i = children; i; i = i->next, n++) {
94 GtkWidget *label = i->data;
96 gtk_widget_get_allocation(label, &alloc);
98 if (g_object_get_data (G_OBJECT (label),
"is-header"))
101 if (n < steps->current_step)
102 layout = steps->check_mark_layout;
103 else if (n == steps->current_step)
104 layout = steps->current_mark_layout;
106 layout = steps->todo_mark_layout;
107 int x = alloc.x, y = alloc.y;
110 pango_layout_get_pixel_extents (layout, NULL, &rect);
111 x += alloc.width - rect.width - 4;
115 if (n == steps->current_step) {
117 if (steps->current_mark_frame < CURRENT_MARK_FRAMES_NB/2)
118 offset = steps->current_mark_frame * CURRENT_MARK_ANIMATION_OFFSET;
120 offset = (CURRENT_MARK_FRAMES_NB - steps->current_mark_frame) *
121 CURRENT_MARK_ANIMATION_OFFSET;
122 x += offset * (reverse ? 1 : -1);
125 cairo_move_to (cr, x, y);
126 pango_cairo_show_layout (cr, layout);
128 g_list_free (children);
132 GtkWidget* ygtk_steps_new (
void)
134 return g_object_new (YGTK_TYPE_STEPS, NULL);
137 gint ygtk_steps_append (
YGtkSteps *steps,
const gchar *text)
139 GtkWidget *label = gtk_label_new (text);
140 GdkColor black = { 0, 0, 0, 0 };
141 gtk_widget_modify_fg (label, GTK_STATE_NORMAL, &black);
142 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
144 pango_layout_get_pixel_size (steps->check_mark_layout, &mark_width, NULL);
145 gtk_misc_set_padding (GTK_MISC (label), mark_width+12, 0);
146 gtk_widget_show (label);
147 gtk_box_pack_start (GTK_BOX (steps), label, FALSE, TRUE, 0);
148 return ygtk_steps_total (steps)-1;
151 void ygtk_steps_append_heading (
YGtkSteps *steps,
const gchar *heading)
153 GtkWidget *label = gtk_label_new (heading);
154 GdkColor black = { 0, 0, 0, 0 };
155 gtk_widget_modify_fg (label, GTK_STATE_NORMAL, &black);
156 g_object_set_data (G_OBJECT (label),
"is-header", GINT_TO_POINTER (1));
157 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
159 PangoAttrList *attrbs = pango_attr_list_new();
160 pango_attr_list_insert (attrbs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
161 pango_attr_list_insert (attrbs, pango_attr_scale_new (PANGO_SCALE_LARGE));
162 gtk_label_set_attributes (GTK_LABEL (label), attrbs);
163 pango_attr_list_unref (attrbs);
165 gtk_widget_show (label);
166 gtk_box_pack_start (GTK_BOX (steps), label, FALSE, TRUE, 6);
169 static gboolean current_mark_animation_cb (
void *steps_ptr)
174 gtk_widget_queue_draw (GTK_WIDGET (steps));
176 if (++steps->current_mark_frame == CURRENT_MARK_FRAMES_NB) {
177 steps->current_mark_frame = 0;
183 void ygtk_steps_set_current (
YGtkSteps *steps, gint step)
185 gint old_step = steps->current_step;
186 steps->current_step = step;
189 if (old_step != step) {
190 ygtk_step_update_layout (steps, old_step);
191 ygtk_step_update_layout (steps, step);
194 if (step != -1 && step != old_step) {
195 steps->current_mark_frame = 0;
196 steps->current_mark_timeout_id = g_timeout_add
197 (CURRENT_MARK_ANIMATION_TIME / CURRENT_MARK_FRAMES_NB,
198 current_mark_animation_cb, steps);
204 GList *children = gtk_container_get_children (GTK_CONTAINER (steps));
205 int steps_nb = g_list_length (children);
206 g_list_free (children);
210 const gchar *ygtk_steps_get_nth_label (
YGtkSteps *steps, gint n)
212 if (n < 0)
return NULL;
214 GList *children = gtk_container_get_children (GTK_CONTAINER (steps));
215 step = g_list_nth_data (children, n);
216 g_list_free (children);
218 return gtk_label_get_text (GTK_LABEL (step));
224 GList *children = gtk_container_get_children (GTK_CONTAINER (steps)), *i;
225 for (i = children; i; i = i->next)
226 gtk_container_remove (GTK_CONTAINER (steps), (GtkWidget *) i->data);
227 g_list_free (children);
232 ygtk_steps_parent_class = g_type_class_peek_parent (klass);
234 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass);
235 widget_class->draw = ygtk_steps_draw;
236 widget_class->destroy = ygtk_steps_destroy;