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);
145 gtk_widget_set_halign (label, GTK_ALIGN_START);
146 gtk_widget_set_valign (label, GTK_ALIGN_START);
149 pango_layout_get_pixel_size (steps->check_mark_layout, &mark_width, NULL);
152 gtk_widget_set_margin_start (label, mark_width+12);
153 gtk_widget_set_margin_end (label, mark_width+12);
154 gtk_widget_set_margin_top (label, 0);
155 gtk_widget_set_margin_bottom (label, 0);
157 gtk_widget_show (label);
158 gtk_box_pack_start (GTK_BOX (steps), label, FALSE, TRUE, 0);
159 return ygtk_steps_total (steps)-1;
162 void ygtk_steps_append_heading (
YGtkSteps *steps,
const gchar *heading)
164 GtkWidget *label = gtk_label_new (heading);
165 GdkRGBA black = { 0.0, 0.0, 0.0, 1.0 };
166 gtk_widget_override_color (label, GTK_STATE_NORMAL, &black);
167 g_object_set_data (G_OBJECT (label),
"is-header", GINT_TO_POINTER (1));
170 gtk_widget_set_halign (label, GTK_ALIGN_START);
171 gtk_widget_set_valign (label, GTK_ALIGN_START);
173 PangoAttrList *attrbs = pango_attr_list_new();
174 pango_attr_list_insert (attrbs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
175 pango_attr_list_insert (attrbs, pango_attr_scale_new (PANGO_SCALE_LARGE));
176 gtk_label_set_attributes (GTK_LABEL (label), attrbs);
177 pango_attr_list_unref (attrbs);
179 gtk_widget_show (label);
180 gtk_box_pack_start (GTK_BOX (steps), label, FALSE, TRUE, 6);
183 static gboolean current_mark_animation_cb (
void *steps_ptr)
188 gtk_widget_queue_draw (GTK_WIDGET (steps));
190 if (++steps->current_mark_frame == CURRENT_MARK_FRAMES_NB) {
191 steps->current_mark_frame = 0;
197 void ygtk_steps_set_current (
YGtkSteps *steps, gint step)
199 gint old_step = steps->current_step;
200 steps->current_step = step;
203 if (old_step != step) {
204 ygtk_step_update_layout (steps, old_step);
205 ygtk_step_update_layout (steps, step);
208 if (step != -1 && step != old_step) {
209 steps->current_mark_frame = 0;
210 steps->current_mark_timeout_id = g_timeout_add
211 (CURRENT_MARK_ANIMATION_TIME / CURRENT_MARK_FRAMES_NB,
212 current_mark_animation_cb, steps);
218 GList *children = gtk_container_get_children (GTK_CONTAINER (steps));
219 int steps_nb = g_list_length (children);
220 g_list_free (children);
224 const gchar *ygtk_steps_get_nth_label (
YGtkSteps *steps, gint n)
226 if (n < 0)
return NULL;
228 GList *children = gtk_container_get_children (GTK_CONTAINER (steps));
229 step = g_list_nth_data (children, n);
230 g_list_free (children);
232 return gtk_label_get_text (GTK_LABEL (step));
238 GList *children = gtk_container_get_children (GTK_CONTAINER (steps)), *i;
239 for (i = children; i; i = i->next)
240 gtk_container_remove (GTK_CONTAINER (steps), (GtkWidget *) i->data);
241 g_list_free (children);
246 ygtk_steps_parent_class = g_type_class_peek_parent (klass);
248 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass);
249 widget_class->draw = ygtk_steps_draw;
250 widget_class->destroy = ygtk_steps_destroy;