From b5a61327da495147f0a45b4a9f6ee3a77687eeab Mon Sep 17 00:00:00 2001 From: Arturo Espinosa Date: Tue, 7 Apr 1998 19:01:42 +0000 Subject: More work in progress, wheeeee - Federico svn path=/trunk/; revision=109 --- calendar/ChangeLog | 42 ++ calendar/calendar.c | 1 + calendar/calendar.h | 1 + calendar/eventedit.c | 9 +- calendar/eventedit.h | 2 + calendar/gncal-day-view.c | 11 +- calendar/gncal-full-day.c | 902 +++++++++++++++++++++++++++++++++++++---- calendar/gncal-full-day.h | 6 + calendar/gncal-week-view.c | 2 +- calendar/gnome-cal.c | 20 +- calendar/gnome-cal.h | 1 - calendar/gui/calendar.c | 1 + calendar/gui/calendar.h | 1 + calendar/gui/eventedit.c | 9 +- calendar/gui/eventedit.h | 2 + calendar/gui/gncal-day-view.c | 11 +- calendar/gui/gncal-full-day.c | 902 +++++++++++++++++++++++++++++++++++++---- calendar/gui/gncal-full-day.h | 6 + calendar/gui/gncal-week-view.c | 2 +- calendar/gui/gnome-cal.c | 20 +- calendar/gui/gnome-cal.h | 1 - calendar/gui/main.c | 5 +- calendar/gui/test.vcf | 9 +- calendar/main.c | 5 +- calendar/test.vcf | 9 +- calendar/timeutil.c | 1 - calendar/timeutil.h | 4 + 27 files changed, 1808 insertions(+), 177 deletions(-) diff --git a/calendar/ChangeLog b/calendar/ChangeLog index 99399d1f38..ced0d7c6ad 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,45 @@ +1998-04-06 Federico Mena Quintero + + * gncal-week-view.c (gncal_week_view_new): Use the new + gtk_table_set_homogeneous() instead of setting the variable directly. + +1998-04-03 Federico Mena Quintero + + * eventedit.c (ee_create_ae): Make it return void. + (ee_alarm_widgets): Remove some unused variables. + (ee_store_alarm): Make it return void. + #include + + * eventedit.h: #include "gnome-cal.h" + + * calobj.c (list_free): Don't use g_free in the g_list_foreach. + + * calendar.h: Add prototype for calendar_load(). + + * timeutil.h: Add prototypes for time_add_*(). + + * calendar.c: + * calobj.c: + * eventedit.c: + * gnome-cal.c: #include "timeutil.h" + + * gncal-day-view.c (gncal_day_view_size_request): Make the minimum + width equal or larger to the title width. + + * main.c: #include "eventedit.h" + (main): Add a return statement. + (new_calendar): Show stuff *after* the calendar has been loaded. + + * gnome-cal.c (gnome_calendar_load): Update the day view. + (setup_widgets): Hackish setup of a day view widget - will fix later. + (gnome_calendar_init): Initialize all fields. + + * gnome-cal.h: Added day_view field. Maybe this should be changed + when the a complete day view panel is complete. + + * gncal-day-view.c (gncal_day_view_update): Draw after update, not + before. + 1998-04-06 Carsten Schaar * versit/.cvsignore: New file. diff --git a/calendar/calendar.c b/calendar/calendar.c index 581a75ee2f..c06414a571 100644 --- a/calendar/calendar.c +++ b/calendar/calendar.c @@ -15,6 +15,7 @@ #include #include "calendar.h" +#include "timeutil.h" #include "versit/vcc.h" Calendar * diff --git a/calendar/calendar.h b/calendar/calendar.h index f990caabd6..8f4e4c1497 100644 --- a/calendar/calendar.h +++ b/calendar/calendar.h @@ -18,6 +18,7 @@ typedef struct { } Calendar; Calendar *calendar_new (char *title); +void calendar_load (Calendar *cal, char *fname); void calendar_add_object (Calendar *cal, iCalObject *obj); void calendar_remove_object (Calendar *cal, iCalObject *obj); void calendar_destroy (Calendar *cal); diff --git a/calendar/eventedit.c b/calendar/eventedit.c index 1a63bd60f5..7846eab86e 100644 --- a/calendar/eventedit.c +++ b/calendar/eventedit.c @@ -6,10 +6,11 @@ */ #include +#include #include "calendar.h" -#include "gnome-cal.h" #include "eventedit.h" #include "main.h" +#include "timeutil.h" static void event_editor_init (EventEditor *ee); GtkWindow *parent_class; @@ -202,10 +203,9 @@ alarm_toggle (GtkToggleButton *toggle, CalendarAlarm *alarm) #define FX GTK_FILL | GTK_EXPAND #define XCOL 6 -static GtkWidget * +static void ee_create_ae (GtkTable *table, char *str, CalendarAlarm *alarm, enum AlarmType type, int y) { - GtkWidget *timesel; char buffer [40]; alarm->w_enabled = gtk_check_button_new_with_label (str); @@ -253,7 +253,7 @@ ee_create_ae (GtkTable *table, char *str, CalendarAlarm *alarm, enum AlarmType t static GtkWidget * ee_alarm_widgets (EventEditor *ee) { - GtkWidget *table, *aalarm, *dalarm, *palarm, *malarm, *mailto, *mailte, *l; + GtkWidget *table, *mailto, *mailte, *l; l = gtk_frame_new (_("Alarms")); @@ -304,6 +304,7 @@ ee_classification_widgets (EventEditor *ee) * Retrieves the information from the CalendarAlarm widgets and stores them * on the CalendarAlarm generic values */ +void ee_store_alarm (CalendarAlarm *alarm, enum AlarmType type) { GtkWidget *item; diff --git a/calendar/eventedit.h b/calendar/eventedit.h index e726270877..2396d302f6 100644 --- a/calendar/eventedit.h +++ b/calendar/eventedit.h @@ -8,6 +8,8 @@ #ifndef EVENT_EDITOR_H #define EVENT_EDITOR_H +#include "gnome-cal.h" + BEGIN_GNOME_DECLS #define EVENT_EDITOR(obj) GTK_CHECK_CAST(obj, event_editor_get_type(), EventEditor) diff --git a/calendar/gncal-day-view.c b/calendar/gncal-day-view.c index 209b6be40a..951b0eb5ae 100644 --- a/calendar/gncal-day-view.c +++ b/calendar/gncal-day-view.c @@ -156,6 +156,7 @@ static void gncal_day_view_size_request (GtkWidget *widget, GtkRequisition *requisition) { GncalDayView *dview; + int str_width, width; g_return_if_fail (widget != NULL); g_return_if_fail (GNCAL_IS_DAY_VIEW (widget)); @@ -165,7 +166,11 @@ gncal_day_view_size_request (GtkWidget *widget, GtkRequisition *requisition) /* border and min width */ - requisition->width = 2 * (widget->style->klass->xthickness + TEXT_BORDER) + MIN_INFO_WIDTH; + str_width = gdk_string_width (widget->style->font, dview->day_str); + + width = MAX (MIN_INFO_WIDTH, str_width); + + requisition->width = 2 * (widget->style->klass->xthickness + TEXT_BORDER) + width; requisition->height = 2 * (widget->style->klass->ythickness + TEXT_BORDER); /* division line */ @@ -297,8 +302,6 @@ gncal_day_view_update (GncalDayView *dview) strftime (buf, sizeof (buf)-1, "%A %d", &tm); dview->day_str = g_strdup (buf); - gtk_widget_draw (GTK_WIDGET (dview), NULL); - if (dview->events) g_list_free (dview->events); @@ -306,6 +309,8 @@ gncal_day_view_update (GncalDayView *dview) dview->lower, dview->upper, calendar_compare_by_dtstart); + + gtk_widget_draw (GTK_WIDGET (dview), NULL); } void diff --git a/calendar/gncal-full-day.c b/calendar/gncal-full-day.c index ba646d5a2e..b6a61a3a9d 100644 --- a/calendar/gncal-full-day.c +++ b/calendar/gncal-full-day.c @@ -6,26 +6,453 @@ */ #include +#include #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 * @@ -94,17 +557,59 @@ gncal_full_day_new (GnomeCalendar *calendar, time_t lower, time_t upper) return GTK_WIDGET (fullday); } +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 diff --git a/calendar/gncal-full-day.h b/calendar/gncal-full-day.h index eeee2278cd..27e60c9326 100644 --- a/calendar/gncal-full-day.h +++ b/calendar/gncal-full-day.h @@ -34,6 +34,12 @@ struct _GncalFullDay { time_t lower; /* lower time to display */ time_t upper; /* upper time to display */ int interval; /* interval between rows in minutes */ + + GList *children; /* container children */ + gpointer drag_info; /* internal drag information */ + + GdkCursor *up_down_cursor; /* for dragging children */ + GdkCursor *beam_cursor; /* for the text widgets */ }; struct _GncalFullDayClass { diff --git a/calendar/gncal-week-view.c b/calendar/gncal-week-view.c index f837b3b2d8..4adf7ba283 100644 --- a/calendar/gncal-week-view.c +++ b/calendar/gncal-week-view.c @@ -58,7 +58,7 @@ gncal_week_view_new (GnomeCalendar *calendar, time_t start_of_week) wview = gtk_type_new (gncal_week_view_get_type ()); - wview->table.homogeneous = TRUE; /* FIXME: eeeeeeeeeek, GtkTable does not have a function to set this */ + gtk_table_set_homogeneous (GTK_TABLE (wview), TRUE); wview->calendar = calendar; diff --git a/calendar/gnome-cal.c b/calendar/gnome-cal.c index 6e6c17ed21..b202422e2d 100644 --- a/calendar/gnome-cal.c +++ b/calendar/gnome-cal.c @@ -10,6 +10,7 @@ #include "gnome-cal.h" #include "gncal-full-day.h" #include "gncal-week-view.h" +#include "timeutil.h" #include "views.h" static void gnome_calendar_init (GnomeCalendar *gcal); @@ -40,21 +41,23 @@ static void setup_widgets (GnomeCalendar *gcal) { time_t now; + GtkWidget *sw; now = time (NULL); gcal->notebook = gtk_notebook_new (); - gcal->day_view = day_view_create (gcal); + gcal->day_view = day_view_create (gcal); gcal->week_view = gncal_week_view_new (gcal, now); gcal->year_view = year_view_create (gcal); gcal->task_view = tasks_create (gcal); - if (0) + if (1) { struct tm tm; time_t a, b; tm = *localtime (&now); +/* tm.tm_mday = 2; */ tm.tm_hour = 0; tm.tm_min = 0; tm.tm_sec = 0; @@ -66,9 +69,16 @@ setup_widgets (GnomeCalendar *gcal) b = mktime (&tm); gcal->day_view = gncal_full_day_new (gcal, a, b); + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_container_add (GTK_CONTAINER (sw), gcal->day_view); + gtk_widget_show (gcal->day_view); } - gtk_notebook_append_page (GTK_NOTEBOOK (gcal->notebook), gcal->day_view, gtk_label_new (_("Day View"))); + gtk_notebook_append_page (GTK_NOTEBOOK (gcal->notebook), sw, gtk_label_new (_("Day View"))); gtk_notebook_append_page (GTK_NOTEBOOK (gcal->notebook), gcal->week_view, gtk_label_new (_("Week View"))); gtk_notebook_append_page (GTK_NOTEBOOK (gcal->notebook), gcal->year_view, gtk_label_new (_("Year View"))); gtk_notebook_append_page (GTK_NOTEBOOK (gcal->notebook), gcal->task_view, gtk_label_new (_("Todo"))); @@ -83,6 +93,9 @@ static void gnome_calendar_init(GnomeCalendar *gcal) { gcal->cal = 0; + gcal->day_view = 0; + gcal->week_view = 0; + gcal->event_editor = 0; setup_widgets (gcal); } @@ -164,6 +177,7 @@ gnome_calendar_new (char *title) void gnome_calendar_update_all (GnomeCalendar *cal) { + gncal_full_day_update (GNCAL_FULL_DAY (cal->day_view)); gncal_week_view_update (GNCAL_WEEK_VIEW (cal->week_view)); } diff --git a/calendar/gnome-cal.h b/calendar/gnome-cal.h index c13162ef65..053737fd4f 100644 --- a/calendar/gnome-cal.h +++ b/calendar/gnome-cal.h @@ -20,7 +20,6 @@ BEGIN_GNOME_DECLS typedef struct { GnomeApp gnome_app; Calendar *cal; - time_t current_display; GtkWidget *notebook; diff --git a/calendar/gui/calendar.c b/calendar/gui/calendar.c index 581a75ee2f..c06414a571 100644 --- a/calendar/gui/calendar.c +++ b/calendar/gui/calendar.c @@ -15,6 +15,7 @@ #include #include "calendar.h" +#include "timeutil.h" #include "versit/vcc.h" Calendar * diff --git a/calendar/gui/calendar.h b/calendar/gui/calendar.h index f990caabd6..8f4e4c1497 100644 --- a/calendar/gui/calendar.h +++ b/calendar/gui/calendar.h @@ -18,6 +18,7 @@ typedef struct { } Calendar; Calendar *calendar_new (char *title); +void calendar_load (Calendar *cal, char *fname); void calendar_add_object (Calendar *cal, iCalObject *obj); void calendar_remove_object (Calendar *cal, iCalObject *obj); void calendar_destroy (Calendar *cal); diff --git a/calendar/gui/eventedit.c b/calendar/gui/eventedit.c index 1a63bd60f5..7846eab86e 100644 --- a/calendar/gui/eventedit.c +++ b/calendar/gui/eventedit.c @@ -6,10 +6,11 @@ */ #include +#include #include "calendar.h" -#include "gnome-cal.h" #include "eventedit.h" #include "main.h" +#include "timeutil.h" static void event_editor_init (EventEditor *ee); GtkWindow *parent_class; @@ -202,10 +203,9 @@ alarm_toggle (GtkToggleButton *toggle, CalendarAlarm *alarm) #define FX GTK_FILL | GTK_EXPAND #define XCOL 6 -static GtkWidget * +static void ee_create_ae (GtkTable *table, char *str, CalendarAlarm *alarm, enum AlarmType type, int y) { - GtkWidget *timesel; char buffer [40]; alarm->w_enabled = gtk_check_button_new_with_label (str); @@ -253,7 +253,7 @@ ee_create_ae (GtkTable *table, char *str, CalendarAlarm *alarm, enum AlarmType t static GtkWidget * ee_alarm_widgets (EventEditor *ee) { - GtkWidget *table, *aalarm, *dalarm, *palarm, *malarm, *mailto, *mailte, *l; + GtkWidget *table, *mailto, *mailte, *l; l = gtk_frame_new (_("Alarms")); @@ -304,6 +304,7 @@ ee_classification_widgets (EventEditor *ee) * Retrieves the information from the CalendarAlarm widgets and stores them * on the CalendarAlarm generic values */ +void ee_store_alarm (CalendarAlarm *alarm, enum AlarmType type) { GtkWidget *item; diff --git a/calendar/gui/eventedit.h b/calendar/gui/eventedit.h index e726270877..2396d302f6 100644 --- a/calendar/gui/eventedit.h +++ b/calendar/gui/eventedit.h @@ -8,6 +8,8 @@ #ifndef EVENT_EDITOR_H #define EVENT_EDITOR_H +#include "gnome-cal.h" + BEGIN_GNOME_DECLS #define EVENT_EDITOR(obj) GTK_CHECK_CAST(obj, event_editor_get_type(), EventEditor) diff --git a/calendar/gui/gncal-day-view.c b/calendar/gui/gncal-day-view.c index 209b6be40a..951b0eb5ae 100644 --- a/calendar/gui/gncal-day-view.c +++ b/calendar/gui/gncal-day-view.c @@ -156,6 +156,7 @@ static void gncal_day_view_size_request (GtkWidget *widget, GtkRequisition *requisition) { GncalDayView *dview; + int str_width, width; g_return_if_fail (widget != NULL); g_return_if_fail (GNCAL_IS_DAY_VIEW (widget)); @@ -165,7 +166,11 @@ gncal_day_view_size_request (GtkWidget *widget, GtkRequisition *requisition) /* border and min width */ - requisition->width = 2 * (widget->style->klass->xthickness + TEXT_BORDER) + MIN_INFO_WIDTH; + str_width = gdk_string_width (widget->style->font, dview->day_str); + + width = MAX (MIN_INFO_WIDTH, str_width); + + requisition->width = 2 * (widget->style->klass->xthickness + TEXT_BORDER) + width; requisition->height = 2 * (widget->style->klass->ythickness + TEXT_BORDER); /* division line */ @@ -297,8 +302,6 @@ gncal_day_view_update (GncalDayView *dview) strftime (buf, sizeof (buf)-1, "%A %d", &tm); dview->day_str = g_strdup (buf); - gtk_widget_draw (GTK_WIDGET (dview), NULL); - if (dview->events) g_list_free (dview->events); @@ -306,6 +309,8 @@ gncal_day_view_update (GncalDayView *dview) dview->lower, dview->upper, calendar_compare_by_dtstart); + + gtk_widget_draw (GTK_WIDGET (dview), NULL); } void 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 +#include #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 * @@ -94,17 +557,59 @@ gncal_full_day_new (GnomeCalendar *calendar, time_t lower, time_t upper) return GTK_WIDGET (fullday); } +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 diff --git a/calendar/gui/gncal-full-day.h b/calendar/gui/gncal-full-day.h index eeee2278cd..27e60c9326 100644 --- a/calendar/gui/gncal-full-day.h +++ b/calendar/gui/gncal-full-day.h @@ -34,6 +34,12 @@ struct _GncalFullDay { time_t lower; /* lower time to display */ time_t upper; /* upper time to display */ int interval; /* interval between rows in minutes */ + + GList *children; /* container children */ + gpointer drag_info; /* internal drag information */ + + GdkCursor *up_down_cursor; /* for dragging children */ + GdkCursor *beam_cursor; /* for the text widgets */ }; struct _GncalFullDayClass { diff --git a/calendar/gui/gncal-week-view.c b/calendar/gui/gncal-week-view.c index f837b3b2d8..4adf7ba283 100644 --- a/calendar/gui/gncal-week-view.c +++ b/calendar/gui/gncal-week-view.c @@ -58,7 +58,7 @@ gncal_week_view_new (GnomeCalendar *calendar, time_t start_of_week) wview = gtk_type_new (gncal_week_view_get_type ()); - wview->table.homogeneous = TRUE; /* FIXME: eeeeeeeeeek, GtkTable does not have a function to set this */ + gtk_table_set_homogeneous (GTK_TABLE (wview), TRUE); wview->calendar = calendar; diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c index 6e6c17ed21..b202422e2d 100644 --- a/calendar/gui/gnome-cal.c +++ b/calendar/gui/gnome-cal.c @@ -10,6 +10,7 @@ #include "gnome-cal.h" #include "gncal-full-day.h" #include "gncal-week-view.h" +#include "timeutil.h" #include "views.h" static void gnome_calendar_init (GnomeCalendar *gcal); @@ -40,21 +41,23 @@ static void setup_widgets (GnomeCalendar *gcal) { time_t now; + GtkWidget *sw; now = time (NULL); gcal->notebook = gtk_notebook_new (); - gcal->day_view = day_view_create (gcal); + gcal->day_view = day_view_create (gcal); gcal->week_view = gncal_week_view_new (gcal, now); gcal->year_view = year_view_create (gcal); gcal->task_view = tasks_create (gcal); - if (0) + if (1) { struct tm tm; time_t a, b; tm = *localtime (&now); +/* tm.tm_mday = 2; */ tm.tm_hour = 0; tm.tm_min = 0; tm.tm_sec = 0; @@ -66,9 +69,16 @@ setup_widgets (GnomeCalendar *gcal) b = mktime (&tm); gcal->day_view = gncal_full_day_new (gcal, a, b); + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_container_add (GTK_CONTAINER (sw), gcal->day_view); + gtk_widget_show (gcal->day_view); } - gtk_notebook_append_page (GTK_NOTEBOOK (gcal->notebook), gcal->day_view, gtk_label_new (_("Day View"))); + gtk_notebook_append_page (GTK_NOTEBOOK (gcal->notebook), sw, gtk_label_new (_("Day View"))); gtk_notebook_append_page (GTK_NOTEBOOK (gcal->notebook), gcal->week_view, gtk_label_new (_("Week View"))); gtk_notebook_append_page (GTK_NOTEBOOK (gcal->notebook), gcal->year_view, gtk_label_new (_("Year View"))); gtk_notebook_append_page (GTK_NOTEBOOK (gcal->notebook), gcal->task_view, gtk_label_new (_("Todo"))); @@ -83,6 +93,9 @@ static void gnome_calendar_init(GnomeCalendar *gcal) { gcal->cal = 0; + gcal->day_view = 0; + gcal->week_view = 0; + gcal->event_editor = 0; setup_widgets (gcal); } @@ -164,6 +177,7 @@ gnome_calendar_new (char *title) void gnome_calendar_update_all (GnomeCalendar *cal) { + gncal_full_day_update (GNCAL_FULL_DAY (cal->day_view)); gncal_week_view_update (GNCAL_WEEK_VIEW (cal->week_view)); } diff --git a/calendar/gui/gnome-cal.h b/calendar/gui/gnome-cal.h index c13162ef65..053737fd4f 100644 --- a/calendar/gui/gnome-cal.h +++ b/calendar/gui/gnome-cal.h @@ -20,7 +20,6 @@ BEGIN_GNOME_DECLS typedef struct { GnomeApp gnome_app; Calendar *cal; - time_t current_display; GtkWidget *notebook; diff --git a/calendar/gui/main.c b/calendar/gui/main.c index d499992b1c..cd4d107421 100644 --- a/calendar/gui/main.c +++ b/calendar/gui/main.c @@ -10,6 +10,7 @@ #include #include #include "calendar.h" +#include "eventedit.h" #include "gnome-cal.h" #include "main.h" @@ -238,7 +239,6 @@ new_calendar (char *full_name, char *calendar_file) toplevel = gnome_calendar_new (title); setup_menu (toplevel); - gtk_widget_show (toplevel); if (g_file_exists (calendar_file)){ printf ("Trying to load %s\n", calendar_file); @@ -248,6 +248,8 @@ new_calendar (char *full_name, char *calendar_file) gnome_calendar_load (GNOME_CALENDAR (toplevel), "./test.vcf"); } active_calendars++; + + gtk_widget_show (toplevel); } int @@ -267,6 +269,7 @@ main(int argc, char *argv[]) new_calendar (full_name, user_calendar_file); gtk_main (); + return 0; } diff --git a/calendar/gui/test.vcf b/calendar/gui/test.vcf index 0e5809021d..e44ccf683f 100644 --- a/calendar/gui/test.vcf +++ b/calendar/gui/test.vcf @@ -1,4 +1,5 @@ BEGIN:VCALENDAR + PRODID:-//K Desktop Environment//NONSGML KOrganizer//EN TZ:-05 VERSION:1.0 @@ -7,8 +8,8 @@ DCREATED:19980402T023552 UID:KOrganizer - 1804289383 SEQUENCE:1 LAST-MODIFIED:19980330T225948 -DTSTART:19980330T120000 -DTEND:19980330T120000 +DTSTART:19980407T003000 +DTEND:19980407T010000 SUMMARY:asdfasdfasfasdfasdf STATUS:NEEDS ACTION CLASS:PUBLIC @@ -24,8 +25,8 @@ DCREATED:19980402T023558 UID:KOrganizer - 846930886 SEQUENCE:1 LAST-MODIFIED:19980402T023558 -DTSTART:19980402T120000 -DTEND:19980402T120000 +DTSTART:19980407T140000 +DTEND:19980407T160000 SUMMARY:asdfasfdasfasdfasfd STATUS:NEEDS ACTION CLASS:PUBLIC diff --git a/calendar/main.c b/calendar/main.c index d499992b1c..cd4d107421 100644 --- a/calendar/main.c +++ b/calendar/main.c @@ -10,6 +10,7 @@ #include #include #include "calendar.h" +#include "eventedit.h" #include "gnome-cal.h" #include "main.h" @@ -238,7 +239,6 @@ new_calendar (char *full_name, char *calendar_file) toplevel = gnome_calendar_new (title); setup_menu (toplevel); - gtk_widget_show (toplevel); if (g_file_exists (calendar_file)){ printf ("Trying to load %s\n", calendar_file); @@ -248,6 +248,8 @@ new_calendar (char *full_name, char *calendar_file) gnome_calendar_load (GNOME_CALENDAR (toplevel), "./test.vcf"); } active_calendars++; + + gtk_widget_show (toplevel); } int @@ -267,6 +269,7 @@ main(int argc, char *argv[]) new_calendar (full_name, user_calendar_file); gtk_main (); + return 0; } diff --git a/calendar/test.vcf b/calendar/test.vcf index 0e5809021d..e44ccf683f 100644 --- a/calendar/test.vcf +++ b/calendar/test.vcf @@ -1,4 +1,5 @@ BEGIN:VCALENDAR + PRODID:-//K Desktop Environment//NONSGML KOrganizer//EN TZ:-05 VERSION:1.0 @@ -7,8 +8,8 @@ DCREATED:19980402T023552 UID:KOrganizer - 1804289383 SEQUENCE:1 LAST-MODIFIED:19980330T225948 -DTSTART:19980330T120000 -DTEND:19980330T120000 +DTSTART:19980407T003000 +DTEND:19980407T010000 SUMMARY:asdfasdfasfasdfasdf STATUS:NEEDS ACTION CLASS:PUBLIC @@ -24,8 +25,8 @@ DCREATED:19980402T023558 UID:KOrganizer - 846930886 SEQUENCE:1 LAST-MODIFIED:19980402T023558 -DTSTART:19980402T120000 -DTEND:19980402T120000 +DTSTART:19980407T140000 +DTEND:19980407T160000 SUMMARY:asdfasfdasfasdfasfd STATUS:NEEDS ACTION CLASS:PUBLIC diff --git a/calendar/timeutil.c b/calendar/timeutil.c index 20d6fa7990..acd2b33ee7 100644 --- a/calendar/timeutil.c +++ b/calendar/timeutil.c @@ -117,4 +117,3 @@ time_add_year (time_t time, int years) } return new_time; } - diff --git a/calendar/timeutil.h b/calendar/timeutil.h index 1683df7527..8f9157351c 100644 --- a/calendar/timeutil.h +++ b/calendar/timeutil.h @@ -18,6 +18,10 @@ time_t time_from_start_duration (time_t start, char *duration); char *isodate_from_time_t (time_t t); int get_time_t_hour (time_t t); +time_t time_add_week (time_t time, int weeks); +time_t time_add_day (time_t time, int weeks); +time_t time_add_year (time_t time, int years); + /* Returns pointer to a statically-allocated buffer with a string of the form * 3am, 4am, 12pm, 08h, 17h, etc. * The string is internationalized, hopefully correctly. -- cgit