Adding an example test program to check icon-lookup functionality. Doc updates.
[hildon] / src / hildon-weekday-picker.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2005, 2006 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; version 2.1 of
11  * the License.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 /**
26  * SECTION:hildon-weekday-picker
27  * @short_description: A widget for picking days on which a certain event 
28  * should take place.
29  * @see_also: #HildonWeekdayPicker 
30  *
31  * #HildonWeekdayPicker supports non-mutually exclusive selection of days of 
32  * the week. Selected days of the week are shown with a pushed-in effect.
33  * 
34  * #HildonWeekdayPicker is used where users are required to pick days on which 
35  * a certain event should take place, for example, which days a Calendar event 
36  * should be repeated on. It is used in Calendar in the Repeat dialog, in Tasks 
37  * in the Repeat dialog and in the Email set-up wizard.
38  * 
39  * <example>
40  * <title>HildonWeekdayPicker example</title>
41  * <programlisting>
42  * gint i;
43  * HildonWeekdayPicker *picker = hildon_weekday_picker_new ();
44  * <!-- -->
45  * hildon_weekday_picker_set_day (picker, i);
46  * hildon_weekday_picker_unset_day (picker, i);
47  * hildon_weekday_picker_toggle_day (picker, i);
48  * hildon_weekday_picker_set_all (picker);
49  * <!-- -->
50  * hildon_weekday_picker_unset_all( picker );
51  * </programlisting>
52  * </example>
53  *
54  */  
55  
56  /* GDate numbers days from 1 to 7 and G_DATE_MONDAY is 1st day. However
57     according to locale settings first day is sunday. To get around this
58     problem, we addjust GDate days numbering to be same as locale
59     numbering */
60
61 #ifdef                                          HAVE_CONFIG_H
62 #include                                        <config.h>
63 #endif
64
65 #include                                        "hildon-weekday-picker.h"
66 #include                                        <stdio.h>
67 #include                                        <stdarg.h>
68 #include                                        <sys/types.h>
69 #include                                        <unistd.h>
70 #include                                        <libintl.h>
71 #include                                        <langinfo.h>
72 #include                                        <time.h>
73 #include                                        <gtk/gtksignal.h>
74 #include                                        <gdk/gdkkeysyms.h>
75 #include                                        <gtk/gtktogglebutton.h>
76 #include                                        <gtk/gtksizegroup.h>
77 #include                                        <gtk/gtkwindow.h>
78 #include                                        "hildon-private.h"
79 #include                                        "hildon-weekday-picker-private.h"
80
81 static GtkContainerClass*                       parent_class;
82
83 static void
84 hildon_weekday_picker_class_init                (HildonWeekdayPickerClass *picker_class);
85
86 static void 
87 hildon_weekday_picker_init                      (HildonWeekdayPicker *picker);
88
89 static void
90 hildon_weekday_picker_size_allocate             (GtkWidget *widget,
91                                                  GtkAllocation *allocation);
92 static void
93 hildon_weekday_picker_size_request              (GtkWidget *widget,
94                                                  GtkRequisition *requisition);
95 static void
96 hildon_weekday_picker_forall                    (GtkContainer *container,
97                                                  gboolean include_internals,
98                                                  GtkCallback callback, 
99                                                  gpointer callback_data);
100
101 static void
102 hildon_weekday_picker_destroy                   (GtkObject *self);
103
104 static void
105 button_toggle                                   (GtkToggleButton *togglebutton, 
106                                                  gpointer wpicker);
107
108 enum 
109 {
110     SELECTION_CHANGED_SIGNAL,
111     LAST_SIGNAL
112 };
113
114 static guint                                    signals [LAST_SIGNAL] = { 0 } ;
115
116 /**
117  * hildon_weekday_picker_get_type:
118  *
119  * Initializes and returns the type of a hildon weekday picker.
120  *
121  * @Returns: GType of #HildonWeekdayPicker
122  */
123 GType G_GNUC_CONST
124 hildon_weekday_picker_get_type                  (void)
125 {
126     static GType picker_type = 0;
127
128     if (! picker_type) {
129         static const GTypeInfo picker_info = {
130             sizeof (HildonWeekdayPickerClass),
131             NULL,       /* base_init */
132             NULL,       /* base_finalize */
133             (GClassInitFunc) hildon_weekday_picker_class_init,
134             NULL,       /* class_finalize */
135             NULL,       /* class_data */
136             sizeof (HildonWeekdayPicker),
137             0,  /* n_preallocs */
138             (GInstanceInitFunc) hildon_weekday_picker_init,
139         };
140         picker_type = g_type_register_static (GTK_TYPE_CONTAINER,
141                 "HildonWeekdayPicker",
142                 &picker_info, 0);
143     }
144
145     return picker_type;
146 }
147
148 static void
149 hildon_weekday_picker_class_init                (HildonWeekdayPickerClass *picker_class)
150 {
151     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (picker_class);
152     GtkContainerClass *container_class = GTK_CONTAINER_CLASS (picker_class);
153     GObjectClass *object_class = G_OBJECT_CLASS (picker_class);
154
155     parent_class = g_type_class_peek_parent (picker_class);
156
157     g_type_class_add_private (picker_class,
158             sizeof (HildonWeekdayPickerPrivate));
159
160     /* Override virtual methods */
161     widget_class->size_request                  = hildon_weekday_picker_size_request;
162     widget_class->size_allocate                 = hildon_weekday_picker_size_allocate;
163     widget_class->focus                         = hildon_private_composite_focus;
164     container_class->forall                     = hildon_weekday_picker_forall;
165     GTK_OBJECT_CLASS (picker_class)->destroy    = hildon_weekday_picker_destroy;
166
167     /* Create a signal for reporting user actions */
168     signals [SELECTION_CHANGED_SIGNAL] = g_signal_new ("selection_changed",
169             G_OBJECT_CLASS_TYPE
170             (object_class),
171             G_SIGNAL_RUN_LAST |
172             G_SIGNAL_ACTION,
173             G_STRUCT_OFFSET (HildonWeekdayPickerClass, selection_changed), 
174             NULL, NULL,
175             gtk_marshal_VOID__INT,
176             G_TYPE_NONE, 1, G_TYPE_INT);
177 }
178
179 static void
180 hildon_weekday_picker_init                      (HildonWeekdayPicker *picker)
181 {
182     HildonWeekdayPickerPrivate *priv;
183     gint i, day;
184     
185     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
186     g_assert (priv);
187
188     /* weekday indexes to be used with nl_langinfo. These are shifted
189      * by one for glib compability */
190     int wdays[] = {
191         -1,        /* 0 = invalid date */
192         ABDAY_2,   /* 1 = monday    in glib */
193         ABDAY_3,   /* 2 = tuesday   in glib */
194         ABDAY_4,   /* 3 = wednesday in glib */
195         ABDAY_5,   /* 4 = thursday  in glib */
196         ABDAY_6,   /* 5 = friday    in glib */
197         ABDAY_7,   /* 6 = saturday  in glib */
198         ABDAY_1 }; /* 7 = sunday    in glib */
199     GtkSizeGroup *sgroup;
200
201     sgroup = gtk_size_group_new (GTK_SIZE_GROUP_BOTH);
202
203     /* Check our first weekday */
204     day = *nl_langinfo (_NL_TIME_FIRST_WEEKDAY); 
205
206
207     /* Shift the days by one. This is done because GDateWeekday 
208      * starts with Monday(1) and langinfo's first day is Sunday */
209     day--;
210
211     if (day < 1)
212         day = 7;
213
214     /* Initialize and pack day buttons */
215     for (i = 1; i <= 7; i++) {
216         priv->buttons [i] = 
217             gtk_toggle_button_new_with_label (nl_langinfo (wdays[day]));
218         priv->day_order_buttons [day] = priv->buttons [i];
219         day++;
220
221         if (day > 7)
222             day = 1;
223
224         g_signal_connect (GTK_WIDGET (priv->buttons [i]),
225                 "toggled", G_CALLBACK (button_toggle), picker);
226
227         gtk_size_group_add_widget (sgroup, priv->buttons [i]);
228
229         gtk_widget_set_parent (priv->buttons [i], GTK_WIDGET (picker));
230         gtk_widget_show (priv->buttons[i]);
231     }
232
233     GTK_WIDGET_SET_FLAGS (picker, GTK_NO_WINDOW);
234
235     g_object_unref (sgroup);
236 }
237
238 /**
239  * hildon_weekday_picker_new:
240  *
241  * Creates a new #HildonWeekdayPicker.
242  *
243  * Returns: pointer to a new #HildonWeekdayPicker widget.
244  */
245 GtkWidget*
246 hildon_weekday_picker_new                       (void)
247 {
248     return g_object_new (HILDON_TYPE_WEEKDAY_PICKER, NULL);
249 }
250
251 static void 
252 hildon_weekday_picker_forall                    (GtkContainer *container,
253                                                  gboolean include_internals, 
254                                                  GtkCallback callback,
255                                                  gpointer callback_data)
256 {
257     HildonWeekdayPicker *picker;
258     HildonWeekdayPickerPrivate *priv;
259     gint i;
260
261     g_assert (container);
262     g_assert (callback);
263
264     picker = HILDON_WEEKDAY_PICKER (container);
265     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
266     g_assert (priv);
267
268     /* We only have internal children */
269     if (! include_internals)
270         return;
271
272     /* Activate callback for each day button */
273     for (i = 1; i <= 7; ++i) {
274         (*callback) (priv->buttons [i], callback_data);
275     }
276 }
277
278 static void 
279 hildon_weekday_picker_destroy                   (GtkObject *self)
280 {
281     HildonWeekdayPickerPrivate *priv;
282     gint i;
283
284     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (self);
285     g_assert (priv);
286
287     /* Destroy internal children... */
288     for (i = 1; i <= 7; ++i) {
289         if (priv->buttons [i])
290         {
291             gtk_widget_unparent (priv->buttons [i]);
292             priv->buttons [i] = NULL;
293         }
294     }
295
296     /* ... and chain to parent. */
297     if (GTK_OBJECT_CLASS (parent_class)->destroy)
298         GTK_OBJECT_CLASS (parent_class)->destroy (self);
299
300 }
301
302 static void 
303 hildon_weekday_picker_size_request              (GtkWidget *widget,
304                                                  GtkRequisition *requisition)
305 {
306     HildonWeekdayPicker *picker;
307     HildonWeekdayPickerPrivate *priv;
308     gint i;
309     GtkRequisition req;
310
311     picker = HILDON_WEEKDAY_PICKER (widget);
312     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
313     g_assert (priv);
314
315     requisition->width = 0;
316     requisition->height = 0;
317
318     /* Request an area that is as wide as all of the buttons
319        together and tall enough to hold heightest button */
320     for (i = 1; i <= 7; ++i) {
321         gtk_widget_size_request (priv->buttons [i], &req);
322         requisition->width += req.width;
323         if (req.height > requisition->height)
324             requisition->height = req.height;
325
326     }
327 }
328
329 static void 
330 hildon_weekday_picker_size_allocate             (GtkWidget *widget,
331                                                  GtkAllocation *allocation)
332 {
333     HildonWeekdayPicker *picker;
334     HildonWeekdayPickerPrivate *priv;
335     gint i;
336     GtkAllocation alloc;
337     GtkRequisition child_requisition;
338     gint header_x;
339     guint sval;
340     GtkTextDirection direction;
341
342     g_assert (widget);
343     g_assert (allocation);
344
345     /* Check orientation */
346     direction = gtk_widget_get_direction (widget);
347
348     picker = HILDON_WEEKDAY_PICKER (widget);
349     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
350     g_assert (priv);
351
352     header_x = allocation->x;
353     widget->allocation = *allocation;
354
355     if (direction == GTK_TEXT_DIR_LTR || direction == GTK_TEXT_DIR_NONE)
356         sval = 1;
357     else
358         sval = 7;
359
360     /* Allocate day buttons side by side honouring the text direction */
361     for (i = 1; i <= 7; ++i) {
362         gtk_widget_get_child_requisition (priv->buttons[sval], &child_requisition);
363
364         alloc.x = header_x;
365         alloc.y = allocation->y;
366         alloc.width = child_requisition.width;
367         alloc.height = child_requisition.height;
368         header_x += alloc.width;
369         gtk_widget_size_allocate (priv->buttons [sval], &alloc);
370         if (direction == GTK_TEXT_DIR_RTL)
371             sval--;
372         else
373             sval++;
374     }
375 }
376
377 static void
378 button_toggle                                   (GtkToggleButton *button, 
379                                                  gpointer wpicker)
380 {
381     HildonWeekdayPicker *picker;
382     HildonWeekdayPickerPrivate *priv;
383     gint i;
384
385     g_assert(button);
386     g_assert(wpicker);
387
388     picker = HILDON_WEEKDAY_PICKER (wpicker);
389     g_assert (picker);
390     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
391     g_assert (priv);
392
393     for (i = 1; i <= 7; ++i) {
394         if (GTK_WIDGET (button) == priv->day_order_buttons [i]) {
395             g_signal_emit (GTK_WIDGET (picker), 
396                     signals [SELECTION_CHANGED_SIGNAL], 0, i);
397             break;
398         }
399     }
400 }
401
402 /**
403  * hildon_weekday_picker_set_day:
404  * @picker: the #HildonWeekdayPicker widget
405  * @day: day to be set active
406  *
407  * Sets specified weekday active.
408  */
409 void 
410 hildon_weekday_picker_set_day                   (HildonWeekdayPicker *picker,
411                                                  GDateWeekday day)
412 {
413     HildonWeekdayPickerPrivate *priv;
414
415     g_return_if_fail (HILDON_IS_WEEKDAY_PICKER (picker));
416     g_return_if_fail (g_date_valid_weekday(day));
417
418     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
419
420     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
421             (priv->day_order_buttons[day]), TRUE);
422 }
423
424 /**
425  * hildon_weekday_picker_unset_day:
426  * @picker: the #HildonWeekdayPicker widget
427  * @day: day to be set inactive 
428  *
429  * Unselect specified weekday.
430  */
431 void 
432 hildon_weekday_picker_unset_day                 (HildonWeekdayPicker *picker,
433                                                  GDateWeekday day)
434 {
435     HildonWeekdayPickerPrivate *priv;
436
437     g_return_if_fail (HILDON_IS_WEEKDAY_PICKER (picker));
438     g_return_if_fail (g_date_valid_weekday (day));
439
440     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
441     g_assert (priv);
442
443     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
444             (priv->day_order_buttons [day]), FALSE);
445 }
446
447 /**
448  * hildon_weekday_picker_toggle_day:
449  * @picker: the #HildonWeekdayPicker widget
450  * @day: day to be toggled
451  *
452  * Toggles current status of the specified weekday.
453  */
454 void 
455 hildon_weekday_picker_toggle_day                (HildonWeekdayPicker *picker,
456                                                  GDateWeekday day)
457 {
458     HildonWeekdayPickerPrivate *priv;
459     
460     g_return_if_fail (HILDON_IS_WEEKDAY_PICKER (picker));
461     g_return_if_fail (g_date_valid_weekday (day));
462
463     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
464     g_assert (priv);
465
466     gtk_toggle_button_set_active (
467             GTK_TOGGLE_BUTTON (priv->day_order_buttons [day]), 
468             ! gtk_toggle_button_get_active(
469                 GTK_TOGGLE_BUTTON (priv->day_order_buttons[day])));
470 }
471
472 /**
473  * hildon_weekday_picker_set_all:
474  * @picker: the #HildonWeekdayPicker widget
475  *
476  * Sets all weekdays active.
477  */
478 void 
479 hildon_weekday_picker_set_all                   (HildonWeekdayPicker *picker)
480 {
481     HildonWeekdayPickerPrivate *priv;
482     gint i;
483
484     g_return_if_fail (HILDON_IS_WEEKDAY_PICKER (picker));
485
486     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
487     g_assert (priv);
488
489     for (i = 1; i <= 7; i++)
490         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->buttons [i]), TRUE);
491 }
492
493 /**
494  * hildon_weekday_picker_unset_all:
495  * @picker: the #HildonWeekdayPicker widget
496  *
497  * Sets all weekdays inactive.
498  */
499 void 
500 hildon_weekday_picker_unset_all                 (HildonWeekdayPicker *picker)
501 {
502     HildonWeekdayPickerPrivate *priv;
503     gint i;
504
505     g_return_if_fail (HILDON_IS_WEEKDAY_PICKER (picker));
506
507     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
508     g_assert (priv);
509
510     for (i = 1; i <= 7; i++)
511         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->buttons [i]), FALSE);
512 }
513
514 /**
515  * hildon_weekday_picker_isset_day:
516  * @picker: the #HildonWeekdayPicker widget
517  * @day: day to be checked.
518  *
519  * Checks if the specified weekday is set active.
520  *
521  * Returns: TRUE if the day is set, FALSE if the day is not set
522  */
523 gboolean 
524 hildon_weekday_picker_isset_day                 (HildonWeekdayPicker *picker,
525                                                  GDateWeekday day)
526 {
527     HildonWeekdayPickerPrivate *priv;
528
529     g_return_val_if_fail (HILDON_IS_WEEKDAY_PICKER (picker), FALSE);
530     g_return_val_if_fail (g_date_valid_weekday (day), FALSE);
531
532     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
533     g_assert (picker);
534
535     return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->day_order_buttons[day]));
536 }
537