ECalDataModelSubscriber interface notify each view only about the events beloging to the subscribed range so there's no need of checking if the event widget will be added. The safety check of not adding the same widget twice its stil being made on each GtkContainer::add implementation.
1430 lines
42 KiB
C
1430 lines
42 KiB
C
/* -*- mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/*
|
|
* gcal-week-view.c
|
|
*
|
|
* Copyright (C) 2012 - Erick Pérez Castellanos
|
|
*
|
|
* 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "gcal-week-view.h"
|
|
#include "gcal-utils.h"
|
|
#include "gcal-view.h"
|
|
#include "gcal-event-widget.h"
|
|
|
|
#include <glib/gi18n.h>
|
|
|
|
#include <math.h>
|
|
|
|
#define ALL_DAY_CELLS_HEIGHT 40
|
|
|
|
static const double dashed [] =
|
|
{
|
|
1.0,
|
|
1.0
|
|
};
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_DATE,
|
|
PROP_MANAGER
|
|
};
|
|
|
|
struct _GcalWeekViewChild
|
|
{
|
|
GtkWidget *widget;
|
|
gboolean hidden_by_me;
|
|
|
|
/* vertical index */
|
|
gint index;
|
|
};
|
|
|
|
typedef struct _GcalWeekViewChild GcalWeekViewChild;
|
|
|
|
typedef struct
|
|
{
|
|
/**
|
|
* This is where we keep the refs of the child widgets.
|
|
* Every child added to the list placed in the position
|
|
* of it corresponding cell number.
|
|
* The cell number is calculated in _add method.
|
|
*/
|
|
GList *days [7];
|
|
|
|
GdkWindow *view_window;
|
|
GdkWindow *grid_window;
|
|
|
|
GtkWidget *vscrollbar;
|
|
|
|
/* property */
|
|
icaltimetype *date;
|
|
GcalManager *manager; /* weak referenced */
|
|
|
|
GdkWindow *event_window;
|
|
|
|
gint clicked_cell;
|
|
} GcalWeekViewPrivate;
|
|
|
|
static void gcal_view_interface_init (GcalViewIface *iface);
|
|
|
|
static void gcal_week_view_constructed (GObject *object);
|
|
|
|
static void gcal_week_view_finalize (GObject *object);
|
|
|
|
static void gcal_week_view_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec);
|
|
|
|
static void gcal_week_view_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec);
|
|
|
|
static void gcal_week_view_realize (GtkWidget *widget);
|
|
|
|
static void gcal_week_view_unrealize (GtkWidget *widget);
|
|
|
|
static void gcal_week_view_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *allocation);
|
|
|
|
static gboolean gcal_week_view_draw (GtkWidget *widget,
|
|
cairo_t *cr);
|
|
|
|
static gboolean gcal_week_view_scroll_event (GtkWidget *widget,
|
|
GdkEventScroll *event);
|
|
|
|
static gboolean gcal_week_view_button_press_event (GtkWidget *widget,
|
|
GdkEventButton *event);
|
|
|
|
static gboolean gcal_week_view_button_release_event (GtkWidget *widget,
|
|
GdkEventButton *event);
|
|
|
|
static void gcal_week_view_add (GtkContainer *constainer,
|
|
GtkWidget *widget);
|
|
|
|
static void gcal_week_view_remove (GtkContainer *constainer,
|
|
GtkWidget *widget);
|
|
|
|
static void gcal_week_view_forall (GtkContainer *container,
|
|
gboolean include_internals,
|
|
GtkCallback callback,
|
|
gpointer callback_data);
|
|
|
|
static void gcal_week_view_set_date (GcalWeekView *view,
|
|
icaltimetype *date);
|
|
|
|
static void gcal_week_view_draw_header (GcalWeekView *view,
|
|
cairo_t *cr,
|
|
GtkAllocation *alloc,
|
|
GtkBorder *padding);
|
|
|
|
static void gcal_week_view_draw_grid_window (GcalWeekView *view,
|
|
cairo_t *cr);
|
|
|
|
static gint gcal_week_view_get_sidebar_width (GtkWidget *widget);
|
|
|
|
static gint gcal_week_view_get_start_grid_y (GtkWidget *widget);
|
|
|
|
static void gcal_week_view_scroll_value_changed (GtkAdjustment *adjusment,
|
|
gpointer user_data);
|
|
|
|
static icaltimetype* gcal_week_view_get_initial_date (GcalView *view);
|
|
|
|
static icaltimetype* gcal_week_view_get_final_date (GcalView *view);
|
|
|
|
static gchar* gcal_week_view_get_left_header (GcalView *view);
|
|
|
|
static gchar* gcal_week_view_get_right_header (GcalView *view);
|
|
|
|
static gboolean gcal_week_view_draw_event (GcalView *view,
|
|
icaltimetype *start_date,
|
|
icaltimetype *end_date);
|
|
|
|
static GtkWidget* gcal_week_view_get_by_uuid (GcalView *view,
|
|
const gchar *uuid);
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (GcalWeekView,
|
|
gcal_week_view,
|
|
GTK_TYPE_CONTAINER,
|
|
G_ADD_PRIVATE (GcalWeekView)
|
|
G_IMPLEMENT_INTERFACE (GCAL_TYPE_VIEW,
|
|
gcal_view_interface_init));
|
|
|
|
static void
|
|
gcal_week_view_class_init (GcalWeekViewClass *klass)
|
|
{
|
|
GtkContainerClass *container_class;
|
|
GtkWidgetClass *widget_class;
|
|
GObjectClass *object_class;
|
|
|
|
container_class = GTK_CONTAINER_CLASS (klass);
|
|
container_class->add = gcal_week_view_add;
|
|
container_class->remove = gcal_week_view_remove;
|
|
container_class->forall = gcal_week_view_forall;
|
|
gtk_container_class_handle_border_width (container_class);
|
|
|
|
widget_class = GTK_WIDGET_CLASS (klass);
|
|
widget_class->realize = gcal_week_view_realize;
|
|
widget_class->unrealize = gcal_week_view_unrealize;
|
|
widget_class->size_allocate = gcal_week_view_size_allocate;
|
|
widget_class->draw = gcal_week_view_draw;
|
|
widget_class->scroll_event = gcal_week_view_scroll_event;
|
|
widget_class->button_press_event = gcal_week_view_button_press_event;
|
|
widget_class->button_release_event = gcal_week_view_button_release_event;
|
|
|
|
object_class = G_OBJECT_CLASS (klass);
|
|
object_class->constructed = gcal_week_view_constructed;
|
|
object_class->finalize = gcal_week_view_finalize;
|
|
object_class->set_property = gcal_week_view_set_property;
|
|
object_class->get_property = gcal_week_view_get_property;
|
|
|
|
g_object_class_override_property (object_class, PROP_DATE, "active-date");
|
|
g_object_class_override_property (object_class, PROP_MANAGER, "manager");
|
|
}
|
|
|
|
static void
|
|
gcal_week_view_init (GcalWeekView *self)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
gint i;
|
|
|
|
gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
|
|
|
|
priv = gcal_week_view_get_instance_private (self);
|
|
|
|
for (i = 0; i < 7; i++)
|
|
{
|
|
priv->days[i] = NULL;
|
|
}
|
|
|
|
priv->view_window = NULL;
|
|
priv->grid_window = NULL;
|
|
|
|
gtk_style_context_add_class (
|
|
gtk_widget_get_style_context (GTK_WIDGET (self)),
|
|
"calendar-view");
|
|
}
|
|
|
|
static void
|
|
gcal_view_interface_init (GcalViewIface *iface)
|
|
{
|
|
iface->get_initial_date = gcal_week_view_get_initial_date;
|
|
iface->get_final_date = gcal_week_view_get_final_date;
|
|
|
|
/* iface->mark_current_unit = gcal_week_view_mark_current_unit; */
|
|
/* iface->clear_marks = gcal_week_view_clear_marks; */
|
|
|
|
iface->get_left_header = gcal_week_view_get_left_header;
|
|
iface->get_right_header = gcal_week_view_get_right_header;
|
|
|
|
iface->draw_event = gcal_week_view_draw_event;
|
|
iface->get_by_uuid = gcal_week_view_get_by_uuid;
|
|
/* iface->clear = gcal_week_view_clear; */
|
|
}
|
|
|
|
static void
|
|
gcal_week_view_constructed (GObject *object)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
|
|
g_return_if_fail (GCAL_IS_WEEK_VIEW (object));
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW (object));
|
|
|
|
if (G_OBJECT_CLASS (gcal_week_view_parent_class)->constructed != NULL)
|
|
G_OBJECT_CLASS (gcal_week_view_parent_class)->constructed (object);
|
|
|
|
priv->vscrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, NULL);
|
|
|
|
gtk_widget_set_parent (priv->vscrollbar, GTK_WIDGET (object));
|
|
gtk_widget_show (priv->vscrollbar);
|
|
|
|
g_signal_connect (gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)),
|
|
"value-changed",
|
|
G_CALLBACK (gcal_week_view_scroll_value_changed),
|
|
object);
|
|
|
|
g_object_ref (priv->vscrollbar);
|
|
}
|
|
|
|
static void
|
|
gcal_week_view_finalize (GObject *object)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW (object));
|
|
|
|
if (priv->date != NULL)
|
|
g_free (priv->date);
|
|
|
|
if (priv->vscrollbar != NULL)
|
|
{
|
|
gtk_widget_unparent (priv->vscrollbar);
|
|
g_clear_object (&(priv->vscrollbar));
|
|
}
|
|
|
|
/* Chain up to parent's finalize() method. */
|
|
G_OBJECT_CLASS (gcal_week_view_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gcal_week_view_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW (object));
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_DATE:
|
|
gcal_week_view_set_date (
|
|
GCAL_WEEK_VIEW (object),
|
|
g_value_dup_boxed (value));
|
|
break;
|
|
case PROP_MANAGER:
|
|
priv->manager = g_value_get_pointer (value);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gcal_week_view_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
|
|
g_return_if_fail (GCAL_IS_WEEK_VIEW (object));
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW (object));
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_DATE:
|
|
g_value_set_boxed (value, priv->date);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gcal_week_view_realize (GtkWidget *widget)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
GdkWindow *parent_window;
|
|
GdkWindowAttr attributes;
|
|
gint attributes_mask;
|
|
GtkAllocation allocation;
|
|
|
|
gint i;
|
|
GList *l;
|
|
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW (widget));
|
|
gtk_widget_set_realized (widget, TRUE);
|
|
|
|
gtk_widget_get_allocation (widget, &allocation);
|
|
|
|
parent_window = gtk_widget_get_parent_window (widget);
|
|
gtk_widget_set_window (widget, parent_window);
|
|
|
|
attributes.window_type = GDK_WINDOW_CHILD;
|
|
attributes.wclass = GDK_INPUT_ONLY;
|
|
attributes.x = allocation.x;
|
|
attributes.y = allocation.y;
|
|
attributes.event_mask = gtk_widget_get_events (widget);
|
|
attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
|
|
GDK_BUTTON_RELEASE_MASK);
|
|
attributes_mask = GDK_WA_X | GDK_WA_Y;
|
|
|
|
priv->event_window = gdk_window_new (parent_window,
|
|
&attributes,
|
|
attributes_mask);
|
|
gdk_window_set_user_data (priv->event_window, widget);
|
|
|
|
attributes.window_type = GDK_WINDOW_CHILD;
|
|
attributes.wclass = GDK_INPUT_OUTPUT;
|
|
attributes.x = allocation.x;
|
|
attributes.y = allocation.y;
|
|
attributes.event_mask = gtk_widget_get_events (widget);
|
|
attributes.event_mask |= (GDK_EXPOSURE_MASK |
|
|
GDK_BUTTON_PRESS_MASK |
|
|
GDK_BUTTON_RELEASE_MASK |
|
|
GDK_BUTTON_MOTION_MASK |
|
|
GDK_POINTER_MOTION_MASK |
|
|
GDK_SCROLL_MASK |
|
|
GDK_TOUCH_MASK |
|
|
GDK_SMOOTH_SCROLL_MASK);
|
|
attributes.visual = gtk_widget_get_visual (widget);
|
|
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
|
|
|
|
priv->view_window = gdk_window_new (parent_window,
|
|
&attributes,
|
|
attributes_mask);
|
|
gdk_window_set_user_data (priv->view_window, widget);
|
|
|
|
attributes.event_mask = gtk_widget_get_events (widget);
|
|
attributes.event_mask |= GDK_EXPOSURE_MASK;
|
|
priv->grid_window = gdk_window_new (priv->view_window,
|
|
&attributes,
|
|
attributes_mask);
|
|
gdk_window_set_user_data (priv->grid_window, widget);
|
|
|
|
gdk_window_show (priv->event_window);
|
|
gdk_window_show (priv->grid_window);
|
|
gdk_window_show (priv->view_window);
|
|
|
|
/* setting parent_window for every event child */
|
|
for (i = 0; i < 7; i++)
|
|
{
|
|
for (l = priv->days[i]; l != NULL; l = l->next)
|
|
{
|
|
GcalWeekViewChild *child;
|
|
|
|
child = (GcalWeekViewChild*) l->data;
|
|
gtk_widget_set_parent_window (child->widget, priv->grid_window);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
gcal_week_view_unrealize (GtkWidget *widget)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW (widget));
|
|
if (priv->view_window != NULL)
|
|
{
|
|
gdk_window_set_user_data (priv->view_window, NULL);
|
|
gdk_window_destroy (priv->view_window);
|
|
priv->view_window = NULL;
|
|
}
|
|
|
|
if (priv->grid_window != NULL)
|
|
{
|
|
gdk_window_set_user_data (priv->grid_window, NULL);
|
|
gdk_window_destroy (priv->grid_window);
|
|
priv->grid_window = NULL;
|
|
}
|
|
if (priv->event_window != NULL)
|
|
{
|
|
gdk_window_set_user_data (priv->event_window, NULL);
|
|
gdk_window_destroy (priv->event_window);
|
|
priv->event_window = NULL;
|
|
}
|
|
|
|
GTK_WIDGET_CLASS (gcal_week_view_parent_class)->unrealize (widget);
|
|
}
|
|
|
|
static void
|
|
gcal_week_view_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *allocation)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
|
|
GtkBorder padding;
|
|
PangoLayout *layout;
|
|
PangoFontDescription *font_desc;
|
|
gint font_height;
|
|
|
|
gint start_grid_y;
|
|
gint sidebar_width;
|
|
|
|
GtkAllocation scroll_allocation;
|
|
gint min;
|
|
gint natural;
|
|
|
|
gdouble horizontal_block;
|
|
gdouble vertical_block;
|
|
gdouble adj_value;
|
|
|
|
gint i;
|
|
GList *l;
|
|
|
|
gboolean scroll_needed;
|
|
gint grid_height;
|
|
gint view_height;
|
|
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW (widget));
|
|
|
|
gtk_widget_set_allocation (widget, allocation);
|
|
|
|
if (! gtk_widget_get_realized (widget))
|
|
return;
|
|
|
|
gtk_style_context_get_padding (
|
|
gtk_widget_get_style_context (widget),
|
|
gtk_widget_get_state_flags (widget),
|
|
&padding);
|
|
|
|
start_grid_y = gcal_week_view_get_start_grid_y (widget);
|
|
|
|
gdk_window_move_resize (priv->event_window,
|
|
allocation->x,
|
|
allocation->y,
|
|
allocation->width,
|
|
start_grid_y);
|
|
|
|
/* Estimating cell height */
|
|
layout = pango_layout_new (gtk_widget_get_pango_context (widget));
|
|
gtk_style_context_get (gtk_widget_get_style_context (widget),
|
|
gtk_widget_get_state_flags (widget),
|
|
"font", &font_desc,
|
|
NULL);
|
|
pango_layout_set_font_description (layout, font_desc);
|
|
pango_layout_get_pixel_size (layout, NULL, &font_height);
|
|
pango_font_description_free (font_desc);
|
|
|
|
gtk_widget_get_preferred_width (priv->vscrollbar, &min, &natural);
|
|
|
|
view_height = allocation->height - start_grid_y;
|
|
grid_height = 24 * (padding.top + padding.bottom + 3 * font_height);
|
|
scroll_needed = grid_height > allocation->height - start_grid_y ? TRUE : FALSE;
|
|
grid_height = scroll_needed ? grid_height : allocation->height - start_grid_y;
|
|
|
|
if (scroll_needed)
|
|
{
|
|
adj_value = gtk_adjustment_get_value (
|
|
gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)));
|
|
}
|
|
else
|
|
{
|
|
adj_value = 0;
|
|
}
|
|
|
|
gdk_window_move_resize (priv->view_window,
|
|
allocation->x,
|
|
allocation->y + start_grid_y,
|
|
allocation->width,
|
|
allocation->height - start_grid_y);
|
|
gdk_window_move_resize (priv->grid_window,
|
|
allocation->x,
|
|
- adj_value,
|
|
allocation->width,
|
|
grid_height);
|
|
|
|
if (scroll_needed)
|
|
{
|
|
/* FIXME: change those values for something not hardcoded */
|
|
scroll_allocation.x = allocation->width - 10;
|
|
scroll_allocation.y = 7 + start_grid_y + 2;
|
|
scroll_allocation.width = 8;
|
|
scroll_allocation.height = view_height - 7 - 2;
|
|
gtk_widget_size_allocate (priv->vscrollbar, &scroll_allocation);
|
|
|
|
gtk_adjustment_set_page_size (
|
|
gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)),
|
|
view_height * view_height / grid_height);
|
|
gtk_adjustment_set_upper (
|
|
gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)),
|
|
grid_height - view_height + (view_height * view_height / grid_height));
|
|
}
|
|
else
|
|
{
|
|
gtk_widget_hide (priv->vscrollbar);
|
|
}
|
|
|
|
sidebar_width = gcal_week_view_get_sidebar_width (widget);
|
|
horizontal_block = (allocation->width - sidebar_width) / 7;
|
|
vertical_block = gdk_window_get_height (priv->grid_window) / 24;
|
|
|
|
for (i = 0; i < 7; i++)
|
|
{
|
|
gdouble *added_height;
|
|
added_height = g_malloc0 (sizeof (gdouble) * 25);
|
|
|
|
for (l = priv->days[i]; l != NULL; l = l->next)
|
|
{
|
|
GcalWeekViewChild *child;
|
|
gint min_height;
|
|
gint natural_height;
|
|
gdouble vertical_span;
|
|
GtkAllocation child_allocation;
|
|
|
|
child = (GcalWeekViewChild*) l->data;
|
|
|
|
if ((! gtk_widget_get_visible (child->widget)) && (! child->hidden_by_me))
|
|
continue;
|
|
|
|
gtk_widget_get_preferred_height (child->widget,
|
|
&min_height,
|
|
&natural_height);
|
|
|
|
child_allocation.x = i * horizontal_block + sidebar_width;
|
|
if (child->index == -1)
|
|
{
|
|
vertical_span = 2 * font_height;
|
|
child_allocation.y = start_grid_y - vertical_span;
|
|
}
|
|
else
|
|
{
|
|
vertical_span = vertical_block;
|
|
child_allocation.y = child->index * vertical_block;
|
|
}
|
|
|
|
child_allocation.width = horizontal_block;
|
|
child_allocation.height = MIN (natural_height, vertical_span);
|
|
if (added_height[child->index + 1] + child_allocation.height > vertical_span)
|
|
{
|
|
gtk_widget_hide (child->widget);
|
|
child->hidden_by_me = TRUE;
|
|
}
|
|
else
|
|
{
|
|
gtk_widget_show (child->widget);
|
|
child->hidden_by_me = FALSE;
|
|
child_allocation.y = child_allocation.y + added_height[child->index + 1];
|
|
gtk_widget_size_allocate (child->widget, &child_allocation);
|
|
added_height[child->index + 1] += child_allocation.height;
|
|
}
|
|
}
|
|
g_free (added_height);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
gcal_week_view_draw (GtkWidget *widget,
|
|
cairo_t *cr)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
GtkStyleContext *context;
|
|
GtkStateFlags state;
|
|
GtkBorder padding;
|
|
GtkAllocation alloc;
|
|
|
|
g_return_val_if_fail (GCAL_IS_WEEK_VIEW (widget), FALSE);
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW (widget));
|
|
|
|
context = gtk_widget_get_style_context (widget);
|
|
state = gtk_widget_get_state_flags (widget);
|
|
|
|
/* getting padding and allocation */
|
|
gtk_style_context_get_padding (context, state, &padding);
|
|
gtk_widget_get_allocation (widget, &alloc);
|
|
|
|
if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)))
|
|
{
|
|
cairo_save (cr);
|
|
cairo_set_line_width (cr, 0.4);
|
|
gcal_week_view_draw_header (GCAL_WEEK_VIEW (widget),
|
|
cr,
|
|
&alloc,
|
|
&padding);
|
|
cairo_restore (cr);
|
|
}
|
|
|
|
if (priv->view_window != NULL &&
|
|
gtk_cairo_should_draw_window (cr, priv->view_window))
|
|
{
|
|
gint y;
|
|
|
|
gdk_window_get_position (priv->view_window, NULL, &y);
|
|
cairo_rectangle (cr,
|
|
alloc.x,
|
|
y,
|
|
alloc.width,
|
|
gdk_window_get_height (priv->view_window));
|
|
cairo_clip (cr);
|
|
}
|
|
|
|
if (priv->grid_window != NULL &&
|
|
gtk_cairo_should_draw_window (cr, priv->grid_window))
|
|
{
|
|
cairo_save (cr);
|
|
cairo_set_line_width (cr, 0.3);
|
|
gcal_week_view_draw_grid_window (GCAL_WEEK_VIEW (widget), cr);
|
|
cairo_restore (cr);
|
|
}
|
|
|
|
GTK_WIDGET_CLASS (gcal_week_view_parent_class)->draw (widget, cr);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
gcal_week_view_scroll_event (GtkWidget *widget,
|
|
GdkEventScroll *event)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
|
|
gdouble delta_y;
|
|
gdouble delta;
|
|
|
|
g_return_val_if_fail (GCAL_IS_WEEK_VIEW (widget), FALSE);
|
|
g_return_val_if_fail (event != NULL, FALSE);
|
|
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW (widget));
|
|
|
|
if (gdk_event_get_scroll_deltas ((GdkEvent *) event, NULL, &delta_y))
|
|
{
|
|
if (delta_y != 0.0 &&
|
|
priv->vscrollbar != NULL &&
|
|
gtk_widget_get_visible (priv->vscrollbar))
|
|
{
|
|
GtkAdjustment *adj;
|
|
gdouble new_value;
|
|
gdouble page_size;
|
|
gdouble scroll_unit;
|
|
|
|
adj = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
|
|
page_size = gtk_adjustment_get_page_size (adj);
|
|
scroll_unit = pow (page_size, 2.0 / 3.0);
|
|
|
|
new_value = CLAMP (gtk_adjustment_get_value (adj) + delta_y * scroll_unit,
|
|
gtk_adjustment_get_lower (adj),
|
|
gtk_adjustment_get_upper (adj) -
|
|
gtk_adjustment_get_page_size (adj));
|
|
|
|
gtk_adjustment_set_value (adj, new_value);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GtkWidget *range = NULL;
|
|
|
|
if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_DOWN)
|
|
range = priv->vscrollbar;
|
|
|
|
if (range != NULL && gtk_widget_get_visible (range))
|
|
{
|
|
GtkAdjustment *adj;
|
|
gdouble new_value;
|
|
gdouble page_size;
|
|
|
|
adj = gtk_range_get_adjustment (GTK_RANGE (range));
|
|
page_size = gtk_adjustment_get_page_size (adj);
|
|
delta = pow (page_size, 2.0 / 3.0);
|
|
|
|
new_value = CLAMP (gtk_adjustment_get_value (adj) + delta,
|
|
gtk_adjustment_get_lower (adj),
|
|
gtk_adjustment_get_upper (adj) -
|
|
gtk_adjustment_get_page_size (adj));
|
|
|
|
gtk_adjustment_set_value (adj, new_value);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
gcal_week_view_button_press_event (GtkWidget *widget,
|
|
GdkEventButton *event)
|
|
{
|
|
gdouble y, start_grid_y;
|
|
|
|
y = event->y;
|
|
|
|
start_grid_y = gcal_week_view_get_start_grid_y (widget);
|
|
|
|
if (y - start_grid_y < 0)
|
|
{
|
|
/* FIXME: click on the header should create all day events */
|
|
return FALSE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
gcal_week_view_button_release_event (GtkWidget *widget,
|
|
GdkEventButton *event)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
gdouble y, start_grid_y;
|
|
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW (widget));
|
|
|
|
y = event->y;
|
|
|
|
start_grid_y = gcal_week_view_get_start_grid_y (widget);
|
|
|
|
if (y - start_grid_y < 0)
|
|
{
|
|
/* FIXME: click on the header should create all day events */
|
|
priv->clicked_cell = -1;
|
|
return FALSE;
|
|
}
|
|
|
|
priv->clicked_cell = -1;
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gcal_week_view_add (GtkContainer *container,
|
|
GtkWidget *widget)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
GList *l;
|
|
|
|
gint day;
|
|
icaltimetype *date;
|
|
|
|
GcalWeekViewChild *new_child;
|
|
|
|
g_return_if_fail (GCAL_IS_WEEK_VIEW (container));
|
|
g_return_if_fail (GCAL_IS_EVENT_WIDGET (widget));
|
|
g_return_if_fail (gtk_widget_get_parent (widget) == NULL);
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW (container));
|
|
|
|
/* Check if it's already added for date */
|
|
date = gcal_event_widget_get_date (GCAL_EVENT_WIDGET (widget));
|
|
day = icaltime_day_of_week (*date);
|
|
|
|
for (l = priv->days[day - 1]; l != NULL; l = l->next)
|
|
{
|
|
GtkWidget *event;
|
|
|
|
event = GTK_WIDGET (((GcalWeekViewChild*) l->data)->widget);
|
|
if (gcal_event_widget_equal (GCAL_EVENT_WIDGET (widget),
|
|
GCAL_EVENT_WIDGET (event)))
|
|
{
|
|
//TODO: remove once the main-dev phase its over
|
|
g_warning ("Trying to add an event with the same uuid to the view");
|
|
g_object_unref (widget); /* FIXME: check if this destroy it */
|
|
return;
|
|
}
|
|
}
|
|
|
|
new_child = g_new0 (GcalWeekViewChild, 1);
|
|
new_child->widget = widget;
|
|
new_child->hidden_by_me = FALSE;
|
|
|
|
if (gcal_event_widget_get_all_day (GCAL_EVENT_WIDGET (widget)))
|
|
{
|
|
new_child->index = -1;
|
|
if (gtk_widget_get_window (widget) != NULL)
|
|
gtk_widget_set_parent_window (widget, gtk_widget_get_window (widget));
|
|
}
|
|
else
|
|
{
|
|
new_child->index = date->hour;
|
|
if (priv->grid_window != NULL)
|
|
gtk_widget_set_parent_window (widget, priv->grid_window);
|
|
}
|
|
|
|
priv->days[day - 1] = g_list_append (priv->days[day - 1], new_child);
|
|
gtk_widget_set_parent (widget, GTK_WIDGET (container));
|
|
|
|
g_free (date);
|
|
}
|
|
|
|
static void
|
|
gcal_week_view_remove (GtkContainer *container,
|
|
GtkWidget *widget)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
GList *l;
|
|
icaltimetype *date;
|
|
gint day;
|
|
gboolean was_visible;
|
|
|
|
g_return_if_fail (GCAL_IS_WEEK_VIEW (container));
|
|
g_return_if_fail (gtk_widget_get_parent (widget) == GTK_WIDGET (container));
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW (container));
|
|
|
|
date = gcal_event_widget_get_date (GCAL_EVENT_WIDGET (widget));
|
|
day = icaltime_day_of_week (*date);
|
|
|
|
for (l = priv->days[day - 1]; l != NULL; l = l->next)
|
|
{
|
|
GcalWeekViewChild *child;
|
|
|
|
child = (GcalWeekViewChild*) l->data;
|
|
if (child->widget == widget)
|
|
{
|
|
priv->days[day - 1] = g_list_remove (priv->days[day - 1], child);
|
|
g_free (child);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
was_visible = gtk_widget_get_visible (widget);
|
|
gtk_widget_unparent (widget);
|
|
|
|
if (was_visible)
|
|
gtk_widget_queue_resize (GTK_WIDGET (container));
|
|
|
|
g_free (date);
|
|
}
|
|
|
|
static void
|
|
gcal_week_view_forall (GtkContainer *container,
|
|
gboolean include_internals,
|
|
GtkCallback callback,
|
|
gpointer callback_data)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
gint i;
|
|
GList *l;
|
|
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW (container));
|
|
|
|
for (i = 0; i < 7; i++)
|
|
{
|
|
l = priv->days[i];
|
|
|
|
while (l)
|
|
{
|
|
GcalWeekViewChild *child;
|
|
|
|
child = (GcalWeekViewChild*) l->data;
|
|
l = l->next;
|
|
|
|
(* callback) (child->widget, callback_data);
|
|
}
|
|
}
|
|
|
|
if (include_internals && priv->vscrollbar != NULL)
|
|
(* callback) (priv->vscrollbar, callback_data);
|
|
}
|
|
|
|
static void
|
|
gcal_week_view_set_date (GcalWeekView *view,
|
|
icaltimetype *date)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
gboolean will_resize;
|
|
|
|
gint i;
|
|
GList *l;
|
|
GList *to_remove;
|
|
|
|
priv = gcal_week_view_get_instance_private (view);
|
|
will_resize = FALSE;
|
|
|
|
/* if span_updated: queue_resize */
|
|
will_resize = ! gcal_week_view_draw_event (GCAL_VIEW (view), date, NULL);
|
|
|
|
if (priv->date != NULL)
|
|
g_free (priv->date);
|
|
|
|
priv->date = date;
|
|
|
|
if (will_resize)
|
|
{
|
|
to_remove = NULL;
|
|
|
|
for (i = 0; i < 7; i++)
|
|
{
|
|
for (l = priv->days[i]; l != NULL; l = l->next)
|
|
{
|
|
GcalWeekViewChild *child;
|
|
icaltimetype *child_date;
|
|
|
|
child = (GcalWeekViewChild*) l->data;
|
|
child_date = gcal_event_widget_get_date (GCAL_EVENT_WIDGET (child->widget));
|
|
if (! gcal_week_view_draw_event (GCAL_VIEW (view), child_date, NULL))
|
|
to_remove = g_list_append (to_remove, child->widget);
|
|
}
|
|
}
|
|
g_list_foreach (to_remove, (GFunc) gtk_widget_destroy, NULL);
|
|
|
|
gtk_widget_queue_resize (GTK_WIDGET (view));
|
|
}
|
|
}
|
|
|
|
static void
|
|
gcal_week_view_draw_header (GcalWeekView *view,
|
|
cairo_t *cr,
|
|
GtkAllocation *alloc,
|
|
GtkBorder *padding)
|
|
{
|
|
GtkWidget *widget;
|
|
GtkStyleContext *context;
|
|
GtkStateFlags state;
|
|
GdkRGBA color;
|
|
|
|
PangoLayout *layout;
|
|
PangoFontDescription *bold_font;
|
|
|
|
gint i;
|
|
gint pos_i;
|
|
gint start_grid_y;
|
|
gint font_height;
|
|
gint sidebar_width;
|
|
icaltimetype *start_of_week;
|
|
icaltimetype *end_of_week;
|
|
|
|
cairo_pattern_t *pattern;
|
|
|
|
widget = GTK_WIDGET (view);
|
|
|
|
cairo_save (cr);
|
|
start_grid_y = gcal_week_view_get_start_grid_y (widget);
|
|
context = gtk_widget_get_style_context (widget);
|
|
state = gtk_widget_get_state_flags (widget);
|
|
|
|
/* adding shadow */
|
|
pattern = cairo_pattern_create_linear(0, start_grid_y - 18, 0, start_grid_y + 6);
|
|
|
|
cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0, 0, 0, 0.6);
|
|
cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0, 0, 0, 0.0);
|
|
|
|
cairo_set_source(cr, pattern);
|
|
cairo_pattern_destroy(pattern);
|
|
|
|
cairo_rectangle(cr, 0, start_grid_y, alloc->width, 6);
|
|
cairo_fill(cr);
|
|
|
|
gtk_style_context_get_color (context, state, &color);
|
|
gdk_cairo_set_source_rgba (cr, &color);
|
|
|
|
/* grid header */
|
|
layout = pango_cairo_create_layout (cr);
|
|
gtk_style_context_get (context, state, "font", &bold_font, NULL);
|
|
pango_font_description_set_weight (bold_font, PANGO_WEIGHT_SEMIBOLD);
|
|
pango_layout_set_font_description (layout, bold_font);
|
|
|
|
start_of_week = gcal_week_view_get_initial_date (GCAL_VIEW (view));
|
|
end_of_week = gcal_week_view_get_initial_date (GCAL_VIEW (view));
|
|
|
|
sidebar_width = gcal_week_view_get_sidebar_width (widget);
|
|
for (i = 0; i < 7; i++)
|
|
{
|
|
gchar *weekday_header;
|
|
gchar *weekday_abv;
|
|
gint n_day;
|
|
|
|
n_day = start_of_week->day + i;
|
|
if (n_day > icaltime_days_in_month (start_of_week->month, start_of_week->year))
|
|
n_day = n_day - icaltime_days_in_month (start_of_week->month, start_of_week->year);
|
|
|
|
weekday_abv = gcal_get_weekday (i);
|
|
weekday_header = g_strdup_printf ("%s %d",weekday_abv, n_day);
|
|
|
|
pango_layout_set_text (layout, weekday_header, -1);
|
|
pango_cairo_update_layout (cr, layout);
|
|
pango_layout_get_pixel_size (layout, NULL, &font_height);
|
|
cairo_move_to (cr,
|
|
padding->left + ((alloc->width - sidebar_width)/ 7) * i + sidebar_width,
|
|
0.0);
|
|
pango_cairo_show_layout (cr, layout);
|
|
|
|
cairo_save (cr);
|
|
gtk_style_context_get_color (context,
|
|
state | GTK_STATE_FLAG_INSENSITIVE,
|
|
&color);
|
|
gdk_cairo_set_source_rgba (cr, &color);
|
|
|
|
pos_i = ((alloc->width - sidebar_width)/ 7) * i + sidebar_width;
|
|
cairo_move_to (cr, pos_i + 0.3, font_height + padding->bottom);
|
|
cairo_rel_line_to (cr, 0.0, ALL_DAY_CELLS_HEIGHT);
|
|
cairo_stroke (cr);
|
|
cairo_restore (cr);
|
|
|
|
g_free (weekday_header);
|
|
}
|
|
|
|
/* horizontal line */
|
|
gtk_style_context_get_color (context,
|
|
state | GTK_STATE_FLAG_INSENSITIVE,
|
|
&color);
|
|
gdk_cairo_set_source_rgba (cr, &color);
|
|
pos_i = font_height + padding->bottom;
|
|
cairo_move_to (cr, sidebar_width, pos_i + 0.3);
|
|
cairo_rel_line_to (cr, alloc->width - sidebar_width, 0);
|
|
|
|
cairo_stroke (cr);
|
|
|
|
cairo_restore (cr);
|
|
|
|
g_free (start_of_week);
|
|
g_free (end_of_week);
|
|
pango_font_description_free (bold_font);
|
|
g_object_unref (layout);
|
|
}
|
|
|
|
static void
|
|
gcal_week_view_draw_grid_window (GcalWeekView *view,
|
|
cairo_t *cr)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
GtkWidget *widget;
|
|
|
|
GtkStyleContext *context;
|
|
GtkStateFlags state;
|
|
GtkBorder padding;
|
|
GdkRGBA color;
|
|
|
|
gint i;
|
|
gint width;
|
|
gint height;
|
|
gint sidebar_width;
|
|
|
|
PangoLayout *layout;
|
|
PangoFontDescription *font_desc;
|
|
|
|
priv = gcal_week_view_get_instance_private (view);
|
|
widget = GTK_WIDGET (view);
|
|
|
|
/* INSENSITIVE to make the lines ligther */
|
|
context = gtk_widget_get_style_context (widget);
|
|
state = gtk_widget_get_state_flags (widget);
|
|
state |= GTK_STATE_FLAG_INSENSITIVE;
|
|
gtk_style_context_get_color (context, state, &color);
|
|
|
|
state = gtk_widget_get_state_flags (widget);
|
|
gtk_style_context_get_padding (context, state, &padding);
|
|
|
|
layout = pango_cairo_create_layout (cr);
|
|
gtk_style_context_get (context, state, "font", &font_desc, NULL);
|
|
pango_layout_set_font_description (layout, font_desc);
|
|
cairo_set_source_rgb (cr, color.red, color.green, color.blue);
|
|
|
|
sidebar_width = gcal_week_view_get_sidebar_width (widget);
|
|
width = gdk_window_get_width (priv->grid_window);
|
|
height = gdk_window_get_height (priv->grid_window);
|
|
|
|
gtk_cairo_transform_to_window (cr, widget, priv->grid_window);
|
|
|
|
/* grid, sidebar hours */
|
|
for (i = 0; i < 24; i++)
|
|
{
|
|
gchar *hours;
|
|
hours = g_strdup_printf ("%d %s", i % 12, i < 12 ? _("AM") : _("PM"));
|
|
|
|
if (i == 0)
|
|
pango_layout_set_text (layout, _("Midnight"), -1);
|
|
else if (i == 12)
|
|
pango_layout_set_text (layout, _("Noon"), -1);
|
|
else
|
|
pango_layout_set_text (layout, hours, -1);
|
|
|
|
pango_cairo_update_layout (cr, layout);
|
|
cairo_move_to (cr, padding.left, padding.top + (height / 24) * i);
|
|
pango_cairo_show_layout (cr, layout);
|
|
|
|
g_free (hours);
|
|
}
|
|
|
|
/* grid, vertical lines first */
|
|
for (i = 0; i < 7; i++)
|
|
{
|
|
cairo_move_to (cr,
|
|
sidebar_width + ((width - sidebar_width) / 7) * i + 0.4,
|
|
0);
|
|
cairo_rel_line_to (cr, 0, height);
|
|
}
|
|
|
|
/* rest of the lines */
|
|
for (i = 0; i < 24; i++)
|
|
{
|
|
/* hours lines */
|
|
cairo_move_to (cr, 0, (height / 24) * i + 0.4);
|
|
cairo_rel_line_to (cr, width, 0);
|
|
}
|
|
|
|
cairo_stroke (cr);
|
|
|
|
cairo_set_dash (cr, dashed, 2, 0);
|
|
for (i = 0; i < 24; i++)
|
|
{
|
|
/* 30 minutes lines */
|
|
cairo_move_to (cr, sidebar_width, (height / 24) * i + (height / 48) + 0.4);
|
|
cairo_rel_line_to (cr, width - sidebar_width, 0);
|
|
}
|
|
|
|
cairo_stroke (cr);
|
|
|
|
pango_font_description_free (font_desc);
|
|
g_object_unref (layout);
|
|
}
|
|
|
|
static gint
|
|
gcal_week_view_get_sidebar_width (GtkWidget *widget)
|
|
{
|
|
GtkStyleContext *context;
|
|
GtkBorder padding;
|
|
|
|
PangoLayout *layout;
|
|
PangoFontDescription *font_desc;
|
|
gint mid_width;
|
|
gint noon_width;
|
|
gint sidebar_width;
|
|
|
|
context = gtk_widget_get_style_context (widget);
|
|
|
|
gtk_style_context_get_padding (
|
|
gtk_widget_get_style_context (widget),
|
|
gtk_widget_get_state_flags (widget),
|
|
&padding);
|
|
|
|
layout = pango_layout_new (gtk_widget_get_pango_context (widget));
|
|
gtk_style_context_get (context,
|
|
gtk_widget_get_state_flags(widget),
|
|
"font", &font_desc,
|
|
NULL);
|
|
pango_layout_set_font_description (layout, font_desc);
|
|
|
|
pango_layout_set_text (layout, _("Midnight"), -1);
|
|
pango_layout_get_pixel_size (layout, &mid_width, NULL);
|
|
|
|
pango_layout_set_text (layout, _("Noon"), -1);
|
|
pango_layout_get_pixel_size (layout, &noon_width, NULL);
|
|
sidebar_width = noon_width > mid_width ? noon_width : mid_width;
|
|
sidebar_width += padding.left + padding.right;
|
|
|
|
pango_font_description_free (font_desc);
|
|
g_object_unref (layout);
|
|
|
|
return sidebar_width;
|
|
}
|
|
|
|
/**
|
|
* gcal_week_view_get_start_grid_y:
|
|
*
|
|
* In GcalMonthView this method returns the height of the headers of the view
|
|
* and the grid. Here this points just the place where the grid_window hides
|
|
* behind the header
|
|
* Here this height includes:
|
|
* - The big header of the view
|
|
* - The grid header dislaying weekdays
|
|
* - The cell containing all-day events.
|
|
*/
|
|
static gint
|
|
gcal_week_view_get_start_grid_y (GtkWidget *widget)
|
|
{
|
|
GtkStyleContext *context;
|
|
GtkBorder padding;
|
|
|
|
PangoLayout *layout;
|
|
PangoFontDescription *font_desc;
|
|
gint font_height;
|
|
gdouble start_grid_y;
|
|
|
|
context = gtk_widget_get_style_context (widget);
|
|
layout = pango_layout_new (gtk_widget_get_pango_context (widget));
|
|
|
|
/* init header values */
|
|
gtk_style_context_get_padding (gtk_widget_get_style_context (widget),
|
|
gtk_widget_get_state_flags (widget),
|
|
&padding);
|
|
|
|
gtk_style_context_get (context,
|
|
gtk_widget_get_state_flags(widget),
|
|
"font", &font_desc,
|
|
NULL);
|
|
pango_font_description_set_weight (font_desc, PANGO_WEIGHT_SEMIBOLD);
|
|
pango_layout_set_font_description (layout, font_desc);
|
|
pango_layout_get_pixel_size (layout, NULL, &font_height);
|
|
pango_font_description_free (font_desc);
|
|
|
|
/* 6: is padding around the header */
|
|
start_grid_y = font_height + padding.bottom;
|
|
|
|
/* for including the all-day cells */
|
|
start_grid_y += ALL_DAY_CELLS_HEIGHT;
|
|
|
|
g_object_unref (layout);
|
|
return start_grid_y;
|
|
}
|
|
|
|
static void
|
|
gcal_week_view_scroll_value_changed (GtkAdjustment *adjusment,
|
|
gpointer user_data)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
|
|
g_return_if_fail (GCAL_IS_WEEK_VIEW (user_data));
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW (user_data));
|
|
|
|
if (priv->grid_window != NULL)
|
|
{
|
|
gdk_window_move (priv->grid_window,
|
|
0,
|
|
- gtk_adjustment_get_value (adjusment));
|
|
}
|
|
}
|
|
|
|
/* GcalView Interface API */
|
|
/**
|
|
* gcal_week_view_get_initial_date:
|
|
*
|
|
* Since: 0.1
|
|
* Return value: the first day of the week
|
|
* Returns: (transfer full): Release with g_free()
|
|
**/
|
|
static icaltimetype*
|
|
gcal_week_view_get_initial_date (GcalView *view)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
icaltimetype *new_date;
|
|
|
|
g_return_val_if_fail (GCAL_IS_WEEK_VIEW (view), NULL);
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW(view));
|
|
new_date = g_new0 (icaltimetype, 1);
|
|
*new_date = icaltime_from_day_of_year (
|
|
icaltime_day_of_year (*(priv->date)) - icaltime_day_of_week (*(priv->date)) + 1,
|
|
priv->date->year);
|
|
new_date->is_date = 0;
|
|
new_date->hour = 0;
|
|
new_date->minute = 0;
|
|
new_date->second = 0;
|
|
*new_date = icaltime_set_timezone (new_date, priv->date->zone);
|
|
return new_date;
|
|
}
|
|
|
|
/**
|
|
* gcal_week_view_get_final_date:
|
|
*
|
|
* Since: 0.1
|
|
* Return value: the last day of the week
|
|
* Returns: (transfer full): Release with g_free()
|
|
**/
|
|
static icaltimetype*
|
|
gcal_week_view_get_final_date (GcalView *view)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
icaltimetype *new_date;
|
|
|
|
g_return_val_if_fail (GCAL_IS_WEEK_VIEW (view), NULL);
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW(view));
|
|
new_date = g_new0 (icaltimetype, 1);
|
|
*new_date = icaltime_from_day_of_year (
|
|
icaltime_day_of_year (*(priv->date)) + 7 - icaltime_day_of_week (*(priv->date)),
|
|
priv->date->year);
|
|
new_date->is_date = 0;
|
|
new_date->hour = 23;
|
|
new_date->minute = 59;
|
|
new_date->second = 0;
|
|
*new_date = icaltime_set_timezone (new_date, priv->date->zone);
|
|
return new_date;
|
|
}
|
|
|
|
static gchar*
|
|
gcal_week_view_get_left_header (GcalView *view)
|
|
{
|
|
icaltimetype *start_of_week;
|
|
icaltimetype *end_of_week;
|
|
gchar start_date[64];
|
|
gchar end_date[64];
|
|
struct tm tm_date;
|
|
gchar *header;
|
|
|
|
start_of_week = gcal_week_view_get_initial_date (view);
|
|
tm_date = icaltimetype_to_tm (start_of_week);
|
|
e_utf8_strftime_fix_am_pm (start_date, 64, "%b %d", &tm_date);
|
|
|
|
end_of_week = gcal_week_view_get_final_date (view);
|
|
tm_date = icaltimetype_to_tm (end_of_week);
|
|
e_utf8_strftime_fix_am_pm (end_date, 64, "%b %d", &tm_date);
|
|
|
|
header = g_strdup_printf ("%s - %s", start_date, end_date);
|
|
|
|
g_free (start_of_week);
|
|
g_free (end_of_week);
|
|
|
|
return header;
|
|
}
|
|
|
|
static gchar*
|
|
gcal_week_view_get_right_header (GcalView *view)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
|
|
icaltimetype *start_of_week;
|
|
gchar *header;
|
|
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW (view));
|
|
start_of_week = gcal_week_view_get_initial_date (view);
|
|
header = g_strdup_printf ("%s %d, %d",
|
|
_("Week"),
|
|
icaltime_week_number (*start_of_week) + 1,
|
|
priv->date->year);
|
|
|
|
g_free (start_of_week);
|
|
|
|
return header;
|
|
}
|
|
|
|
static gboolean
|
|
gcal_week_view_draw_event (GcalView *view,
|
|
icaltimetype *start_date,
|
|
icaltimetype *end_date)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
|
|
g_return_val_if_fail (GCAL_IS_WEEK_VIEW (view), FALSE);
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW(view));
|
|
|
|
if (priv->date == NULL)
|
|
return FALSE;
|
|
|
|
if (icaltime_week_number (*(priv->date)) == icaltime_week_number (*start_date)
|
|
&& priv->date->year == start_date->year)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
static GtkWidget*
|
|
gcal_week_view_get_by_uuid (GcalView *view,
|
|
const gchar *uuid)
|
|
{
|
|
GcalWeekViewPrivate *priv;
|
|
gint i;
|
|
GList *l;
|
|
|
|
g_return_val_if_fail (GCAL_IS_WEEK_VIEW (view), NULL);
|
|
priv = gcal_week_view_get_instance_private (GCAL_WEEK_VIEW(view));
|
|
|
|
for (i = 0; i < 7; i++)
|
|
{
|
|
for (l = priv->days[i]; l != NULL; l = l->next)
|
|
{
|
|
GcalWeekViewChild *child;
|
|
const gchar* widget_uuid;
|
|
|
|
child = (GcalWeekViewChild*) l->data;
|
|
widget_uuid = gcal_event_widget_peek_uuid (GCAL_EVENT_WIDGET (child->widget));
|
|
if (g_strcmp0 (uuid, widget_uuid) == 0)
|
|
return child->widget;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* Public API */
|
|
/**
|
|
* gcal_week_view_new:
|
|
* @manager: App singleton #GcalManager instance
|
|
*
|
|
* Create a week-view widget
|
|
*
|
|
* Returns: (transfer full):
|
|
**/
|
|
GtkWidget*
|
|
gcal_week_view_new (GcalManager *manager)
|
|
{
|
|
return g_object_new (GCAL_TYPE_WEEK_VIEW, "manager", manager, NULL);
|
|
}
|