From 4493ff829e3634fbbdcfe05bebcd2cc882551b62 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Fri, 8 Mar 2013 06:54:08 -0500 Subject: Rename WeekdayPicker to EWeekdayChooser. Also add a "week-start-day" property and make it extensible. --- calendar/gui/Makefile.am | 8 +- calendar/gui/dialogs/recurrence-page.c | 38 +- calendar/gui/e-weekday-chooser.c | 691 +++++++++++++++++++++++++++++++++ calendar/gui/e-weekday-chooser.h | 79 ++++ calendar/gui/weekday-picker.c | 624 ----------------------------- calendar/gui/weekday-picker.h | 70 ---- 6 files changed, 793 insertions(+), 717 deletions(-) create mode 100644 calendar/gui/e-weekday-chooser.c create mode 100644 calendar/gui/e-weekday-chooser.h delete mode 100644 calendar/gui/weekday-picker.c delete mode 100644 calendar/gui/weekday-picker.h (limited to 'calendar') diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am index b0869028ef..b2947d256d 100644 --- a/calendar/gui/Makefile.am +++ b/calendar/gui/Makefile.am @@ -39,12 +39,12 @@ ecalendarinclude_HEADERS = \ e-week-view-main-item.h \ e-week-view-titles-item.h \ e-week-view.h \ + e-weekday-chooser.h \ e-timezone-entry.h \ gnome-cal.h \ itip-utils.h \ misc.h \ - tag-calendar.h \ - weekday-picker.h + tag-calendar.h search_files = tasktypes.xml memotypes.xml caltypes.xml @@ -160,6 +160,8 @@ libevolution_calendar_la_SOURCES = \ e-week-view-titles-item.h \ e-week-view.c \ e-week-view.h \ + e-weekday-chooser.c \ + e-weekday-chooser.h \ e-timezone-entry.c \ e-timezone-entry.h \ gnome-cal.c \ @@ -172,8 +174,6 @@ libevolution_calendar_la_SOURCES = \ print.h \ tag-calendar.c \ tag-calendar.h \ - weekday-picker.c \ - weekday-picker.h \ ea-calendar.c \ ea-calendar.h \ ea-calendar-helpers.c \ diff --git a/calendar/gui/dialogs/recurrence-page.c b/calendar/gui/dialogs/recurrence-page.c index 09dad77bef..39e2372229 100644 --- a/calendar/gui/dialogs/recurrence-page.c +++ b/calendar/gui/dialogs/recurrence-page.c @@ -34,7 +34,7 @@ #include #include "../tag-calendar.h" -#include "../weekday-picker.h" +#include "../e-weekday-chooser.h" #include "comp-editor-util.h" #include "../e-date-time-list.h" #include "recurrence-page.h" @@ -145,7 +145,7 @@ struct _RecurrencePagePrivate { GtkWidget *custom_warning_bin; /* For weekly recurrences, created by hand */ - GtkWidget *weekday_picker; + GtkWidget *weekday_chooser; guint8 weekday_day_mask; guint8 weekday_blocked_day_mask; @@ -760,10 +760,10 @@ simple_recur_to_comp (RecurrencePage *rpage, gint i; g_return_if_fail (gtk_bin_get_child (GTK_BIN (priv->special)) != NULL); - g_return_if_fail (priv->weekday_picker != NULL); - g_return_if_fail (IS_WEEKDAY_PICKER (priv->weekday_picker)); + g_return_if_fail (E_IS_WEEKDAY_CHOOSER (priv->weekday_chooser)); - day_mask = weekday_picker_get_days (WEEKDAY_PICKER (priv->weekday_picker)); + day_mask = e_weekday_chooser_get_days ( + E_WEEKDAY_CHOOSER (priv->weekday_chooser)); i = 0; @@ -1029,13 +1029,13 @@ make_weekly_special (RecurrencePage *rpage) RecurrencePagePrivate *priv; GtkWidget *hbox; GtkWidget *label; - WeekdayPicker *wp; + EWeekdayChooser *chooser; gint week_start_day; priv = rpage->priv; g_return_if_fail (gtk_bin_get_child (GTK_BIN (priv->special)) == NULL); - g_return_if_fail (priv->weekday_picker == NULL); + g_return_if_fail (priv->weekday_chooser == NULL); /* Create the widgets */ @@ -1047,21 +1047,21 @@ make_weekly_special (RecurrencePage *rpage) label = gtk_label_new (_("on")); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 6); - wp = WEEKDAY_PICKER (weekday_picker_new ()); + priv->weekday_chooser = e_weekday_chooser_new (); + chooser = E_WEEKDAY_CHOOSER (priv->weekday_chooser); - priv->weekday_picker = GTK_WIDGET (wp); - gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (wp), FALSE, FALSE, 6); + gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (chooser), FALSE, FALSE, 6); gtk_widget_show_all (hbox); /* Set the weekdays */ week_start_day = e_meeting_store_get_week_start_day (priv->meeting_store); - weekday_picker_set_week_start_day (wp, week_start_day); - weekday_picker_set_days (wp, priv->weekday_day_mask); + e_weekday_chooser_set_week_start_day (chooser, week_start_day); + e_weekday_chooser_set_days (chooser, priv->weekday_day_mask); g_signal_connect_swapped ( - wp, "changed", + chooser, "changed", G_CALLBACK (comp_editor_page_changed), rpage); } @@ -1403,7 +1403,7 @@ make_recurrence_special (RecurrencePage *rpage) if (child != NULL) { gtk_widget_destroy (child); - priv->weekday_picker = NULL; + priv->weekday_chooser = NULL; priv->month_day_combo = NULL; } @@ -2085,12 +2085,12 @@ recurrence_page_set_dates (CompEditorPage *page, priv->weekday_day_mask = priv->weekday_day_mask | mask; priv->weekday_blocked_day_mask = mask; - if (priv->weekday_picker != NULL) { - weekday_picker_set_days ( - WEEKDAY_PICKER (priv->weekday_picker), + if (priv->weekday_chooser != NULL) { + e_weekday_chooser_set_days ( + E_WEEKDAY_CHOOSER (priv->weekday_chooser), priv->weekday_day_mask); - weekday_picker_set_blocked_days ( - WEEKDAY_PICKER (priv->weekday_picker), + e_weekday_chooser_set_blocked_days ( + E_WEEKDAY_CHOOSER (priv->weekday_chooser), priv->weekday_blocked_day_mask); } } diff --git a/calendar/gui/e-weekday-chooser.c b/calendar/gui/e-weekday-chooser.c new file mode 100644 index 0000000000..4585699f9c --- /dev/null +++ b/calendar/gui/e-weekday-chooser.c @@ -0,0 +1,691 @@ +/* + * e-weekday-chooser.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + */ + +#include "e-weekday-chooser.h" + +#include +#include + +#include +#include +#include + +#include +#include + +#define PADDING 2 + +#define E_WEEKDAY_CHOOSER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_WEEKDAY_CHOOSER, EWeekdayChooserPrivate)) + +/* Private part of the EWeekdayChooser structure */ +struct _EWeekdayChooserPrivate { + /* Selected days; see weekday_chooser_set_days() */ + guint8 day_mask; + + /* Blocked days; these cannot be modified */ + guint8 blocked_day_mask; + + /* Day that defines the start of the week; 0 = Sunday, ..., 6 = Saturday */ + gint week_start_day; + + /* Current keyboard focus day */ + gint focus_day; + + /* Metrics */ + gint font_ascent, font_descent; + gint max_letter_width; + + /* Components */ + GnomeCanvasItem *boxes[7]; + GnomeCanvasItem *labels[7]; +}; + +enum { + PROP_0, + PROP_WEEK_START_DAY +}; + +enum { + CHANGED, + LAST_SIGNAL +}; + +static guint chooser_signals[LAST_SIGNAL]; + +G_DEFINE_TYPE_WITH_CODE ( + EWeekdayChooser, + e_weekday_chooser, + GNOME_TYPE_CANVAS, + G_IMPLEMENT_INTERFACE ( + E_TYPE_EXTENSIBLE, NULL)) + +static gchar * +get_day_text (gint day_index) +{ + GDateWeekday weekday; + + /* Convert from tm_wday to GDateWeekday. */ + weekday = (day_index == 0) ? G_DATE_SUNDAY : day_index; + + return g_strdup (e_get_weekday_name (weekday, TRUE)); +} + +static void +colorize_items (EWeekdayChooser *chooser) +{ + EWeekdayChooserPrivate *priv; + GdkColor *outline, *focus_outline; + GdkColor *fill, *sel_fill; + GdkColor *text_fill, *sel_text_fill; + GtkStateType state; + GtkStyle *style; + gint i; + + priv = chooser->priv; + + state = gtk_widget_get_state (GTK_WIDGET (chooser)); + style = gtk_widget_get_style (GTK_WIDGET (chooser)); + + outline = &style->fg[state]; + focus_outline = &style->bg[state]; + + fill = &style->base[state]; + text_fill = &style->fg[state]; + + sel_fill = &style->bg[GTK_STATE_SELECTED]; + sel_text_fill = &style->fg[GTK_STATE_SELECTED]; + + for (i = 0; i < 7; i++) { + gint day; + GdkColor *f, *t, *o; + + day = i + priv->week_start_day; + if (day >= 7) + day -= 7; + + if (priv->day_mask & (0x1 << day)) { + f = sel_fill; + t = sel_text_fill; + } else { + f = fill; + t = text_fill; + } + + if (day == priv->focus_day) + o = focus_outline; + else + o = outline; + + gnome_canvas_item_set ( + priv->boxes[i], + "fill_color_gdk", f, + "outline_color_gdk", o, + NULL); + + gnome_canvas_item_set ( + priv->labels[i], + "fill_color_gdk", t, + NULL); + } +} + +static void +configure_items (EWeekdayChooser *chooser) +{ + EWeekdayChooserPrivate *priv; + GtkAllocation allocation; + gint width, height; + gint box_width; + gint i; + + priv = chooser->priv; + + gtk_widget_get_allocation (GTK_WIDGET (chooser), &allocation); + + width = allocation.width; + height = allocation.height; + + box_width = (width - 1) / 7; + + for (i = 0; i < 7; i++) { + gchar *c; + gint day; + + day = i + priv->week_start_day; + if (day >= 7) + day -= 7; + + gnome_canvas_item_set ( + priv->boxes[i], + "x1", (gdouble) (i * box_width), + "y1", (gdouble) 0, + "x2", (gdouble) ((i + 1) * box_width), + "y2", (gdouble) (height - 1), + "line_width", 0.0, + NULL); + + c = get_day_text (day); + gnome_canvas_item_set ( + priv->labels[i], + "text", c, + "x", (gdouble) (i * box_width) + PADDING, + "y", (gdouble) (1 + PADDING), + NULL); + g_free (c); + } + + colorize_items (chooser); +} + +static void +weekday_chooser_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_WEEK_START_DAY: + e_weekday_chooser_set_week_start_day ( + E_WEEKDAY_CHOOSER (object), + g_value_get_int (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +weekday_chooser_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_WEEK_START_DAY: + g_value_set_int ( + value, + e_weekday_chooser_get_week_start_day ( + E_WEEKDAY_CHOOSER (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +weekday_chooser_constructed (GObject *object) +{ + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_weekday_chooser_parent_class)->constructed (object); + + e_extensible_load_extensions (E_EXTENSIBLE (object)); +} + +static void +weekday_chooser_realize (GtkWidget *widget) +{ + EWeekdayChooser *chooser; + + chooser = E_WEEKDAY_CHOOSER (widget); + + /* Chain up to parent's realize() method. */ + GTK_WIDGET_CLASS (e_weekday_chooser_parent_class)->realize (widget); + + configure_items (chooser); +} + +static void +weekday_chooser_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkWidgetClass *widget_class; + EWeekdayChooser *chooser; + + chooser = E_WEEKDAY_CHOOSER (widget); + + /* Chain up to parent's size_allocate() method. */ + widget_class = GTK_WIDGET_CLASS (e_weekday_chooser_parent_class); + widget_class->size_allocate (widget, allocation); + + gnome_canvas_set_scroll_region ( + GNOME_CANVAS (chooser), 0, 0, + allocation->width, allocation->height); + + configure_items (chooser); +} + +static void +weekday_chooser_style_set (GtkWidget *widget, + GtkStyle *previous_style) +{ + GtkWidgetClass *widget_class; + EWeekdayChooser *chooser; + EWeekdayChooserPrivate *priv; + gint max_width; + gint i; + PangoFontDescription *font_desc; + PangoContext *pango_context; + PangoFontMetrics *font_metrics; + PangoLayout *layout; + + chooser = E_WEEKDAY_CHOOSER (widget); + priv = chooser->priv; + + /* Set up Pango prerequisites */ + font_desc = gtk_widget_get_style (widget)->font_desc; + pango_context = gtk_widget_get_pango_context (widget); + font_metrics = pango_context_get_metrics ( + pango_context, font_desc, + pango_context_get_language (pango_context)); + layout = pango_layout_new (pango_context); + + priv->font_ascent = + PANGO_PIXELS (pango_font_metrics_get_ascent (font_metrics)); + priv->font_descent = + PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics)); + + max_width = 0; + + for (i = 0; i < 7; i++) { + gchar *c; + gint w; + + c = get_day_text (i); + pango_layout_set_text (layout, c, strlen (c)); + pango_layout_get_pixel_size (layout, &w, NULL); + g_free (c); + + if (w > max_width) + max_width = w; + } + + priv->max_letter_width = max_width; + + configure_items (chooser); + g_object_unref (layout); + pango_font_metrics_unref (font_metrics); + + /* Chain up to parent's style_set() method. */ + widget_class = GTK_WIDGET_CLASS (e_weekday_chooser_parent_class); + widget_class->style_set (widget, previous_style); +} + +static void +weekday_chooser_get_preferred_height (GtkWidget *widget, + gint *minimum_height, + gint *natural_height) +{ + EWeekdayChooser *chooser; + EWeekdayChooserPrivate *priv; + + chooser = E_WEEKDAY_CHOOSER (widget); + priv = chooser->priv; + + *minimum_height = *natural_height = + (priv->font_ascent + priv->font_descent + 2 * PADDING + 2); +} + +static void +weekday_chooser_get_preferred_width (GtkWidget *widget, + gint *minimum_width, + gint *natural_width) +{ + EWeekdayChooser *chooser; + EWeekdayChooserPrivate *priv; + + chooser = E_WEEKDAY_CHOOSER (widget); + priv = chooser->priv; + + *minimum_width = *natural_width = + (priv->max_letter_width + 2 * PADDING + 1) * 7 + 1; +} + +static gboolean +weekday_chooser_focus (GtkWidget *widget, + GtkDirectionType direction) +{ + EWeekdayChooser *chooser; + EWeekdayChooserPrivate *priv; + + g_return_val_if_fail (E_IS_WEEKDAY_CHOOSER (widget), FALSE); + chooser = E_WEEKDAY_CHOOSER (widget); + priv = chooser->priv; + + if (!gtk_widget_get_can_focus (widget)) + return FALSE; + + if (gtk_widget_has_focus (widget)) { + priv->focus_day = -1; + colorize_items (chooser); + return FALSE; + } + + priv->focus_day = priv->week_start_day; + gnome_canvas_item_grab_focus (priv->boxes[priv->focus_day]); + colorize_items (chooser); + + return TRUE; +} + +static void +e_weekday_chooser_class_init (EWeekdayChooserClass *class) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + + g_type_class_add_private (class, sizeof (EWeekdayChooserPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = weekday_chooser_set_property; + object_class->get_property = weekday_chooser_get_property; + object_class->constructed = weekday_chooser_constructed; + + widget_class = GTK_WIDGET_CLASS (class); + widget_class->realize = weekday_chooser_realize; + widget_class->size_allocate = weekday_chooser_size_allocate; + widget_class->style_set = weekday_chooser_style_set; + widget_class->get_preferred_height = weekday_chooser_get_preferred_height; + widget_class->get_preferred_width = weekday_chooser_get_preferred_width; + widget_class->focus = weekday_chooser_focus; + + g_object_class_install_property ( + object_class, + PROP_WEEK_START_DAY, + g_param_spec_int ( + "week-start-day", + "Week Start Day", + NULL, + 0, /* Monday */ + 6, /* Sunday */ + 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + chooser_signals[CHANGED] = g_signal_new ( + "changed", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EWeekdayChooserClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +day_clicked (EWeekdayChooser *chooser, + gint index) +{ + EWeekdayChooserPrivate *priv = chooser->priv; + guint8 day_mask; + + if (priv->blocked_day_mask & (0x1 << index)) + return; + + if (priv->day_mask & (0x1 << index)) + day_mask = priv->day_mask & ~(0x1 << index); + else + day_mask = priv->day_mask | (0x1 << index); + + e_weekday_chooser_set_days (chooser, day_mask); +} + +static gint +handle_key_press_event (EWeekdayChooser *chooser, + GdkEvent *event) +{ + EWeekdayChooserPrivate *priv = chooser->priv; + guint keyval = event->key.keyval; + + if (priv->focus_day == -1) + priv->focus_day = priv->week_start_day; + + switch (keyval) { + case GDK_KEY_Up: + case GDK_KEY_Right: + priv->focus_day += 1; + break; + case GDK_KEY_Down: + case GDK_KEY_Left: + priv->focus_day -= 1; + break; + case GDK_KEY_space: + case GDK_KEY_Return: + day_clicked (chooser, priv->focus_day); + return TRUE; + default: + return FALSE; + } + + if (priv->focus_day > 6) + priv->focus_day = 0; + if (priv->focus_day < 0) + priv->focus_day = 6; + + colorize_items (chooser); + gnome_canvas_item_grab_focus (priv->boxes[priv->focus_day]); + return TRUE; +} + +/* Event handler for the day items */ +static gint +day_event_cb (GnomeCanvasItem *item, + GdkEvent *event, + gpointer data) +{ + EWeekdayChooser *chooser; + EWeekdayChooserPrivate *priv; + gint i; + + chooser = E_WEEKDAY_CHOOSER (data); + priv = chooser->priv; + + if (event->type == GDK_KEY_PRESS) + return handle_key_press_event (chooser, event); + + if (!(event->type == GDK_BUTTON_PRESS && event->button.button == 1)) + return FALSE; + + /* Find which box was clicked */ + + for (i = 0; i < 7; i++) + if (priv->boxes[i] == item || priv->labels[i] == item) + break; + + g_return_val_if_fail (i != 7, TRUE); + + i += priv->week_start_day; + if (i >= 7) + i -= 7; + + priv->focus_day = i; + gnome_canvas_item_grab_focus (priv->boxes[i]); + day_clicked (chooser, i); + return TRUE; +} + +/* Creates the canvas items for the weekday chooser. + * The items are empty until they are configured elsewhere. */ +static void +create_items (EWeekdayChooser *chooser) +{ + EWeekdayChooserPrivate *priv; + GnomeCanvasGroup *parent; + gint i; + + priv = chooser->priv; + + parent = gnome_canvas_root (GNOME_CANVAS (chooser)); + + for (i = 0; i < 7; i++) { + priv->boxes[i] = gnome_canvas_item_new ( + parent, + GNOME_TYPE_CANVAS_RECT, + NULL); + g_signal_connect ( + priv->boxes[i], "event", + G_CALLBACK (day_event_cb), chooser); + + priv->labels[i] = gnome_canvas_item_new ( + parent, + GNOME_TYPE_CANVAS_TEXT, + NULL); + g_signal_connect ( + priv->labels[i], "event", + G_CALLBACK (day_event_cb), chooser); + } +} + +static void +e_weekday_chooser_init (EWeekdayChooser *chooser) +{ + chooser->priv = E_WEEKDAY_CHOOSER_GET_PRIVATE (chooser); + + create_items (chooser); + chooser->priv->focus_day = -1; +} + +/** + * e_weekday_chooser_new: + * + * Creates a new #EWeekdayChooser. + * + * Returns: an #EWeekdayChooser + **/ +GtkWidget * +e_weekday_chooser_new (void) +{ + return g_object_new (E_TYPE_WEEKDAY_CHOOSER, NULL); +} + +/** + * e_weekday_chooser_get_days: + * @chooser: an #EWeekdayChooser + * + * Queries the days that are selected in @chooser. + * + * Return value: Bit mask of selected days. Sunday is bit 0, Monday is bit 1, + * etc. + **/ +guint8 +e_weekday_chooser_get_days (EWeekdayChooser *chooser) +{ + g_return_val_if_fail (E_IS_WEEKDAY_CHOOSER (chooser), 0); + + return chooser->priv->day_mask; +} + +/** + * e_weekday_chooser_set_days: + * @chooser: an #EWeekdayChooser + * @day_mask: Bitmask with the days to be selected. + * + * Sets the days that are selected in @chooser. In the @day_mask, + * Sunday is bit 0, Monday is bit 1, etc. + **/ +void +e_weekday_chooser_set_days (EWeekdayChooser *chooser, + guint8 day_mask) +{ + g_return_if_fail (E_IS_WEEKDAY_CHOOSER (chooser)); + + chooser->priv->day_mask = day_mask; + colorize_items (chooser); + + g_signal_emit (chooser, chooser_signals[CHANGED], 0); +} + +/** + * e_weekday_chooser_get_blocked_days: + * @chooser: an #EWeekdayChooser + * + * Queries the set of days that the @chooser prevents from being modified + * by the user. + * + * Return value: Bit mask of blocked days, with the same format as that + * returned by e_weekday_chooser_get_days(). + **/ +guint +e_weekday_chooser_get_blocked_days (EWeekdayChooser *chooser) +{ + g_return_val_if_fail (E_IS_WEEKDAY_CHOOSER (chooser), 0); + + return chooser->priv->blocked_day_mask; +} + +/** + * e_weekday_chooser_set_blocked_days: + * @chooser: an #EWeekdayChooser + * @blocked_day_mask: Bitmask with the days to be blocked. + * + * Sets the days that the @chooser will prevent from being modified by + * the user. The @blocked_day_mask is specified in the same way as in + * e_weekday_chooser_set_days(). + **/ +void +e_weekday_chooser_set_blocked_days (EWeekdayChooser *chooser, + guint8 blocked_day_mask) +{ + g_return_if_fail (E_IS_WEEKDAY_CHOOSER (chooser)); + + chooser->priv->blocked_day_mask = blocked_day_mask; +} + +/** + * e_weekday_chooser_get_week_start_day: + * @chooser: an #EWeekdayChooser + * + * Queries the day that defines the start of the week in @chooser. + * + * Return value: Index of the day that defines the start of the week. See + * weekday_chooser_set_week_start_day() to see how this is represented. + **/ +gint +e_weekday_chooser_get_week_start_day (EWeekdayChooser *chooser) +{ + g_return_val_if_fail (E_IS_WEEKDAY_CHOOSER (chooser), -1); + + return chooser->priv->week_start_day; +} + +/** + * e_weekday_chooser_set_week_start_day: + * @chooser: an #EWeekdayChooser + * @week_start_day: Index of the day that defines the start of the week; 0 is + * Sunday, 1 is Monday, etc. + * + * Sets the day that defines the start of the week for @chooser. + **/ +void +e_weekday_chooser_set_week_start_day (EWeekdayChooser *chooser, + gint week_start_day) +{ + g_return_if_fail (E_IS_WEEKDAY_CHOOSER (chooser)); + g_return_if_fail (week_start_day >= 0 && week_start_day < 7); + + if (week_start_day == chooser->priv->week_start_day) + return; + + chooser->priv->week_start_day = week_start_day; + + configure_items (chooser); + + g_object_notify (G_OBJECT (chooser), "week-start-day"); +} + diff --git a/calendar/gui/e-weekday-chooser.h b/calendar/gui/e-weekday-chooser.h new file mode 100644 index 0000000000..cde70e411e --- /dev/null +++ b/calendar/gui/e-weekday-chooser.h @@ -0,0 +1,79 @@ +/* + * e-weekday-chooser.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + */ + +#ifndef E_WEEKDAY_CHOOSER_H +#define E_WEEKDAY_CHOOSER_H + +#include + +/* Standard GObject macros */ +#define E_TYPE_WEEKDAY_CHOOSER \ + (e_weekday_chooser_get_type ()) +#define E_WEEKDAY_CHOOSER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_WEEKDAY_CHOOSER, EWeekdayChooser)) +#define E_WEEKDAY_CHOOSER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_WEEKDAY_CHOOSER, EWeekdayChooserClass)) +#define E_IS_WEEKDAY_CHOOSER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_WEEKDAY_CHOOSER)) +#define E_IS_WEEKDAY_CHOOSER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_WEEKDAY_CHOOSER)) +#define E_WEEKDAY_CHOOSER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_WEEKDAY_CHOOSER, EWeekdayChooser)) + +G_BEGIN_DECLS + +typedef struct _EWeekdayChooser EWeekdayChooser; +typedef struct _EWeekdayChooserClass EWeekdayChooserClass; +typedef struct _EWeekdayChooserPrivate EWeekdayChooserPrivate; + +struct _EWeekdayChooser { + GnomeCanvas canvas; + EWeekdayChooserPrivate *priv; +}; + +struct _EWeekdayChooserClass { + GnomeCanvasClass parent_class; + + void (*changed) (EWeekdayChooser *chooser); +}; + +GType e_weekday_chooser_get_type (void) G_GNUC_CONST; +GtkWidget * e_weekday_chooser_new (void); +guint8 e_weekday_chooser_get_days (EWeekdayChooser *chooser); +void e_weekday_chooser_set_days (EWeekdayChooser *chooser, + guint8 day_mask); +guint e_weekday_chooser_get_blocked_days + (EWeekdayChooser *chooser); +void e_weekday_chooser_set_blocked_days + (EWeekdayChooser *chooser, + guint8 blocked_day_mask); +gint e_weekday_chooser_get_week_start_day + (EWeekdayChooser *chooser); +void e_weekday_chooser_set_week_start_day + (EWeekdayChooser *chooser, + gint week_start_day); + +G_END_DECLS + +#endif /* E_WEEKDAY_CHOOSER_H */ + diff --git a/calendar/gui/weekday-picker.c b/calendar/gui/weekday-picker.c deleted file mode 100644 index a37b4b7320..0000000000 --- a/calendar/gui/weekday-picker.c +++ /dev/null @@ -1,624 +0,0 @@ -/* - * Evolution calendar - Week day picker widget - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Federico Mena-Quintero - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include "weekday-picker.h" - -#define PADDING 2 - -#define WEEKDAY_PICKER_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), TYPE_WEEKDAY_PICKER, WeekdayPickerPrivate)) - -/* Private part of the WeekdayPicker structure */ -struct _WeekdayPickerPrivate { - /* Selected days; see weekday_picker_set_days() */ - guint8 day_mask; - - /* Blocked days; these cannot be modified */ - guint8 blocked_day_mask; - - /* Day that defines the start of the week; 0 = Sunday, ..., 6 = Saturday */ - gint week_start_day; - - /* Current keyboard focus day */ - gint focus_day; - - /* Metrics */ - gint font_ascent, font_descent; - gint max_letter_width; - - /* Components */ - GnomeCanvasItem *boxes[7]; - GnomeCanvasItem *labels[7]; -}; - -/* Signal IDs */ -enum { - CHANGED, - LAST_SIGNAL -}; - -static guint wp_signals[LAST_SIGNAL]; - -G_DEFINE_TYPE (WeekdayPicker, weekday_picker, GNOME_TYPE_CANVAS) - -static gchar * -get_day_text (gint day_index) -{ - GDateWeekday weekday; - - /* Convert from tm_wday to GDateWeekday. */ - weekday = (day_index == 0) ? G_DATE_SUNDAY : day_index; - - return g_strdup (e_get_weekday_name (weekday, TRUE)); -} - -static void -colorize_items (WeekdayPicker *wp) -{ - WeekdayPickerPrivate *priv; - GdkColor *outline, *focus_outline; - GdkColor *fill, *sel_fill; - GdkColor *text_fill, *sel_text_fill; - GtkStateType state; - GtkStyle *style; - gint i; - - priv = wp->priv; - - state = gtk_widget_get_state (GTK_WIDGET (wp)); - style = gtk_widget_get_style (GTK_WIDGET (wp)); - - outline = &style->fg[state]; - focus_outline = &style->bg[state]; - - fill = &style->base[state]; - text_fill = &style->fg[state]; - - sel_fill = &style->bg[GTK_STATE_SELECTED]; - sel_text_fill = &style->fg[GTK_STATE_SELECTED]; - - for (i = 0; i < 7; i++) { - gint day; - GdkColor *f, *t, *o; - - day = i + priv->week_start_day; - if (day >= 7) - day -= 7; - - if (priv->day_mask & (0x1 << day)) { - f = sel_fill; - t = sel_text_fill; - } else { - f = fill; - t = text_fill; - } - - if (day == priv->focus_day) - o = focus_outline; - else - o = outline; - - gnome_canvas_item_set ( - priv->boxes[i], - "fill_color_gdk", f, - "outline_color_gdk", o, - NULL); - - gnome_canvas_item_set ( - priv->labels[i], - "fill_color_gdk", t, - NULL); - } -} - -static void -configure_items (WeekdayPicker *wp) -{ - WeekdayPickerPrivate *priv; - GtkAllocation allocation; - gint width, height; - gint box_width; - gint i; - - priv = wp->priv; - - gtk_widget_get_allocation (GTK_WIDGET (wp), &allocation); - - width = allocation.width; - height = allocation.height; - - box_width = (width - 1) / 7; - - for (i = 0; i < 7; i++) { - gchar *c; - gint day; - - day = i + priv->week_start_day; - if (day >= 7) - day -= 7; - - gnome_canvas_item_set ( - priv->boxes[i], - "x1", (gdouble) (i * box_width), - "y1", (gdouble) 0, - "x2", (gdouble) ((i + 1) * box_width), - "y2", (gdouble) (height - 1), - "line_width", 0.0, - NULL); - - c = get_day_text (day); - gnome_canvas_item_set ( - priv->labels[i], - "text", c, - "x", (gdouble) (i * box_width) + PADDING, - "y", (gdouble) (1 + PADDING), - NULL); - g_free (c); - } - - colorize_items (wp); -} - -static void -weekday_picker_realize (GtkWidget *widget) -{ - WeekdayPicker *wp; - - wp = WEEKDAY_PICKER (widget); - - /* Chain up to parent's realize() method. */ - GTK_WIDGET_CLASS (weekday_picker_parent_class)->realize (widget); - - configure_items (wp); -} - -static void -weekday_picker_get_preferred_width (GtkWidget *widget, - gint *minimum_width, - gint *natural_width) -{ - WeekdayPicker *wp; - WeekdayPickerPrivate *priv; - - wp = WEEKDAY_PICKER (widget); - priv = wp->priv; - - *minimum_width = *natural_width = - (priv->max_letter_width + 2 * PADDING + 1) * 7 + 1; -} - -static void -weekday_picker_get_preferred_height (GtkWidget *widget, - gint *minimum_height, - gint *natural_height) -{ - WeekdayPicker *wp; - WeekdayPickerPrivate *priv; - - wp = WEEKDAY_PICKER (widget); - priv = wp->priv; - - *minimum_height = *natural_height = - (priv->font_ascent + priv->font_descent + 2 * PADDING + 2); -} - -static void -weekday_picker_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) -{ - GtkWidgetClass *widget_class; - WeekdayPicker *wp; - - wp = WEEKDAY_PICKER (widget); - - /* Chain up to parent's size_allocate() method. */ - widget_class = GTK_WIDGET_CLASS (weekday_picker_parent_class); - widget_class->size_allocate (widget, allocation); - - gnome_canvas_set_scroll_region ( - GNOME_CANVAS (wp), 0, 0, - allocation->width, allocation->height); - - configure_items (wp); -} - -static void -weekday_picker_style_set (GtkWidget *widget, - GtkStyle *previous_style) -{ - GtkWidgetClass *widget_class; - WeekdayPicker *wp; - WeekdayPickerPrivate *priv; - gint max_width; - gint i; - PangoFontDescription *font_desc; - PangoContext *pango_context; - PangoFontMetrics *font_metrics; - PangoLayout *layout; - - wp = WEEKDAY_PICKER (widget); - priv = wp->priv; - - /* Set up Pango prerequisites */ - font_desc = gtk_widget_get_style (widget)->font_desc; - pango_context = gtk_widget_get_pango_context (widget); - font_metrics = pango_context_get_metrics ( - pango_context, font_desc, - pango_context_get_language (pango_context)); - layout = pango_layout_new (pango_context); - - priv->font_ascent = - PANGO_PIXELS (pango_font_metrics_get_ascent (font_metrics)); - priv->font_descent = - PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics)); - - max_width = 0; - - for (i = 0; i < 7; i++) { - gchar *c; - gint w; - - c = get_day_text (i); - pango_layout_set_text (layout, c, strlen (c)); - pango_layout_get_pixel_size (layout, &w, NULL); - g_free (c); - - if (w > max_width) - max_width = w; - } - - priv->max_letter_width = max_width; - - configure_items (wp); - g_object_unref (layout); - pango_font_metrics_unref (font_metrics); - - /* Chain up to parent's style_set() method. */ - widget_class = GTK_WIDGET_CLASS (weekday_picker_parent_class); - widget_class->style_set (widget, previous_style); -} - -static gboolean -weekday_picker_focus (GtkWidget *widget, - GtkDirectionType direction) -{ - WeekdayPicker *wp; - WeekdayPickerPrivate *priv; - - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (IS_WEEKDAY_PICKER (widget), FALSE); - wp = WEEKDAY_PICKER (widget); - priv = wp->priv; - - if (!gtk_widget_get_can_focus (widget)) - return FALSE; - - if (gtk_widget_has_focus (widget)) { - priv->focus_day = -1; - colorize_items (wp); - return FALSE; - } - - priv->focus_day = priv->week_start_day; - gnome_canvas_item_grab_focus (priv->boxes[priv->focus_day]); - colorize_items (wp); - - return TRUE; -} -static void -weekday_picker_class_init (WeekdayPickerClass *class) -{ - GtkWidgetClass *widget_class; - - g_type_class_add_private (class, sizeof (WeekdayPickerPrivate)); - - widget_class = GTK_WIDGET_CLASS (class); - widget_class->realize = weekday_picker_realize; - widget_class->get_preferred_width = weekday_picker_get_preferred_width; - widget_class->get_preferred_height = weekday_picker_get_preferred_height; - widget_class->size_allocate = weekday_picker_size_allocate; - widget_class->style_set = weekday_picker_style_set; - widget_class->focus = weekday_picker_focus; - - class->changed = NULL; - - wp_signals[CHANGED] = g_signal_new ( - "changed", - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (WeekdayPickerClass, changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -static void -day_clicked (WeekdayPicker *wp, - gint index) -{ - WeekdayPickerPrivate *priv = wp->priv; - guint8 day_mask; - - if (priv->blocked_day_mask & (0x1 << index)) - return; - - if (priv->day_mask & (0x1 << index)) - day_mask = priv->day_mask & ~(0x1 << index); - else - day_mask = priv->day_mask | (0x1 << index); - - weekday_picker_set_days (wp, day_mask); -} - -static gint -handle_key_press_event (WeekdayPicker *wp, - GdkEvent *event) -{ - WeekdayPickerPrivate *priv = wp->priv; - guint keyval = event->key.keyval; - - if (priv->focus_day == -1) - priv->focus_day = priv->week_start_day; - - switch (keyval) { - case GDK_KEY_Up: - case GDK_KEY_Right: - priv->focus_day += 1; - break; - case GDK_KEY_Down: - case GDK_KEY_Left: - priv->focus_day -= 1; - break; - case GDK_KEY_space: - case GDK_KEY_Return: - day_clicked (wp, priv->focus_day); - return TRUE; - default: - return FALSE; - } - - if (priv->focus_day > 6) - priv->focus_day = 0; - if (priv->focus_day < 0) - priv->focus_day = 6; - - colorize_items (wp); - gnome_canvas_item_grab_focus (priv->boxes[priv->focus_day]); - return TRUE; -} - -/* Event handler for the day items */ -static gint -day_event_cb (GnomeCanvasItem *item, - GdkEvent *event, - gpointer data) -{ - WeekdayPicker *wp; - WeekdayPickerPrivate *priv; - gint i; - - wp = WEEKDAY_PICKER (data); - priv = wp->priv; - - if (event->type == GDK_KEY_PRESS) - return handle_key_press_event (wp, event); - - if (!(event->type == GDK_BUTTON_PRESS && event->button.button == 1)) - return FALSE; - - /* Find which box was clicked */ - - for (i = 0; i < 7; i++) - if (priv->boxes[i] == item || priv->labels[i] == item) - break; - - g_return_val_if_fail (i != 7, TRUE); - - i += priv->week_start_day; - if (i >= 7) - i -= 7; - - priv->focus_day = i; - gnome_canvas_item_grab_focus (priv->boxes[i]); - day_clicked (wp, i); - return TRUE; -} - -/* Creates the canvas items for the weekday picker. The items are empty until - * they are configured elsewhere. - */ -static void -create_items (WeekdayPicker *wp) -{ - WeekdayPickerPrivate *priv; - GnomeCanvasGroup *parent; - gint i; - - priv = wp->priv; - - parent = gnome_canvas_root (GNOME_CANVAS (wp)); - - for (i = 0; i < 7; i++) { - priv->boxes[i] = gnome_canvas_item_new ( - parent, - GNOME_TYPE_CANVAS_RECT, - NULL); - g_signal_connect ( - priv->boxes[i], "event", - G_CALLBACK (day_event_cb), wp); - - priv->labels[i] = gnome_canvas_item_new ( - parent, - GNOME_TYPE_CANVAS_TEXT, - NULL); - g_signal_connect ( - priv->labels[i], "event", - G_CALLBACK (day_event_cb), wp); - } -} - -static void -weekday_picker_init (WeekdayPicker *wp) -{ - wp->priv = WEEKDAY_PICKER_GET_PRIVATE (wp); - - create_items (wp); - wp->priv->focus_day = -1; -} - -/** - * weekday_picker_new: - * @void: - * - * Creates a new weekday picker widget. - * - * Return value: A newly-created weekday picker. - **/ -GtkWidget * -weekday_picker_new (void) -{ - return g_object_new (TYPE_WEEKDAY_PICKER, NULL); -} - -/** - * weekday_picker_set_days: - * @wp: A weekday picker. - * @day_mask: Bitmask with the days to be selected. - * - * Sets the days that are selected in a weekday picker. In the @day_mask, - * Sunday is bit 0, Monday is bit 1, etc. - **/ -void -weekday_picker_set_days (WeekdayPicker *wp, - guint8 day_mask) -{ - g_return_if_fail (IS_WEEKDAY_PICKER (wp)); - - wp->priv->day_mask = day_mask; - colorize_items (wp); - - g_signal_emit (wp, wp_signals[CHANGED], 0); -} - -/** - * weekday_picker_get_days: - * @wp: A weekday picker. - * - * Queries the days that are selected in a weekday picker. - * - * Return value: Bit mask of selected days. Sunday is bit 0, Monday is bit 1, - * etc. - **/ -guint8 -weekday_picker_get_days (WeekdayPicker *wp) -{ - g_return_val_if_fail (IS_WEEKDAY_PICKER (wp), 0); - - return wp->priv->day_mask; -} - -/** - * weekday_picker_set_blocked_days: - * @wp: A weekday picker. - * @blocked_day_mask: Bitmask with the days to be blocked. - * - * Sets the days that the weekday picker will prevent from being modified by the - * user. The @blocked_day_mask is specified in the same way as in - * weekday_picker_set_days(). - **/ -void -weekday_picker_set_blocked_days (WeekdayPicker *wp, - guint8 blocked_day_mask) -{ - g_return_if_fail (IS_WEEKDAY_PICKER (wp)); - - wp->priv->blocked_day_mask = blocked_day_mask; -} - -/** - * weekday_picker_get_blocked_days: - * @wp: A weekday picker. - * - * Queries the set of days that the weekday picker prevents from being modified - * by the user. - * - * Return value: Bit mask of blocked days, with the same format as that returned - * by weekday_picker_get_days(). - **/ -guint -weekday_picker_get_blocked_days (WeekdayPicker *wp) -{ - g_return_val_if_fail (IS_WEEKDAY_PICKER (wp), 0); - - return wp->priv->blocked_day_mask; -} - -/** - * weekday_picker_set_week_start_day: - * @wp: A weekday picker. - * @week_start_day: Index of the day that defines the start of the week; 0 is - * Sunday, 1 is Monday, etc. - * - * Sets the day that defines the start of the week for a weekday picker. - **/ -void -weekday_picker_set_week_start_day (WeekdayPicker *wp, - gint week_start_day) -{ - g_return_if_fail (IS_WEEKDAY_PICKER (wp)); - g_return_if_fail (week_start_day >= 0 && week_start_day < 7); - - wp->priv->week_start_day = week_start_day; - - configure_items (wp); -} - -/** - * weekday_picker_get_week_start_day: - * @wp: A weekday picker. - * - * Queries the day that defines the start of the week in a weekday picker. - * - * Return value: Index of the day that defines the start of the week. See - * weekday_picker_set_week_start_day() to see how this is represented. - **/ -gint -weekday_picker_get_week_start_day (WeekdayPicker *wp) -{ - g_return_val_if_fail (IS_WEEKDAY_PICKER (wp), -1); - - return wp->priv->week_start_day; -} - diff --git a/calendar/gui/weekday-picker.h b/calendar/gui/weekday-picker.h deleted file mode 100644 index 315fa5bf53..0000000000 --- a/calendar/gui/weekday-picker.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Federico Mena-Quintero - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef WEEKDAY_PICKER_H -#define WEEKDAY_PICKER_H - -#include - -G_BEGIN_DECLS - -#define TYPE_WEEKDAY_PICKER (weekday_picker_get_type ()) -#define WEEKDAY_PICKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_WEEKDAY_PICKER, WeekdayPicker)) -#define WEEKDAY_PICKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_WEEKDAY_PICKER, \ - WeekdayPickerClass)) -#define IS_WEEKDAY_PICKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_WEEKDAY_PICKER)) -#define IS_WEEKDAY_PICKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_WEEKDAY_PICKER)) - -typedef struct _WeekdayPicker WeekdayPicker; -typedef struct _WeekdayPickerClass WeekdayPickerClass; -typedef struct _WeekdayPickerPrivate WeekdayPickerPrivate; - -struct _WeekdayPicker { - GnomeCanvas canvas; - - /* Private data */ - WeekdayPickerPrivate *priv; -}; - -struct _WeekdayPickerClass { - GnomeCanvasClass parent_class; - - void (* changed) (WeekdayPicker *wp); -}; - -GType weekday_picker_get_type (void); - -GtkWidget *weekday_picker_new (void); - -void weekday_picker_set_days (WeekdayPicker *wp, guint8 day_mask); -guint8 weekday_picker_get_days (WeekdayPicker *wp); - -void weekday_picker_set_blocked_days (WeekdayPicker *wp, guint8 blocked_day_mask); -guint weekday_picker_get_blocked_days (WeekdayPicker *wp); - -void weekday_picker_set_week_start_day (WeekdayPicker *wp, gint week_start_day); -gint weekday_picker_get_week_start_day (WeekdayPicker *wp); - -G_END_DECLS - -#endif -- cgit