Fix compilation warnings
[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: Rodrigo Novo <rodrigo.novo@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, or (at your option) any later version.
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 #undef                                          HILDON_DISABLE_DEPRECATED
62
63 #ifdef                                          HAVE_CONFIG_H
64 #include                                        <config.h>
65 #endif
66
67 #include                                        <stdio.h>
68 #include                                        <stdarg.h>
69 #include                                        <sys/types.h>
70 #include                                        <unistd.h>
71 #include                                        <libintl.h>
72 #include                                        <langinfo.h>
73 #include                                        <time.h>
74 #include                                        <gdk/gdkkeysyms.h>
75
76 #include                                        "hildon-weekday-picker.h"
77 #include                                        "hildon-private.h"
78 #include                                        "hildon-weekday-picker-private.h"
79
80 static GtkContainerClass*                       parent_class;
81
82 static void
83 hildon_weekday_picker_class_init                (HildonWeekdayPickerClass *picker_class);
84
85 static void 
86 hildon_weekday_picker_init                      (HildonWeekdayPicker *picker);
87
88 static void
89 hildon_weekday_picker_size_allocate             (GtkWidget *widget,
90                                                  GtkAllocation *allocation);
91 static gboolean
92 hildon_weekday_picker_focus                     (GtkWidget *widget,
93                                                  GtkDirectionType direction);
94 static void
95 hildon_weekday_picker_size_request              (GtkWidget *widget,
96                                                  GtkRequisition *requisition);
97 static void
98 hildon_weekday_picker_forall                    (GtkContainer *container,
99                                                  gboolean include_internals,
100                                                  GtkCallback callback, 
101                                                  gpointer callback_data);
102
103 static void
104 hildon_weekday_picker_destroy                   (GtkObject *self);
105
106 static void
107 button_toggle                                   (GtkToggleButton *togglebutton, 
108                                                  gpointer wpicker);
109
110 enum 
111 {
112     SELECTION_CHANGED_SIGNAL,
113     LAST_SIGNAL
114 };
115
116 static guint                                    signals [LAST_SIGNAL] = { 0 } ;
117
118 /**
119  * hildon_weekday_picker_get_type:
120  *
121  * Initializes and returns the type of a hildon weekday picker.
122  *
123  * Returns: GType of #HildonWeekdayPicker
124  */
125 GType G_GNUC_CONST
126 hildon_weekday_picker_get_type                  (void)
127 {
128     static GType picker_type = 0;
129
130     if (! picker_type) {
131         static const GTypeInfo picker_info = {
132             sizeof (HildonWeekdayPickerClass),
133             NULL,       /* base_init */
134             NULL,       /* base_finalize */
135             (GClassInitFunc) hildon_weekday_picker_class_init,
136             NULL,       /* class_finalize */
137             NULL,       /* class_data */
138             sizeof (HildonWeekdayPicker),
139             0,  /* n_preallocs */
140             (GInstanceInitFunc) hildon_weekday_picker_init,
141         };
142         picker_type = g_type_register_static (GTK_TYPE_CONTAINER,
143                 "HildonWeekdayPicker",
144                 &picker_info, 0);
145     }
146
147     return picker_type;
148 }
149
150 static void
151 hildon_weekday_picker_class_init                (HildonWeekdayPickerClass *picker_class)
152 {
153     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (picker_class);
154     GtkContainerClass *container_class = GTK_CONTAINER_CLASS (picker_class);
155     GObjectClass *object_class = G_OBJECT_CLASS (picker_class);
156
157     parent_class = g_type_class_peek_parent (picker_class);
158
159     g_type_class_add_private (picker_class,
160             sizeof (HildonWeekdayPickerPrivate));
161
162     /* Override virtual methods */
163     widget_class->size_request                  = hildon_weekday_picker_size_request;
164     widget_class->size_allocate                 = hildon_weekday_picker_size_allocate;
165     widget_class->focus                         = hildon_weekday_picker_focus;
166     container_class->forall                     = hildon_weekday_picker_forall;
167     GTK_OBJECT_CLASS (picker_class)->destroy    = hildon_weekday_picker_destroy;
168
169     /* Create a signal for reporting user actions */
170     signals [SELECTION_CHANGED_SIGNAL] = g_signal_new ("selection_changed",
171             G_OBJECT_CLASS_TYPE
172             (object_class),
173             G_SIGNAL_RUN_LAST |
174             G_SIGNAL_ACTION,
175             G_STRUCT_OFFSET (HildonWeekdayPickerClass, selection_changed), 
176             NULL, NULL,
177             g_cclosure_marshal_VOID__INT,
178             G_TYPE_NONE, 1, G_TYPE_INT);
179 }
180
181 static void
182 hildon_weekday_picker_init                      (HildonWeekdayPicker *picker)
183 {
184     HildonWeekdayPickerPrivate *priv;
185     gint i, day;
186     
187     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
188     g_assert (priv);
189
190     /* weekday indexes to be used with nl_langinfo. These are shifted
191      * by one for glib compability */
192     int wdays[] = {
193         -1,        /* 0 = invalid date */
194         ABDAY_2,   /* 1 = monday    in glib */
195         ABDAY_3,   /* 2 = tuesday   in glib */
196         ABDAY_4,   /* 3 = wednesday in glib */
197         ABDAY_5,   /* 4 = thursday  in glib */
198         ABDAY_6,   /* 5 = friday    in glib */
199         ABDAY_7,   /* 6 = saturday  in glib */
200         ABDAY_1 }; /* 7 = sunday    in glib */
201     GtkSizeGroup *sgroup;
202
203     sgroup = gtk_size_group_new (GTK_SIZE_GROUP_BOTH);
204
205     /* Check our first weekday */
206     day = *nl_langinfo (_NL_TIME_FIRST_WEEKDAY); 
207
208
209     /* Shift the days by one. This is done because GDateWeekday 
210      * starts with Monday(1) and langinfo's first day is Sunday */
211     day--;
212
213     if (day < 1)
214         day = 7;
215
216     /* Initialize and pack day buttons */
217     for (i = 1; i <= 7; i++) {
218         priv->buttons [i] = 
219             gtk_toggle_button_new_with_label (nl_langinfo (wdays[day]));
220         priv->day_order_buttons [day] = priv->buttons [i];
221         day++;
222
223         if (day > 7)
224             day = 1;
225
226         g_signal_connect (GTK_WIDGET (priv->buttons [i]),
227                 "toggled", G_CALLBACK (button_toggle), picker);
228
229         gtk_size_group_add_widget (sgroup, priv->buttons [i]);
230
231         gtk_widget_set_parent (priv->buttons [i], GTK_WIDGET (picker));
232         gtk_widget_show (priv->buttons[i]);
233     }
234
235     GTK_WIDGET_SET_FLAGS (picker, GTK_NO_WINDOW);
236
237     g_object_unref (sgroup);
238 }
239
240 /**
241  * hildon_weekday_picker_new:
242  *
243  * Creates a new #HildonWeekdayPicker.
244  *
245  * Returns: pointer to a new #HildonWeekdayPicker widget.
246  */
247 GtkWidget*
248 hildon_weekday_picker_new                       (void)
249 {
250     return g_object_new (HILDON_TYPE_WEEKDAY_PICKER, NULL);
251 }
252
253 static void 
254 hildon_weekday_picker_forall                    (GtkContainer *container,
255                                                  gboolean include_internals, 
256                                                  GtkCallback callback,
257                                                  gpointer callback_data)
258 {
259     HildonWeekdayPicker *picker;
260     HildonWeekdayPickerPrivate *priv;
261     gint i;
262
263     g_assert (container);
264     g_assert (callback);
265
266     picker = HILDON_WEEKDAY_PICKER (container);
267     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
268     g_assert (priv);
269
270     /* We only have internal children */
271     if (! include_internals)
272         return;
273
274     /* Activate callback for each day button */
275     for (i = 1; i <= 7; ++i) {
276         (*callback) (priv->buttons [i], callback_data);
277     }
278 }
279
280 static void 
281 hildon_weekday_picker_destroy                   (GtkObject *self)
282 {
283     HildonWeekdayPickerPrivate *priv;
284     gint i;
285
286     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (self);
287     g_assert (priv);
288
289     /* Destroy internal children... */
290     for (i = 1; i <= 7; ++i) {
291         if (priv->buttons [i])
292         {
293             gtk_widget_unparent (priv->buttons [i]);
294             priv->buttons [i] = NULL;
295         }
296     }
297
298     /* ... and chain to parent. */
299     if (GTK_OBJECT_CLASS (parent_class)->destroy)
300         GTK_OBJECT_CLASS (parent_class)->destroy (self);
301
302 }
303
304 static void 
305 hildon_weekday_picker_size_request              (GtkWidget *widget,
306                                                  GtkRequisition *requisition)
307 {
308     HildonWeekdayPicker *picker;
309     HildonWeekdayPickerPrivate *priv;
310     gint i;
311     GtkRequisition req;
312
313     picker = HILDON_WEEKDAY_PICKER (widget);
314     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
315     g_assert (priv);
316
317     requisition->width = 0;
318     requisition->height = 0;
319
320     /* Request an area that is as wide as all of the buttons
321        together and tall enough to hold heightest button */
322     for (i = 1; i <= 7; ++i) {
323         gtk_widget_size_request (priv->buttons [i], &req);
324         requisition->width += req.width;
325         if (req.height > requisition->height)
326             requisition->height = req.height;
327
328     }
329 }
330
331 static void 
332 hildon_weekday_picker_size_allocate             (GtkWidget *widget,
333                                                  GtkAllocation *allocation)
334 {
335     HildonWeekdayPicker *picker;
336     HildonWeekdayPickerPrivate *priv;
337     gint i;
338     GtkAllocation alloc;
339     GtkRequisition child_requisition;
340     gint header_x;
341     guint sval;
342     GtkTextDirection direction;
343
344     g_assert (widget);
345     g_assert (allocation);
346
347     /* Check orientation */
348     direction = gtk_widget_get_direction (widget);
349
350     picker = HILDON_WEEKDAY_PICKER (widget);
351     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
352     g_assert (priv);
353
354     header_x = allocation->x;
355     widget->allocation = *allocation;
356
357     if (direction == GTK_TEXT_DIR_LTR || direction == GTK_TEXT_DIR_NONE)
358         sval = 1;
359     else
360         sval = 7;
361
362     /* Allocate day buttons side by side honouring the text direction */
363     for (i = 1; i <= 7; ++i) {
364         gtk_widget_get_child_requisition (priv->buttons[sval], &child_requisition);
365
366         alloc.x = header_x;
367         alloc.y = allocation->y;
368         alloc.width = child_requisition.width;
369         alloc.height = child_requisition.height;
370         header_x += alloc.width;
371         gtk_widget_size_allocate (priv->buttons [sval], &alloc);
372         if (direction == GTK_TEXT_DIR_RTL)
373             sval--;
374         else
375             sval++;
376     }
377 }
378
379 static gboolean
380 hildon_weekday_picker_focus                      (GtkWidget *widget,
381                                                   GtkDirectionType direction)
382 {
383   gboolean retval;
384   GtkDirectionType effective_direction;
385
386   g_assert (HILDON_IS_WEEKDAY_PICKER (widget));
387
388   retval = hildon_private_composite_focus (widget, direction, &effective_direction);
389
390   if (retval == TRUE)
391     return GTK_WIDGET_CLASS (parent_class)->focus (widget, effective_direction);
392   else
393     return FALSE;
394 }
395
396 static void
397 button_toggle                                   (GtkToggleButton *button, 
398                                                  gpointer wpicker)
399 {
400     HildonWeekdayPicker *picker;
401     HildonWeekdayPickerPrivate *priv;
402     gint i;
403
404     g_assert(button);
405     g_assert(wpicker);
406
407     picker = HILDON_WEEKDAY_PICKER (wpicker);
408     g_assert (picker);
409     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
410     g_assert (priv);
411
412     for (i = 1; i <= 7; ++i) {
413         if (GTK_WIDGET (button) == priv->day_order_buttons [i]) {
414             g_signal_emit (GTK_WIDGET (picker), 
415                     signals [SELECTION_CHANGED_SIGNAL], 0, i);
416             break;
417         }
418     }
419 }
420
421 /**
422  * hildon_weekday_picker_set_day:
423  * @picker: the #HildonWeekdayPicker widget
424  * @day: day to be set active
425  *
426  * Sets specified weekday active.
427  */
428 void 
429 hildon_weekday_picker_set_day                   (HildonWeekdayPicker *picker,
430                                                  GDateWeekday day)
431 {
432     HildonWeekdayPickerPrivate *priv;
433
434     g_return_if_fail (HILDON_IS_WEEKDAY_PICKER (picker));
435     g_return_if_fail (g_date_valid_weekday(day));
436
437     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
438
439     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
440             (priv->day_order_buttons[day]), TRUE);
441 }
442
443 /**
444  * hildon_weekday_picker_unset_day:
445  * @picker: the #HildonWeekdayPicker widget
446  * @day: day to be set inactive 
447  *
448  * Unselect specified weekday.
449  */
450 void 
451 hildon_weekday_picker_unset_day                 (HildonWeekdayPicker *picker,
452                                                  GDateWeekday day)
453 {
454     HildonWeekdayPickerPrivate *priv;
455
456     g_return_if_fail (HILDON_IS_WEEKDAY_PICKER (picker));
457     g_return_if_fail (g_date_valid_weekday (day));
458
459     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
460     g_assert (priv);
461
462     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
463             (priv->day_order_buttons [day]), FALSE);
464 }
465
466 /**
467  * hildon_weekday_picker_toggle_day:
468  * @picker: the #HildonWeekdayPicker widget
469  * @day: day to be toggled
470  *
471  * Toggles current status of the specified weekday.
472  */
473 void 
474 hildon_weekday_picker_toggle_day                (HildonWeekdayPicker *picker,
475                                                  GDateWeekday day)
476 {
477     HildonWeekdayPickerPrivate *priv;
478     
479     g_return_if_fail (HILDON_IS_WEEKDAY_PICKER (picker));
480     g_return_if_fail (g_date_valid_weekday (day));
481
482     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
483     g_assert (priv);
484
485     gtk_toggle_button_set_active (
486             GTK_TOGGLE_BUTTON (priv->day_order_buttons [day]), 
487             ! gtk_toggle_button_get_active(
488                 GTK_TOGGLE_BUTTON (priv->day_order_buttons[day])));
489 }
490
491 /**
492  * hildon_weekday_picker_set_all:
493  * @picker: the #HildonWeekdayPicker widget
494  *
495  * Sets all weekdays active.
496  */
497 void 
498 hildon_weekday_picker_set_all                   (HildonWeekdayPicker *picker)
499 {
500     HildonWeekdayPickerPrivate *priv;
501     gint i;
502
503     g_return_if_fail (HILDON_IS_WEEKDAY_PICKER (picker));
504
505     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
506     g_assert (priv);
507
508     for (i = 1; i <= 7; i++)
509         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->buttons [i]), TRUE);
510 }
511
512 /**
513  * hildon_weekday_picker_unset_all:
514  * @picker: the #HildonWeekdayPicker widget
515  *
516  * Sets all weekdays inactive.
517  */
518 void 
519 hildon_weekday_picker_unset_all                 (HildonWeekdayPicker *picker)
520 {
521     HildonWeekdayPickerPrivate *priv;
522     gint i;
523
524     g_return_if_fail (HILDON_IS_WEEKDAY_PICKER (picker));
525
526     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
527     g_assert (priv);
528
529     for (i = 1; i <= 7; i++)
530         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->buttons [i]), FALSE);
531 }
532
533 /**
534  * hildon_weekday_picker_isset_day:
535  * @picker: the #HildonWeekdayPicker widget
536  * @day: day to be checked.
537  *
538  * Checks if the specified weekday is set active.
539  *
540  * Returns: TRUE if the day is set, FALSE if the day is not set
541  */
542 gboolean 
543 hildon_weekday_picker_isset_day                 (HildonWeekdayPicker *picker,
544                                                  GDateWeekday day)
545 {
546     HildonWeekdayPickerPrivate *priv;
547
548     g_return_val_if_fail (HILDON_IS_WEEKDAY_PICKER (picker), FALSE);
549     g_return_val_if_fail (g_date_valid_weekday (day), FALSE);
550
551     priv = HILDON_WEEKDAY_PICKER_GET_PRIVATE (picker);
552     g_assert (picker);
553
554     return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->day_order_buttons[day]));
555 }
556