views/dazzling-month-view: Handle events
Most of the code is copied from GcalMonthView, so it sucks slightly. But it seems to work reasonably well so far.
This commit is contained in:
@@ -26,6 +26,7 @@
|
|||||||
#include "gcal-dazzling-month-view.h"
|
#include "gcal-dazzling-month-view.h"
|
||||||
#include "gcal-debug.h"
|
#include "gcal-debug.h"
|
||||||
#include "gcal-month-view-row.h"
|
#include "gcal-month-view-row.h"
|
||||||
|
#include "gcal-range-tree.h"
|
||||||
#include "gcal-timeline-subscriber.h"
|
#include "gcal-timeline-subscriber.h"
|
||||||
#include "gcal-utils.h"
|
#include "gcal-utils.h"
|
||||||
#include "gcal-view-private.h"
|
#include "gcal-view-private.h"
|
||||||
@@ -50,6 +51,8 @@ struct _GcalDazzlingMonthView
|
|||||||
GtkWidget *weekday_label[7];
|
GtkWidget *weekday_label[7];
|
||||||
|
|
||||||
GPtrArray *week_rows;
|
GPtrArray *week_rows;
|
||||||
|
GcalRangeTree *events;
|
||||||
|
GHashTable *events2;
|
||||||
|
|
||||||
/* Ranges from [0.0, 1.0] */
|
/* Ranges from [0.0, 1.0] */
|
||||||
gdouble row_offset;
|
gdouble row_offset;
|
||||||
@@ -511,6 +514,44 @@ static void
|
|||||||
gcal_dazzling_month_view_add_event (GcalTimelineSubscriber *subscriber,
|
gcal_dazzling_month_view_add_event (GcalTimelineSubscriber *subscriber,
|
||||||
GcalEvent *event)
|
GcalEvent *event)
|
||||||
{
|
{
|
||||||
|
GcalDazzlingMonthView *self;
|
||||||
|
|
||||||
|
GCAL_ENTRY;
|
||||||
|
|
||||||
|
g_assert (event != NULL);
|
||||||
|
|
||||||
|
self = GCAL_DAZZLING_MONTH_VIEW (subscriber);
|
||||||
|
|
||||||
|
if (!g_hash_table_add (self->events2, g_object_ref (event)))
|
||||||
|
{
|
||||||
|
g_warning ("Event with uuid: %s already added", gcal_event_get_uid (event));
|
||||||
|
GCAL_RETURN ();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (guint i = 0; i < self->week_rows->len; i++)
|
||||||
|
{
|
||||||
|
g_autoptr (GcalRange) row_range = NULL;
|
||||||
|
GcalRangePosition position;
|
||||||
|
GcalRangeOverlap overlap;
|
||||||
|
GcalMonthViewRow *row;
|
||||||
|
|
||||||
|
row = g_ptr_array_index (self->week_rows, i);
|
||||||
|
row_range = gcal_month_view_row_get_range (row);
|
||||||
|
|
||||||
|
overlap = gcal_range_calculate_overlap (row_range, gcal_event_get_range (event), &position);
|
||||||
|
if (overlap != GCAL_RANGE_NO_OVERLAP)
|
||||||
|
{
|
||||||
|
g_message ("Adding event %s to row %u", gcal_event_get_uid (event), i);
|
||||||
|
gcal_month_view_row_add_event (row, event);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (position == GCAL_RANGE_AFTER)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GCAL_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -523,6 +564,48 @@ static void
|
|||||||
gcal_dazzling_month_view_remove_event (GcalTimelineSubscriber *subscriber,
|
gcal_dazzling_month_view_remove_event (GcalTimelineSubscriber *subscriber,
|
||||||
GcalEvent *event)
|
GcalEvent *event)
|
||||||
{
|
{
|
||||||
|
g_autoptr (GcalEvent) owned_event = NULL;
|
||||||
|
GcalDazzlingMonthView *self;
|
||||||
|
|
||||||
|
GCAL_ENTRY;
|
||||||
|
|
||||||
|
g_assert (event != NULL);
|
||||||
|
|
||||||
|
self = GCAL_DAZZLING_MONTH_VIEW (subscriber);
|
||||||
|
|
||||||
|
/* Keep event alive while removing it */
|
||||||
|
owned_event = g_object_ref (event);
|
||||||
|
|
||||||
|
if (!g_hash_table_remove (self->events2, event))
|
||||||
|
{
|
||||||
|
g_warning ("Event with uuid: %s not in %s", gcal_event_get_uid (event), G_OBJECT_TYPE_NAME (self));
|
||||||
|
GCAL_RETURN ();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (guint i = 0; i < self->week_rows->len; i++)
|
||||||
|
{
|
||||||
|
g_autoptr (GcalRange) row_range = NULL;
|
||||||
|
GcalRangePosition position;
|
||||||
|
GcalRangeOverlap overlap;
|
||||||
|
GcalMonthViewRow *row;
|
||||||
|
|
||||||
|
row = g_ptr_array_index (self->week_rows, i);
|
||||||
|
row_range = gcal_month_view_row_get_range (row);
|
||||||
|
|
||||||
|
overlap = gcal_range_calculate_overlap (row_range, gcal_event_get_range (event), &position);
|
||||||
|
if (overlap != GCAL_RANGE_NO_OVERLAP)
|
||||||
|
{
|
||||||
|
g_message ("Remove event %s to row %u", gcal_event_get_uid (event), i);
|
||||||
|
gcal_month_view_row_remove_event (row, event);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (position == GCAL_RANGE_AFTER)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GCAL_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -814,6 +897,9 @@ gcal_dazzling_month_view_dispose (GObject *object)
|
|||||||
|
|
||||||
GCAL_ENTRY;
|
GCAL_ENTRY;
|
||||||
|
|
||||||
|
g_clear_pointer (&self->events2, g_hash_table_destroy);
|
||||||
|
g_clear_pointer (&self->events, gcal_range_tree_unref);
|
||||||
|
|
||||||
g_clear_object (&self->kinetic_scroll_animation);
|
g_clear_object (&self->kinetic_scroll_animation);
|
||||||
g_clear_object (&self->row_offset_animation);
|
g_clear_object (&self->row_offset_animation);
|
||||||
|
|
||||||
@@ -932,6 +1018,9 @@ gcal_dazzling_month_view_init (GcalDazzlingMonthView *self)
|
|||||||
{
|
{
|
||||||
g_autoptr (GDateTime) now = NULL;
|
g_autoptr (GDateTime) now = NULL;
|
||||||
|
|
||||||
|
self->events = gcal_range_tree_new_with_free_func (g_object_unref);
|
||||||
|
self->events2 = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
|
||||||
|
|
||||||
gtk_widget_init_template (GTK_WIDGET (self));
|
gtk_widget_init_template (GTK_WIDGET (self));
|
||||||
update_weekday_labels (self);
|
update_weekday_labels (self);
|
||||||
|
|
||||||
|
|||||||
@@ -24,9 +24,19 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "gcal-date-time-utils.h"
|
#include "gcal-date-time-utils.h"
|
||||||
#include "gcal-debug.h"
|
#include "gcal-debug.h"
|
||||||
|
#include "gcal-event-widget.h"
|
||||||
#include "gcal-month-cell.h"
|
#include "gcal-month-cell.h"
|
||||||
#include "gcal-month-view-row.h"
|
#include "gcal-month-view-row.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GtkWidget *event_widget;
|
||||||
|
gboolean visible;
|
||||||
|
guint8 length;
|
||||||
|
guint8 height;
|
||||||
|
guint8 cell;
|
||||||
|
} GcalEventBlock;
|
||||||
|
|
||||||
struct _GcalMonthViewRow
|
struct _GcalMonthViewRow
|
||||||
{
|
{
|
||||||
GtkWidget parent;
|
GtkWidget parent;
|
||||||
@@ -34,6 +44,33 @@ struct _GcalMonthViewRow
|
|||||||
GtkWidget *day_cells[7];
|
GtkWidget *day_cells[7];
|
||||||
|
|
||||||
GcalRange *range;
|
GcalRange *range;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hash to keep children widgets (all of them, parent widgets and its parts if there's any),
|
||||||
|
* uuid as key and a list of all the instances of the event as value. Here, the first widget
|
||||||
|
* on the list is the master, and the rest are the parts. Note: the master is a part itself.
|
||||||
|
*/
|
||||||
|
GHashTable *children;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hash containing single-cell events, day of the month, on month-view, month of the year on
|
||||||
|
* year-view as key anda list of the events that belongs to this cell
|
||||||
|
*/
|
||||||
|
GHashTable *single_cell_children;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A sorted list containing multiday events. This one contains only parents events, to find out
|
||||||
|
* its parts @children will be used.
|
||||||
|
*/
|
||||||
|
GList *multi_cell_children;
|
||||||
|
|
||||||
|
/* Hash containing cells that who has overflow per list of hidden widgets */
|
||||||
|
GHashTable *overflow_cells;
|
||||||
|
|
||||||
|
gboolean needs_reallocation;
|
||||||
|
gint last_width;
|
||||||
|
gint last_height;
|
||||||
|
|
||||||
GcalContext *context;
|
GcalContext *context;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -49,6 +86,676 @@ enum
|
|||||||
static GParamSpec *properties [N_PROPS];
|
static GParamSpec *properties [N_PROPS];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
setup_child_widget (GcalMonthViewRow *self,
|
||||||
|
GtkWidget *widget)
|
||||||
|
{
|
||||||
|
gtk_widget_insert_after (widget, GTK_WIDGET (self), self->day_cells[6]);
|
||||||
|
|
||||||
|
// g_signal_connect_object (widget, "activate", G_CALLBACK (on_event_activated_cb), self, 0);
|
||||||
|
// g_signal_connect_object (widget, "notify::visible", G_CALLBACK (on_event_widget_visibility_changed_cb), self, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline guint
|
||||||
|
get_child_weekday (GcalMonthViewRow *self,
|
||||||
|
GcalEventWidget *child)
|
||||||
|
{
|
||||||
|
GcalEvent *event;
|
||||||
|
GDateTime *dt;
|
||||||
|
gint weekday;
|
||||||
|
|
||||||
|
event = gcal_event_widget_get_event (child);
|
||||||
|
dt = gcal_event_get_date_start (event);
|
||||||
|
|
||||||
|
/* Don't adjust the date when the event is all day */
|
||||||
|
if (gcal_event_get_all_day (event))
|
||||||
|
{
|
||||||
|
weekday = g_date_time_get_day_of_week (dt) % 7;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dt = g_date_time_to_local (dt);
|
||||||
|
weekday = g_date_time_get_day_of_week (dt) % 7;
|
||||||
|
|
||||||
|
g_clear_pointer (&dt, g_date_time_unref);
|
||||||
|
}
|
||||||
|
|
||||||
|
return weekday;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_event_widget (GcalMonthViewRow *self,
|
||||||
|
GtkWidget *widget)
|
||||||
|
{
|
||||||
|
GcalEvent *event;
|
||||||
|
const gchar *uuid;
|
||||||
|
GList *l = NULL;
|
||||||
|
|
||||||
|
g_return_if_fail (GCAL_IS_EVENT_WIDGET (widget));
|
||||||
|
g_return_if_fail (gtk_widget_get_parent (widget) == NULL);
|
||||||
|
|
||||||
|
event = gcal_event_widget_get_event (GCAL_EVENT_WIDGET (widget));
|
||||||
|
uuid = gcal_event_get_uid (event);
|
||||||
|
|
||||||
|
/* inserting in all children hash */
|
||||||
|
if (g_hash_table_contains (self->children, uuid))
|
||||||
|
{
|
||||||
|
g_warning ("Event with uuid: %s already added", uuid);
|
||||||
|
g_object_unref (widget);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
l = g_list_append (l, widget);
|
||||||
|
g_hash_table_insert (self->children, g_strdup (uuid), l);
|
||||||
|
|
||||||
|
if (gcal_event_is_multiday (event))
|
||||||
|
{
|
||||||
|
self->multi_cell_children = g_list_insert_sorted (self->multi_cell_children,
|
||||||
|
widget,
|
||||||
|
(GCompareFunc) gcal_event_widget_sort_events);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
guint weekday;
|
||||||
|
|
||||||
|
weekday = get_child_weekday (self, GCAL_EVENT_WIDGET (widget));
|
||||||
|
|
||||||
|
l = g_hash_table_lookup (self->single_cell_children, GINT_TO_POINTER (weekday));
|
||||||
|
l = g_list_insert_sorted (l, widget, (GCompareFunc) gcal_event_widget_compare_by_start_date);
|
||||||
|
|
||||||
|
if (g_list_length (l) != 1)
|
||||||
|
g_hash_table_steal (self->single_cell_children, GINT_TO_POINTER (weekday));
|
||||||
|
|
||||||
|
g_hash_table_insert (self->single_cell_children, GINT_TO_POINTER (weekday), l);
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_child_widget (self, widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_event_widget (GcalMonthViewRow *self,
|
||||||
|
GtkWidget *widget)
|
||||||
|
{
|
||||||
|
GtkWidget *master_widget;
|
||||||
|
GcalEvent *event;
|
||||||
|
GList *l, *aux;
|
||||||
|
const gchar *uuid;
|
||||||
|
|
||||||
|
g_assert (gtk_widget_get_parent (widget) == GTK_WIDGET (self));
|
||||||
|
|
||||||
|
if (!GCAL_IS_EVENT_WIDGET (widget))
|
||||||
|
return;
|
||||||
|
|
||||||
|
event = gcal_event_widget_get_event (GCAL_EVENT_WIDGET (widget));
|
||||||
|
uuid = gcal_event_get_uid (event);
|
||||||
|
|
||||||
|
l = g_hash_table_lookup (self->children, uuid);
|
||||||
|
|
||||||
|
if (l)
|
||||||
|
{
|
||||||
|
gtk_widget_unparent (widget);
|
||||||
|
|
||||||
|
master_widget = (GtkWidget*) l->data;
|
||||||
|
if (widget == master_widget)
|
||||||
|
{
|
||||||
|
if (g_list_find (self->multi_cell_children, widget) != NULL)
|
||||||
|
{
|
||||||
|
self->multi_cell_children = g_list_remove (self->multi_cell_children, widget);
|
||||||
|
|
||||||
|
aux = g_list_next (l);
|
||||||
|
if (aux != NULL)
|
||||||
|
{
|
||||||
|
l->next = NULL;
|
||||||
|
aux->prev = NULL;
|
||||||
|
g_list_foreach (aux, (GFunc) gtk_widget_unparent, NULL);
|
||||||
|
g_list_free (aux);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GHashTableIter iter;
|
||||||
|
gpointer key, value;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When an event is changed, we can't rely on it's old date
|
||||||
|
* to remove the corresponding widget. Because of that, we have
|
||||||
|
* to iter through all the widgets to see which one matches
|
||||||
|
*/
|
||||||
|
g_hash_table_iter_init (&iter, self->single_cell_children);
|
||||||
|
|
||||||
|
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||||
|
{
|
||||||
|
gboolean should_break;
|
||||||
|
|
||||||
|
should_break = FALSE;
|
||||||
|
|
||||||
|
for (aux = value; aux != NULL; aux = aux->next)
|
||||||
|
{
|
||||||
|
if (aux->data == widget)
|
||||||
|
{
|
||||||
|
aux = g_list_remove (g_list_copy (value), widget);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we removed the event and there's no event left for
|
||||||
|
* the day, remove the key from the table. If there are
|
||||||
|
* events for that day, replace the list.
|
||||||
|
*/
|
||||||
|
if (!aux)
|
||||||
|
g_hash_table_remove (self->single_cell_children, key);
|
||||||
|
else
|
||||||
|
g_hash_table_replace (self->single_cell_children, key, aux);
|
||||||
|
|
||||||
|
should_break = TRUE;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_break)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
l = g_list_remove (g_list_copy (l), widget);
|
||||||
|
|
||||||
|
if (!l)
|
||||||
|
g_hash_table_remove (self->children, uuid);
|
||||||
|
else
|
||||||
|
g_hash_table_replace (self->children, g_strdup (uuid), l);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
calculate_event_cells (GcalMonthViewRow *self,
|
||||||
|
GcalEvent *event,
|
||||||
|
gint *out_first_cell,
|
||||||
|
gint *out_last_cell)
|
||||||
|
{
|
||||||
|
gboolean all_day;
|
||||||
|
|
||||||
|
all_day = gcal_event_get_all_day (event);
|
||||||
|
|
||||||
|
/* Start date */
|
||||||
|
if (out_first_cell)
|
||||||
|
{
|
||||||
|
g_autoptr (GDateTime) start_date = NULL;
|
||||||
|
gint first_cell = 0;
|
||||||
|
|
||||||
|
start_date = gcal_event_get_date_start (event);
|
||||||
|
start_date = all_day ? g_date_time_ref (start_date) : g_date_time_to_local (start_date);
|
||||||
|
|
||||||
|
if (gcal_range_contains_datetime (self->range, start_date))
|
||||||
|
first_cell = g_date_time_get_day_of_week (start_date) % 7;
|
||||||
|
|
||||||
|
*out_first_cell = first_cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The logic for the end date is the same, except that we have to check
|
||||||
|
* if the event is all day or not.
|
||||||
|
*/
|
||||||
|
if (out_last_cell)
|
||||||
|
{
|
||||||
|
g_autoptr (GDateTime) end_date = NULL;
|
||||||
|
gint last_cell = 6;
|
||||||
|
|
||||||
|
end_date = gcal_event_get_date_end (event);
|
||||||
|
end_date = all_day ? g_date_time_ref (end_date) : g_date_time_to_local (end_date);
|
||||||
|
|
||||||
|
if (gcal_range_contains_datetime (self->range, end_date))
|
||||||
|
{
|
||||||
|
last_cell = g_date_time_get_day_of_week (end_date) % 7;
|
||||||
|
|
||||||
|
/* If the event is all day, we have to subtract 1 to find the the real date */
|
||||||
|
if (all_day)
|
||||||
|
last_cell--;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_last_cell = last_cell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cleanup_overflow_information (GcalMonthViewRow *self)
|
||||||
|
{
|
||||||
|
g_autoptr (GList) widget_lists = NULL;
|
||||||
|
GList *l = NULL;
|
||||||
|
|
||||||
|
/* Remove every widget' parts, but the master widget */
|
||||||
|
widget_lists = g_hash_table_get_values (self->children);
|
||||||
|
|
||||||
|
for (l = widget_lists; l; l = l->next)
|
||||||
|
{
|
||||||
|
g_autoptr (GList) widgets = g_list_copy (l->data);
|
||||||
|
GList *l2;
|
||||||
|
|
||||||
|
for (l2 = widgets->next; l2; l2 = l2->next)
|
||||||
|
remove_event_widget (self, l2->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean overflow information */
|
||||||
|
g_hash_table_remove_all (self->overflow_cells);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
count_events_per_day (GcalMonthViewRow *self,
|
||||||
|
gint events_per_day[7])
|
||||||
|
{
|
||||||
|
GHashTableIter iter;
|
||||||
|
gpointer key;
|
||||||
|
GList *children;
|
||||||
|
|
||||||
|
/* Multiday events */
|
||||||
|
for (GList *l = self->multi_cell_children; l; l = l->next)
|
||||||
|
{
|
||||||
|
GcalEvent *event;
|
||||||
|
gint first_cell;
|
||||||
|
gint last_cell;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
if (!gtk_widget_get_visible (l->data))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
event = gcal_event_widget_get_event (l->data);
|
||||||
|
|
||||||
|
calculate_event_cells (self, event, &first_cell, &last_cell);
|
||||||
|
|
||||||
|
for (i = first_cell; i <= last_cell; i++)
|
||||||
|
events_per_day[i]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Single day events */
|
||||||
|
g_hash_table_iter_init (&iter, self->single_cell_children);
|
||||||
|
while (g_hash_table_iter_next (&iter, &key, (gpointer*) &children))
|
||||||
|
{
|
||||||
|
gint cell;
|
||||||
|
|
||||||
|
cell = GPOINTER_TO_INT (key);
|
||||||
|
|
||||||
|
for (GList *l = children; l; l = l->next)
|
||||||
|
{
|
||||||
|
if (!gtk_widget_get_visible (l->data))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
events_per_day[cell]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GPtrArray*
|
||||||
|
calculate_multiday_event_blocks (GcalMonthViewRow *self,
|
||||||
|
GtkWidget *event_widget,
|
||||||
|
gdouble *vertical_cell_space,
|
||||||
|
gdouble *size_left,
|
||||||
|
gint *events_at_day,
|
||||||
|
gint *allocated_events_at_day)
|
||||||
|
{
|
||||||
|
GcalEventBlock *block;
|
||||||
|
GcalEvent *event;
|
||||||
|
GPtrArray *blocks;
|
||||||
|
gboolean was_visible;
|
||||||
|
gdouble old_y;
|
||||||
|
gdouble y;
|
||||||
|
gint first_cell;
|
||||||
|
gint last_cell;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
GCAL_ENTRY;
|
||||||
|
|
||||||
|
old_y = -1.0;
|
||||||
|
was_visible = FALSE;
|
||||||
|
|
||||||
|
/* Get the event cells */
|
||||||
|
event = gcal_event_widget_get_event (GCAL_EVENT_WIDGET (event_widget));
|
||||||
|
calculate_event_cells (self, event, &first_cell, &last_cell);
|
||||||
|
|
||||||
|
blocks = g_ptr_array_new_full (last_cell - first_cell + 1, g_free);
|
||||||
|
block = NULL;
|
||||||
|
|
||||||
|
GCAL_TRACE_MSG ("Positioning '%s' (multiday) from %d to %d", gcal_event_get_summary (event), first_cell, last_cell);
|
||||||
|
|
||||||
|
for (i = first_cell; i <= last_cell; i++)
|
||||||
|
{
|
||||||
|
gboolean visible_at_range;
|
||||||
|
gboolean different_row;
|
||||||
|
gboolean will_overflow;
|
||||||
|
gdouble real_height;
|
||||||
|
gint remaining_events;
|
||||||
|
gint minimum_height;
|
||||||
|
|
||||||
|
real_height = size_left[i];
|
||||||
|
|
||||||
|
/* Calculate the minimum event height */
|
||||||
|
gtk_widget_measure (GTK_WIDGET (event_widget),
|
||||||
|
GTK_ORIENTATION_VERTICAL,
|
||||||
|
-1,
|
||||||
|
&minimum_height,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
|
||||||
|
/* Count this event at this cell */
|
||||||
|
different_row = i / 7 != (i - 1) / 7;
|
||||||
|
remaining_events = events_at_day[i] - allocated_events_at_day[i];
|
||||||
|
will_overflow = remaining_events * minimum_height > real_height;
|
||||||
|
|
||||||
|
if (will_overflow)
|
||||||
|
real_height -= gcal_month_cell_get_overflow_height (GCAL_MONTH_CELL (self->day_cells[i]));
|
||||||
|
|
||||||
|
visible_at_range = real_height >= minimum_height;
|
||||||
|
|
||||||
|
if (visible_at_range)
|
||||||
|
allocated_events_at_day[i]++;
|
||||||
|
|
||||||
|
y = vertical_cell_space[i] - size_left[i];
|
||||||
|
|
||||||
|
/* At the first iteration, make was_visible and visible_at_range equal */
|
||||||
|
if (i == first_cell)
|
||||||
|
was_visible = visible_at_range;
|
||||||
|
|
||||||
|
if (!block || y != old_y || different_row || was_visible != visible_at_range)
|
||||||
|
{
|
||||||
|
GCAL_TRACE_MSG ("Breaking event at cell %d", i);
|
||||||
|
|
||||||
|
/* Only create a new event widget after the first one is consumed */
|
||||||
|
if (block)
|
||||||
|
{
|
||||||
|
GcalEvent *event;
|
||||||
|
GList *aux;
|
||||||
|
|
||||||
|
GCAL_TRACE_MSG ("Cloning event widget");
|
||||||
|
|
||||||
|
event = gcal_event_widget_get_event (GCAL_EVENT_WIDGET (event_widget));
|
||||||
|
|
||||||
|
event_widget = gcal_event_widget_clone (GCAL_EVENT_WIDGET (event_widget));
|
||||||
|
setup_child_widget (self, event_widget);
|
||||||
|
|
||||||
|
aux = g_hash_table_lookup (self->children, gcal_event_get_uid (event));
|
||||||
|
aux = g_list_append (aux, event_widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
old_y = y;
|
||||||
|
|
||||||
|
/* Add a new block */
|
||||||
|
block = g_new (GcalEventBlock, 1);
|
||||||
|
block->event_widget = event_widget;
|
||||||
|
block->visible = visible_at_range;
|
||||||
|
block->height = minimum_height;
|
||||||
|
block->length = 1;
|
||||||
|
block->cell = i;
|
||||||
|
|
||||||
|
g_ptr_array_add (blocks, block);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
block->length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
was_visible = visible_at_range;
|
||||||
|
}
|
||||||
|
|
||||||
|
GCAL_RETURN (blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
allocate_multiday_events (GcalMonthViewRow *self,
|
||||||
|
gdouble *vertical_cell_space,
|
||||||
|
gdouble *size_left,
|
||||||
|
gint *events_at_day,
|
||||||
|
gint *allocated_events_at_day,
|
||||||
|
gint baseline)
|
||||||
|
{
|
||||||
|
GtkAllocation event_allocation;
|
||||||
|
GList *l;
|
||||||
|
gboolean is_rtl;
|
||||||
|
|
||||||
|
is_rtl = gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL;
|
||||||
|
|
||||||
|
for (l = self->multi_cell_children; l; l = g_list_next (l))
|
||||||
|
{
|
||||||
|
g_autoptr (GPtrArray) blocks = NULL;
|
||||||
|
GtkWidget *child_widget;
|
||||||
|
GcalEvent *event;
|
||||||
|
gint block_idx;
|
||||||
|
|
||||||
|
child_widget = (GtkWidget*) l->data;
|
||||||
|
|
||||||
|
if (!gtk_widget_should_layout (child_widget))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
event = gcal_event_widget_get_event (l->data);
|
||||||
|
|
||||||
|
if (gcal_range_calculate_overlap (self->range, gcal_event_get_range (event), NULL) == GCAL_RANGE_NO_OVERLAP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Multiday events can "break" following these rules:
|
||||||
|
*
|
||||||
|
* - Break when line changed
|
||||||
|
* - Break when the vertical position in the cells changed
|
||||||
|
* - Break when the previous part's visibility is different than the current
|
||||||
|
*/
|
||||||
|
blocks = calculate_multiday_event_blocks (self,
|
||||||
|
child_widget,
|
||||||
|
vertical_cell_space,
|
||||||
|
size_left,
|
||||||
|
events_at_day,
|
||||||
|
allocated_events_at_day);
|
||||||
|
|
||||||
|
for (block_idx = 0; block_idx < blocks->len; block_idx++)
|
||||||
|
{
|
||||||
|
g_autoptr (GDateTime) range_start = NULL;
|
||||||
|
g_autoptr (GDateTime) dt_start = NULL;
|
||||||
|
g_autoptr (GDateTime) dt_end = NULL;
|
||||||
|
GcalEventBlock *block;
|
||||||
|
GtkAllocation first_cell_allocation;
|
||||||
|
GtkAllocation last_cell_allocation;
|
||||||
|
GtkWidget *last_month_cell;
|
||||||
|
GtkWidget *month_cell;
|
||||||
|
GList *aux;
|
||||||
|
gdouble pos_x;
|
||||||
|
gdouble pos_y;
|
||||||
|
gdouble width;
|
||||||
|
gint last_block_cell;
|
||||||
|
gint minimum_height;
|
||||||
|
gint length;
|
||||||
|
gint cell;
|
||||||
|
gint day;
|
||||||
|
gint j;
|
||||||
|
|
||||||
|
block = g_ptr_array_index (blocks, block_idx);
|
||||||
|
length = block->length;
|
||||||
|
cell = block->cell;
|
||||||
|
last_block_cell = cell + length - 1;
|
||||||
|
day = cell;
|
||||||
|
|
||||||
|
child_widget = block->event_widget;
|
||||||
|
|
||||||
|
/* No space left, add to the overflow and continue */
|
||||||
|
if (!block->visible)
|
||||||
|
{
|
||||||
|
gint idx;
|
||||||
|
|
||||||
|
gtk_widget_set_child_visible (child_widget, FALSE);
|
||||||
|
|
||||||
|
for (idx = cell; idx < cell + length; idx++)
|
||||||
|
{
|
||||||
|
aux = g_hash_table_lookup (self->overflow_cells, GINT_TO_POINTER (idx));
|
||||||
|
aux = g_list_append (aux, child_widget);
|
||||||
|
|
||||||
|
if (g_list_length (aux) == 1)
|
||||||
|
g_hash_table_insert (self->overflow_cells, GINT_TO_POINTER (idx), aux);
|
||||||
|
else
|
||||||
|
g_hash_table_replace (self->overflow_cells, GINT_TO_POINTER (idx), g_list_copy (aux));
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Retrieve the cell widget. On RTL languages, swap the first and last cells */
|
||||||
|
month_cell = self->day_cells[cell];
|
||||||
|
last_month_cell = self->day_cells[last_block_cell];
|
||||||
|
|
||||||
|
if (is_rtl)
|
||||||
|
{
|
||||||
|
GtkWidget *aux = month_cell;
|
||||||
|
month_cell = last_month_cell;
|
||||||
|
last_month_cell = aux;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_widget_get_allocation (month_cell, &first_cell_allocation);
|
||||||
|
gtk_widget_get_allocation (last_month_cell, &last_cell_allocation);
|
||||||
|
|
||||||
|
gtk_widget_set_child_visible (child_widget, TRUE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup the widget's start date as the first day of the row,
|
||||||
|
* and the widget's end date as the last day of the row. We don't
|
||||||
|
* have to worry about the dates, since GcalEventWidget performs
|
||||||
|
* some checks and only applies the dates when it's valid.
|
||||||
|
*/
|
||||||
|
range_start = gcal_range_get_start (self->range);
|
||||||
|
dt_start = g_date_time_new (g_date_time_get_timezone (gcal_event_get_date_start (event)),
|
||||||
|
g_date_time_get_year (range_start),
|
||||||
|
g_date_time_get_month (range_start),
|
||||||
|
g_date_time_get_day_of_month (range_start) + day,
|
||||||
|
0, 0, 0);
|
||||||
|
|
||||||
|
/* FIXME: use end date's timezone here */
|
||||||
|
dt_end = g_date_time_add_days (dt_start, length);
|
||||||
|
|
||||||
|
gcal_event_widget_set_date_start (GCAL_EVENT_WIDGET (child_widget), dt_start);
|
||||||
|
gcal_event_widget_set_date_end (GCAL_EVENT_WIDGET (child_widget), dt_end);
|
||||||
|
|
||||||
|
pos_x = first_cell_allocation.x;
|
||||||
|
pos_y = first_cell_allocation.y + gcal_month_cell_get_header_height (GCAL_MONTH_CELL (month_cell));
|
||||||
|
width = last_cell_allocation.x + last_cell_allocation.width - first_cell_allocation.x;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can only get the minimum height after making all these calculations,
|
||||||
|
* otherwise GTK complains about allocating without calling get_preferred_height.
|
||||||
|
*/
|
||||||
|
gtk_widget_measure (GTK_WIDGET (child_widget),
|
||||||
|
GTK_ORIENTATION_VERTICAL,
|
||||||
|
-1,
|
||||||
|
&minimum_height,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
|
||||||
|
event_allocation.x = pos_x;
|
||||||
|
event_allocation.y = pos_y + vertical_cell_space[cell] - size_left[cell];
|
||||||
|
event_allocation.width = width;
|
||||||
|
event_allocation.height = minimum_height;
|
||||||
|
|
||||||
|
gtk_widget_size_allocate (child_widget, &event_allocation, baseline);
|
||||||
|
|
||||||
|
/* update size_left */
|
||||||
|
for (j = 0; j < length; j++)
|
||||||
|
size_left[cell + j] -= minimum_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
allocate_single_day_events (GcalMonthViewRow *self,
|
||||||
|
gdouble *vertical_cell_space,
|
||||||
|
gdouble *size_left,
|
||||||
|
gint *events_at_day,
|
||||||
|
gint *allocated_events_at_day,
|
||||||
|
gint baseline)
|
||||||
|
{
|
||||||
|
GHashTableIter iter;
|
||||||
|
GtkAllocation event_allocation;
|
||||||
|
GtkAllocation cell_allocation;
|
||||||
|
gpointer key, value;
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&iter, self->single_cell_children);
|
||||||
|
|
||||||
|
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||||
|
{
|
||||||
|
GtkWidget *month_cell;
|
||||||
|
gboolean will_overflow;
|
||||||
|
gint day;
|
||||||
|
|
||||||
|
day = GPOINTER_TO_INT (key);
|
||||||
|
month_cell = self->day_cells[day];
|
||||||
|
|
||||||
|
gtk_widget_get_allocation (month_cell, &cell_allocation);
|
||||||
|
|
||||||
|
for (GList *l = (GList *)value; l; l = l->next)
|
||||||
|
{
|
||||||
|
GcalEvent *event;
|
||||||
|
GtkWidget *child_widget;
|
||||||
|
gdouble real_height;
|
||||||
|
gdouble pos_y;
|
||||||
|
gdouble pos_x;
|
||||||
|
gdouble width;
|
||||||
|
gint remaining_events;
|
||||||
|
gint minimum_height;
|
||||||
|
|
||||||
|
child_widget = l->data;
|
||||||
|
event = gcal_event_widget_get_event (GCAL_EVENT_WIDGET (child_widget));
|
||||||
|
|
||||||
|
if (!gtk_widget_should_layout (child_widget))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (gcal_range_calculate_overlap (self->range, gcal_event_get_range (event), NULL) == GCAL_RANGE_NO_OVERLAP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
gtk_widget_measure (GTK_WIDGET (child_widget),
|
||||||
|
GTK_ORIENTATION_VERTICAL,
|
||||||
|
-1,
|
||||||
|
&minimum_height,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
|
||||||
|
/* Check for overflow */
|
||||||
|
remaining_events = events_at_day[day] - allocated_events_at_day[day];
|
||||||
|
will_overflow = remaining_events * minimum_height >= size_left[day];
|
||||||
|
real_height = size_left[day];
|
||||||
|
|
||||||
|
if (will_overflow)
|
||||||
|
real_height -= gcal_month_cell_get_overflow_height (GCAL_MONTH_CELL (month_cell));
|
||||||
|
|
||||||
|
/* No space left, add to the overflow and continue */
|
||||||
|
if (real_height < minimum_height)
|
||||||
|
{
|
||||||
|
gtk_widget_set_child_visible (child_widget, FALSE);
|
||||||
|
|
||||||
|
l = g_hash_table_lookup (self->overflow_cells, GINT_TO_POINTER (day));
|
||||||
|
l = g_list_append (l, child_widget);
|
||||||
|
|
||||||
|
if (g_list_length (l) == 1)
|
||||||
|
g_hash_table_insert (self->overflow_cells, GINT_TO_POINTER (day), l);
|
||||||
|
else
|
||||||
|
g_hash_table_replace (self->overflow_cells, GINT_TO_POINTER (day), g_list_copy (l));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
allocated_events_at_day[day]++;
|
||||||
|
|
||||||
|
gtk_widget_set_child_visible (child_widget, TRUE);
|
||||||
|
|
||||||
|
pos_x = cell_allocation.x;
|
||||||
|
pos_y = cell_allocation.y + gcal_month_cell_get_header_height (GCAL_MONTH_CELL (month_cell));
|
||||||
|
width = cell_allocation.width;
|
||||||
|
|
||||||
|
event_allocation.x = pos_x;
|
||||||
|
event_allocation.y = pos_y + vertical_cell_space[day] - size_left[day];
|
||||||
|
event_allocation.width = width;
|
||||||
|
event_allocation.height = minimum_height;
|
||||||
|
|
||||||
|
gtk_widget_set_child_visible (child_widget, TRUE);
|
||||||
|
gtk_widget_size_allocate (child_widget, &event_allocation, baseline);
|
||||||
|
|
||||||
|
size_left[day] -= minimum_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GtkWidget overrides
|
* GtkWidget overrides
|
||||||
*/
|
*/
|
||||||
@@ -110,6 +817,7 @@ gcal_month_view_row_size_allocate (GtkWidget *widget,
|
|||||||
is_ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
|
is_ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
|
||||||
cell_width = width / 7.0;
|
cell_width = width / 7.0;
|
||||||
|
|
||||||
|
/* Month cells */
|
||||||
for (guint i = 0; i < 7; i++)
|
for (guint i = 0; i < 7; i++)
|
||||||
{
|
{
|
||||||
GtkAllocation allocation;
|
GtkAllocation allocation;
|
||||||
@@ -123,16 +831,53 @@ gcal_month_view_row_size_allocate (GtkWidget *widget,
|
|||||||
cell = is_ltr ? self->day_cells[i] : self->day_cells[7 - i + 1];
|
cell = is_ltr ? self->day_cells[i] : self->day_cells[7 - i + 1];
|
||||||
gtk_widget_size_allocate (cell, &allocation, baseline);
|
gtk_widget_size_allocate (cell, &allocation, baseline);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
/* Event widgets */
|
||||||
gcal_month_view_row_snapshot (GtkWidget *widget,
|
if (self->needs_reallocation || self->last_width != width || self->last_height != height)
|
||||||
GtkSnapshot *snapshot)
|
{
|
||||||
{
|
gdouble vertical_cell_space [7];
|
||||||
GcalMonthViewRow *self = GCAL_MONTH_VIEW_ROW (widget);
|
gdouble size_left [7];
|
||||||
|
gint allocated_events_at_day [7] = { 0, };
|
||||||
|
gint events_at_day [7] = { 0, };
|
||||||
|
|
||||||
for (guint i = 0; i < 7; i++)
|
/* Remove every widget' parts, but the main widget */
|
||||||
gtk_widget_snapshot_child (widget, self->day_cells[i], snapshot);
|
cleanup_overflow_information (self);
|
||||||
|
|
||||||
|
/* Event widgets */
|
||||||
|
count_events_per_day (self, events_at_day);
|
||||||
|
|
||||||
|
for (guint i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
gint content_space = gcal_month_cell_get_content_space (GCAL_MONTH_CELL (self->day_cells[i]));
|
||||||
|
|
||||||
|
vertical_cell_space[i] = content_space;
|
||||||
|
size_left[i] = content_space;
|
||||||
|
}
|
||||||
|
|
||||||
|
allocate_multiday_events (self, vertical_cell_space, size_left, events_at_day, allocated_events_at_day, baseline);
|
||||||
|
allocate_single_day_events (self, vertical_cell_space, size_left, events_at_day, allocated_events_at_day, baseline);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GtkWidget *child;
|
||||||
|
|
||||||
|
for (child = gtk_widget_get_first_child (widget);
|
||||||
|
child;
|
||||||
|
child = gtk_widget_get_next_sibling (child))
|
||||||
|
{
|
||||||
|
GtkAllocation allocation;
|
||||||
|
|
||||||
|
if (!GCAL_IS_EVENT_WIDGET (child))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
gtk_widget_get_allocation (child, &allocation);
|
||||||
|
gtk_widget_size_allocate (child, &allocation, baseline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self->last_width = width;
|
||||||
|
self->last_height = height;
|
||||||
|
self->needs_reallocation = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -144,10 +889,19 @@ static void
|
|||||||
gcal_month_view_row_dispose (GObject *object)
|
gcal_month_view_row_dispose (GObject *object)
|
||||||
{
|
{
|
||||||
GcalMonthViewRow *self = (GcalMonthViewRow *)object;
|
GcalMonthViewRow *self = (GcalMonthViewRow *)object;
|
||||||
|
GtkWidget *child;
|
||||||
|
|
||||||
for (guint i = 0; i < 7; i++)
|
for (guint i = 0; i < 7; i++)
|
||||||
g_clear_pointer (&self->day_cells[i], gtk_widget_unparent);
|
g_clear_pointer (&self->day_cells[i], gtk_widget_unparent);
|
||||||
|
|
||||||
|
while ((child = gtk_widget_get_first_child (GTK_WIDGET (self))) != NULL)
|
||||||
|
remove_event_widget (self, child);
|
||||||
|
|
||||||
|
g_clear_pointer (&self->children, g_hash_table_destroy);
|
||||||
|
g_clear_pointer (&self->single_cell_children, g_hash_table_destroy);
|
||||||
|
g_clear_pointer (&self->overflow_cells, g_hash_table_destroy);
|
||||||
|
g_clear_pointer (&self->multi_cell_children, g_list_free);
|
||||||
|
|
||||||
G_OBJECT_CLASS (gcal_month_view_row_parent_class)->dispose (object);
|
G_OBJECT_CLASS (gcal_month_view_row_parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +966,6 @@ gcal_month_view_row_class_init (GcalMonthViewRowClass *klass)
|
|||||||
|
|
||||||
widget_class->measure = gcal_month_view_row_measure;
|
widget_class->measure = gcal_month_view_row_measure;
|
||||||
widget_class->size_allocate = gcal_month_view_row_size_allocate;
|
widget_class->size_allocate = gcal_month_view_row_size_allocate;
|
||||||
widget_class->snapshot = gcal_month_view_row_snapshot;
|
|
||||||
|
|
||||||
properties[PROP_CONTEXT] = g_param_spec_object ("context",
|
properties[PROP_CONTEXT] = g_param_spec_object ("context",
|
||||||
"Context",
|
"Context",
|
||||||
@@ -228,6 +981,12 @@ gcal_month_view_row_class_init (GcalMonthViewRowClass *klass)
|
|||||||
static void
|
static void
|
||||||
gcal_month_view_row_init (GcalMonthViewRow *self)
|
gcal_month_view_row_init (GcalMonthViewRow *self)
|
||||||
{
|
{
|
||||||
|
self->last_width = -1;
|
||||||
|
self->last_height = -1;
|
||||||
|
self->children = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_list_free);
|
||||||
|
self->single_cell_children = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_list_free);
|
||||||
|
self->overflow_cells = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_list_free);
|
||||||
|
|
||||||
for (guint i = 0; i < 7; i++)
|
for (guint i = 0; i < 7; i++)
|
||||||
{
|
{
|
||||||
self->day_cells[i] = gcal_month_cell_new ();
|
self->day_cells[i] = gcal_month_cell_new ();
|
||||||
@@ -278,6 +1037,7 @@ gcal_month_view_row_set_range (GcalMonthViewRow *self,
|
|||||||
GcalRange *range)
|
GcalRange *range)
|
||||||
{
|
{
|
||||||
g_autoptr (GDateTime) start = NULL;
|
g_autoptr (GDateTime) start = NULL;
|
||||||
|
GtkWidget *child;
|
||||||
|
|
||||||
g_return_if_fail (GCAL_IS_MONTH_VIEW_ROW (self));
|
g_return_if_fail (GCAL_IS_MONTH_VIEW_ROW (self));
|
||||||
g_return_if_fail (range != NULL);
|
g_return_if_fail (range != NULL);
|
||||||
@@ -290,7 +1050,17 @@ gcal_month_view_row_set_range (GcalMonthViewRow *self,
|
|||||||
g_clear_pointer (&self->range, gcal_range_unref);
|
g_clear_pointer (&self->range, gcal_range_unref);
|
||||||
self->range = gcal_range_ref (range);
|
self->range = gcal_range_ref (range);
|
||||||
|
|
||||||
/* TODO: remove all widgets */
|
/* Preemptively remove all event widgets */
|
||||||
|
child = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||||
|
while (child)
|
||||||
|
{
|
||||||
|
GtkWidget *next = gtk_widget_get_next_sibling (child);
|
||||||
|
|
||||||
|
if (GCAL_IS_EVENT_WIDGET (child))
|
||||||
|
remove_event_widget (self, child);
|
||||||
|
|
||||||
|
child = next;
|
||||||
|
}
|
||||||
|
|
||||||
start = gcal_range_get_start (range);
|
start = gcal_range_get_start (range);
|
||||||
for (guint i = 0; i < 7; i++)
|
for (guint i = 0; i < 7; i++)
|
||||||
@@ -299,3 +1069,54 @@ gcal_month_view_row_set_range (GcalMonthViewRow *self,
|
|||||||
gcal_month_cell_set_date (GCAL_MONTH_CELL (self->day_cells[i]), day);
|
gcal_month_cell_set_date (GCAL_MONTH_CELL (self->day_cells[i]), day);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gcal_month_view_row_add_event (GcalMonthViewRow *self,
|
||||||
|
GcalEvent *event)
|
||||||
|
{
|
||||||
|
GcalCalendar *calendar;
|
||||||
|
GtkWidget *event_widget;
|
||||||
|
|
||||||
|
g_assert (GCAL_IS_MONTH_VIEW_ROW (self));
|
||||||
|
g_assert (GCAL_IS_EVENT (event));
|
||||||
|
|
||||||
|
calendar = gcal_event_get_calendar (event);
|
||||||
|
|
||||||
|
event_widget = gcal_event_widget_new (self->context, event);
|
||||||
|
gcal_event_widget_set_read_only (GCAL_EVENT_WIDGET (event_widget), gcal_calendar_is_read_only (calendar));
|
||||||
|
if (!gcal_event_get_all_day (event) && !gcal_event_is_multiday (event))
|
||||||
|
gcal_event_widget_set_timestamp_policy (GCAL_EVENT_WIDGET (event_widget), GCAL_TIMESTAMP_POLICY_START);
|
||||||
|
|
||||||
|
add_event_widget (self, event_widget);
|
||||||
|
|
||||||
|
self->needs_reallocation = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gcal_month_view_row_remove_event (GcalMonthViewRow *self,
|
||||||
|
GcalEvent *event)
|
||||||
|
{
|
||||||
|
const gchar *uid;
|
||||||
|
GList *l;
|
||||||
|
|
||||||
|
g_assert (GCAL_IS_MONTH_VIEW_ROW (self));
|
||||||
|
g_assert (GCAL_IS_EVENT (event));
|
||||||
|
|
||||||
|
GCAL_ENTRY;
|
||||||
|
|
||||||
|
uid = gcal_event_get_uid (event);
|
||||||
|
l = g_hash_table_lookup (self->children, uid);
|
||||||
|
|
||||||
|
if (!l)
|
||||||
|
{
|
||||||
|
g_warning ("%s: Widget with uuid: %s not found in view: %s",
|
||||||
|
G_STRFUNC,uid, G_OBJECT_TYPE_NAME (self));
|
||||||
|
GCAL_RETURN ();
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_event_widget (self, l->data);
|
||||||
|
|
||||||
|
self->needs_reallocation = TRUE;
|
||||||
|
|
||||||
|
GCAL_EXIT;
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
#include "gcal-context.h"
|
#include "gcal-context.h"
|
||||||
|
#include "gcal-event.h"
|
||||||
#include "gcal-range.h"
|
#include "gcal-range.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
@@ -43,4 +44,10 @@ GcalRange * gcal_month_view_row_get_range (GcalMonthViewR
|
|||||||
void gcal_month_view_row_set_range (GcalMonthViewRow *self,
|
void gcal_month_view_row_set_range (GcalMonthViewRow *self,
|
||||||
GcalRange *range);
|
GcalRange *range);
|
||||||
|
|
||||||
|
void gcal_month_view_row_add_event (GcalMonthViewRow *self,
|
||||||
|
GcalEvent *event);
|
||||||
|
|
||||||
|
void gcal_month_view_row_remove_event (GcalMonthViewRow *self,
|
||||||
|
GcalEvent *event);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|||||||
Reference in New Issue
Block a user