diff options
Diffstat (limited to 'calendar/gui/gncal-full-day.c')
-rw-r--r-- | calendar/gui/gncal-full-day.c | 902 |
1 files changed, 831 insertions, 71 deletions
diff --git a/calendar/gui/gncal-full-day.c b/calendar/gui/gncal-full-day.c index ba646d5a2e..b6a61a3a9d 100644 --- a/calendar/gui/gncal-full-day.c +++ b/calendar/gui/gncal-full-day.c @@ -6,26 +6,453 @@ */ #include <gtk/gtkdrawingarea.h> +#include <gtk/gtktext.h> #include "gncal-full-day.h" +#include "view-utils.h" #define TEXT_BORDER 2 +#define HANDLE_SIZE 3 #define MIN_WIDTH 200 +#define XOR_RECT_WIDTH 2 + + +typedef struct { + iCalObject *ico; + GtkWidget *widget; + GdkWindow *window; + int lower_row; /* zero is first displayed row */ + int rows_used; + int x; /* coords of child's window */ + int y; + int width; + int height; +} Child; + +struct layout_row { + int intersections; + int *slots; +}; + +struct drag_info { + Child *child; + enum { + DRAG_MOVE, + DRAG_SIZE + } drag_mode; + int new_y; + int new_height; +}; + + +static void gncal_full_day_class_init (GncalFullDayClass *class); +static void gncal_full_day_init (GncalFullDay *fullday); +static void gncal_full_day_destroy (GtkObject *object); +static void gncal_full_day_map (GtkWidget *widget); +static void gncal_full_day_unmap (GtkWidget *widget); +static void gncal_full_day_realize (GtkWidget *widget); +static void gncal_full_day_unrealize (GtkWidget *widget); +static void gncal_full_day_draw (GtkWidget *widget, + GdkRectangle *area); +static void gncal_full_day_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gncal_full_day_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gncal_full_day_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gncal_full_day_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gncal_full_day_motion (GtkWidget *widget, + GdkEventMotion *event); +static gint gncal_full_day_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gncal_full_day_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); -static void gncal_full_day_class_init (GncalFullDayClass *class); -static void gncal_full_day_init (GncalFullDay *fullday); -static void gncal_full_day_realize (GtkWidget *widget); -static void gncal_full_day_size_request (GtkWidget *widget, - GtkRequisition *requisition); -static void gncal_full_day_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); -static gint gncal_full_day_expose (GtkWidget *widget, - GdkEventExpose *event); +static GtkContainerClass *parent_class; -static GtkContainerClass *parent_class; +static void +get_tm_range (GncalFullDay *fullday, + time_t time_lower, time_t time_upper, + struct tm *lower, struct tm *upper, + int *lower_row, int *rows_used) +{ + struct tm tm_lower, tm_upper; + int lmin, umin; + int lrow; + + /* Lower */ + + tm_lower = *localtime (&time_lower); + + if ((tm_lower.tm_min % fullday->interval) != 0) { + tm_lower.tm_min -= tm_lower.tm_min % fullday->interval; /* round down */ + mktime (&tm_lower); + } + + /* Upper */ + + tm_upper = *localtime (&time_upper); + + if ((tm_upper.tm_min % fullday->interval) != 0) { + tm_upper.tm_min += fullday->interval - (tm_upper.tm_min % fullday->interval); /* round up */ + mktime (&tm_upper); + } + + if (lower) + *lower = tm_lower; + + if (upper) + *upper = tm_upper; + + lmin = 60 * tm_lower.tm_hour + tm_lower.tm_min; + umin = 60 * tm_upper.tm_hour + tm_upper.tm_min; + + if (umin == 0) /* midnight of next day? */ + umin = 60 * 24; + + lrow = lmin / fullday->interval; + + if (lower_row) + *lower_row = lrow; + + if (rows_used) + *rows_used = (umin - lmin) / fullday->interval; +} + +static void +child_map (GncalFullDay *fullday, Child *child) +{ + gdk_window_show (child->window); + + if (GTK_WIDGET_VISIBLE (child->widget) && !GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_map (child->widget); +} + +static void +child_unmap (GncalFullDay *fullday, Child *child) +{ + gdk_window_hide (child->window); + + if (GTK_WIDGET_VISIBLE (child->widget) && GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_unmap (child->widget); +} + +static void +child_move_text (Child *child) +{ + GtkAllocation allocation; + + allocation.x = 0; + allocation.y = HANDLE_SIZE; + allocation.width = child->width; + allocation.height = child->height - 2 * HANDLE_SIZE; + + gtk_widget_size_request (child->widget, &child->widget->requisition); /* FIXME: is this needed? */ + gtk_widget_size_allocate (child->widget, &allocation); +} + +static void +child_realize (GncalFullDay *fullday, Child *child) +{ + GdkWindowAttr attributes; + gint attributes_mask; + GtkWidget *widget; + + widget = GTK_WIDGET (fullday); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = child->x; + attributes.y = child->y; + attributes.width = child->width; + attributes.height = child->height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.cursor = fullday->up_down_cursor; + attributes.event_mask = (GDK_EXPOSURE_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_BUTTON_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_CURSOR; + + child->window = gdk_window_new (widget->window, &attributes, attributes_mask); + gdk_window_set_user_data (child->window, widget); + + gtk_style_set_background (widget->style, child->window, GTK_STATE_NORMAL); + + gtk_widget_set_parent_window (child->widget, child->window); + + child_move_text (child); +} + +static void +child_unrealize (GncalFullDay *fullday, Child *child) +{ + gdk_window_set_user_data (child->window, NULL); + gdk_window_destroy (child->window); + child->window = NULL; +} + +static void +child_draw (GncalFullDay *fullday, Child *child, GdkRectangle *area, int draw_child) +{ + GdkRectangle arect, rect, dest; + gint w, h; + + gdk_window_get_size (child->window, &w, &h); + + if (!area) { + arect.x = 0; + arect.y = 0; + + arect.width = w; + arect.height = h; + + area = &arect; + } + + /* Top handle */ + + rect.x = 0; + rect.y = 0; + rect.width = w; + rect.height = HANDLE_SIZE; + + if (gdk_rectangle_intersect (&rect, area, &dest)) + view_utils_draw_textured_frame (GTK_WIDGET (fullday), child->window, &rect, GTK_SHADOW_OUT); + + /* Bottom handle */ + + rect.y = h - HANDLE_SIZE; + + if (gdk_rectangle_intersect (&rect, area, &dest)) + view_utils_draw_textured_frame (GTK_WIDGET (fullday), child->window, &rect, GTK_SHADOW_OUT); + + if (draw_child) { + area->y -= HANDLE_SIZE; + gtk_widget_draw (child->widget, area); + } +} + +static void +child_set_beam_cursor (GtkWidget *widget, gpointer data) +{ + GncalFullDay *fullday = data; + + gdk_window_set_cursor (widget->window, fullday->beam_cursor); +} + +static Child * +child_new (GncalFullDay *fullday, iCalObject *ico) +{ + Child *child; + struct tm start, end; + int lower_row, rows_used; + int f_lower_row; + + child = g_new (Child, 1); + + child->ico = ico; + child->widget = gtk_text_new (NULL, NULL); + child->window = NULL; + child->x = 0; + child->y = 0; + child->width = 0; + child->height = 0; + + /* Calc display range for event */ + + get_tm_range (fullday, child->ico->dtstart, child->ico->dtend, &start, &end, &lower_row, &rows_used); + get_tm_range (fullday, fullday->lower, fullday->upper, NULL, NULL, &f_lower_row, NULL); + + child->lower_row = lower_row - f_lower_row; + child->rows_used = rows_used; + + /* Finish setup */ + + gtk_signal_connect (GTK_OBJECT (child->widget), "realize", + (GtkSignalFunc) child_set_beam_cursor, + fullday); + + gtk_text_set_editable (GTK_TEXT (child->widget), TRUE); + gtk_text_set_word_wrap (GTK_TEXT (child->widget), TRUE); + gtk_widget_set_parent (child->widget, GTK_WIDGET (fullday)); + gtk_widget_show (child->widget); + + return child; +} + +static void +child_destroy (GncalFullDay *fullday, Child *child) +{ + /* FIXME */ +} + +static void +child_set_pos (GncalFullDay *fullday, Child *child, int x, int y, int width, int height) +{ + child->x = x; + child->y = y; + child->width = width; + child->height = height; + + if (!GTK_WIDGET_REALIZED (fullday)) + return; + + child_move_text (child); + gdk_window_move_resize (child->window, x, y, width, height); +} + +static struct layout_row * +layout_get_rows (GncalFullDay *fullday) +{ + struct layout_row *rows; + int max_i; + int f_rows; + GList *children; + Child *child; + int i, n; + + get_tm_range (fullday, fullday->lower, fullday->upper, NULL, NULL, NULL, &f_rows); + + rows = g_new0 (struct layout_row, f_rows); + max_i = 0; + + for (children = fullday->children; children; children = children->next) { + child = children->data; + + for (i = 0; i < child->rows_used; i++) { + n = child->lower_row + i; + + rows[n].intersections++; + + if (rows[n].intersections > max_i) + max_i = rows[n].intersections; + } + } + + for (i = 0; i < f_rows; i++) + rows[i].slots = g_new0 (int, max_i); + + return rows; +} + +static void +layout_get_child_intersections (Child *child, struct layout_row *rows, int *min, int *max) +{ + int i, n; + int imin, imax; + + imax = 0; + + for (i = 0; i < child->rows_used; i++) { + n = child->lower_row + i; + + if (rows[n].intersections > imax) + imax = rows[n].intersections; + } + + imin = imax; + + for (i = 0; i < child->rows_used; i++) { + n = child->lower_row + i; + + if (rows[n].intersections < imin) + imin = rows[n].intersections; + } + + if (min) + *min = imin; + + if (max) + *max = imax; +} + +static int +calc_labels_width (GncalFullDay *fullday) +{ + struct tm cur, upper; + time_t tim, time_upper; + int width, max_w; + char buf[256]; + + get_tm_range (fullday, fullday->lower, fullday->upper, &cur, &upper, NULL, NULL); + + max_w = 0; + + tim = mktime (&cur); + time_upper = mktime (&upper); + + while (tim < time_upper) { + strftime (buf, 256, "%X", &cur); + + width = gdk_string_width (GTK_WIDGET (fullday)->style->font, buf); + + if (width > max_w) + max_w = width; + + cur.tm_min += fullday->interval; + tim = mktime (&cur); + } + + return max_w; +} + +static void +layout_child (GncalFullDay *fullday, Child *child, struct layout_row *rows) +{ + int c_x, c_y, c_width, c_height; + GtkWidget *widget; + int labels_width; + int height, f_rows; + int row_height; + + /* Calculate child position */ + + widget = GTK_WIDGET (fullday); + + labels_width = calc_labels_width (fullday); /* FIXME: this is expensive to do for each child */ + + get_tm_range (fullday, fullday->lower, fullday->upper, NULL, NULL, NULL, &f_rows); + + height = widget->allocation.height - 2 * widget->style->klass->ythickness; + row_height = height / f_rows; + + c_x = 2 * (widget->style->klass->xthickness + TEXT_BORDER) + labels_width; + c_y = widget->style->klass->ythickness; + + /* FIXME: for now, the children overlap. Make it layout them nicely. */ + + c_width = widget->allocation.width - (widget->style->klass->xthickness + c_x); + + c_y += child->lower_row * row_height; + c_height = child->rows_used * row_height; + + /* Position child */ + + child_set_pos (fullday, child, c_x, c_y, c_width, c_height); +} + +static void +layout_children (GncalFullDay *fullday) +{ + struct layout_row *rows; + GList *children; + + rows = layout_get_rows (fullday); + + for (children = fullday->children; children; children = children->next) + layout_child (fullday, children->data, rows); + + g_free (rows); +} guint gncal_full_day_get_type (void) @@ -52,18 +479,31 @@ gncal_full_day_get_type (void) static void gncal_full_day_class_init (GncalFullDayClass *class) { + GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkContainerClass *container_class; + object_class = (GtkObjectClass *) class; widget_class = (GtkWidgetClass *) class; container_class = (GtkContainerClass *) class; parent_class = gtk_type_class (gtk_container_get_type ()); + object_class->destroy = gncal_full_day_destroy; + + widget_class->map = gncal_full_day_map; + widget_class->unmap = gncal_full_day_unmap; widget_class->realize = gncal_full_day_realize; + widget_class->unrealize = gncal_full_day_unrealize; + widget_class->draw = gncal_full_day_draw; widget_class->size_request = gncal_full_day_size_request; widget_class->size_allocate = gncal_full_day_size_allocate; + widget_class->button_press_event = gncal_full_day_button_press; + widget_class->button_release_event = gncal_full_day_button_release; + widget_class->motion_notify_event = gncal_full_day_motion; widget_class->expose_event = gncal_full_day_expose; + + container_class->foreach = gncal_full_day_foreach; } static void @@ -76,6 +516,29 @@ gncal_full_day_init (GncalFullDay *fullday) fullday->lower = 0; fullday->upper = 0; fullday->interval = 30; /* 30 minutes by default */ + + fullday->children = NULL; + fullday->drag_info = g_new (struct drag_info, 1); + + fullday->up_down_cursor = NULL; + fullday->beam_cursor = NULL; +} + +static void +gncal_full_day_destroy (GtkObject *object) +{ + GncalFullDay *fullday; + + g_return_if_fail (object != NULL); + g_return_if_fail (GNCAL_IS_FULL_DAY (object)); + + fullday = GNCAL_FULL_DAY (object); + + g_list_free (fullday->children); + g_free (fullday->drag_info); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); } GtkWidget * @@ -95,16 +558,58 @@ gncal_full_day_new (GnomeCalendar *calendar, time_t lower, time_t upper) } static void +gncal_full_day_map (GtkWidget *widget) +{ + GncalFullDay *fullday; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GNCAL_IS_FULL_DAY (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + fullday = GNCAL_FULL_DAY (widget); + + gdk_window_show (widget->window); + + for (children = fullday->children; children; children = children->next) + child_map (fullday, children->data); +} + +static void +gncal_full_day_unmap (GtkWidget *widget) +{ + GncalFullDay *fullday; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GNCAL_IS_FULL_DAY (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + + fullday = GNCAL_FULL_DAY (widget); + + gdk_window_hide (widget->window); + + for (children = fullday->children; children; children = children->next) + child_unmap (fullday, children->data); +} + +static void gncal_full_day_realize (GtkWidget *widget) { + GncalFullDay *fullday; GdkWindowAttr attributes; gint attributes_mask; + GList *children; g_return_if_fail (widget != NULL); g_return_if_fail (GNCAL_IS_FULL_DAY (widget)); GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + fullday = GNCAL_FULL_DAY (widget); + attributes.window_type = GDK_WINDOW_CHILD; attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; @@ -123,75 +628,53 @@ gncal_full_day_realize (GtkWidget *widget) widget->style = gtk_style_attach (widget->style, widget->window); gdk_window_set_background (widget->window, &widget->style->bg[GTK_STATE_PRELIGHT]); -} -static int -get_tm_bounds (GncalFullDay *fullday, struct tm *lower, struct tm *upper) -{ - struct tm tm_lower, tm_upper; - int lmin, umin; - - /* Lower */ - - tm_lower = *localtime (&fullday->lower); - - if ((tm_lower.tm_min % fullday->interval) != 0) { - tm_lower.tm_min -= tm_lower.tm_min % fullday->interval; /* round down */ - mktime (&tm_lower); - } + fullday->up_down_cursor = gdk_cursor_new (GDK_DOUBLE_ARROW); + fullday->beam_cursor = gdk_cursor_new (GDK_XTERM); - /* Upper */ + for (children = fullday->children; children; children = children->next) + child_realize (fullday, children->data); +} - tm_upper = *localtime (&fullday->upper); +static void +gncal_full_day_unrealize (GtkWidget *widget) +{ + GncalFullDay *fullday; + GList *children; - if ((tm_upper.tm_min % fullday->interval) != 0) { - tm_upper.tm_min += fullday->interval - (tm_upper.tm_min % fullday->interval); /* round up */ - mktime (&tm_upper); - } + g_return_if_fail (widget != NULL); + g_return_if_fail (GNCAL_IS_FULL_DAY (widget)); - if (lower) - *lower = tm_lower; + fullday = GNCAL_FULL_DAY (widget); - if (upper) - *upper = tm_upper; + for (children = fullday->children; children; children = children->next) + child_unrealize (fullday, children->data); - lmin = 60 * tm_lower.tm_hour + tm_lower.tm_min; - umin = 60 * tm_upper.tm_hour + tm_upper.tm_min; + gdk_cursor_destroy (fullday->up_down_cursor); + fullday->up_down_cursor = NULL; - if (umin == 0) /* midnight of next day? */ - umin = 60 * 24; + gdk_cursor_destroy (fullday->beam_cursor); + fullday->beam_cursor = NULL; - return (umin - lmin) / fullday->interval; /* number of rows in view */ + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); } -static int -calc_labels_width (GncalFullDay *fullday) +static void +gncal_full_day_draw (GtkWidget *widget, GdkRectangle *area) { - struct tm cur, upper; - time_t tim, time_upper; - int width, max_w; - char buf[256]; - - get_tm_bounds (fullday, &cur, &upper); - - max_w = 0; - - tim = mktime (&cur); - time_upper = mktime (&upper); - - while (tim < time_upper) { - strftime (buf, 256, "%X", &cur); + GncalFullDay *fullday; - width = gdk_string_width (GTK_WIDGET (fullday)->style->font, buf); + g_return_if_fail (widget != NULL); + g_return_if_fail (GNCAL_IS_FULL_DAY (widget)); + g_return_if_fail (area != NULL); - if (width > max_w) - max_w = width; + if (!GTK_WIDGET_DRAWABLE (widget)) + return; - cur.tm_min += fullday->interval; - tim = mktime (&cur); - } + fullday = GNCAL_FULL_DAY (widget); - return max_w; + /* FIXME */ } static void @@ -216,7 +699,7 @@ gncal_full_day_size_request (GtkWidget *widget, GtkRequisition *requisition) /* Rows */ - rows = get_tm_bounds (fullday, NULL, NULL); + get_tm_range (fullday, fullday->lower, fullday->upper, NULL, NULL, NULL, &rows); requisition->height += (rows * (2 * TEXT_BORDER + widget->style->font->ascent + widget->style->font->descent) + (rows - 1)); /* division lines */ @@ -225,18 +708,220 @@ gncal_full_day_size_request (GtkWidget *widget, GtkRequisition *requisition) static void gncal_full_day_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { + GncalFullDay *fullday; + g_return_if_fail (widget != NULL); g_return_if_fail (GNCAL_IS_FULL_DAY (widget)); g_return_if_fail (allocation != NULL); widget->allocation = *allocation; + fullday = GNCAL_FULL_DAY (widget); + if (GTK_WIDGET_REALIZED (widget)) gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height); - /* FIXME: adjust children */ + layout_children (fullday); +} + +static Child * +find_child_by_window (GncalFullDay *fullday, GdkWindow *window) +{ + GList *children; + Child *child; + + for (children = fullday->children; children; children = children->next) { + child = children->data; + + if (child->window == window) + return child; + } + + return NULL; +} + +static void +draw_xor_rect (GncalFullDay *fullday) +{ + GtkWidget *widget; + struct drag_info *di; + int i; + + widget = GTK_WIDGET (fullday); + + gdk_gc_set_function (widget->style->white_gc, GDK_INVERT); + gdk_gc_set_subwindow (widget->style->white_gc, GDK_INCLUDE_INFERIORS); + + di = fullday->drag_info; + + for (i = 0; i < XOR_RECT_WIDTH; i++) + gdk_draw_rectangle (widget->window, + widget->style->white_gc, + FALSE, + di->child->x + i, + di->new_y + i, + di->child->width - 2 * i - 1, + di->new_height - 2 * i - 1); + + gdk_gc_set_function (widget->style->white_gc, GDK_COPY); + gdk_gc_set_subwindow (widget->style->white_gc, GDK_CLIP_BY_CHILDREN); +} + +static gint +gncal_full_day_button_press (GtkWidget *widget, GdkEventButton *event) +{ + GncalFullDay *fullday; + Child *child; + struct drag_info *di; + gint y; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GNCAL_IS_FULL_DAY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + fullday = GNCAL_FULL_DAY (widget); + + if (event->window == widget->window) + return FALSE; /* FIXME: do range selection thing */ + else { + child = find_child_by_window (fullday, event->window); + + if (!child) + return FALSE; + + di = fullday->drag_info; + + di->child = child; + + gtk_widget_get_pointer (widget, NULL, &y); + + if (event->y < HANDLE_SIZE) + di->drag_mode = DRAG_MOVE; + else + di->drag_mode = DRAG_SIZE; + + di->new_y = child->y; + di->new_height = child->height; + + gdk_pointer_grab (child->window, FALSE, + (GDK_BUTTON_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK + | GDK_BUTTON_RELEASE_MASK), + NULL, + NULL, + event->time); + + draw_xor_rect (fullday); + } + + return FALSE; +} + +static void +recompute_motion (GncalFullDay *fullday, int y) +{ + GtkWidget *widget; + struct drag_info *di; + int rows, row_height; + int ythickness; + + widget = GTK_WIDGET (fullday); + + get_tm_range (fullday, fullday->lower, fullday->upper, NULL, NULL, NULL, &rows); + + ythickness = widget->style->klass->ythickness; + + row_height = (widget->allocation.height - 2 * ythickness) / rows; + + y -= ythickness; + y = (y + row_height / 2) / row_height; /* round to nearest bound */ + y = y * row_height + ythickness; + + di = fullday->drag_info; + + switch (di->drag_mode) { + case DRAG_MOVE: + if (y < ythickness) + y = ythickness; + else if (y >= (ythickness + rows * row_height - di->new_height)) + y = ythickness + rows * row_height - di->new_height; + + di->new_y = y; + + break; + + case DRAG_SIZE: + if (y <= di->child->y) + y = di->child->y + row_height; + else if (y >= (ythickness + rows * row_height)) + y = ythickness + rows * row_height; + + di->new_height = y - di->new_y; + + break; + + default: + g_assert_not_reached (); + } +} + +static gint +gncal_full_day_button_release (GtkWidget *widget, GdkEventButton *event) +{ + GncalFullDay *fullday; + struct drag_info *di; + gint y; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GNCAL_IS_FULL_DAY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + fullday = GNCAL_FULL_DAY (widget); + + di = fullday->drag_info; + + if (!di->child || (event->window != di->child->window)) + return FALSE; + + gtk_widget_get_pointer (widget, NULL, &y); + + draw_xor_rect (fullday); + recompute_motion (fullday, y); + gdk_pointer_ungrab (event->time); + + /* FIXME: update child, notify, etc. */ + + di->child = NULL; + + return FALSE; +} + +static gint +gncal_full_day_motion (GtkWidget *widget, GdkEventMotion *event) +{ + GncalFullDay *fullday; + struct drag_info *di; + gint y; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GNCAL_IS_FULL_DAY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + fullday = GNCAL_FULL_DAY (widget); + di = fullday->drag_info; + + if (!di->child || (event->window != di->child->window)) + return FALSE; + + gtk_widget_get_pointer (widget, NULL, &y); + + draw_xor_rect (fullday); + recompute_motion (fullday, y); + draw_xor_rect (fullday); + + return FALSE; } static void @@ -296,11 +981,11 @@ paint_back (GncalFullDay *fullday, GdkRectangle *area) /* Horizontal divisions */ - rows = get_tm_bounds (fullday, &tm, NULL); + get_tm_range (fullday, fullday->lower, fullday->upper, &tm, NULL, NULL, &rows); - row_height = height / rows; /* includes division line */ + row_height = height / rows; /* includes division line at bottom of row */ - y = row_height; + y = y1 + row_height - 1; for (i = 1; i < rows; i++) { gdk_draw_line (widget->window, @@ -315,6 +1000,8 @@ paint_back (GncalFullDay *fullday, GdkRectangle *area) y = y1 + ((row_height - 1) - (widget->style->font->ascent + widget->style->font->descent)) / 2; + rect.height = row_height - 1; + for (i = 0; i < rows; i++) { mktime (&tm); @@ -340,6 +1027,8 @@ static gint gncal_full_day_expose (GtkWidget *widget, GdkEventExpose *event) { GncalFullDay *fullday; + GList *children; + Child *child; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GNCAL_IS_FULL_DAY (widget), FALSE); @@ -352,19 +1041,90 @@ gncal_full_day_expose (GtkWidget *widget, GdkEventExpose *event) if (event->window == widget->window) paint_back (fullday, &event->area); - - /* FIXME: paint handles in windows if event->window == blah blah */ + else + for (children = fullday->children; children; children = children->next) { + child = children->data; + + if (event->window == child->window) { + child_draw (fullday, child, &event->area, FALSE); + break; + } + } return FALSE; } +static void +gncal_full_day_foreach (GtkContainer *container, GtkCallback callback, gpointer callback_data) +{ + GncalFullDay *fullday; + GList *children; + Child *child; + + g_return_if_fail (container != NULL); + g_return_if_fail (GNCAL_IS_FULL_DAY (container)); + g_return_if_fail (callback != NULL); + + fullday = GNCAL_FULL_DAY (container); + + for (children = fullday->children; children; children = children->next) { + child = children->data; + + (*callback) (child->widget, callback_data); + } +} + void gncal_full_day_update (GncalFullDay *fullday) { + GList *children; + GList *l_events, *events; + Child *child; + g_return_if_fail (fullday != NULL); g_return_if_fail (GNCAL_IS_FULL_DAY (fullday)); - /* FIXME */ + if (!fullday->calendar->cal) + return; + + l_events = calendar_get_events_in_range (fullday->calendar->cal, + fullday->lower, + fullday->upper, + calendar_compare_by_dtstart); + + /* FIXME: this is expensive and looks ugly -- use some form of cache? */ + + for (children = fullday->children; children; children = children->next) + child_destroy (fullday, children->data); + + g_list_free (fullday->children); + + children = NULL; + + for (events = l_events; events; events = events->next) { + child = child_new (fullday, events->data); + children = g_list_append (children, child); + } + + g_list_free (l_events); + + fullday->children = g_list_first (children); + + layout_children (fullday); + + /* Realize and map children */ + + for (children = fullday->children; children; children = children->next) { + if (GTK_WIDGET_REALIZED (fullday)) + child_realize (fullday, children->data); + + if (GTK_WIDGET_MAPPED (fullday)) + child_map (fullday, children->data); + } + + /* FIXME: paint or something */ + + gtk_widget_draw (GTK_WIDGET (fullday), NULL); } void |