diff options
author | Damon Chaplin <damon@ximian.com> | 2001-05-29 10:18:00 +0800 |
---|---|---|
committer | Damon Chaplin <damon@src.gnome.org> | 2001-05-29 10:18:00 +0800 |
commit | ff523035dd2592f6ff25955e7f1e379f24640347 (patch) | |
tree | 586ea9b1c89726cace082c42865d82d61db5eb19 /calendar/gui/e-week-view-layout.c | |
parent | aaa9b9bb2ab4ff9fba2a6b9cc68fbc7fdfaa71bc (diff) | |
download | gsoc2013-evolution-ff523035dd2592f6ff25955e7f1e379f24640347.tar.gz gsoc2013-evolution-ff523035dd2592f6ff25955e7f1e379f24640347.tar.zst gsoc2013-evolution-ff523035dd2592f6ff25955e7f1e379f24640347.zip |
new files to contain layout code split off from EDayView an EWeekView, so
2001-05-28 Damon Chaplin <damon@ximian.com>
* gui/e-week-view-layout.[hc]:
* gui/e-day-view-layout.[hc]: new files to contain layout code split
off from EDayView an EWeekView, so we can use it for printing.
* gui/print.c: rewritten to use the same layout code as the EDayView
and EWeekView widgets.
* gui/gnome-cal.c (gnome_calendar_get_task_pad_cal_client): added
function so we can get the CalClient used for the TaskPad for printing.
* gui/Makefile.am (evolution_calendar_SOURCES): added
e-day-view-layout.[hc] amd e-week-view-layout.[hc].
* cal-util/timeutil.c (time_week_begin):
(time_week_end): added week_start_day argument.
* cal-util/cal-recur.c: added comments describing problems in it.
svn path=/trunk/; revision=10037
Diffstat (limited to 'calendar/gui/e-week-view-layout.c')
-rw-r--r-- | calendar/gui/e-week-view-layout.c | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/calendar/gui/e-week-view-layout.c b/calendar/gui/e-week-view-layout.c new file mode 100644 index 0000000000..21552e5f17 --- /dev/null +++ b/calendar/gui/e-week-view-layout.c @@ -0,0 +1,426 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Author : + * Damon Chaplin <damon@ximian.com> + * + * Copyright 2001, Ximian, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* + * Lays out events for the Week & Month views of the calendar. It is also + * used for printing. + */ + +#include <config.h> + +#include "e-week-view-layout.h" + + +static void e_week_view_layout_event (EWeekViewEvent *event, + guint8 *grid, + GArray *spans, + GArray *old_spans, + gboolean multi_week_view, + gint weeks_shown, + gboolean compress_weekend, + gint start_weekday, + time_t *day_starts, + gint *rows_per_day); +static gint e_week_view_find_day (time_t time_to_find, + gboolean include_midnight_in_prev_day, + gint days_shown, + time_t *day_starts); +static gint e_week_view_find_span_end (gboolean multi_week_view, + gboolean compress_weekend, + gint display_start_day, + gint day); + + +GArray* +e_week_view_layout_events (GArray *events, + GArray *old_spans, + gboolean multi_week_view, + gint weeks_shown, + gboolean compress_weekend, + gint start_weekday, + time_t *day_starts, + gint *rows_per_day) +{ + EWeekViewEvent *event; + EWeekViewEventSpan *span; + gint num_days, day, event_num, span_num; + guint8 *grid; + GArray *spans; + + /* This is a temporary 2-d grid which is used to place events. + Each element is 0 if the position is empty, or 1 if occupied. + We allocate the maximum size possible here, assuming that each + event will need its own row. */ + grid = g_new0 (guint8, E_WEEK_VIEW_MAX_ROWS_PER_CELL * 7 + * E_WEEK_VIEW_MAX_WEEKS); + + /* We create a new array of spans, which will replace the old one. */ + spans = g_array_new (FALSE, FALSE, sizeof (EWeekViewEventSpan)); + + /* Clear the number of rows used per day. */ + num_days = multi_week_view ? weeks_shown * 7 : 7; + for (day = 0; day <= num_days; day++) { + rows_per_day[day] = 0; + } + + /* Iterate over the events, finding which weeks they cover, and putting + them in the first free row available. */ + for (event_num = 0; event_num < events->len; event_num++) { + event = &g_array_index (events, EWeekViewEvent, event_num); + e_week_view_layout_event (event, grid, spans, old_spans, + multi_week_view, + weeks_shown, compress_weekend, + start_weekday, day_starts, + rows_per_day); + } + + /* Free the grid. */ + g_free (grid); + + /* Destroy the old spans array, destroying any unused canvas items. */ + if (old_spans) { + for (span_num = 0; span_num < old_spans->len; span_num++) { + span = &g_array_index (old_spans, EWeekViewEventSpan, + span_num); + if (span->background_item) + gtk_object_destroy (GTK_OBJECT (span->background_item)); + if (span->text_item) + gtk_object_destroy (GTK_OBJECT (span->text_item)); + } + g_array_free (old_spans, TRUE); + } + + return spans; +} + + +static void +e_week_view_layout_event (EWeekViewEvent *event, + guint8 *grid, + GArray *spans, + GArray *old_spans, + gboolean multi_week_view, + gint weeks_shown, + gboolean compress_weekend, + gint start_weekday, + time_t *day_starts, + gint *rows_per_day) +{ + gint start_day, end_day, span_start_day, span_end_day, rows_per_cell; + gint free_row, row, day, span_num, spans_index, num_spans, days_shown; + EWeekViewEventSpan span, *old_span; + + days_shown = multi_week_view ? weeks_shown * 7 - 1 : 7 - 1; + start_day = e_week_view_find_day (event->start, FALSE, days_shown, + day_starts); + end_day = e_week_view_find_day (event->end, TRUE, days_shown, + day_starts); + start_day = CLAMP (start_day, 0, days_shown - 1); + end_day = CLAMP (end_day, 0, days_shown - 1); + +#if 0 + g_print ("In e_week_view_layout_event Start:%i End: %i\n", + start_day, end_day); +#endif + + /* Iterate through each of the spans of the event, where each span + is a sequence of 1 or more days displayed next to each other. */ + span_start_day = start_day; + rows_per_cell = E_WEEK_VIEW_MAX_ROWS_PER_CELL; + span_num = 0; + spans_index = spans->len; + num_spans = 0; + while (span_start_day <= end_day) { + span_end_day = e_week_view_find_span_end (multi_week_view, + compress_weekend, + start_weekday, + span_start_day); + span_end_day = MIN (span_end_day, end_day); +#if 0 + g_print (" Span start:%i end:%i\n", span_start_day, + span_end_day); +#endif + /* Try each row until we find a free one or we fall off the + bottom of the available rows. */ + row = 0; + free_row = -1; + while (free_row == -1 && row < rows_per_cell) { + free_row = row; + for (day = span_start_day; day <= span_end_day; + day++) { + if (grid[day * rows_per_cell + row]) { + free_row = -1; + break; + } + } + row++; + }; + + if (free_row != -1) { + /* Mark the cells as full. */ + for (day = span_start_day; day <= span_end_day; + day++) { + grid[day * rows_per_cell + free_row] = 1; + rows_per_day[day] = MAX (rows_per_day[day], + free_row + 1); + } +#if 0 + g_print (" Span start:%i end:%i row:%i\n", + span_start_day, span_end_day, free_row); +#endif + /* Add the span to the array, and try to reuse any + canvas items from the old spans. */ + span.start_day = span_start_day; + span.num_days = span_end_day - span_start_day + 1; + span.row = free_row; + span.background_item = NULL; + span.text_item = NULL; + if (event->num_spans > span_num) { + old_span = &g_array_index (old_spans, EWeekViewEventSpan, event->spans_index + span_num); + span.background_item = old_span->background_item; + span.text_item = old_span->text_item; + old_span->background_item = NULL; + old_span->text_item = NULL; + } + + g_array_append_val (spans, span); + num_spans++; + } + + span_start_day = span_end_day + 1; + span_num++; + } + + /* Set the event's spans. */ + event->spans_index = spans_index; + event->num_spans = num_spans; +} + + +/* Finds the day containing the given time. + If include_midnight_in_prev_day is TRUE then if the time exactly + matches the start of a day the previous day is returned. This is useful + when calculating the end day of an event. */ +static gint +e_week_view_find_day (time_t time_to_find, + gboolean include_midnight_in_prev_day, + gint days_shown, + time_t *day_starts) +{ + gint day; + + if (time_to_find < day_starts[0]) + return -1; + if (time_to_find > day_starts[days_shown]) + return days_shown; + + for (day = 1; day <= days_shown; day++) { + if (time_to_find <= day_starts[day]) { + if (time_to_find == day_starts[day] + && !include_midnight_in_prev_day) + return day; + return day - 1; + } + } + + g_assert_not_reached (); + return days_shown; +} + + +/* This returns the last possible day in the same span as the given day. + A span is all the days which are displayed next to each other from left to + right. In the week view all spans are only 1 day, since Tuesday is below + Monday rather than beside it etc. In the month view, if the weekends are not + compressed then each week is a span, otherwise we have to break a span up + on Saturday, use a separate span for Sunday, and start again on Monday. */ +static gint +e_week_view_find_span_end (gboolean multi_week_view, + gboolean compress_weekend, + gint display_start_day, + gint day) +{ + gint week, col, sat_col, end_col; + + if (multi_week_view) { + week = day / 7; + col = day % 7; + + /* We default to the last column in the row. */ + end_col = 6; + + /* If the weekend is compressed we must end any spans on + Saturday and Sunday. */ + if (compress_weekend) { + sat_col = (5 + 7 - display_start_day) % 7; + if (col <= sat_col) + end_col = sat_col; + else if (col == sat_col + 1) + end_col = sat_col + 1; + } + + return week * 7 + end_col; + } else { + return day; + } +} + + +void +e_week_view_layout_get_day_position (gint day, + gboolean multi_week_view, + gint weeks_shown, + gint display_start_day, + gboolean compress_weekend, + gint *day_x, + gint *day_y, + gint *rows) +{ + gint week, day_of_week, row, col, weekend_col, box, weekend_box; + + *day_x = *day_y = *rows = 0; + g_return_if_fail (day >= 0); + + if (multi_week_view) { + g_return_if_fail (day < weeks_shown * 7); + + week = day / 7; + col = day % 7; + day_of_week = (display_start_day + day) % 7; + if (compress_weekend && day_of_week >= 5) { + /* In the compressed view Saturday is above Sunday and + both have just one row as opposed to 2 for all the + other days. */ + if (day_of_week == 5) { + *day_y = week * 2; + *rows = 1; + } else { + *day_y = week * 2 + 1; + *rows = 1; + col--; + } + /* Both Saturday and Sunday are in the same column. */ + *day_x = col; + } else { + /* If the weekend is compressed and the day is after + the weekend we have to move back a column. */ + if (compress_weekend) { + /* Calculate where the weekend column is. + Note that 5 is Saturday. */ + weekend_col = (5 + 7 - display_start_day) % 7; + if (col > weekend_col) + col--; + } + + *day_y = week * 2; + *rows = 2; + *day_x = col; + } + } else { + g_return_if_fail (day < 7); + + /* Calculate which box to place the day in, from 0-5. + Note that in the week view the weekends are always + compressed and share a box. */ + box = day; + day_of_week = (display_start_day + day) % 7; + weekend_box = (5 + 7 - display_start_day) % 7; + if (box > weekend_box) + box--; + + if (box < 3) + *day_x = 0; + else + *day_x = 1; + + row = (box % 3) * 2; + if (day_of_week < 5) { + *day_y = row; + *rows = 2; + } else if (day_of_week == 5) { + /* Saturday. */ + *day_y = row; + *rows = 1; + + } else { + /* Sunday. */ + *day_y = row + 1; + *rows = 1; + } + } +} + + +/* Returns TRUE if the event span is visible or FALSE if it isn't. + It also returns the number of days of the span that are visible. + Usually this can easily be determined by the start & end days and row of + the span, which are set in e_week_view_layout_event(). Though we need a + special case for the weekends when they are compressed, since the span may + not fit. */ +gboolean +e_week_view_layout_get_span_position (EWeekViewEvent *event, + EWeekViewEventSpan *span, + gint rows_per_cell, + gint rows_per_compressed_cell, + gint display_start_day, + gboolean multi_week_view, + gboolean compress_weekend, + gint *span_num_days) +{ + gint end_day_of_week; + + if (span->row >= rows_per_cell) + return FALSE; + + end_day_of_week = (display_start_day + span->start_day + + span->num_days - 1) % 7; + *span_num_days = span->num_days; + /* Check if the row will not be visible in compressed cells. */ + if (span->row >= rows_per_compressed_cell) { + if (multi_week_view) { + if (compress_weekend) { + /* If it ends on a Saturday and is 1 day long + we skip it, else we shorten it. If it ends + on a Sunday it must be 1 day long and we + skip it. */ + if (end_day_of_week == 5) { /* Sat */ + if (*span_num_days == 1) { + return FALSE; + } else { + (*span_num_days)--; + } + } else if (end_day_of_week == 6) { /* Sun */ + return FALSE; + } + } + } else { + /* All spans are 1 day long in the week view, so we + just skip it. */ + if (end_day_of_week > 4) + return FALSE; + } + } + + return TRUE; +} |