4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 #include "evolution-config.h"
23 #include <glib/gi18n-lib.h>
24 #include <gdk/gdkkeysyms.h>
26 #include <libgnomecanvas/libgnomecanvas.h>
27 #include <e-util/e-util.h>
29 #include "e-weekday-chooser.h"
33 #define E_WEEKDAY_CHOOSER_GET_PRIVATE(obj) \
34 (G_TYPE_INSTANCE_GET_PRIVATE \
35 ((obj), E_TYPE_WEEKDAY_CHOOSER, EWeekdayChooserPrivate))
37 /* Private part of the EWeekdayChooser structure */
38 struct _EWeekdayChooserPrivate
{
39 gboolean blocked_weekdays
[8]; /* indexed by GDateWeekday */
40 gboolean selected_weekdays
[8]; /* indexed by GDateWeekday */
42 /* Day that defines the start of the week. */
43 GDateWeekday week_start_day
;
45 /* Current keyboard focus day */
46 GDateWeekday focus_day
;
49 gint font_ascent
, font_descent
;
50 gint max_letter_width
;
53 GnomeCanvasItem
*boxes
[7];
54 GnomeCanvasItem
*labels
[7];
67 static guint chooser_signals
[LAST_SIGNAL
];
69 G_DEFINE_TYPE_WITH_CODE (
73 G_IMPLEMENT_INTERFACE (
74 E_TYPE_EXTENSIBLE
, NULL
))
77 colorize_items (EWeekdayChooser
*chooser
)
79 GdkColor outline
, focus_outline
;
80 GdkColor fill
, sel_fill
;
81 GdkColor text_fill
, sel_text_fill
;
86 widget
= GTK_WIDGET (chooser
);
88 e_utils_get_theme_color_color (widget
, "theme_base_color", E_UTILS_DEFAULT_THEME_BASE_COLOR
, &outline
);
89 e_utils_get_theme_color_color (widget
, "theme_bg_color", E_UTILS_DEFAULT_THEME_BG_COLOR
, &focus_outline
);
90 e_utils_get_theme_color_color (widget
, "theme_base_color", E_UTILS_DEFAULT_THEME_BASE_COLOR
, &fill
);
91 e_utils_get_theme_color_color (widget
, "theme_fg_color", E_UTILS_DEFAULT_THEME_FG_COLOR
, &text_fill
);
92 e_utils_get_theme_color_color (widget
, "theme_selected_bg_color", E_UTILS_DEFAULT_THEME_SELECTED_BG_COLOR
, &sel_fill
);
93 e_utils_get_theme_color_color (widget
, "theme_selected_fg_color", E_UTILS_DEFAULT_THEME_SELECTED_FG_COLOR
, &sel_text_fill
);
95 weekday
= e_weekday_chooser_get_week_start_day (chooser
);
97 for (ii
= 0; ii
< 7; ii
++) {
100 if (chooser
->priv
->selected_weekdays
[weekday
]) {
108 if (weekday
== chooser
->priv
->focus_day
)
113 gnome_canvas_item_set (
114 chooser
->priv
->boxes
[ii
],
116 "outline_color_gdk", o
,
119 gnome_canvas_item_set (
120 chooser
->priv
->labels
[ii
],
124 weekday
= e_weekday_get_next (weekday
);
129 configure_items (EWeekdayChooser
*chooser
)
131 GtkAllocation allocation
;
134 GDateWeekday weekday
;
137 gtk_widget_get_allocation (GTK_WIDGET (chooser
), &allocation
);
139 width
= allocation
.width
;
140 height
= allocation
.height
;
142 box_width
= (width
- 1) / 7;
144 weekday
= e_weekday_chooser_get_week_start_day (chooser
);
146 for (ii
= 0; ii
< 7; ii
++) {
147 gnome_canvas_item_set (
148 chooser
->priv
->boxes
[ii
],
149 "x1", (gdouble
) (ii
* box_width
),
151 "x2", (gdouble
) ((ii
+ 1) * box_width
),
152 "y2", (gdouble
) (height
- 1),
156 gnome_canvas_item_set (
157 chooser
->priv
->labels
[ii
],
158 "text", e_get_weekday_name (weekday
, TRUE
),
159 "x", (gdouble
) (ii
* box_width
) + PADDING
,
160 "y", (gdouble
) (1 + PADDING
),
163 weekday
= e_weekday_get_next (weekday
);
166 colorize_items (chooser
);
170 weekday_chooser_set_property (GObject
*object
,
175 switch (property_id
) {
176 case PROP_WEEK_START_DAY
:
177 e_weekday_chooser_set_week_start_day (
178 E_WEEKDAY_CHOOSER (object
),
179 g_value_get_enum (value
));
183 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
187 weekday_chooser_get_property (GObject
*object
,
192 switch (property_id
) {
193 case PROP_WEEK_START_DAY
:
196 e_weekday_chooser_get_week_start_day (
197 E_WEEKDAY_CHOOSER (object
)));
201 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
205 weekday_chooser_constructed (GObject
*object
)
207 /* Chain up to parent's constructed() method. */
208 G_OBJECT_CLASS (e_weekday_chooser_parent_class
)->constructed (object
);
210 e_extensible_load_extensions (E_EXTENSIBLE (object
));
214 weekday_chooser_realize (GtkWidget
*widget
)
216 EWeekdayChooser
*chooser
;
218 chooser
= E_WEEKDAY_CHOOSER (widget
);
220 /* Chain up to parent's realize() method. */
221 GTK_WIDGET_CLASS (e_weekday_chooser_parent_class
)->realize (widget
);
223 configure_items (chooser
);
227 weekday_chooser_size_allocate (GtkWidget
*widget
,
228 GtkAllocation
*allocation
)
230 GtkWidgetClass
*widget_class
;
231 EWeekdayChooser
*chooser
;
233 chooser
= E_WEEKDAY_CHOOSER (widget
);
235 /* Chain up to parent's size_allocate() method. */
236 widget_class
= GTK_WIDGET_CLASS (e_weekday_chooser_parent_class
);
237 widget_class
->size_allocate (widget
, allocation
);
239 gnome_canvas_set_scroll_region (
240 GNOME_CANVAS (chooser
), 0, 0,
241 allocation
->width
, allocation
->height
);
243 configure_items (chooser
);
247 weekday_chooser_style_updated (GtkWidget
*widget
)
249 GtkWidgetClass
*widget_class
;
250 EWeekdayChooser
*chooser
;
251 EWeekdayChooserPrivate
*priv
;
253 PangoContext
*pango_context
;
254 PangoFontMetrics
*font_metrics
;
256 GDateWeekday weekday
;
258 chooser
= E_WEEKDAY_CHOOSER (widget
);
259 priv
= chooser
->priv
;
261 /* Set up Pango prerequisites */
262 pango_context
= gtk_widget_get_pango_context (widget
);
263 font_metrics
= pango_context_get_metrics (
265 pango_context_get_language (pango_context
));
266 layout
= pango_layout_new (pango_context
);
269 PANGO_PIXELS (pango_font_metrics_get_ascent (font_metrics
));
271 PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics
));
275 for (weekday
= G_DATE_MONDAY
; weekday
<= G_DATE_SUNDAY
; weekday
++) {
279 name
= e_get_weekday_name (weekday
, TRUE
);
280 pango_layout_set_text (layout
, name
, strlen (name
));
281 pango_layout_get_pixel_size (layout
, &w
, NULL
);
287 priv
->max_letter_width
= max_width
;
289 configure_items (chooser
);
290 g_object_unref (layout
);
291 pango_font_metrics_unref (font_metrics
);
293 /* Chain up to parent's style_updated() method. */
294 widget_class
= GTK_WIDGET_CLASS (e_weekday_chooser_parent_class
);
295 widget_class
->style_updated (widget
);
299 weekday_chooser_get_preferred_height (GtkWidget
*widget
,
300 gint
*minimum_height
,
301 gint
*natural_height
)
303 EWeekdayChooser
*chooser
;
304 EWeekdayChooserPrivate
*priv
;
306 chooser
= E_WEEKDAY_CHOOSER (widget
);
307 priv
= chooser
->priv
;
309 *minimum_height
= *natural_height
=
310 (priv
->font_ascent
+ priv
->font_descent
+ 2 * PADDING
+ 2);
314 weekday_chooser_get_preferred_width (GtkWidget
*widget
,
318 EWeekdayChooser
*chooser
;
319 EWeekdayChooserPrivate
*priv
;
321 chooser
= E_WEEKDAY_CHOOSER (widget
);
322 priv
= chooser
->priv
;
324 *minimum_width
= *natural_width
=
325 (priv
->max_letter_width
+ 2 * PADDING
+ 1) * 7 + 1;
329 weekday_chooser_focus (GtkWidget
*widget
,
330 GtkDirectionType direction
)
332 EWeekdayChooser
*chooser
;
334 chooser
= E_WEEKDAY_CHOOSER (widget
);
336 if (!gtk_widget_get_can_focus (widget
))
339 if (gtk_widget_has_focus (widget
)) {
340 chooser
->priv
->focus_day
= G_DATE_BAD_WEEKDAY
;
341 colorize_items (chooser
);
345 chooser
->priv
->focus_day
= chooser
->priv
->week_start_day
;
346 gnome_canvas_item_grab_focus (chooser
->priv
->boxes
[0]);
348 colorize_items (chooser
);
354 e_weekday_chooser_class_init (EWeekdayChooserClass
*class)
356 GObjectClass
*object_class
;
357 GtkWidgetClass
*widget_class
;
359 g_type_class_add_private (class, sizeof (EWeekdayChooserPrivate
));
361 object_class
= G_OBJECT_CLASS (class);
362 object_class
->set_property
= weekday_chooser_set_property
;
363 object_class
->get_property
= weekday_chooser_get_property
;
364 object_class
->constructed
= weekday_chooser_constructed
;
366 widget_class
= GTK_WIDGET_CLASS (class);
367 widget_class
->realize
= weekday_chooser_realize
;
368 widget_class
->size_allocate
= weekday_chooser_size_allocate
;
369 widget_class
->style_updated
= weekday_chooser_style_updated
;
370 widget_class
->get_preferred_height
= weekday_chooser_get_preferred_height
;
371 widget_class
->get_preferred_width
= weekday_chooser_get_preferred_width
;
372 widget_class
->focus
= weekday_chooser_focus
;
374 g_object_class_install_property (
384 G_PARAM_STATIC_STRINGS
));
386 chooser_signals
[CHANGED
] = g_signal_new (
388 G_TYPE_FROM_CLASS (class),
390 G_STRUCT_OFFSET (EWeekdayChooserClass
, changed
),
392 g_cclosure_marshal_VOID__VOID
,
397 day_clicked (EWeekdayChooser
*chooser
,
398 GDateWeekday weekday
)
402 if (chooser
->priv
->blocked_weekdays
[weekday
])
405 selected
= e_weekday_chooser_get_selected (chooser
, weekday
);
406 e_weekday_chooser_set_selected (chooser
, weekday
, !selected
);
410 handle_key_press_event (EWeekdayChooser
*chooser
,
413 EWeekdayChooserPrivate
*priv
= chooser
->priv
;
414 guint keyval
= event
->key
.keyval
;
417 if (chooser
->priv
->focus_day
== G_DATE_BAD_WEEKDAY
)
418 chooser
->priv
->focus_day
= chooser
->priv
->week_start_day
;
423 chooser
->priv
->focus_day
=
424 e_weekday_get_next (chooser
->priv
->focus_day
);
428 chooser
->priv
->focus_day
=
429 e_weekday_get_prev (chooser
->priv
->focus_day
);
433 case GDK_KEY_KP_Enter
:
434 day_clicked (chooser
, priv
->focus_day
);
440 colorize_items (chooser
);
442 index
= e_weekday_get_days_between (
443 chooser
->priv
->week_start_day
,
444 chooser
->priv
->focus_day
);
446 gnome_canvas_item_grab_focus (chooser
->priv
->boxes
[index
]);
451 /* Event handler for the day items */
453 day_event_cb (GnomeCanvasItem
*item
,
457 EWeekdayChooser
*chooser
;
460 chooser
= E_WEEKDAY_CHOOSER (data
);
462 if (event
->type
== GDK_KEY_PRESS
)
463 return handle_key_press_event (chooser
, event
);
465 if (!(event
->type
== GDK_BUTTON_PRESS
&& event
->button
.button
== 1))
468 /* Find which box was clicked */
470 for (ii
= 0; ii
< 7; ii
++) {
471 if (chooser
->priv
->boxes
[ii
] == item
)
473 if (chooser
->priv
->labels
[ii
] == item
)
478 g_warn_if_reached ();
482 chooser
->priv
->focus_day
= e_weekday_add_days (
483 chooser
->priv
->week_start_day
, ii
);
485 gnome_canvas_item_grab_focus (chooser
->priv
->boxes
[ii
]);
487 day_clicked (chooser
, chooser
->priv
->focus_day
);
492 /* Creates the canvas items for the weekday chooser.
493 * The items are empty until they are configured elsewhere. */
495 create_items (EWeekdayChooser
*chooser
)
497 GnomeCanvasGroup
*parent
;
500 parent
= gnome_canvas_root (GNOME_CANVAS (chooser
));
502 for (ii
= 0; ii
< 7; ii
++) {
503 chooser
->priv
->boxes
[ii
] = gnome_canvas_item_new (
505 GNOME_TYPE_CANVAS_RECT
,
508 chooser
->priv
->boxes
[ii
], "event",
509 G_CALLBACK (day_event_cb
), chooser
);
511 chooser
->priv
->labels
[ii
] = gnome_canvas_item_new (
513 GNOME_TYPE_CANVAS_TEXT
,
516 chooser
->priv
->labels
[ii
], "event",
517 G_CALLBACK (day_event_cb
), chooser
);
522 e_weekday_chooser_init (EWeekdayChooser
*chooser
)
524 chooser
->priv
= E_WEEKDAY_CHOOSER_GET_PRIVATE (chooser
);
526 create_items (chooser
);
527 chooser
->priv
->focus_day
= -1;
531 * e_weekday_chooser_new:
533 * Creates a new #EWeekdayChooser.
535 * Returns: an #EWeekdayChooser
538 e_weekday_chooser_new (void)
540 return g_object_new (E_TYPE_WEEKDAY_CHOOSER
, NULL
);
544 * e_weekday_chooser_get_days:
545 * @chooser: an #EWeekdayChooser
546 * @weekday: a #GDateWeekday
548 * Returns whether @weekday is selected.
550 * Returns: whether @weekday is selected
553 e_weekday_chooser_get_selected (EWeekdayChooser
*chooser
,
554 GDateWeekday weekday
)
556 g_return_val_if_fail (E_IS_WEEKDAY_CHOOSER (chooser
), FALSE
);
557 g_return_val_if_fail (g_date_valid_weekday (weekday
), FALSE
);
559 return chooser
->priv
->selected_weekdays
[weekday
];
563 * e_weekday_chooser_set_selected:
564 * @chooser: an #EWeekdayChooser
565 * @weekday: a #GDateWeekday
566 * @selected: selected flag
568 * Selects or deselects @weekday.
571 e_weekday_chooser_set_selected (EWeekdayChooser
*chooser
,
572 GDateWeekday weekday
,
575 g_return_if_fail (E_IS_WEEKDAY_CHOOSER (chooser
));
576 g_return_if_fail (g_date_valid_weekday (weekday
));
578 chooser
->priv
->selected_weekdays
[weekday
] = selected
;
580 colorize_items (chooser
);
582 g_signal_emit (chooser
, chooser_signals
[CHANGED
], 0);
586 * e_weekday_chooser_get_blocked:
587 * @chooser: an #EWeekdayChooser
588 * @weekday: a #GDateWeekday
590 * Returns whether @weekday is blocked from being modified by the user.
592 * Returns: whether @weekday is blocked
595 e_weekday_chooser_get_blocked (EWeekdayChooser
*chooser
,
596 GDateWeekday weekday
)
598 g_return_val_if_fail (E_IS_WEEKDAY_CHOOSER (chooser
), FALSE
);
599 g_return_val_if_fail (g_date_valid_weekday (weekday
), FALSE
);
601 return chooser
->priv
->blocked_weekdays
[weekday
];
605 * e_weekday_chooser_set_blocked:
606 * @chooser: an #EWeekdayChooser
607 * @weekday: a #GDateWeekday
608 * @blocked: blocked flag
610 * Sets whether @weekday is blocked from being modified by the user.
613 e_weekday_chooser_set_blocked (EWeekdayChooser
*chooser
,
614 GDateWeekday weekday
,
617 g_return_if_fail (E_IS_WEEKDAY_CHOOSER (chooser
));
618 g_return_if_fail (g_date_valid_weekday (weekday
));
620 chooser
->priv
->blocked_weekdays
[weekday
] = blocked
;
624 * e_weekday_chooser_get_week_start_day:
625 * @chooser: an #EWeekdayChooser
627 * Queries the day that defines the start of the week in @chooser.
629 * Returns: a #GDateWeekday
632 e_weekday_chooser_get_week_start_day (EWeekdayChooser
*chooser
)
634 g_return_val_if_fail (E_IS_WEEKDAY_CHOOSER (chooser
), G_DATE_BAD_WEEKDAY
);
636 return chooser
->priv
->week_start_day
;
640 * e_weekday_chooser_set_week_start_day:
641 * @chooser: an #EWeekdayChooser
642 * @week_start_day: a #GDateWeekday
644 * Sets the day that defines the start of the week for @chooser.
647 e_weekday_chooser_set_week_start_day (EWeekdayChooser
*chooser
,
648 GDateWeekday week_start_day
)
650 g_return_if_fail (E_IS_WEEKDAY_CHOOSER (chooser
));
651 g_return_if_fail (g_date_valid_weekday (week_start_day
));
653 if (week_start_day
== chooser
->priv
->week_start_day
)
656 chooser
->priv
->week_start_day
= week_start_day
;
658 configure_items (chooser
);
660 g_object_notify (G_OBJECT (chooser
), "week-start-day");