aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--calendar/ChangeLog17
-rw-r--r--calendar/gncal-full-day.c171
-rw-r--r--calendar/gui/gncal-full-day.c171
-rw-r--r--calendar/gui/layout.c155
-rw-r--r--calendar/gui/layout.h20
-rw-r--r--calendar/gui/quick-view.c2
-rw-r--r--calendar/layout.c155
-rw-r--r--calendar/layout.h20
-rw-r--r--calendar/quick-view.c2
9 files changed, 313 insertions, 400 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog
index 2012f7155d..4bb47d706f 100644
--- a/calendar/ChangeLog
+++ b/calendar/ChangeLog
@@ -1,3 +1,20 @@
+1998-10-08 Federico Mena Quintero <federico@nuclecu.unam.mx>
+
+ * layout.c: Do some cleanup; now we pass a struct with the layout
+ algorithm's state instead of passing a trillion parameters around.
+
+ * gncal-full-day.c (layout_children): Use the new generic layout
+ engine.
+ (child_compare): Sort keys are start time then end time, not just
+ start time. This produces somewhat nicer results for the layout
+ algorithm.
+
+ The new layout code uses a partition of the time range occupied by
+ the events, rather than using a fixed time granularity. This is
+ better since the different parts of the program that use the
+ layout module will have different semantics regarding snapping the
+ event bounds to a fixed "time grid".
+
1998-10-07 Federico Mena Quintero <federico@nuclecu.unam.mx>
* layout.[ch]: New files that abstract the event layout code from
diff --git a/calendar/gncal-full-day.c b/calendar/gncal-full-day.c
index 6acc8ca16b..402c19acee 100644
--- a/calendar/gncal-full-day.c
+++ b/calendar/gncal-full-day.c
@@ -12,6 +12,7 @@
#include "eventedit.h"
#include "gncal-full-day.h"
#include "view-utils.h"
+#include "layout.h"
#include "main.h"
#include "popup-menu.h"
@@ -46,11 +47,6 @@ typedef struct {
time_t start, end;
} Child;
-struct layout_row {
- int intersections;
- int *slots;
-};
-
struct drag_info {
enum {
DRAG_NONE,
@@ -778,145 +774,64 @@ calc_labels_width (GncalFullDay *fullday)
return max_w;
}
-#define MAX_CHILDREN_ON_ROW 32
-
-#define xy(a,x,y) (a[((y) * MAX_CHILDREN_ON_ROW) + (x)])
-
-static int
-range_empty (char *array, int slot, int lower, int count)
-{
- int i;
-
- for (i = 0; i < count; i++)
- if (xy (array, slot, lower+i) != 0)
- return 0;
- return 1;
-}
-
+/* Used with layout_events(), takes in a list element and returns the start and end times for the
+ * event corresponding to that element.
+ */
static void
-range_allocate (char *array, int slot, int lower, int count, int val)
+child_layout_query_func (GList *event, time_t *start, time_t *end)
{
- int i;
-
- for (i = 0; i < count; i++)
- xy (array, slot, lower+i) = val;
-}
-
-static int
-can_expand (char *array, int *allocations, int top_slot, int val, int lower, int count)
-{
- int slot, i;
- int cols = 0;
-
- for (slot = allocations [val] + 1; slot < top_slot; slot++){
- for (i = 0; i < count; i++)
- if (xy (array, slot, lower+i))
- return cols;
- cols++;
- }
- return cols;
-}
+ Child *child;
-static void
-expand_space (char *array, int *allocations, int val, int lower, int count, int cols)
-{
- int j, i, slot;
+ child = event->data;
- for (i = 0; i < count; i++){
- slot = allocations [val] + 1;
- for (j = 0; j < cols; j++)
- xy (array, slot + j, lower+i) = val;
- }
+ *start = child->start;
+ *end = child->end;
}
+/* Takes the list of children in the full day view and lays them out nicely without overlapping.
+ * Basically it calls the layout_events() function in layout.c and resizes the fullday's children.
+ */
static void
layout_children (GncalFullDay *fullday)
{
GtkWidget *widget;
- int lines = (24 * 60) / fullday->interval;
- char *array = g_malloc0 (sizeof (char) * lines * MAX_CHILDREN_ON_ROW);
GList *children;
- int val, slot;
- int *allocations, *columns;
- int top_slot = 0;
- int left_x, cols;
- int pixels_per_col, extra_pixels, extra, usable_pixels;
- int child_count;
-
+ Child *child;
+ int num_slots;
+ int *allocations;
+ int *slots;
+ int left_x;
+ int usable_pixels, pixels_per_col, extra_pixels;
+ int i;
+
if (!fullday->children)
return;
-
- /* initial allocation */
- child_count = g_list_length (fullday->children) + 2;
- allocations = g_malloc0 (sizeof (int) * child_count);
- columns = g_malloc0 (sizeof (int) * child_count);
- val = 1;
- for (children = fullday->children; children; children = children->next, val++){
- Child *child = children->data;
-
- allocations [val] = 0;
- columns [val] = 1;
- for (slot = 0; slot < MAX_CHILDREN_ON_ROW; slot++){
- if (range_empty (array, slot, child->lower_row, child->rows_used)){
- /*
- printf ("Child %d uses %d-%d allocates slot=%d\n", val, child->lower_row,
- child->lower_row + child->rows_used, slot);
- */
-
- range_allocate (array, slot, child->lower_row, child->rows_used, val);
- allocations [val] = slot;
- columns [val] = 1;
- if (slot+1 > top_slot)
- top_slot = slot+1;
- break;
- }
- }
- }
-#if DEBUGME
- for (val = 0; val < 48; val++){
- int j;
-
- printf ("%d: ", val);
- for (j = 0; j < top_slot; j++){
- printf (" %d", xy (array, j, val));
- }
- printf ("\n");
- }
-#endif
- /* Expand */
- val = 1;
- for (children = fullday->children; children; children = children->next, val++){
- Child *child = children->data;
-
- cols = can_expand (array, allocations, top_slot, val, child->lower_row, child->rows_used);
- /* printf ("Can expand regresa: %d\n", cols); */
- if (!cols)
- continue;
- expand_space (array, allocations, val, child->lower_row, child->rows_used, cols);
- columns [val] += cols;
- }
- /* Assign the spaces */
+ layout_events (fullday->children, child_layout_query_func, &num_slots, &allocations, &slots);
+
+ /* Set the size and position of each child */
+
widget = GTK_WIDGET (fullday);
left_x = 2 * (widget->style->klass->xthickness + TEXT_BORDER) + calc_labels_width (fullday);
- usable_pixels = widget->allocation.width-left_x - widget->style->klass->xthickness;
- pixels_per_col = usable_pixels / top_slot;
- extra_pixels = usable_pixels % top_slot;
-
- val = 1;
- for (children = fullday->children; children; children = children->next, val++){
- Child *child = children->data;
-
- child->x = left_x + pixels_per_col * allocations [val];
- extra = (allocations [val] + columns [val] == top_slot) ? extra_pixels : 0;
- child->width = pixels_per_col * columns [val] + extra;
- child_set_size (child);
+ usable_pixels = widget->allocation.width - left_x - widget->style->klass->xthickness;
+ pixels_per_col = usable_pixels / num_slots;
+ extra_pixels = usable_pixels % num_slots;
+
+ for (children = fullday->children, i = 0; children; children = children->next, i++) {
+ child = children->data;
- /* printf ("Setting child %d to %d for %d pixels\n", val, allocations [val], columns [val]); */
+ child->x = left_x + pixels_per_col * allocations[i];
+ child->width = pixels_per_col * slots[i];
+
+ if ((allocations[i] + slots[i]) == num_slots)
+ child->width += extra_pixels;
+
+ child_set_size (child);
}
+
g_free (allocations);
- g_free (columns);
+ g_free (slots);
}
guint
@@ -2118,13 +2033,17 @@ gncal_full_day_forall (GtkContainer *container, gboolean include_internals, GtkC
}
static gint
-child_compare_by_start (gconstpointer a, gconstpointer b)
+child_compare (gconstpointer a, gconstpointer b)
{
const Child *ca = a;
const Child *cb = b;
time_t diff;
diff = ca->start - cb->start;
+
+ if (diff == 0)
+ diff = cb->end - ca->end;
+
return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
}
@@ -2135,7 +2054,7 @@ fullday_add_children (iCalObject *obj, time_t start, time_t end, void *c)
Child *child;
child = child_new (fullday, start, end, obj);
- fullday->children = g_list_insert_sorted (fullday->children, child, child_compare_by_start);
+ fullday->children = g_list_insert_sorted (fullday->children, child, child_compare);
return 1;
}
diff --git a/calendar/gui/gncal-full-day.c b/calendar/gui/gncal-full-day.c
index 6acc8ca16b..402c19acee 100644
--- a/calendar/gui/gncal-full-day.c
+++ b/calendar/gui/gncal-full-day.c
@@ -12,6 +12,7 @@
#include "eventedit.h"
#include "gncal-full-day.h"
#include "view-utils.h"
+#include "layout.h"
#include "main.h"
#include "popup-menu.h"
@@ -46,11 +47,6 @@ typedef struct {
time_t start, end;
} Child;
-struct layout_row {
- int intersections;
- int *slots;
-};
-
struct drag_info {
enum {
DRAG_NONE,
@@ -778,145 +774,64 @@ calc_labels_width (GncalFullDay *fullday)
return max_w;
}
-#define MAX_CHILDREN_ON_ROW 32
-
-#define xy(a,x,y) (a[((y) * MAX_CHILDREN_ON_ROW) + (x)])
-
-static int
-range_empty (char *array, int slot, int lower, int count)
-{
- int i;
-
- for (i = 0; i < count; i++)
- if (xy (array, slot, lower+i) != 0)
- return 0;
- return 1;
-}
-
+/* Used with layout_events(), takes in a list element and returns the start and end times for the
+ * event corresponding to that element.
+ */
static void
-range_allocate (char *array, int slot, int lower, int count, int val)
+child_layout_query_func (GList *event, time_t *start, time_t *end)
{
- int i;
-
- for (i = 0; i < count; i++)
- xy (array, slot, lower+i) = val;
-}
-
-static int
-can_expand (char *array, int *allocations, int top_slot, int val, int lower, int count)
-{
- int slot, i;
- int cols = 0;
-
- for (slot = allocations [val] + 1; slot < top_slot; slot++){
- for (i = 0; i < count; i++)
- if (xy (array, slot, lower+i))
- return cols;
- cols++;
- }
- return cols;
-}
+ Child *child;
-static void
-expand_space (char *array, int *allocations, int val, int lower, int count, int cols)
-{
- int j, i, slot;
+ child = event->data;
- for (i = 0; i < count; i++){
- slot = allocations [val] + 1;
- for (j = 0; j < cols; j++)
- xy (array, slot + j, lower+i) = val;
- }
+ *start = child->start;
+ *end = child->end;
}
+/* Takes the list of children in the full day view and lays them out nicely without overlapping.
+ * Basically it calls the layout_events() function in layout.c and resizes the fullday's children.
+ */
static void
layout_children (GncalFullDay *fullday)
{
GtkWidget *widget;
- int lines = (24 * 60) / fullday->interval;
- char *array = g_malloc0 (sizeof (char) * lines * MAX_CHILDREN_ON_ROW);
GList *children;
- int val, slot;
- int *allocations, *columns;
- int top_slot = 0;
- int left_x, cols;
- int pixels_per_col, extra_pixels, extra, usable_pixels;
- int child_count;
-
+ Child *child;
+ int num_slots;
+ int *allocations;
+ int *slots;
+ int left_x;
+ int usable_pixels, pixels_per_col, extra_pixels;
+ int i;
+
if (!fullday->children)
return;
-
- /* initial allocation */
- child_count = g_list_length (fullday->children) + 2;
- allocations = g_malloc0 (sizeof (int) * child_count);
- columns = g_malloc0 (sizeof (int) * child_count);
- val = 1;
- for (children = fullday->children; children; children = children->next, val++){
- Child *child = children->data;
-
- allocations [val] = 0;
- columns [val] = 1;
- for (slot = 0; slot < MAX_CHILDREN_ON_ROW; slot++){
- if (range_empty (array, slot, child->lower_row, child->rows_used)){
- /*
- printf ("Child %d uses %d-%d allocates slot=%d\n", val, child->lower_row,
- child->lower_row + child->rows_used, slot);
- */
-
- range_allocate (array, slot, child->lower_row, child->rows_used, val);
- allocations [val] = slot;
- columns [val] = 1;
- if (slot+1 > top_slot)
- top_slot = slot+1;
- break;
- }
- }
- }
-#if DEBUGME
- for (val = 0; val < 48; val++){
- int j;
-
- printf ("%d: ", val);
- for (j = 0; j < top_slot; j++){
- printf (" %d", xy (array, j, val));
- }
- printf ("\n");
- }
-#endif
- /* Expand */
- val = 1;
- for (children = fullday->children; children; children = children->next, val++){
- Child *child = children->data;
-
- cols = can_expand (array, allocations, top_slot, val, child->lower_row, child->rows_used);
- /* printf ("Can expand regresa: %d\n", cols); */
- if (!cols)
- continue;
- expand_space (array, allocations, val, child->lower_row, child->rows_used, cols);
- columns [val] += cols;
- }
- /* Assign the spaces */
+ layout_events (fullday->children, child_layout_query_func, &num_slots, &allocations, &slots);
+
+ /* Set the size and position of each child */
+
widget = GTK_WIDGET (fullday);
left_x = 2 * (widget->style->klass->xthickness + TEXT_BORDER) + calc_labels_width (fullday);
- usable_pixels = widget->allocation.width-left_x - widget->style->klass->xthickness;
- pixels_per_col = usable_pixels / top_slot;
- extra_pixels = usable_pixels % top_slot;
-
- val = 1;
- for (children = fullday->children; children; children = children->next, val++){
- Child *child = children->data;
-
- child->x = left_x + pixels_per_col * allocations [val];
- extra = (allocations [val] + columns [val] == top_slot) ? extra_pixels : 0;
- child->width = pixels_per_col * columns [val] + extra;
- child_set_size (child);
+ usable_pixels = widget->allocation.width - left_x - widget->style->klass->xthickness;
+ pixels_per_col = usable_pixels / num_slots;
+ extra_pixels = usable_pixels % num_slots;
+
+ for (children = fullday->children, i = 0; children; children = children->next, i++) {
+ child = children->data;
- /* printf ("Setting child %d to %d for %d pixels\n", val, allocations [val], columns [val]); */
+ child->x = left_x + pixels_per_col * allocations[i];
+ child->width = pixels_per_col * slots[i];
+
+ if ((allocations[i] + slots[i]) == num_slots)
+ child->width += extra_pixels;
+
+ child_set_size (child);
}
+
g_free (allocations);
- g_free (columns);
+ g_free (slots);
}
guint
@@ -2118,13 +2033,17 @@ gncal_full_day_forall (GtkContainer *container, gboolean include_internals, GtkC
}
static gint
-child_compare_by_start (gconstpointer a, gconstpointer b)
+child_compare (gconstpointer a, gconstpointer b)
{
const Child *ca = a;
const Child *cb = b;
time_t diff;
diff = ca->start - cb->start;
+
+ if (diff == 0)
+ diff = cb->end - ca->end;
+
return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
}
@@ -2135,7 +2054,7 @@ fullday_add_children (iCalObject *obj, time_t start, time_t end, void *c)
Child *child;
child = child_new (fullday, start, end, obj);
- fullday->children = g_list_insert_sorted (fullday->children, child, child_compare_by_start);
+ fullday->children = g_list_insert_sorted (fullday->children, child, child_compare);
return 1;
}
diff --git a/calendar/gui/layout.c b/calendar/gui/layout.c
index 03fac94cc6..f97f0d5ffd 100644
--- a/calendar/gui/layout.c
+++ b/calendar/gui/layout.c
@@ -6,9 +6,25 @@
* Federico Mena <federico@nuclecu.unam.mx>
*/
+#include <config.h>
+#include <stdlib.h>
#include "layout.h"
+/* This structure is used to pass around layout information among the internal layout functions */
+struct layout_info {
+ GList *events; /* List of events from client */
+ int num_events; /* The number of events (length of the list) */
+ LayoutQueryTimeFunc func; /* Function to convert a list item to a start/end time pair */
+ int num_rows; /* Size of the time partition */
+ time_t *partition; /* The time partition containing start and end time values */
+ int *array; /* Working array of free and allocated time slots */
+ int *allocations; /* Returned array of slot allocations */
+ int *slots; /* Returned array of slots used */
+ int num_slots; /* Number of slots used */
+};
+
+
/* This defines the maximum number of events to overlap per row. More than that number of events
* will not be displayed. This is not ideal, so sue me.
*/
@@ -35,37 +51,35 @@ compare_time_t (const void *a, const void *b)
/* Builds a partition of the time range occupied by the events in the list. It returns an array
* with the times that define the partition and the number of items in the partition.
*/
-static time_t *
-build_partition (GList *events, int num_events, int *num_rows)
+static void
+build_partition (struct layout_info *li)
{
time_t *rows, *p, *q;
GList *list;
- CalendarObject *co;
int i, unique_vals;
/* This is the maximum number of rows we would need */
- *num_rows = num_events * 2;
+ li->num_rows = li->num_events * 2;
/* Fill the rows with the times */
- rows = g_new (time_t, *num_rows);
+ rows = g_new (time_t, li->num_rows);
- for (list = events, p = rows; list; list = list->next) {
- co = list->data;
- *p++ = co->ev_start;
- *p++ = co->ev_end;
+ for (list = li->events, p = rows; list; list = list->next) {
+ (* li->func) (list, &p[0], &p[1]);
+ p += 2;
}
/* Do a sort | uniq on the array */
- qsort (rows, *num_rows, sizeof (time_t), compare_time_t);
+ qsort (rows, li->num_rows, sizeof (time_t), compare_time_t);
p = rows;
q = rows + 1;
unique_vals = 1;
- for (i = 1; i < *num_rows; i++, q++)
+ for (i = 1; i < li->num_rows; i++, q++)
if (*q != *p) {
unique_vals++;
p++;
@@ -74,33 +88,33 @@ build_partition (GList *events, int num_events, int *num_rows)
/* Return the number of unique values in the partition and the partition array itself */
- *num_rows = unique_vals;
- return rows;
+ li->num_rows = unique_vals;
+ li->partition = rows;
}
/* Returns the index of the element in the partition that corresponds to the specified time */
int
-find_index (time_t *partition, time_t t)
+find_index (struct layout_info *li, time_t t)
{
int i;
for (i = 0; ; i++)
- if (partition[i] == t)
+ if (li->partition[i] == t)
return i;
}
-#define xy(slot_array, x, y) slot_array[(y * MAX_EVENTS_PER_ROW) + (x)]
+#define xy(li, x, y) li->array[(y * MAX_EVENTS_PER_ROW) + (x)]
/* Checks that all the cells in the slot array at the specified slot column are free to use by an
* event that has the specified range.
*/
static int
-range_is_empty (time_t *partition, int *slot_array, int slot, time_t start, time_t end)
+range_is_empty (struct layout_info *li, int slot, time_t start, time_t end)
{
int i;
- for (i = find_index (partition, start); partition[i] < end; i++)
- if (xy (slot_array, slot, i) != -1)
+ for (i = find_index (li, start); li->partition[i] < end; i++)
+ if (xy (li, slot, i) != -1)
return FALSE;
return TRUE;
@@ -108,43 +122,44 @@ range_is_empty (time_t *partition, int *slot_array, int slot, time_t start, time
/* Allocates a time in the slot array for the specified event's index */
static void
-range_allocate (time_t *partition, int *slot_array, int slot, time_t start, time_t end, int ev_num)
+range_allocate (struct layout_info *li, int slot, time_t start, time_t end, int ev_num)
{
int i;
- for (i = find_index (partition, start); partition[i] < end; i++)
- xy (slot_array, slot, i) = ev_num;
+ for (i = find_index (li, start); li->partition[i] < end; i++)
+ xy (li, slot, i) = ev_num;
}
/* Performs the initial allocation of slots for events. Each event gets one column; they will be
* expanded in a later stage. Returns the number of columns used.
*/
-static int
-initial_allocate (GList *events, time_t *partition, int *slot_array, int *allocations, int *columns_used)
+static void
+initial_allocate (struct layout_info *li)
{
- CalendarObject *co;
+ GList *events;
int i;
int slot;
int num_slots;
+ time_t start, end;
num_slots = 0;
- for (i = 0; events; events = events->next, i++) {
- co = events->data;
+ for (i = 0, events = li->events; events; events = events->next, i++) {
+ (* li->func) (events, &start, &end);
/* Start with no allocation, no columns */
- allocations[i] = -1;
- columns_used[i] = 0;
+ li->allocations[i] = -1;
+ li->slots[i] = 0;
/* Find a free column for the event */
for (slot = 0; slot < MAX_EVENTS_PER_ROW; slot++)
- if (range_is_empty (partition, slot_array, slot, co->ev_start, co->ev_end)) {
- range_allocate (partition, slot_array, slot, co->ev_start, co->ev_end, i);
+ if (range_is_empty (li, slot, start, end)) {
+ range_allocate (li, slot, start, end, i);
- allocations[i] = slot;
- columns_used[i] = 1;
+ li->allocations[i] = slot;
+ li->slots[i] = 1;
if ((slot + 1) > num_slots)
num_slots = slot + 1;
@@ -153,13 +168,12 @@ initial_allocate (GList *events, time_t *partition, int *slot_array, int *alloca
}
}
- return num_slots;
+ li->num_slots = num_slots;
}
/* Returns the maximum number of columns that an event can expanded by in the slot array */
static int
-columns_to_expand (time_t *partition, int *slot_array, int *allocations, int num_slots, int ev_num,
- time_t start, time_t end)
+columns_to_expand (struct layout_info *li, int ev_num, time_t start, time_t end)
{
int cols;
int slot;
@@ -168,11 +182,11 @@ columns_to_expand (time_t *partition, int *slot_array, int *allocations, int num
cols = 0;
- i_start = find_index (partition, start);
+ i_start = find_index (li, start);
- for (slot = allocations[ev_num] + 1; slot < num_slots; slot++) {
- for (i = i_start; partition[i] < end; i++)
- if (xy (slot_array, slot, i) != -1)
+ for (slot = li->allocations[ev_num] + 1; slot < li->num_slots; slot++) {
+ for (i = i_start; li->partition[i] < end; i++)
+ if (xy (li, slot, i) != -1)
return cols;
cols++;
@@ -181,18 +195,18 @@ columns_to_expand (time_t *partition, int *slot_array, int *allocations, int num
return cols;
}
-/* Expands an event to occupy the specified number of columns */
+/* Expands an event by the specified number of columns */
static void
-do_expansion (time_t *partition, int *slot_array, int *allocations, int ev_num, time_t start, time_t end, int num_cols)
+do_expansion (struct layout_info *li, int ev_num, time_t start, time_t end, int num_cols)
{
int i, j;
int slot;
- for (i = find_index (partition, start); partition[i] < end; i++) {
- slot = allocations[ev_num] + 1;
+ for (i = find_index (li, start); li->partition[i] < end; i++) {
+ slot = li->allocations[ev_num] + 1;
for (j = 0; j < num_cols; j++)
- xy (slot_array, slot + j, i) = ev_num;
+ xy (li, slot + j, i) = ev_num;
}
}
@@ -200,33 +214,31 @@ do_expansion (time_t *partition, int *slot_array, int *allocations, int ev_num,
* pass of the layout algorithm.
*/
static void
-expand_events (GList *events, time_t *partition, int *slot_array, int num_slots, int *allocations, int *columns_used)
+expand_events (struct layout_info *li)
{
+ GList *events;
+ time_t start, end;
int i;
- CalendarObject *co;
int cols;
- for (i = 0; events; events = events->next, i++) {
- co = events->data;
+ for (i = 0, events = li->events; events; events = events->next, i++) {
+ (* li->func) (events, &start, &end);
- cols = columns_to_expand (partition, slot_array, allocations, num_slots, i, co->ev_start, co->ev_end);
+ cols = columns_to_expand (li, i, start, end);
if (cols == 0)
continue; /* We can't expand this event */
- do_expansion (partition, slot_array, allocations, i, co->ev_start, co->ev_end, cols);
+ do_expansion (li, i, start, end, cols);
- columns_used[i] += cols;
+ li->slots[i] += cols;
}
}
void
-layout_events (GList *events, int *num_slots, int **allocations, int **slots)
+layout_events (GList *events, LayoutQueryTimeFunc func, int *num_slots, int **allocations, int **slots)
{
- time_t *time_partition;
- int *slot_array;
- int num_events;
- int num_rows;
+ struct layout_info li;
int i;
g_return_if_fail (num_slots != NULL);
@@ -241,28 +253,33 @@ layout_events (GList *events, int *num_slots, int **allocations, int **slots)
return;
}
- num_events = g_list_length (events);
+ li.events = events;
+ li.num_events = g_list_length (events);
+ li.func = func;
/* Build the partition of the time range, and then build the array of slots */
- time_partition = build_partition (events, num_events, &num_rows);
+ build_partition (&li);
- slot_array = g_new (int, num_rows * MAX_EVENTS_PER_ROW);
- for (i = 0; i < (num_rows * MAX_EVENTS_PER_ROW); i++)
- slot_array[i] = -1; /* This is our 'empty' value */
+ li.array = g_new (int, li.num_rows * MAX_EVENTS_PER_ROW);
+ for (i = 0; i < (li.num_rows * MAX_EVENTS_PER_ROW); i++)
+ li.array[i] = -1; /* This is our 'empty' value */
/* Build the arrays for allocations and columns used */
- *allocations = g_new (int, num_events);
- *slots = g_new (int, num_events);
+ li.allocations = g_new (int, li.num_events);
+ li.slots = g_new (int, li.num_events);
- /* Perform initial allocation -- each event gets one column */
+ /* Perform initial allocation and then expand the events to as many slots as they can occupy */
- *num_slots = initial_allocate (events, time_partition, slot_array, *allocations, *slots);
+ initial_allocate (&li);
+ expand_events (&li);
- /* Expand the events to as many columns as possible */
+ /* Clean up and return values */
- expand_events (events, time_partition, slot_array, *num_slots, *allocations, *slots);
+ g_free (li.array);
- g_free (slot_array);
+ *num_slots = li.num_slots;
+ *allocations = li.allocations;
+ *slots = li.slots;
}
diff --git a/calendar/gui/layout.h b/calendar/gui/layout.h
index b87cf7e36b..734b720b8b 100644
--- a/calendar/gui/layout.h
+++ b/calendar/gui/layout.h
@@ -9,17 +9,29 @@
#ifndef LAYOUT_H
#define LAYOUT_H
-#include "calendar.h"
+#include <glib.h>
+#include <time.h>
-/* This is the main layout function for overlapping events. You pass in a list of CalendarObject
- * structures and it will calculate a nice non-overlapping layout for them.
+/* Functions of this type must translate the list item into two time_t values for the start and end
+ * of an event.
+ */
+typedef void (* LayoutQueryTimeFunc) (GList *event, time_t *start, time_t *end);
+
+
+/* This is the main layout function for overlapping events. You pass in a list of (presumably)
+ * events and a function that should take a list element and return the start and end times for the
+ * event corresponding to that list element.
*
* It returns the number of slots ("columns") that you need to take into account when actually
* painting the events, the array of the first slot index that each event occupies, and the array of
* number of slots that each event occupies. You have to free both arrays.
+ *
+ * You will get somewhat better-looking results if the list of events is sorted by using the start
+ * time as the primary sort key and the end time as the secondary sort key -- so that "longer"
+ * events go first in the list.
*/
-void layout_events (GList *events, int *num_slots, int **allocations, int **slots);
+void layout_events (GList *events, LayoutQueryTimeFunc func, int *num_slots, int **allocations, int **slots);
#endif
diff --git a/calendar/gui/quick-view.c b/calendar/gui/quick-view.c
index 62cb433447..9f647841cb 100644
--- a/calendar/gui/quick-view.c
+++ b/calendar/gui/quick-view.c
@@ -194,7 +194,7 @@ quick_view_new (GnomeCalendar *calendar, char *title, GList *event_list)
/* Create base widgets for the popup window */
w = gtk_frame_new (NULL);
- gtk_frame_set_shadow_type (GTK_FRAME (w), GTK_SHADOW_OUT);
+ gtk_frame_set_shadow_type (GTK_FRAME (w), GTK_SHADOW_ETCHED_OUT);
gtk_container_add (GTK_CONTAINER (qv), w);
vbox = gtk_vbox_new (FALSE, 0);
diff --git a/calendar/layout.c b/calendar/layout.c
index 03fac94cc6..f97f0d5ffd 100644
--- a/calendar/layout.c
+++ b/calendar/layout.c
@@ -6,9 +6,25 @@
* Federico Mena <federico@nuclecu.unam.mx>
*/
+#include <config.h>
+#include <stdlib.h>
#include "layout.h"
+/* This structure is used to pass around layout information among the internal layout functions */
+struct layout_info {
+ GList *events; /* List of events from client */
+ int num_events; /* The number of events (length of the list) */
+ LayoutQueryTimeFunc func; /* Function to convert a list item to a start/end time pair */
+ int num_rows; /* Size of the time partition */
+ time_t *partition; /* The time partition containing start and end time values */
+ int *array; /* Working array of free and allocated time slots */
+ int *allocations; /* Returned array of slot allocations */
+ int *slots; /* Returned array of slots used */
+ int num_slots; /* Number of slots used */
+};
+
+
/* This defines the maximum number of events to overlap per row. More than that number of events
* will not be displayed. This is not ideal, so sue me.
*/
@@ -35,37 +51,35 @@ compare_time_t (const void *a, const void *b)
/* Builds a partition of the time range occupied by the events in the list. It returns an array
* with the times that define the partition and the number of items in the partition.
*/
-static time_t *
-build_partition (GList *events, int num_events, int *num_rows)
+static void
+build_partition (struct layout_info *li)
{
time_t *rows, *p, *q;
GList *list;
- CalendarObject *co;
int i, unique_vals;
/* This is the maximum number of rows we would need */
- *num_rows = num_events * 2;
+ li->num_rows = li->num_events * 2;
/* Fill the rows with the times */
- rows = g_new (time_t, *num_rows);
+ rows = g_new (time_t, li->num_rows);
- for (list = events, p = rows; list; list = list->next) {
- co = list->data;
- *p++ = co->ev_start;
- *p++ = co->ev_end;
+ for (list = li->events, p = rows; list; list = list->next) {
+ (* li->func) (list, &p[0], &p[1]);
+ p += 2;
}
/* Do a sort | uniq on the array */
- qsort (rows, *num_rows, sizeof (time_t), compare_time_t);
+ qsort (rows, li->num_rows, sizeof (time_t), compare_time_t);
p = rows;
q = rows + 1;
unique_vals = 1;
- for (i = 1; i < *num_rows; i++, q++)
+ for (i = 1; i < li->num_rows; i++, q++)
if (*q != *p) {
unique_vals++;
p++;
@@ -74,33 +88,33 @@ build_partition (GList *events, int num_events, int *num_rows)
/* Return the number of unique values in the partition and the partition array itself */
- *num_rows = unique_vals;
- return rows;
+ li->num_rows = unique_vals;
+ li->partition = rows;
}
/* Returns the index of the element in the partition that corresponds to the specified time */
int
-find_index (time_t *partition, time_t t)
+find_index (struct layout_info *li, time_t t)
{
int i;
for (i = 0; ; i++)
- if (partition[i] == t)
+ if (li->partition[i] == t)
return i;
}
-#define xy(slot_array, x, y) slot_array[(y * MAX_EVENTS_PER_ROW) + (x)]
+#define xy(li, x, y) li->array[(y * MAX_EVENTS_PER_ROW) + (x)]
/* Checks that all the cells in the slot array at the specified slot column are free to use by an
* event that has the specified range.
*/
static int
-range_is_empty (time_t *partition, int *slot_array, int slot, time_t start, time_t end)
+range_is_empty (struct layout_info *li, int slot, time_t start, time_t end)
{
int i;
- for (i = find_index (partition, start); partition[i] < end; i++)
- if (xy (slot_array, slot, i) != -1)
+ for (i = find_index (li, start); li->partition[i] < end; i++)
+ if (xy (li, slot, i) != -1)
return FALSE;
return TRUE;
@@ -108,43 +122,44 @@ range_is_empty (time_t *partition, int *slot_array, int slot, time_t start, time
/* Allocates a time in the slot array for the specified event's index */
static void
-range_allocate (time_t *partition, int *slot_array, int slot, time_t start, time_t end, int ev_num)
+range_allocate (struct layout_info *li, int slot, time_t start, time_t end, int ev_num)
{
int i;
- for (i = find_index (partition, start); partition[i] < end; i++)
- xy (slot_array, slot, i) = ev_num;
+ for (i = find_index (li, start); li->partition[i] < end; i++)
+ xy (li, slot, i) = ev_num;
}
/* Performs the initial allocation of slots for events. Each event gets one column; they will be
* expanded in a later stage. Returns the number of columns used.
*/
-static int
-initial_allocate (GList *events, time_t *partition, int *slot_array, int *allocations, int *columns_used)
+static void
+initial_allocate (struct layout_info *li)
{
- CalendarObject *co;
+ GList *events;
int i;
int slot;
int num_slots;
+ time_t start, end;
num_slots = 0;
- for (i = 0; events; events = events->next, i++) {
- co = events->data;
+ for (i = 0, events = li->events; events; events = events->next, i++) {
+ (* li->func) (events, &start, &end);
/* Start with no allocation, no columns */
- allocations[i] = -1;
- columns_used[i] = 0;
+ li->allocations[i] = -1;
+ li->slots[i] = 0;
/* Find a free column for the event */
for (slot = 0; slot < MAX_EVENTS_PER_ROW; slot++)
- if (range_is_empty (partition, slot_array, slot, co->ev_start, co->ev_end)) {
- range_allocate (partition, slot_array, slot, co->ev_start, co->ev_end, i);
+ if (range_is_empty (li, slot, start, end)) {
+ range_allocate (li, slot, start, end, i);
- allocations[i] = slot;
- columns_used[i] = 1;
+ li->allocations[i] = slot;
+ li->slots[i] = 1;
if ((slot + 1) > num_slots)
num_slots = slot + 1;
@@ -153,13 +168,12 @@ initial_allocate (GList *events, time_t *partition, int *slot_array, int *alloca
}
}
- return num_slots;
+ li->num_slots = num_slots;
}
/* Returns the maximum number of columns that an event can expanded by in the slot array */
static int
-columns_to_expand (time_t *partition, int *slot_array, int *allocations, int num_slots, int ev_num,
- time_t start, time_t end)
+columns_to_expand (struct layout_info *li, int ev_num, time_t start, time_t end)
{
int cols;
int slot;
@@ -168,11 +182,11 @@ columns_to_expand (time_t *partition, int *slot_array, int *allocations, int num
cols = 0;
- i_start = find_index (partition, start);
+ i_start = find_index (li, start);
- for (slot = allocations[ev_num] + 1; slot < num_slots; slot++) {
- for (i = i_start; partition[i] < end; i++)
- if (xy (slot_array, slot, i) != -1)
+ for (slot = li->allocations[ev_num] + 1; slot < li->num_slots; slot++) {
+ for (i = i_start; li->partition[i] < end; i++)
+ if (xy (li, slot, i) != -1)
return cols;
cols++;
@@ -181,18 +195,18 @@ columns_to_expand (time_t *partition, int *slot_array, int *allocations, int num
return cols;
}
-/* Expands an event to occupy the specified number of columns */
+/* Expands an event by the specified number of columns */
static void
-do_expansion (time_t *partition, int *slot_array, int *allocations, int ev_num, time_t start, time_t end, int num_cols)
+do_expansion (struct layout_info *li, int ev_num, time_t start, time_t end, int num_cols)
{
int i, j;
int slot;
- for (i = find_index (partition, start); partition[i] < end; i++) {
- slot = allocations[ev_num] + 1;
+ for (i = find_index (li, start); li->partition[i] < end; i++) {
+ slot = li->allocations[ev_num] + 1;
for (j = 0; j < num_cols; j++)
- xy (slot_array, slot + j, i) = ev_num;
+ xy (li, slot + j, i) = ev_num;
}
}
@@ -200,33 +214,31 @@ do_expansion (time_t *partition, int *slot_array, int *allocations, int ev_num,
* pass of the layout algorithm.
*/
static void
-expand_events (GList *events, time_t *partition, int *slot_array, int num_slots, int *allocations, int *columns_used)
+expand_events (struct layout_info *li)
{
+ GList *events;
+ time_t start, end;
int i;
- CalendarObject *co;
int cols;
- for (i = 0; events; events = events->next, i++) {
- co = events->data;
+ for (i = 0, events = li->events; events; events = events->next, i++) {
+ (* li->func) (events, &start, &end);
- cols = columns_to_expand (partition, slot_array, allocations, num_slots, i, co->ev_start, co->ev_end);
+ cols = columns_to_expand (li, i, start, end);
if (cols == 0)
continue; /* We can't expand this event */
- do_expansion (partition, slot_array, allocations, i, co->ev_start, co->ev_end, cols);
+ do_expansion (li, i, start, end, cols);
- columns_used[i] += cols;
+ li->slots[i] += cols;
}
}
void
-layout_events (GList *events, int *num_slots, int **allocations, int **slots)
+layout_events (GList *events, LayoutQueryTimeFunc func, int *num_slots, int **allocations, int **slots)
{
- time_t *time_partition;
- int *slot_array;
- int num_events;
- int num_rows;
+ struct layout_info li;
int i;
g_return_if_fail (num_slots != NULL);
@@ -241,28 +253,33 @@ layout_events (GList *events, int *num_slots, int **allocations, int **slots)
return;
}
- num_events = g_list_length (events);
+ li.events = events;
+ li.num_events = g_list_length (events);
+ li.func = func;
/* Build the partition of the time range, and then build the array of slots */
- time_partition = build_partition (events, num_events, &num_rows);
+ build_partition (&li);
- slot_array = g_new (int, num_rows * MAX_EVENTS_PER_ROW);
- for (i = 0; i < (num_rows * MAX_EVENTS_PER_ROW); i++)
- slot_array[i] = -1; /* This is our 'empty' value */
+ li.array = g_new (int, li.num_rows * MAX_EVENTS_PER_ROW);
+ for (i = 0; i < (li.num_rows * MAX_EVENTS_PER_ROW); i++)
+ li.array[i] = -1; /* This is our 'empty' value */
/* Build the arrays for allocations and columns used */
- *allocations = g_new (int, num_events);
- *slots = g_new (int, num_events);
+ li.allocations = g_new (int, li.num_events);
+ li.slots = g_new (int, li.num_events);
- /* Perform initial allocation -- each event gets one column */
+ /* Perform initial allocation and then expand the events to as many slots as they can occupy */
- *num_slots = initial_allocate (events, time_partition, slot_array, *allocations, *slots);
+ initial_allocate (&li);
+ expand_events (&li);
- /* Expand the events to as many columns as possible */
+ /* Clean up and return values */
- expand_events (events, time_partition, slot_array, *num_slots, *allocations, *slots);
+ g_free (li.array);
- g_free (slot_array);
+ *num_slots = li.num_slots;
+ *allocations = li.allocations;
+ *slots = li.slots;
}
diff --git a/calendar/layout.h b/calendar/layout.h
index b87cf7e36b..734b720b8b 100644
--- a/calendar/layout.h
+++ b/calendar/layout.h
@@ -9,17 +9,29 @@
#ifndef LAYOUT_H
#define LAYOUT_H
-#include "calendar.h"
+#include <glib.h>
+#include <time.h>
-/* This is the main layout function for overlapping events. You pass in a list of CalendarObject
- * structures and it will calculate a nice non-overlapping layout for them.
+/* Functions of this type must translate the list item into two time_t values for the start and end
+ * of an event.
+ */
+typedef void (* LayoutQueryTimeFunc) (GList *event, time_t *start, time_t *end);
+
+
+/* This is the main layout function for overlapping events. You pass in a list of (presumably)
+ * events and a function that should take a list element and return the start and end times for the
+ * event corresponding to that list element.
*
* It returns the number of slots ("columns") that you need to take into account when actually
* painting the events, the array of the first slot index that each event occupies, and the array of
* number of slots that each event occupies. You have to free both arrays.
+ *
+ * You will get somewhat better-looking results if the list of events is sorted by using the start
+ * time as the primary sort key and the end time as the secondary sort key -- so that "longer"
+ * events go first in the list.
*/
-void layout_events (GList *events, int *num_slots, int **allocations, int **slots);
+void layout_events (GList *events, LayoutQueryTimeFunc func, int *num_slots, int **allocations, int **slots);
#endif
diff --git a/calendar/quick-view.c b/calendar/quick-view.c
index 62cb433447..9f647841cb 100644
--- a/calendar/quick-view.c
+++ b/calendar/quick-view.c
@@ -194,7 +194,7 @@ quick_view_new (GnomeCalendar *calendar, char *title, GList *event_list)
/* Create base widgets for the popup window */
w = gtk_frame_new (NULL);
- gtk_frame_set_shadow_type (GTK_FRAME (w), GTK_SHADOW_OUT);
+ gtk_frame_set_shadow_type (GTK_FRAME (w), GTK_SHADOW_ETCHED_OUT);
gtk_container_add (GTK_CONTAINER (qv), w);
vbox = gtk_vbox_new (FALSE, 0);