aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/misc/e-calendar.c
diff options
context:
space:
mode:
Diffstat (limited to 'widgets/misc/e-calendar.c')
-rw-r--r--widgets/misc/e-calendar.c490
1 files changed, 357 insertions, 133 deletions
diff --git a/widgets/misc/e-calendar.c b/widgets/misc/e-calendar.c
index ec85e3471f..33a6874562 100644
--- a/widgets/misc/e-calendar.c
+++ b/widgets/misc/e-calendar.c
@@ -39,8 +39,24 @@
#define E_CALENDAR_SMALL_FONT_FALLBACK \
"-adobe-helvetica-medium-r-normal-*-*-80-*-*-p-*-iso8859-*"
-#define E_CALENDAR_BUTTON_X_PAD 2
-#define E_CALENDAR_BUTTON_Y_PAD 0
+/* The space between the arrow buttons and the edge of the widget. */
+#define E_CALENDAR_ARROW_BUTTON_X_PAD 2
+#define E_CALENDAR_ARROW_BUTTON_Y_PAD 0
+
+/* Vertical padding. The padding above the button includes the space for the
+ horizontal line. */
+#define E_CALENDAR_YPAD_ABOVE_LOWER_BUTTONS 4
+#define E_CALENDAR_YPAD_BELOW_LOWER_BUTTONS 3
+
+/* Horizontal padding inside & between buttons. */
+#define E_CALENDAR_IXPAD_BUTTONS 4
+#define E_CALENDAR_XPAD_BUTTONS 8
+
+/* The time between steps when the prev/next buttons is pressed, in 1/1000ths
+ of a second, and the number of timeouts we skip before we start
+ automatically moving back/forward. */
+#define E_CALENDAR_AUTO_MOVE_TIMEOUT 150
+#define E_CALENDAR_AUTO_MOVE_TIMEOUT_DELAY 2
static void e_calendar_class_init (ECalendarClass *class);
static void e_calendar_init (ECalendar *cal);
@@ -52,28 +68,32 @@ static void e_calendar_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void e_calendar_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
-static gint e_calendar_expose (GtkWidget *widget,
- GdkEventExpose *event);
static void e_calendar_draw (GtkWidget *widget,
GdkRectangle *area);
-#if 0
-static gint e_calendar_button_press (GtkWidget *widget,
- GdkEventButton *event);
-static gint e_calendar_button_release (GtkWidget *widget,
- GdkEventButton *event);
-#endif
static gint e_calendar_focus_in (GtkWidget *widget,
GdkEventFocus *event);
static gint e_calendar_focus_out (GtkWidget *widget,
GdkEventFocus *event);
static gint e_calendar_key_press (GtkWidget *widget,
GdkEventKey *event);
-
-static void e_calendar_paint (ECalendar *cal,
- GdkRectangle *area);
-
-static void e_calendar_on_prev_clicked (ECalendar *cal);
-static void e_calendar_on_next_clicked (ECalendar *cal);
+static gint e_calendar_drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time);
+static void e_calendar_drag_leave (GtkWidget *widget,
+ GdkDragContext *context,
+ guint time);
+
+static void e_calendar_on_prev_pressed (ECalendar *cal);
+static void e_calendar_on_prev_released (ECalendar *cal);
+static void e_calendar_on_next_pressed (ECalendar *cal);
+static void e_calendar_on_next_released (ECalendar *cal);
+
+static void e_calendar_start_auto_move (ECalendar *cal,
+ gboolean moving_forward);
+static gboolean e_calendar_auto_move_handler (gpointer data);
+static void e_calendar_stop_auto_move (ECalendar *cal);
static GnomeCanvasClass *parent_class;
static GtkLayoutClass *grandparent_class;
@@ -100,15 +120,12 @@ e_calendar_class_init (ECalendarClass *class)
widget_class->style_set = e_calendar_style_set;
widget_class->size_request = e_calendar_size_request;
widget_class->size_allocate = e_calendar_size_allocate;
- widget_class->expose_event = e_calendar_expose;
widget_class->draw = e_calendar_draw;
-#if 0
- widget_class->button_press_event = e_calendar_button_press;
- widget_class->button_release_event = e_calendar_button_release;
-#endif
widget_class->focus_in_event = e_calendar_focus_in;
widget_class->focus_out_event = e_calendar_focus_out;
widget_class->key_press_event = e_calendar_key_press;
+ widget_class->drag_motion = e_calendar_drag_motion;
+ widget_class->drag_leave = e_calendar_drag_leave;
}
@@ -131,25 +148,39 @@ e_calendar_init (ECalendar *cal)
cal->calitem = E_CALENDAR_ITEM (gnome_canvas_item_new (canvas_group,
e_calendar_item_get_type (),
"week_number_font", small_font,
- "week_start_day", 6,
NULL));
-#if 0
- "show_week_numbers", TRUE,
- "minimum_columns", 5,
- "maximum_columns", 5,
-#endif
-
if (small_font)
gdk_font_unref (small_font);
+ /* Create the 'Today' and 'None' buttons but don't show them. */
+ cal->today_button = gtk_button_new_with_label (_("Today"));
+ cal->today_button_item = gnome_canvas_item_new (canvas_group,
+ gnome_canvas_widget_get_type (),
+ "widget", cal->today_button,
+ NULL);
+ gnome_canvas_item_hide (cal->today_button_item);
+
+
+ cal->none_button = gtk_button_new_with_label (_("None"));
+ cal->none_button_item = gnome_canvas_item_new (canvas_group,
+ gnome_canvas_widget_get_type (),
+ "widget", cal->none_button,
+ NULL);
+ gnome_canvas_item_hide (cal->none_button_item);
+
+
+ /* Create the arrow buttons to move to the previous/next month. */
button = gtk_button_new ();
/* FIXME: The buttons doesn't display properly if we do this. */
/*gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);*/
gtk_widget_show (button);
- gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
- GTK_SIGNAL_FUNC (e_calendar_on_prev_clicked),
+ gtk_signal_connect_object (GTK_OBJECT (button), "pressed",
+ GTK_SIGNAL_FUNC (e_calendar_on_prev_pressed),
+ GTK_OBJECT (cal));
+ gtk_signal_connect_object (GTK_OBJECT (button), "released",
+ GTK_SIGNAL_FUNC (e_calendar_on_prev_released),
GTK_OBJECT (cal));
arrow = gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_OUT);
gtk_widget_show (arrow);
@@ -162,8 +193,11 @@ e_calendar_init (ECalendar *cal)
button = gtk_button_new ();
/*gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);*/
gtk_widget_show (button);
- gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
- GTK_SIGNAL_FUNC (e_calendar_on_next_clicked),
+ gtk_signal_connect_object (GTK_OBJECT (button), "pressed",
+ GTK_SIGNAL_FUNC (e_calendar_on_next_pressed),
+ GTK_OBJECT (cal));
+ gtk_signal_connect_object (GTK_OBJECT (button), "released",
+ GTK_SIGNAL_FUNC (e_calendar_on_next_released),
GTK_OBJECT (cal));
arrow = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_OUT);
gtk_widget_show (arrow);
@@ -177,6 +211,8 @@ e_calendar_init (ECalendar *cal)
cal->min_cols = 1;
cal->max_rows = -1;
cal->max_cols = -1;
+
+ cal->timeout_id = 0;
}
@@ -207,8 +243,10 @@ e_calendar_destroy (GtkObject *object)
cal = E_CALENDAR (object);
-
-
+ if (cal->timeout_id != 0) {
+ gtk_timeout_remove (cal->timeout_id);
+ cal->timeout_id = 0;
+ }
}
@@ -223,6 +261,10 @@ static void
e_calendar_style_set (GtkWidget *widget,
GtkStyle *previous_style)
{
+
+ if (GTK_WIDGET_CLASS (parent_class)->style_set)
+ (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget,
+ previous_style);
}
@@ -232,8 +274,13 @@ e_calendar_size_request (GtkWidget *widget,
{
ECalendar *cal;
GtkStyle *style;
- gdouble col_width, row_height;
- gint width, height;
+ gint col_width, row_height, width, height;
+ gboolean today_button_shown, none_button_shown;
+ gint buttons_shown = 0, button_height, button_width, buttons_width;
+ GtkRequisition today_button_requisition = { 0 };
+ GtkRequisition none_button_requisition = { 0 };
+ gint today_button_width = 0, today_button_height = 0;
+ gint none_button_width = 0, none_button_height = 0;
cal = E_CALENDAR (widget);
style = GTK_WIDGET (cal)->style;
@@ -246,7 +293,39 @@ e_calendar_size_request (GtkWidget *widget,
height = row_height * cal->min_rows;
width = col_width * cal->min_cols;
- /* FIXME: Add on space for line & button if shown. */
+ /* Add on space for line & button if shown. */
+ today_button_shown = GTK_WIDGET_VISIBLE (cal->today_button);
+ none_button_shown = GTK_WIDGET_VISIBLE (cal->none_button);
+
+ if (today_button_shown || none_button_shown) {
+ /* Note that we use the buttons' requisition fields directly
+ since we want the sizes without any usize modification. */
+ if (today_button_shown) {
+ gtk_widget_size_request (cal->today_button,
+ &today_button_requisition);
+ today_button_width = cal->today_button->requisition.width;
+ today_button_height = cal->today_button->requisition.height;
+ buttons_shown++;
+ }
+ if (none_button_shown) {
+ gtk_widget_size_request (cal->none_button,
+ &none_button_requisition);
+ none_button_width = cal->none_button->requisition.width;
+ none_button_height = cal->none_button->requisition.height;
+ buttons_shown++;
+ }
+
+ button_height = MAX (today_button_height, none_button_height);
+ height += E_CALENDAR_YPAD_ABOVE_LOWER_BUTTONS + button_height
+ + E_CALENDAR_YPAD_BELOW_LOWER_BUTTONS;
+
+ button_width = MAX (today_button_width, none_button_width);
+ button_width += E_CALENDAR_IXPAD_BUTTONS;
+ buttons_width = buttons_shown * button_width
+ + (buttons_shown - 1) * E_CALENDAR_XPAD_BUTTONS;
+
+ width = MAX (width, buttons_width);
+ }
requisition->width = width + style->klass->xthickness * 2;
requisition->height = height + style->klass->ythickness * 2;
@@ -260,7 +339,16 @@ e_calendar_size_allocate (GtkWidget *widget,
ECalendar *cal;
GdkFont *font;
gdouble old_x2, old_y2, new_x2, new_y2;
- gdouble xthickness, ythickness, button_size;
+ gdouble buttons_x1, buttons_y1;
+ gdouble button_width, button_height;
+ gdouble buttons_width = 0, buttons_height = 0;
+ gdouble xthickness, ythickness, arrow_button_size;
+ gboolean today_button_shown, none_button_shown;
+ gint buttons_shown = 0;
+ GtkRequisition today_button_requisition = { 0 };
+ GtkRequisition none_button_requisition = { 0 };
+ gint today_button_width = 0, today_button_height = 0;
+ gint none_button_width = 0, none_button_height = 0;
cal = E_CALENDAR (widget);
font = widget->style->font;
@@ -278,50 +366,97 @@ e_calendar_size_allocate (GtkWidget *widget,
gnome_canvas_set_scroll_region (GNOME_CANVAS (cal),
0, 0, new_x2, new_y2);
- /* FIXME: Take off space for line & buttons if shown. */
+ /* Set the positions of the Today & None buttons if shown. */
+ today_button_shown = GTK_WIDGET_VISIBLE (cal->today_button);
+ none_button_shown = GTK_WIDGET_VISIBLE (cal->none_button);
+
+ if (today_button_shown || none_button_shown) {
+ if (today_button_shown) {
+ gtk_widget_size_request (cal->today_button,
+ &today_button_requisition);
+ today_button_width = cal->today_button->requisition.width;
+ today_button_height = cal->today_button->requisition.height;
+ buttons_shown++;
+ }
+ if (none_button_shown) {
+ gtk_widget_size_request (cal->none_button,
+ &none_button_requisition);
+ none_button_width = cal->none_button->requisition.width;
+ none_button_height = cal->none_button->requisition.height;
+ buttons_shown++;
+ }
+
+ button_height = MAX (today_button_height, none_button_height);
+ buttons_height = E_CALENDAR_YPAD_ABOVE_LOWER_BUTTONS
+ + button_height + E_CALENDAR_YPAD_BELOW_LOWER_BUTTONS;
+
+ button_width = MAX (today_button_width, none_button_width);
+ button_width += E_CALENDAR_IXPAD_BUTTONS;
+ buttons_width = buttons_shown * button_width
+ + (buttons_shown - 1) * E_CALENDAR_XPAD_BUTTONS;
+
+ buttons_x1 = (new_x2 + 1 - buttons_width) / 2;
+ buttons_x1 = MAX (0, buttons_x1);
+
+ buttons_y1 = new_y2 + 1 - E_CALENDAR_YPAD_BELOW_LOWER_BUTTONS
+ - button_height - ythickness;
+ buttons_y1 = MAX (0, buttons_y1);
+
+ gnome_canvas_item_set (cal->today_button_item,
+ "x", buttons_x1,
+ "y", buttons_y1,
+ "width", (gdouble) button_width,
+ "height", (gdouble) button_height,
+ NULL);
+
+ if (today_button_shown)
+ buttons_x1 += button_width + E_CALENDAR_XPAD_BUTTONS;
+
+ gnome_canvas_item_set (cal->none_button_item,
+ "x", buttons_x1,
+ "y", buttons_y1,
+ "width", (gdouble) button_width,
+ "height", (gdouble) button_height,
+ NULL);
+ }
+
+ /* Take off space for line & buttons if shown. */
gnome_canvas_item_set (GNOME_CANVAS_ITEM (cal->calitem),
"x1", 0.0,
"y1", 0.0,
"x2", new_x2,
"y2", new_y2,
+ "buttons_space", buttons_height,
NULL);
- button_size = font->ascent + font->descent + E_CALENDAR_ITEM_YPAD1
- + E_CALENDAR_ITEM_YPAD2 - E_CALENDAR_BUTTON_Y_PAD * 2;
+
+ /* Position the arrow buttons. */
+ arrow_button_size = font->ascent + font->descent
+ + E_CALENDAR_ITEM_YPAD_ABOVE_MONTH_NAME
+ + E_CALENDAR_ITEM_YPAD_BELOW_MONTH_NAME
+ - E_CALENDAR_ARROW_BUTTON_Y_PAD * 2;
gnome_canvas_item_set (cal->prev_item,
- "x", xthickness * 2 + E_CALENDAR_BUTTON_X_PAD,
- "y", ythickness * 2 + E_CALENDAR_BUTTON_Y_PAD,
- "width", button_size,
- "height", button_size,
+ "x", xthickness * 2
+ + E_CALENDAR_ARROW_BUTTON_X_PAD,
+ "y", ythickness * 2
+ + E_CALENDAR_ARROW_BUTTON_Y_PAD,
+ "width", arrow_button_size,
+ "height", arrow_button_size,
NULL);
gnome_canvas_item_set (cal->next_item,
"x", new_x2 + 1 - xthickness * 2
- - E_CALENDAR_BUTTON_X_PAD - button_size,
- "y", ythickness * 2 + E_CALENDAR_BUTTON_Y_PAD,
- "width", button_size,
- "height", button_size,
+ - E_CALENDAR_ARROW_BUTTON_X_PAD
+ - arrow_button_size,
+ "y", ythickness * 2
+ + E_CALENDAR_ARROW_BUTTON_Y_PAD,
+ "width", arrow_button_size,
+ "height", arrow_button_size,
NULL);
}
-static gint
-e_calendar_expose (GtkWidget *widget,
- GdkEventExpose *event)
-{
- ECalendar *cal;
-
- cal = E_CALENDAR (widget);
-
- (*GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
-
- e_calendar_paint (cal, &event->area);
-
- return FALSE;
-}
-
-
static void
e_calendar_draw (GtkWidget *widget,
GdkRectangle *area)
@@ -332,51 +467,13 @@ e_calendar_draw (GtkWidget *widget,
(*GTK_WIDGET_CLASS (parent_class)->draw) (widget, area);
- (*GTK_WIDGET_CLASS (grandparent_class)->draw) (widget, area);
-
- e_calendar_paint (cal, area);
-}
-
-
-static void
-e_calendar_paint (ECalendar *cal,
- GdkRectangle *area)
-{
+ /* GnomeCanvas bug workaround to draw the GnomeCanvasWidgets. */
#if 0
- g_print ("In e_calendar_paint: %i,%i %ix%i\n", area->x, area->y,
- area->width, area->height);
+ (*GTK_WIDGET_CLASS (grandparent_class)->draw) (widget, area);
#endif
}
-/* FIXME These aren't used? */
-
-#if 0
-static gint
-e_calendar_button_press (GtkWidget *widget,
- GdkEventButton *event)
-{
- ECalendar *cal;
-
- cal = E_CALENDAR (widget);
-
- g_print ("In e_calendar_button_press\n");
-
- return FALSE;
-}
-
-
-static gint
-e_calendar_button_release (GtkWidget *widget,
- GdkEventButton *event)
-{
- g_print ("In e_calendar_button_release\n");
-
- return FALSE;
-}
-#endif
-
-
static gint
e_calendar_focus_in (GtkWidget *widget,
GdkEventFocus *event)
@@ -439,48 +536,175 @@ e_calendar_set_maximum_size (ECalendar *cal,
}
+/* Returns the border size on each side of the month displays. */
+void
+e_calendar_get_border_size (ECalendar *cal,
+ gint *top,
+ gint *bottom,
+ gint *left,
+ gint *right)
+{
+ GtkStyle *style;
+
+ g_return_if_fail (E_IS_CALENDAR (cal));
+
+ style = GTK_WIDGET (cal)->style;
+
+ if (style) {
+ *top = style->klass->ythickness;
+ *bottom = style->klass->ythickness
+ + cal->calitem->buttons_space;
+ *left = style->klass->xthickness;
+ *right = style->klass->xthickness;
+ } else {
+ *top = *bottom = *left = *right = 0;
+ }
+}
+
+
static void
-e_calendar_on_prev_clicked (ECalendar *cal)
+e_calendar_on_prev_pressed (ECalendar *cal)
{
- gint year, month;
+ e_calendar_start_auto_move (cal, FALSE);
+}
- gtk_object_get (GTK_OBJECT (cal->calitem),
- "year", &year,
- "month", &month,
- NULL);
- month--;
- if (month == -1) {
- year--;
- month = 11;
+static void
+e_calendar_on_next_pressed (ECalendar *cal)
+{
+ e_calendar_start_auto_move (cal, TRUE);
+}
+
+
+static void
+e_calendar_start_auto_move (ECalendar *cal,
+ gboolean moving_forward)
+{
+ ECalendarItem *calitem;
+ gint offset;
+
+ if (cal->timeout_id == 0) {
+ cal->timeout_id = g_timeout_add (E_CALENDAR_AUTO_MOVE_TIMEOUT,
+ e_calendar_auto_move_handler,
+ cal);
}
+ cal->timeout_delay = E_CALENDAR_AUTO_MOVE_TIMEOUT_DELAY;
+ cal->moving_forward = moving_forward;
- gnome_canvas_item_set (GNOME_CANVAS_ITEM (cal->calitem),
- "year", year,
- "month", month,
- NULL);
+ calitem = cal->calitem;
+ offset = cal->moving_forward ? 1 : -1;
+ e_calendar_item_set_first_month (calitem, calitem->year,
+ calitem->month + offset);
+}
+
+
+static gboolean
+e_calendar_auto_move_handler (gpointer data)
+{
+ ECalendar *cal;
+ ECalendarItem *calitem;
+ gint offset;
+
+ g_return_val_if_fail (E_IS_CALENDAR (data), FALSE);
+
+ cal = E_CALENDAR (data);
+ calitem = cal->calitem;
+
+ GDK_THREADS_ENTER ();
+
+ if (cal->timeout_delay > 0) {
+ cal->timeout_delay--;
+ } else {
+ offset = cal->moving_forward ? 1 : -1;
+ e_calendar_item_set_first_month (calitem, calitem->year,
+ calitem->month + offset);
+ }
+
+ GDK_THREADS_LEAVE ();
+ return TRUE;
}
static void
-e_calendar_on_next_clicked (ECalendar *cal)
+e_calendar_on_prev_released (ECalendar *cal)
{
- gint year, month;
+ e_calendar_stop_auto_move (cal);
+}
- gtk_object_get (GTK_OBJECT (cal->calitem),
- "year", &year,
- "month", &month,
- NULL);
- month++;
- if (month == 12) {
- year++;
- month = 0;
+static void
+e_calendar_on_next_released (ECalendar *cal)
+{
+ e_calendar_stop_auto_move (cal);
+}
+
+
+static void
+e_calendar_stop_auto_move (ECalendar *cal)
+{
+ if (cal->timeout_id != 0) {
+ gtk_timeout_remove (cal->timeout_id);
+ cal->timeout_id = 0;
}
+}
- gnome_canvas_item_set (GNOME_CANVAS_ITEM (cal->calitem),
- "year", year,
- "month", month,
- NULL);
+
+/* Set which, if any, of the buttons to show beneath the month displays.
+ You must connect to the button's clicked signal and perform the
+ required action yourself. */
+void
+e_calendar_set_buttons (ECalendar *cal,
+ gboolean show_today_button,
+ gboolean show_none_button)
+{
+ if (show_today_button) {
+ gtk_widget_show (cal->today_button);
+ gnome_canvas_item_show (cal->today_button_item);
+ } else {
+ gtk_widget_hide (cal->today_button);
+ gnome_canvas_item_hide (cal->today_button_item);
+ }
+
+ if (show_none_button) {
+ gtk_widget_show (cal->none_button);
+ gnome_canvas_item_show (cal->none_button_item);
+ } else {
+ gtk_widget_hide (cal->none_button);
+ gnome_canvas_item_hide (cal->none_button_item);
+ }
+}
+
+
+static gint
+e_calendar_drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time)
+{
+ ECalendar *cal;
+
+ g_return_val_if_fail (E_IS_CALENDAR (widget), FALSE);
+
+ cal = E_CALENDAR (widget);
+
+ g_print ("In e_calendar_drag_motion\n");
+
+ return FALSE;
+}
+
+
+static void
+e_calendar_drag_leave (GtkWidget *widget,
+ GdkDragContext *context,
+ guint time)
+{
+ ECalendar *cal;
+
+ g_return_if_fail (E_IS_CALENDAR (widget));
+
+ cal = E_CALENDAR (widget);
+
+ g_print ("In e_calendar_drag_leave\n");
}