Merge branch 'wip/pandusonu/week-view'

This commit is contained in:
Georges Basile Stavracas Neto
2017-01-17 11:25:53 -02:00
24 changed files with 5147 additions and 1518 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ AC_CONFIG_AUX_DIR([build-aux])
AM_SILENT_RULES([yes])
# require automake 1.13
AM_INIT_AUTOMAKE([1.13 dist-xz no-dist-gzip tar-ustar])
AM_INIT_AUTOMAKE([1.13 dist-xz no-dist-gzip tar-ustar subdir-objects])
AM_MAINTAINER_MODE([enable])
dnl ***************************************************************************
+2
View File
@@ -61,6 +61,8 @@ EXTRA_DIST= \
ui/search-view.ui \
ui/source-dialog.ui \
ui/time-selector.ui \
ui/week-header.ui \
ui/week-view.ui \
ui/window.ui \
ui/year-view.ui \
theme/gtk-styles.css \
+2
View File
@@ -12,6 +12,8 @@
<file alias="search-view.ui" compressed="true" preprocess="xml-stripblanks">ui/search-view.ui</file>
<file alias="source-dialog.ui" compressed="true" preprocess="xml-stripblanks">ui/source-dialog.ui</file>
<file alias="time-selector.ui" compressed="true" preprocess="xml-stripblanks">ui/time-selector.ui</file>
<file alias="week-header.ui" compressed="true" preprocess="xml-stripblanks">ui/week-header.ui</file>
<file alias="week-view.ui" compressed="true" preprocess="xml-stripblanks">ui/week-view.ui</file>
<file alias="window.ui" compressed="true" preprocess="xml-stripblanks">ui/window.ui</file>
<file alias="year-view.ui" compressed="true" preprocess="xml-stripblanks">ui/year-view.ui</file>
<file alias="gtk-styles.css" compressed="true">theme/gtk-styles.css</file>
+75 -3
View File
@@ -28,7 +28,8 @@ calendar-view.header {
font-weight: bold;
}
calendar-view.current {
calendar-view.current,
weekgrid.current {
background-color: alpha(@theme_selected_bg_color, 0.3);
}
@@ -52,14 +53,14 @@ calendar-view.lines {
color: alpha(@theme_fg_color, 0.4);
}
calendar-view.first-view-header {
calendar-view .first-view-header {
font-size: 16pt;
font-weight: bold;
color: @theme_selected_bg_color;
padding: 12px;
}
calendar-view.second-view-header {
calendar-view .second-view-header {
font-size: 16pt;
font-weight: bold;
padding: 12px;
@@ -358,3 +359,74 @@ datechooser day:selected:hover {
background-color: @theme_selected_bg_color;
font-weight: bold;
}
/* Week View CSS */
.week-header {
padding: 0px;
border-bottom: solid @borders 1px;
}
.week-header .month-name {
font-size: 16pt;
font-weight: bold;
color: alpha(@theme_selected_bg_color, 0.75);
padding: 12px;
}
.week-header .week-number {
font-size: 16pt;
font-weight: bold;
padding: 12px 12px 18px 12px;
color: alpha(@theme_fg_color, 0.25);
}
.week-header.week-names {
font-size: 10pt;
font-weight: bold;
color: alpha(@theme_fg_color, 0.55);
}
.week-header.week-dates {
font-size: 16pt;
font-weight: bold;
color: alpha(@theme_fg_color, 0.70);
}
.week-header.lines {
color: alpha(@theme_fg_color, 0.4);
}
.week-header .margin {
color: alpha(@theme_fg_color, 0.6);
}
.week-header .today {
color: @theme_selected_bg_color;
}
.week-view {
padding: 0px;
}
.week-view .hours {
font-size: 11pt;
font-weight: normal;
color: alpha(@theme_fg_color, 0.25);
padding: 18px 12px;
}
weekgrid.now-strip {
background-color: alpha(@theme_selected_bg_color, 0.8);
margin: 0 0 0 1px;
min-height: 2px;
}
weekgrid:selected,
.week-header:selected {
background-color: alpha(@theme_selected_bg_color, 0.25);
}
.week-header:selected {
border: solid 1px alpha(@theme_selected_bg_color, 0.8);
}
+7
View File
@@ -93,6 +93,13 @@
<object class="GtkShortcutsGroup">
<property name="visible">True</property>
<property name="title" translatable="yes" context="shortcut window">View</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">True</property>
<property name="title" translatable="yes" context="shortcut window">Week view</property>
<property name="accelerator">&lt;Primary&gt;1</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">True</property>
+205
View File
@@ -0,0 +1,205 @@
<?xml version="1.0"?>
<interface>
<template class="GcalWeekHeader" parent="GtkGrid">
<property name="visible">True</property>
<property name="hexpand">True</property>
<property name="vexpand">False</property>
<style>
<class name="week-header" />
</style>
<child>
<object class="GtkBox" id="header_labels_box">
<property name="visible">True</property>
<property name="orientation">horizontal</property>
<child>
<object class="GtkLabel" id="month_label">
<property name="visible">True</property>
<property name="label">Month</property>
<style>
<class name="month-name" />
</style>
</object>
</child>
<child>
<object class="GtkLabel" id="week_label">
<property name="visible">True</property>
<property name="hexpand">True</property>
<property name="xalign">0</property>
<property name="label">Week</property>
<style>
<class name="week-number" />
</style>
</object>
</child>
<child>
<object class="GtkLabel" id="year_label">
<property name="visible">True</property>
<property name="label">Year</property>
<style>
<class name="week-number" />
</style>
</object>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">horizontal</property>
<child>
<object class="GtkBox" id="expand_button_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">False</property>
<child>
<object class="GtkButton" id="expand_button">
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="halign">center</property>
<property name="valign">end</property>
<property name="margin-bottom">6</property>
<signal name="clicked" handler="on_expand_action_activated" object="GcalWeekHeader" swapped="yes"/>
<style>
<class name="flat" />
<class name="circular" />
</style>
<child>
<object class="GtkImage" id="expand_button_image">
<property name="visible">True</property>
<property name="icon_name">go-down-symbolic</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkEventBox">
<property name="visible">True</property>
<signal name="button-press-event" handler="on_button_pressed" object="GcalWeekHeader" swapped="yes" />
<signal name="motion-notify-event" handler="on_motion_notify" object="GcalWeekHeader" swapped="yes" />
<signal name="button-release-event" handler="on_button_released" object="GcalWeekHeader" swapped="yes" />
<child>
<object class="GtkScrolledWindow" id="scrolledwindow">
<property name="visible">True</property>
<property name="hscrollbar-policy">never</property>
<property name="vscrollbar-policy">never</property>
<property name="propagate-natural-height">True</property>
<property name="margin-bottom">2</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkGrid" id="grid">
<property name="visible">True</property>
<property name="column-homogeneous">True</property>
<property name="hexpand">True</property>
<property name="column-spacing">6</property>
<property name="row-spacing">2</property>
<property name="margin-start">6</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">3</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">4</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">5</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">6</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
</template>
<object class="GtkSizeGroup" id="sizegroup">
<property name="mode">horizontal</property>
<widgets>
<widget name="expand_button_box"/>
</widgets>
</object>
</interface>
+51
View File
@@ -0,0 +1,51 @@
<?xml version="1.0"?>
<interface>
<template class="GcalWeekView" parent="GtkBox">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<style>
<class name="week-view" />
</style>
<child>
<object class="GcalWeekHeader" id="header">
<property name="visible">True</property>
<property name="active-date" bind-source="GcalWeekView" bind-property="active-date" bind-flags="default" />
<signal name="event-activated" handler="on_event_activated" object="GcalWeekView" swapped="yes" />
</object>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolled_window">
<property name="visible">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">horizontal</property>
<child>
<object class="GtkDrawingArea" id="hours_bar">
<property name="visible">True</property>
<property name="height-request">2568</property>
<signal name="draw" handler="gcal_week_view_draw_hours" object="GcalWeekView" swapped="yes" />
</object>
</child>
<child>
<object class="GcalWeekGrid" id="week_grid">
<property name="visible">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="active-date" bind-source="GcalWeekView" bind-property="active-date" bind-flags="default" />
<signal name="event-activated" handler="on_event_activated" object="GcalWeekView" swapped="yes" />
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>
+14 -1
View File
@@ -52,6 +52,18 @@
<style>
<class name="view"/>
</style>
<child>
<object class="GcalWeekView" id="week_view">
<property name="visible">True</property>
<property name="active-date" bind-source="GcalWindow" bind-property="active-date" bind-flags="bidirectional"/>
<signal name="create-event" handler="show_new_event_widget" object="GcalWindow" swapped="no"/>
<signal name="event-activated" handler="event_activated" object="GcalWindow" swapped="no"/>
</object>
<packing>
<property name="name">week</property>
<property name="title" translatable="yes">Week</property>
</packing>
</child>
<child>
<object class="GcalMonthView" id="month_view">
<property name="visible">True</property>
@@ -62,6 +74,7 @@
<signal name="event-activated" handler="event_activated" object="GcalWindow" swapped="no"/>
</object>
<packing>
<property name="position">1</property>
<property name="name">month</property>
<property name="title" translatable="yes">Month</property>
</packing>
@@ -75,7 +88,7 @@
<signal name="event-activated" handler="event_activated" object="GcalWindow" swapped="no"/>
</object>
<packing>
<property name="position">1</property>
<property name="position">2</property>
<property name="name">year</property>
<property name="title" translatable="yes">Year</property>
</packing>
+2
View File
@@ -14,6 +14,8 @@ data/org.gnome.calendar.gschema.xml.in
[type: gettext/glade]data/ui/time-selector.ui
[type: gettext/glade]data/ui/window.ui
[type: gettext/glade]data/ui/year-view.ui
src/views/gcal-week-header.c
src/views/gcal-week-view.c
src/gcal-application.c
src/gcal-date-selector.c
src/gcal-edit-dialog.c
+9 -2
View File
@@ -1,4 +1,5 @@
AM_CPPFLAGS = \
-I$(srcdir)/views \
-DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \
-DPACKAGE_SRC_DIR=\""$(srcdir)"\" \
-DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \
@@ -66,8 +67,14 @@ gnome_calendar_SOURCES = \
gcal-utils.h \
gcal-view.c \
gcal-view.h \
gcal-week-view.c \
gcal-week-view.h \
views/gcal-range-tree.c \
views/gcal-range-tree.h \
views/gcal-week-grid.c \
views/gcal-week-grid.h \
views/gcal-week-header.c \
views/gcal-week-header.h \
views/gcal-week-view.c \
views/gcal-week-view.h \
gcal-window.h \
gcal-window.c \
gcal-year-view.c \
+113 -33
View File
@@ -17,10 +17,13 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "gcal-event-widget.h"
#include "gcal-utils.h"
#define INTENSITY(c) ((c->red) * 0.30 + (c->green) * 0.59 + (c->blue) * 0.11)
#define ICON_SIZE 16
struct _GcalEventWidget
{
@@ -37,8 +40,7 @@ struct _GcalEventWidget
GcalEvent *event;
/* Drag n' Drop icon */
GdkPixbuf *dnd_pixbuf;
GtkOrientation orientation;
GdkWindow *event_window;
gboolean button_pressed;
@@ -50,6 +52,7 @@ enum
PROP_DATE_END,
PROP_DATE_START,
PROP_EVENT,
PROP_ORIENTATION,
NUM_PROPS
};
@@ -61,7 +64,8 @@ enum
static guint signals[NUM_SIGNALS] = { 0, };
G_DEFINE_TYPE (GcalEventWidget, gcal_event_widget, GTK_TYPE_WIDGET)
G_DEFINE_TYPE_WITH_CODE (GcalEventWidget, gcal_event_widget, GTK_TYPE_WIDGET,
G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL));
static void
gcal_event_widget_update_style (GcalEventWidget *self)
@@ -188,13 +192,10 @@ static void
gcal_event_widget_init (GcalEventWidget *self)
{
GtkWidget *widget;
GSettings *settings;
gchar *clock_format;
widget = GTK_WIDGET (self);
settings = g_settings_new ("org.gnome.desktop.interface");
clock_format = g_settings_get_string (settings, "clock-format");
self->clock_format_24h = g_strcmp0 (clock_format, "24h") == 0;
self->clock_format_24h = is_clock_format_24h ();
self->orientation = GTK_ORIENTATION_HORIZONTAL;
gtk_widget_set_has_window (widget, FALSE);
gtk_widget_set_can_focus (widget, TRUE);
@@ -207,9 +208,6 @@ gcal_event_widget_init (GcalEventWidget *self)
GDK_ACTION_COPY);
gtk_drag_source_add_text_targets (widget);
g_clear_object (&settings);
g_free (clock_format);
}
static void
@@ -234,6 +232,12 @@ gcal_event_widget_set_property (GObject *object,
gcal_event_widget_set_event_internal (self, g_value_get_object (value));
break;
case PROP_ORIENTATION:
self->orientation = g_value_get_enum (value);
gtk_widget_queue_draw (GTK_WIDGET (object));
g_object_notify (object, "orientation");
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -261,6 +265,10 @@ gcal_event_widget_get_property (GObject *object,
g_value_set_object (value, self->event);
break;
case PROP_ORIENTATION:
g_value_set_enum (value, self->orientation);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -279,7 +287,6 @@ gcal_event_widget_finalize (GObject *object)
/* releasing properties */
g_clear_pointer (&self->css_class, g_free);
g_clear_object (&self->dnd_pixbuf);
g_clear_object (&self->event);
G_OBJECT_CLASS (gcal_event_widget_parent_class)->finalize (object);
@@ -314,11 +321,14 @@ gcal_event_widget_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
{
GcalEventWidget *self;
GtkBorder border, padding;
GtkStyleContext *context;
PangoLayout *layout;
gint layout_height;
gint factor;
self = GCAL_EVENT_WIDGET (widget);
context = gtk_widget_get_style_context (widget);
layout = gtk_widget_create_pango_layout (widget, NULL);
pango_layout_get_pixel_size (layout, NULL, &layout_height);
@@ -327,10 +337,12 @@ gcal_event_widget_get_preferred_height (GtkWidget *widget,
gtk_style_context_get_border (context, gtk_style_context_get_state (context), &border);
gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
factor = self->orientation == GTK_ORIENTATION_HORIZONTAL ? 1 : 2;
if (minimum != NULL)
*minimum = layout_height + padding.top + padding.bottom + border.top + border.bottom;
*minimum = (factor * layout_height) + padding.top + padding.bottom + border.top + border.bottom;
if (natural != NULL)
*natural = layout_height + padding.top + padding.bottom + border.top + border.bottom;
*natural = (factor * layout_height) + padding.top + padding.bottom + border.top + border.bottom;
}
static void
@@ -494,10 +506,22 @@ gcal_event_widget_draw (GtkWidget *widget,
else
start_time = g_date_time_format (local_start_time, "%I:%M %P");
if (is_ltr)
display_text = g_strdup_printf ("(%s) %s", start_time, gcal_event_get_summary (self->event));
/*
* When in horizontal, draw the elements sequentially; otherwise,
* draw the time in the first line, and the title in subsequent
* lines.
*/
if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
{
if (is_ltr)
display_text = g_strdup_printf ("(%s) %s", start_time, gcal_event_get_summary (self->event));
else
display_text = g_strdup_printf ("%s (%s)", gcal_event_get_summary (self->event), start_time);
}
else
display_text = g_strdup_printf ("%s (%s)", gcal_event_get_summary (self->event), start_time);
{
display_text = g_strdup_printf ("<b>%s</b>\n%s", start_time, gcal_event_get_summary (self->event));
}
g_clear_pointer (&local_start_time, g_date_time_unref);
g_clear_pointer (&start_time, g_free);
@@ -505,16 +529,13 @@ gcal_event_widget_draw (GtkWidget *widget,
/* Retrieve the font description */
gtk_style_context_get (context, state, "font", &font_desc, NULL);
layout = gtk_widget_create_pango_layout (widget, display_text);
layout = gtk_widget_create_pango_layout (widget, "");
pango_layout_set_markup (layout, display_text, -1);
pango_layout_set_font_description (layout, font_desc);
pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
pango_layout_set_width (layout, (width - (padding.left + padding.right) ) * PANGO_SCALE);
pango_cairo_update_layout (cr, layout);
/* Icon size */
pango_layout_get_pixel_size (layout, NULL, &layout_height);
icon_size = 4 * (layout_height / 4);
icon_size = ICON_SIZE;
end_gap = 0;
if (gcal_event_has_alarms (self->event))
@@ -526,8 +547,36 @@ gcal_event_widget_draw (GtkWidget *widget,
x = is_ltr ? padding.left : padding.left + end_gap;
pango_layout_set_width (layout, (width - (padding.left + padding.right + end_gap)) * PANGO_SCALE);
pango_layout_get_pixel_size (layout, NULL, &layout_height);
gtk_render_layout (context, cr, x, padding.top, layout);
#if 0
/* TODO: find out a good way to handle this */
/*
* On vertical event widgets, we assume we might have space to draw the
* event's detail (or at least part of it).
*/
if (self->orientation == GTK_ORIENTATION_VERTICAL &&
2 * padding.top + layout_height + padding.bottom < height &&
strlen (gcal_event_get_description (self->event)) > 0)
{
g_autofree gchar *description;
description = g_strdup_printf ("<small>%s</small>", gcal_event_get_description (self->event));
pango_layout_set_markup (layout, description, -1);
pango_layout_set_width (layout, (width - (padding.left + padding.right) ) * PANGO_SCALE);
pango_layout_set_height (layout, (height - (2 * padding.top + layout_height + padding.bottom) ) * PANGO_SCALE);
pango_layout_set_font_description (layout, font_desc);
pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
gtk_render_layout (context,
cr,
x,
2 * padding.top + layout_height + padding.bottom,
layout);
}
#endif
x += is_ltr ? (width - end_gap - padding.left - padding.right) : (- padding.right - padding.left - icon_size);
/* render reminder icon */
@@ -548,7 +597,11 @@ gcal_event_widget_draw (GtkWidget *widget,
&was_symbolic,
NULL);
gdk_cairo_set_source_pixbuf (cr, pixbuf, x + padding.left, padding.top);
gtk_render_icon (context,
cr,
pixbuf,
x + padding.left,
padding.top);
x += is_ltr ? (padding.left + icon_size) : (- padding.right - icon_size);
@@ -574,7 +627,12 @@ gcal_event_widget_draw (GtkWidget *widget,
&was_symbolic,
NULL);
gdk_cairo_set_source_pixbuf (cr, pixbuf, x + padding.left, padding.top);
gtk_render_icon (context,
cr,
pixbuf,
x + padding.left,
padding.top);
g_object_unref (pixbuf);
cairo_paint (cr);
}
@@ -616,13 +674,30 @@ gcal_event_widget_button_release_event (GtkWidget *widget,
return FALSE;
}
static cairo_surface_t*
get_dnd_icon (GtkWidget *widget)
{
cairo_surface_t *surface;
cairo_t *cr;
/* Make it transparent */
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
gtk_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget));
cr = cairo_create (surface);
gtk_widget_draw (widget, cr);
return surface;
}
static void
gcal_event_widget_drag_begin (GtkWidget *widget,
GdkDragContext *context)
{
GcalEventWidget *self = GCAL_EVENT_WIDGET (widget);
g_clear_object (&self->dnd_pixbuf);
cairo_surface_t *surface;
if (self->read_only)
{
@@ -631,13 +706,11 @@ gcal_event_widget_drag_begin (GtkWidget *widget,
}
/* Setup the drag n' drop icon */
self->dnd_pixbuf = gdk_pixbuf_get_from_window (self->event_window,
0,
0,
gtk_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget));
surface = get_dnd_icon (widget);
gtk_drag_set_icon_pixbuf (context, self->dnd_pixbuf, 0, 0);
gtk_drag_set_icon_surface (context, surface);
g_clear_pointer (&surface, cairo_surface_destroy);
}
static gboolean
@@ -717,6 +790,13 @@ gcal_event_widget_class_init(GcalEventWidgetClass *klass)
GCAL_TYPE_EVENT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
/**
* GcalEventWidget::orientation:
*
* The orientation of the event widget.
*/
g_object_class_override_property (object_class, PROP_ORIENTATION, "orientation");
signals[ACTIVATE] = g_signal_new ("activate",
GCAL_TYPE_EVENT_WIDGET,
G_SIGNAL_RUN_LAST,
+56 -24
View File
@@ -39,6 +39,8 @@ struct _GcalQuickAddPopover
GtkWidget *selected_row;
gboolean clock_format_24h;
GcalManager *manager;
};
@@ -213,6 +215,7 @@ update_header (GcalQuickAddPopover *self)
{
icaltimetype *dtstart;
struct tm stm_date, etm_date;
gboolean multiday_or_timed;
gboolean all_day;
gchar start[64], end[64];
gchar *title_date;
@@ -227,9 +230,17 @@ update_header (GcalQuickAddPopover *self)
stm_date = icaltimetype_to_tm (dtstart);
e_utf8_strftime_fix_am_pm (start, 64, C_("event date format", "%B %d"), &stm_date);
if (self->date_end &&
(!all_day ||
(all_day && g_date_time_difference (self->date_end, self->date_start) / G_TIME_SPAN_DAY > 1)))
if (self->date_end)
{
multiday_or_timed = g_date_time_difference (self->date_end, self->date_start) / G_TIME_SPAN_DAY > 1 ||
g_date_time_difference (self->date_end, self->date_start) / G_TIME_SPAN_MINUTE > 1;
}
else
{
multiday_or_timed = FALSE;
}
if (multiday_or_timed)
{
icaltimetype *dtend;
@@ -238,14 +249,39 @@ update_header (GcalQuickAddPopover *self)
if (dtend->is_date)
icaltime_adjust (dtend, -1, 0, 0, 0);
/* Translators:
* this is the format string for representing a date consisting of a month name
* and a date of month.
*/
etm_date = icaltimetype_to_tm (dtend);
e_utf8_strftime_fix_am_pm (end, 64, C_("event date format", "%B %d"), &etm_date);
if (all_day &&
(g_date_time_difference (self->date_end, self->date_start) / G_TIME_SPAN_DAY > 1 &&
g_date_time_difference (self->date_end, self->date_start) / G_TIME_SPAN_MINUTE > 1))
{
/* Translators:
* this is the format string for representing a date consisting of a month name
* and a date of month.
*/
etm_date = icaltimetype_to_tm (dtend);
e_utf8_strftime_fix_am_pm (end, 64, C_("event date format", "%B %d"), &etm_date);
title_date = g_strdup_printf (_("New Event from %s to %s"), start, end);
title_date = g_strdup_printf (_("New Event from %s to %s"), start, end);
}
else
{
g_autofree gchar *start_hour, *end_hour;
if (self->clock_format_24h)
{
start_hour = g_date_time_format (self->date_start, "%R");
end_hour = g_date_time_format (self->date_end, "%R");
}
else
{
start_hour = g_date_time_format (self->date_start, "%I:%M %P");
end_hour = g_date_time_format (self->date_end, "%I:%M %P");
}
title_date = g_strdup_printf (_("New Event on %s, %s - %s"),
start,
start_hour,
end_hour);
}
g_free (dtend);
}
@@ -413,27 +449,21 @@ edit_or_create_event (GcalQuickAddPopover *self,
GtkWidget *button)
{
ECalComponent *component;
GDateTime *date_start, *date_end, *now;
GDateTime *date_start, *date_end;
GTimeZone *tz;
GcalEvent *event;
ESource *source;
const gchar *summary;
gboolean all_day, single_day, is_today;
gboolean all_day, single_day;
if (!self->selected_row)
return;
now = g_date_time_new_now_local ();
source = g_object_get_data (G_OBJECT (self->selected_row), "source");
/*
* We consider all day events multiday and/or non-today events.
* Events on today starts now and lasts 1 hour.
*/
single_day = datetime_compare_date (self->date_end, self->date_start) == 0;
is_today = single_day && datetime_compare_date (now, self->date_start) == 0;
all_day = datetime_compare_date (self->date_end, self->date_start) > 1 || !is_today;
all_day = datetime_compare_date (self->date_end, self->date_start) > 1 ||
g_date_time_compare (self->date_end, self->date_start) == 0;
tz = all_day ? g_time_zone_new_utc () : g_time_zone_new_local ();
/* Gather start date */
@@ -441,8 +471,8 @@ edit_or_create_event (GcalQuickAddPopover *self,
g_date_time_get_year (self->date_start),
g_date_time_get_month (self->date_start),
g_date_time_get_day_of_month (self->date_start),
all_day ? 0 : g_date_time_get_hour (now),
all_day ? 0 : g_date_time_get_minute (now),
g_date_time_get_hour (self->date_start),
g_date_time_get_minute (self->date_start),
0);
/* Gather date end */
@@ -452,8 +482,8 @@ edit_or_create_event (GcalQuickAddPopover *self,
g_date_time_get_year (self->date_end),
g_date_time_get_month (self->date_end),
g_date_time_get_day_of_month (self->date_end) + (single_day && all_day ? 1 : 0),
all_day ? 0 : g_date_time_get_hour (now) + (is_today ? 1 : 0),
all_day ? 0 : g_date_time_get_minute (now),
g_date_time_get_hour (self->date_end),
g_date_time_get_minute (self->date_end),
0);
}
else
@@ -681,6 +711,8 @@ gcal_quick_add_popover_init (GcalQuickAddPopover *self)
gtk_widget_init_template (GTK_WIDGET (self));
gtk_list_box_set_sort_func (GTK_LIST_BOX (self->calendars_listbox), sort_func, NULL, NULL);
self->clock_format_24h = is_clock_format_24h ();
}
GtkWidget*
+51
View File
@@ -524,6 +524,57 @@ icaltime_compare_with_current (const icaltimetype *date1,
return result;
}
GDateTime*
get_start_of_week (icaltimetype *date)
{
icaltimetype *new_date;
GDateTime *dt;
new_date = g_new0 (icaltimetype, 1);
*new_date = icaltime_from_day_of_year (icaltime_start_doy_week (*date, get_first_weekday () + 1),
date->year);
new_date->is_date = 0;
new_date->hour = 0;
new_date->minute = 0;
new_date->second = 0;
dt = g_date_time_new_local (new_date->year,
new_date->month,
new_date->day,
0, 0, 0);
g_clear_pointer (&new_date, g_free);
return dt;
}
GDateTime*
get_end_of_week (icaltimetype *date)
{
GDateTime *week_start, *week_end;
week_start = get_start_of_week (date);
week_end = g_date_time_add_days (week_start, 7);
g_clear_pointer (&week_start, g_date_time_unref);
return week_end;
}
gboolean
is_clock_format_24h (void)
{
static GSettings *settings = NULL;
g_autofree gchar *clock_format = NULL;
if (!settings)
settings = g_settings_new ("org.gnome.desktop.interface");
clock_format = g_settings_get_string (settings, "clock-format");
return g_strcmp0 (clock_format, "24h") == 0;
}
/* Function to do a last minute fixup of the AM/PM stuff if the locale
* and gettext haven't done it right. Most English speaking countries
* except the USA use the 24 hour clock (UK, Australia etc). However
+12
View File
@@ -27,6 +27,12 @@
#define ICAL_TIME_TYPE (icaltime_get_type ())
#define ALIGNED(x) (round (x) + 0.5)
#define MINUTES_PER_DAY 1440
#define MAX_MINUTES (7 * MINUTES_PER_DAY)
#define gcal_clear_datetime(dt) g_clear_pointer (dt, g_date_time_unref)
typedef enum
{
GCAL_WINDOW_VIEW_DAY,
@@ -95,6 +101,12 @@ gint icaltime_compare_with_current (const icaltimet
const icaltimetype *date2,
time_t *current_time_t);
GDateTime* get_start_of_week (icaltimetype *date);
GDateTime* get_end_of_week (icaltimetype *date);
gboolean is_clock_format_24h (void);
/* code brought from evolution */
gsize e_strftime_fix_am_pm (gchar *str,
gsize max,
-1422
View File
File diff suppressed because it is too large Load Diff
+40 -11
View File
@@ -22,8 +22,8 @@
#include "gcal-manager.h"
#include "gcal-view.h"
#include "gcal-month-view.h"
#include "gcal-week-view.h"
#include "gcal-month-view.h"
#include "gcal-year-view.h"
#include "gcal-search-view.h"
#include "gcal-event-widget.h"
@@ -66,6 +66,7 @@ struct _GcalWindow
GtkWidget *search_bar;
GtkWidget *views_overlay;
GtkWidget *views_stack;
GtkWidget *week_view;
GtkWidget *month_view;
GtkWidget *year_view;
GtkWidget *notification;
@@ -336,7 +337,7 @@ on_view_action_activated (GSimpleAction *action,
else if (view == -2)
view = --(window->active_view);
window->active_view = CLAMP (view, GCAL_WINDOW_VIEW_MONTH, GCAL_WINDOW_VIEW_YEAR);
window->active_view = CLAMP (view, CLAMP(view, GCAL_WINDOW_VIEW_WEEK, GCAL_WINDOW_VIEW_MONTH), GCAL_WINDOW_VIEW_YEAR);
gtk_stack_set_visible_child (GTK_STACK (window->views_stack), window->views[window->active_view]);
g_object_notify (G_OBJECT (user_data), "active-view");
@@ -364,6 +365,7 @@ update_active_date (GcalWindow *window,
GDateTime *date_start, *date_end;
time_t range_start, range_end;
icaltimetype *previous_date;
GDate old_week, new_week;
previous_date = window->active_date;
window->active_date = new_date;
@@ -399,6 +401,32 @@ update_active_date (GcalWindow *window,
g_clear_pointer (&date_end, g_date_time_unref);
}
/* week_view */
g_date_clear (&old_week, 1);
if (previous_date->day > 0 && previous_date->month > 0 && previous_date->year)
g_date_set_dmy (&old_week, previous_date->day, previous_date->month, previous_date->year);
g_date_clear (&new_week, 1);
g_date_set_dmy (&new_week, new_date->day, new_date->month, new_date->year);
if (previous_date->year != new_date->year ||
!g_date_valid (&old_week) ||
g_date_get_iso8601_week_of_year (&old_week) != g_date_get_iso8601_week_of_year (&new_week))
{
date_start = g_date_time_new_local (new_date->year, new_date->month, new_date->day, 0, 0, 0);
date_start = g_date_time_add_days (date_start, (get_first_weekday () - g_date_time_get_day_of_week (date_start) + 7) % 7 - 7);
range_start = g_date_time_to_unix (date_start);
date_end = g_date_time_add_days (date_start, 7);
range_end = g_date_time_to_unix (date_end);
gcal_manager_set_subscriber (window->manager, E_CAL_DATA_MODEL_SUBSCRIBER (window->week_view), range_start, range_end);
g_clear_pointer (&date_start, g_date_time_unref);
g_clear_pointer (&date_end, g_date_time_unref);
}
update_today_button_sensitive (window);
g_free (previous_date);
@@ -415,6 +443,7 @@ update_current_date (GcalWindow *window)
*(window->current_date) = icaltime_current_time_with_zone (gcal_manager_get_system_timezone (window->manager));
*(window->current_date) = icaltime_set_timezone (window->current_date, gcal_manager_get_system_timezone (window->manager));
gcal_week_view_set_current_date (GCAL_WEEK_VIEW (window->week_view), window->current_date);
gcal_month_view_set_current_date (GCAL_MONTH_VIEW (window->month_view), window->current_date);
gcal_year_view_set_current_date (GCAL_YEAR_VIEW (window->year_view), window->current_date);
@@ -437,8 +466,8 @@ update_today_button_sensitive (GcalWindow *window)
break;
case GCAL_WINDOW_VIEW_WEEK:
/* TODO: determine when the today button would be sensitive on week view */
sensitive = TRUE;
sensitive = window->active_date->year != window->current_date->year ||
icaltime_week_number (*window->active_date) != icaltime_week_number (*window->current_date);
break;
case GCAL_WINDOW_VIEW_MONTH:
@@ -1311,6 +1340,7 @@ gcal_window_class_init(GcalWindowClass *klass)
gtk_widget_class_bind_template_child (widget_class, GcalWindow, forward_button);
gtk_widget_class_bind_template_child (widget_class, GcalWindow, views_overlay);
gtk_widget_class_bind_template_child (widget_class, GcalWindow, views_stack);
gtk_widget_class_bind_template_child (widget_class, GcalWindow, week_view);
gtk_widget_class_bind_template_child (widget_class, GcalWindow, month_view);
gtk_widget_class_bind_template_child (widget_class, GcalWindow, year_view);
gtk_widget_class_bind_template_child (widget_class, GcalWindow, views_switcher);
@@ -1404,18 +1434,15 @@ gcal_window_constructed (GObject *object)
g_object_unref (builder);
/* XXX: Week view disabled until after the release when we restart the work on it*/
//priv->views[GCAL_WINDOW_VIEW_WEEK] = gcal_week_view_new ();
//gcal_week_view_set_manager (GCAL_WEEK_VIEW (priv->views[GCAL_WINDOW_VIEW_WEEK]), priv->manager);
//gcal_week_view_set_first_weekday (GCAL_WEEK_VIEW (priv->views[GCAL_WINDOW_VIEW_WEEK]), get_first_weekday ());
//gcal_week_view_set_use_24h_format (GCAL_WEEK_VIEW (priv->views[GCAL_WINDOW_VIEW_WEEK]), use_24h_format);
//gtk_stack_add_titled (GTK_STACK (priv->views_stack), priv->views[GCAL_WINDOW_VIEW_WEEK], "week", _("Week"));
window->views[GCAL_WINDOW_VIEW_WEEK] = window->week_view;
window->views[GCAL_WINDOW_VIEW_MONTH] = window->month_view;
window->views[GCAL_WINDOW_VIEW_YEAR] = window->year_view;
gcal_edit_dialog_set_time_format (GCAL_EDIT_DIALOG (window->edit_dialog), use_24h_format);
gcal_week_view_set_first_weekday (GCAL_WEEK_VIEW (window->views[GCAL_WINDOW_VIEW_WEEK]), get_first_weekday ());
gcal_week_view_set_use_24h_format (GCAL_WEEK_VIEW (window->views[GCAL_WINDOW_VIEW_WEEK]), use_24h_format);
gcal_month_view_set_first_weekday (GCAL_MONTH_VIEW (window->views[GCAL_WINDOW_VIEW_MONTH]), get_first_weekday ());
gcal_month_view_set_use_24h_format (GCAL_MONTH_VIEW (window->views[GCAL_WINDOW_VIEW_MONTH]), use_24h_format);
@@ -1515,6 +1542,7 @@ gcal_window_set_property (GObject *object,
g_signal_connect_swapped (self->manager, "source-changed", G_CALLBACK (source_changed), object);
gcal_edit_dialog_set_manager (GCAL_EDIT_DIALOG (self->edit_dialog), self->manager);
gcal_week_view_set_manager (GCAL_WEEK_VIEW (self->week_view), self->manager);
gcal_month_view_set_manager (GCAL_MONTH_VIEW (self->month_view), self->manager);
gcal_year_view_set_manager (GCAL_YEAR_VIEW (self->year_view), self->manager);
gcal_quick_add_popover_set_manager (GCAL_QUICK_ADD_POPOVER (self->quick_add_popover), self->manager);
@@ -1628,6 +1656,7 @@ gcal_window_new_with_view_and_date (GcalApplication *app,
gcal_window_add_accelerator (app, "win.change-view(-1)", "<Ctrl>Page_Down");
gcal_window_add_accelerator (app, "win.change-view(-2)", "<Ctrl>Page_Up");
gcal_window_add_accelerator (app, "win.change-view(1)", "<Ctrl>1")
gcal_window_add_accelerator (app, "win.change-view(2)", "<Ctrl>2");
gcal_window_add_accelerator (app, "win.change-view(3)", "<Ctrl>3");
+604
View File
@@ -0,0 +1,604 @@
/* gcal-range-tree.c
*
* Copyright (C) 2016 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* 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 3 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-range-tree.h"
typedef struct _Node
{
struct _Node *left;
struct _Node *right;
guint16 start;
guint16 end;
guint16 max;
guint16 hits;
gint64 height;
GPtrArray *data_array;
} Node;
struct _GcalRangeTree
{
guint ref_count;
Node *root;
};
G_DEFINE_BOXED_TYPE (GcalRangeTree, gcal_range_tree, gcal_range_tree_ref, gcal_range_tree_unref)
/* Auxiliary methods */
static void
destroy_tree (Node *n)
{
if (!n)
return;
destroy_tree (n->left);
destroy_tree (n->right);
g_ptr_array_unref (n->data_array);
g_free (n);
}
static inline gint32
height (Node *n)
{
return n ? n->height : 0;
}
static inline void
update_height (Node *n)
{
n->height = MAX (height (n->left), height (n->right)) + 1;
}
static inline guint32
balance (Node *n)
{
return n ? height (n->left) - height (n->right) : 0;
}
static inline gboolean
compare_intervals (guint16 a_start,
guint16 a_end,
guint16 b_start,
guint16 b_end)
{
if (a_start != b_start)
return b_start - a_start;
if (a_end != b_end)
return b_end - a_end;
return 0;
}
static inline gboolean
is_interval_lower (Node *n,
guint32 start,
guint32 end)
{
return start < n->start || (start == n->start && end < n->end);
}
static inline gboolean
is_interval_higher (Node *n,
guint32 start,
guint32 end)
{
return start > n->start || (start == n->start && end > n->end);
}
static Node*
node_new (guint32 start,
guint32 end,
gpointer data)
{
Node *n;
n = g_new0 (Node, 1);
n->start = start;
n->end = end;
n->max = end;
n->height = 1;
n->hits = 1;
n->data_array = g_ptr_array_new ();
g_ptr_array_add (n->data_array, data);
return n;
}
/* AVL rotations */
static Node*
rotate_left (Node *n)
{
Node *tmp;
tmp = n->right;
n->right = tmp->left;
tmp->left = n;
/* Update heights */
update_height (n);
update_height (tmp);
return tmp;
}
static Node*
rotate_right (Node *n)
{
Node *tmp;
tmp = n->left;
n->left = tmp->right;
tmp->right = n;
/* Update heights */
update_height (n);
update_height (tmp);
return tmp;
}
static inline Node*
hit_node (Node *n,
gpointer data)
{
n->hits++;
g_ptr_array_add (n->data_array, data);
return n;
}
static inline Node*
rebalance (Node *n)
{
gint32 node_balance;
update_height (n);
/* Rotate the tree */
node_balance = balance (n);
if (node_balance > 1)
{
if (n->left && height (n->left->right) > height (n->left->left))
n->left = rotate_left (n->left);
return rotate_right (n);
}
else if (node_balance < -1)
{
if (n->right && height (n->right->right) < height (n->right->left))
n->right = rotate_right (n->right);
return rotate_left (n);
}
return n;
}
static Node*
insert (Node *n,
guint32 start,
guint32 end,
gpointer data)
{
if (!n)
return node_new (start, end, data);
if (compare_intervals (n->start, n->end, start, end) < 0)
n->left = insert (n->left, start, end, data);
else if (compare_intervals (n->start, n->end, start, end) > 0)
n->right = insert (n->right, start, end, data);
else
return hit_node (n, data);
/* Update the current node's maximum subrange value */
n->max = MAX (n->max, end);
return rebalance (n);
}
/* Remove */
static Node*
find_minimum (Node *n)
{
if (n->left)
return find_minimum (n->left);
return n;
}
static Node*
delete_minimum (Node *n)
{
if (!n->left)
return n->right;
n->left = delete_minimum (n->left);
return rebalance (n);
}
static inline Node*
delete_node (Node *n,
gpointer data)
{
Node *left, *right, *min;
n->hits--;
g_ptr_array_remove (n->data_array, data);
/* Only remove the node when the hit count reaches zero */
if (n->hits > 0)
return n;
left = n->left;
right = n->right;
g_ptr_array_unref (n->data_array);
g_free (n);
if (!right)
return left;
min = find_minimum (right);
min->right = delete_minimum (right);
min->left = left;
return rebalance (min);
}
static Node*
remove (Node *n,
guint32 start,
guint32 end,
gpointer data)
{
if (!n)
return NULL;
if (is_interval_lower (n, start, end))
n->left = remove (n->left, start, end, data);
else if (is_interval_higher (n, start, end))
n->right = remove (n->right, start, end, data);
else
return delete_node (n, data);
return rebalance (n);
}
/* Traverse */
static inline gboolean
run_traverse_func (Node *n,
GcalRangeTraverseFunc func,
gpointer user_data)
{
guint i;
for (i = 0; i < n->hits; i++)
{
if (func (n->start, n->end, g_ptr_array_index (n->data_array, i), user_data))
return TRUE;
}
return FALSE;
}
static gboolean
traverse (Node *n,
GTraverseType type,
GcalRangeTraverseFunc func,
gpointer user_data)
{
if (!n)
return FALSE;
if (type == G_PRE_ORDER)
{
if (run_traverse_func (n, func, user_data))
return TRUE;
}
if (traverse (n->left, type, func, user_data))
return TRUE;
if (type == G_IN_ORDER)
{
if (run_traverse_func (n, func, user_data))
return TRUE;
}
if (traverse (n->right, type, func, user_data))
return TRUE;
if (type == G_POST_ORDER)
{
if (run_traverse_func (n, func, user_data))
return TRUE;
}
return FALSE;
}
/* Internal traverse functions */
static inline gboolean
gather_data_at_range (guint16 start,
guint16 end,
gpointer data,
gpointer user_data)
{
struct {
guint16 start, end;
GPtrArray **array;
} *range = user_data;
/* Since we're traversing in order, stop here */
if (compare_intervals (range->start, range->end, start, end) > 0 &&
start >= range->end)
{
return TRUE;
}
/*
* If the current range doesn't overlap but we're before the desired range, keep
* traversing the tree
*/
if (range->start >= end)
return FALSE;
if (!*range->array)
*range->array = g_ptr_array_new ();
g_ptr_array_add (*range->array, data);
return FALSE;
}
static inline gboolean
count_entries_at_range (guint16 start,
guint16 end,
gpointer data,
gpointer user_data)
{
struct {
guint16 start, end;
guint64 counter;
} *range = user_data;
/* Since we're traversing in order, stop here */
if (compare_intervals (range->start, range->end, start, end) > 0 &&
start >= range->end)
{
return TRUE;
}
/*
* If the current range doesn't overlap but we're before the desired range, keep
* traversing the tree
*/
if (range->start >= end)
return FALSE;
range->counter++;
return FALSE;
}
static void
gcal_range_tree_free (GcalRangeTree *self)
{
g_assert (self);
g_assert_cmpint (self->ref_count, ==, 0);
destroy_tree (self->root);
g_slice_free (GcalRangeTree, self);
}
/**
* gcal_range_tree_new:
*
* Creates a new range tree
*
* Returns: (transfer full): a newly created #GcalRangeTree.
* Free with gcal_range_tree_unref() when done.
*/
GcalRangeTree*
gcal_range_tree_new (void)
{
GcalRangeTree *self;
self = g_slice_new0 (GcalRangeTree);
self->ref_count = 1;
return self;
}
/**
* gcal_range_tree_copy:
* @self: a #GcalRangeTree
*
* Copies @self into a new range tree.
*
* Returns: (transfer full): a newly created #GcalRangeTree.
* Free with gcal_range_tree_unref() when done.
*/
GcalRangeTree*
gcal_range_tree_copy (GcalRangeTree *self)
{
GcalRangeTree *copy;
g_return_val_if_fail (self, NULL);
g_return_val_if_fail (self->ref_count, NULL);
copy = gcal_range_tree_new ();
return copy;
}
/**
* gcal_range_tree_ref:
* @self: a #GcalRangeTree
*
* Increases the reference count of @self.
*
* Returns: (transfer full): pointer to the just-referenced tree.
*/
GcalRangeTree*
gcal_range_tree_ref (GcalRangeTree *self)
{
g_return_val_if_fail (self, NULL);
g_return_val_if_fail (self->ref_count, NULL);
g_atomic_int_inc (&self->ref_count);
return self;
}
/**
* gcal_range_tree_unref:
* @self: a #GcalRangeTree
*
* Decreases the reference count of @self, and frees it when
* if the reference count reaches zero.
*/
void
gcal_range_tree_unref (GcalRangeTree *self)
{
g_return_if_fail (self);
g_return_if_fail (self->ref_count);
if (g_atomic_int_dec_and_test (&self->ref_count))
gcal_range_tree_free (self);
}
/**
* gcal_range_tree_add_range:
* @self: a #GcalRangeTree
* @start: start of the interval
* @end: end of the interval
* @data: user data
*
* Adds the range into @self, and attach @data do it. It is
* possible to have multiple entries in the same interval,
* in which case the interval will have a reference counting like
* behavior.
*/
void
gcal_range_tree_add_range (GcalRangeTree *self,
guint16 start,
guint16 end,
gpointer data)
{
g_return_if_fail (self);
g_return_if_fail (end >= start);
self->root = insert (self->root, start, end, data);
}
/**
* gcal_range_tree_remove_range:
* @self: a #GcalRangeTree
* @start: the start of the range
* @end: the end of the range
* @data: user data
*
* Removes (or decreases the reference count) of the given interval.
*/
void
gcal_range_tree_remove_range (GcalRangeTree *self,
guint16 start,
guint16 end,
gpointer data)
{
g_return_if_fail (self);
g_return_if_fail (end >= start);
self->root = remove (self->root, start, end, data);
}
/**
* gcal_range_tree_traverse:
* @self: a #GcalRangeTree
* @type: the type of traverse to perform
* @func: the function to call on each traverse iteration
* @user_data: user data for @func
*
* Traverse @self calling @func according to the @type specified.
*/
void
gcal_range_tree_traverse (GcalRangeTree *self,
GTraverseType type,
GcalRangeTraverseFunc func,
gpointer user_data)
{
g_return_if_fail (self);
traverse (self->root, type, func, user_data);
}
/**
* gcal_range_tree_get_data_at_range:
* @self: a #GcalRangeTree
* @start: inclusive start of the range
* @end: exclusive end of the range
*
* Retrieves the data of every node between @start and @end.
*
* Returns: (transfer full): a #GPtrArray. Unref with g_ptr_array_unref()
* when finished.
*/
GPtrArray*
gcal_range_tree_get_data_at_range (GcalRangeTree *self,
guint16 start,
guint16 end)
{
GPtrArray *data;
struct {
guint16 start, end;
GPtrArray **array;
} range = { start, end, &data };
g_return_val_if_fail (self, NULL);
g_return_val_if_fail (end >= start, NULL);
data = NULL;
gcal_range_tree_traverse (self, G_IN_ORDER, gather_data_at_range, &range);
return data;
}
guint64
gcal_range_tree_count_entries_at_range (GcalRangeTree *self,
guint16 start,
guint16 end)
{
struct {
guint16 start, end;
guint64 counter;
} range = { start, end, 0 };
g_return_val_if_fail (self, 0);
g_return_val_if_fail (end >= start, 0);
gcal_range_tree_traverse (self, G_IN_ORDER, count_entries_at_range, &range);
return range.counter;
}
+72
View File
@@ -0,0 +1,72 @@
/* gcal-range-tree.h
*
* Copyright (C) 2016 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* 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 3 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/>.
*/
#ifndef GCAL_RANGE_TREE_H
#define GCAL_RANGE_TREE_H
#include <glib-object.h>
G_BEGIN_DECLS
#define GCAL_TYPE_RANGE_TREE (gcal_range_tree_get_type())
typedef struct _GcalRangeTree GcalRangeTree;
typedef gboolean (*GcalRangeTraverseFunc) (guint16 start,
guint16 end,
gpointer data,
gpointer user_data);
GType gcal_range_tree_get_type (void) G_GNUC_CONST;
GcalRangeTree* gcal_range_tree_new (void);
GcalRangeTree* gcal_range_tree_copy (GcalRangeTree *self);
GcalRangeTree* gcal_range_tree_ref (GcalRangeTree *self);
void gcal_range_tree_unref (GcalRangeTree *self);
void gcal_range_tree_add_range (GcalRangeTree *self,
guint16 start,
guint16 end,
gpointer data);
void gcal_range_tree_remove_range (GcalRangeTree *self,
guint16 start,
guint16 end,
gpointer data);
void gcal_range_tree_traverse (GcalRangeTree *self,
GTraverseType type,
GcalRangeTraverseFunc func,
gpointer user_data);
GPtrArray* gcal_range_tree_get_data_at_range (GcalRangeTree *self,
guint16 start,
guint16 end);
guint64 gcal_range_tree_count_entries_at_range (GcalRangeTree *self,
guint16 start,
guint16 end);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GcalRangeTree, gcal_range_tree_unref)
G_END_DECLS
#endif /* GCAL_RANGE_TREE_H */
File diff suppressed because it is too large Load Diff
+59
View File
@@ -0,0 +1,59 @@
/* gcal-week-grid.h
*
* Copyright (C) 2016 Vamsi Krishna Gollapudi <pandu.sonu@yahoo.com>
*
* 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 3 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/>.
*/
#ifndef GCAL_WEEK_GRID_H
#define GCAL_WEEK_GRID_H
#include "gcal-manager.h"
#include "gcal-event-widget.h"
#include "gcal-subscriber-view.h"
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GCAL_TYPE_WEEK_GRID (gcal_week_grid_get_type())
G_DECLARE_FINAL_TYPE (GcalWeekGrid, gcal_week_grid, GCAL, WEEK_GRID, GtkContainer)
void gcal_week_grid_set_manager (GcalWeekGrid *week_grid,
GcalManager *manager);
void gcal_week_grid_set_first_weekday (GcalWeekGrid *week_grid,
gint nr_day);
void gcal_week_grid_set_use_24h_format (GcalWeekGrid *week_grid,
gboolean use_24h_format);
void gcal_week_grid_set_current_date (GcalWeekGrid *week_grid,
icaltimetype *current_date);
void gcal_week_grid_add_event (GcalWeekGrid *self,
GcalEvent *event);
void gcal_week_grid_remove_event (GcalWeekGrid *self,
const gchar *uid);
GList* gcal_week_grid_get_children_by_uuid (GcalWeekGrid *self,
const gchar *uid);
void gcal_week_grid_clear_marks (GcalWeekGrid *self);
G_END_DECLS
#endif /* GCAL_WEEK_GRID_H */
File diff suppressed because it is too large Load Diff
+61
View File
@@ -0,0 +1,61 @@
/* gcal-week-header.h
*
* Copyright (C) 2016 Vamsi Krishna Gollapudi <pandu.sonu@yahoo.com>
*
* 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 3 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/>.
*/
#ifndef GCAL_WEEK_HEADER_H
#define GCAL_WEEK_HEADER_H
#include "gcal-manager.h"
#include "gcal-event-widget.h"
#include "gcal-subscriber-view.h"
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GCAL_TYPE_WEEK_HEADER (gcal_week_header_get_type())
G_DECLARE_FINAL_TYPE (GcalWeekHeader, gcal_week_header, GCAL, WEEK_HEADER, GtkGrid)
void gcal_week_header_set_manager (GcalWeekHeader *self,
GcalManager *manager);
void gcal_week_header_set_first_weekday (GcalWeekHeader *self,
gint nr_day);
void gcal_week_header_set_use_24h_format (GcalWeekHeader *self,
gboolean use_24h_format);
void gcal_week_header_set_current_date (GcalWeekHeader *self,
icaltimetype *current_date);
void gcal_week_header_add_event (GcalWeekHeader *self,
GcalEvent *event);
void gcal_week_header_remove_event (GcalWeekHeader *self,
const gchar *uuid);
GList* gcal_week_header_get_children_by_uuid (GcalWeekHeader *self,
const gchar *uuid);
GtkSizeGroup* gcal_week_header_get_sidebar_size_group (GcalWeekHeader *self);
void gcal_week_header_clear_marks (GcalWeekHeader *self);
G_END_DECLS
#endif /* GCAL_WEEK_HEADER_H */
+684
View File
@@ -0,0 +1,684 @@
/* -*- mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* gcal-week-view.c
*
* Copyright (C) 2015 - 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 "gcal-week-header.h"
#include "gcal-week-grid.h"
#include <glib/gi18n.h>
#include <math.h>
#define ALL_DAY_CELLS_HEIGHT 40
static const double dashed [] =
{
5.0,
6.0
};
enum
{
PROP_0,
PROP_DATE
};
struct _GcalWeekView
{
GtkBox parent;
GtkWidget *header;
GtkWidget *hours_bar;
GtkWidget *scrolled_window;
GtkWidget *week_grid;
/*
* first day of the week according to user locale, being
* 0 for Sunday, 1 for Monday and so on
*/
gint first_weekday;
/*
* clock format from GNOME desktop settings
*/
gboolean use_24h_format;
/* property */
icaltimetype *date;
icaltimetype *current_date;
GcalManager *manager; /* weak referenced */
guint scroll_grid_timeout_id;
gint clicked_cell;
};
static void gcal_week_view_component_added (ECalDataModelSubscriber *subscriber,
ECalClient *client,
ECalComponent *comp);
static void gcal_week_view_component_modified (ECalDataModelSubscriber *subscriber,
ECalClient *client,
ECalComponent *comp);
static void gcal_week_view_component_removed (ECalDataModelSubscriber *subscriber,
ECalClient *client,
const gchar *uid,
const gchar *rid);
static void gcal_week_view_freeze (ECalDataModelSubscriber *subscriber);
static void gcal_week_view_thaw (ECalDataModelSubscriber *subscriber);
static gboolean gcal_week_view_draw_hours (GcalWeekView *self,
cairo_t *cr,
GtkWidget *widget);
static void gcal_view_interface_init (GcalViewInterface *iface);
static void gcal_data_model_subscriber_interface_init (ECalDataModelSubscriberInterface *iface);
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 icaltimetype* gcal_week_view_get_final_date (GcalView *view);
enum
{
EVENT_ACTIVATED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE_WITH_CODE (GcalWeekView, gcal_week_view, GTK_TYPE_BOX,
G_IMPLEMENT_INTERFACE (GCAL_TYPE_VIEW, gcal_view_interface_init)
G_IMPLEMENT_INTERFACE (E_TYPE_CAL_DATA_MODEL_SUBSCRIBER,
gcal_data_model_subscriber_interface_init));
/* Callbacks */
static void
on_event_activated (GcalWeekView *self,
GtkWidget *widget)
{
g_signal_emit (self, signals[EVENT_ACTIVATED], 0, widget);
}
/* Auxiliary methods */
static gboolean
update_grid_scroll_position (GcalWeekView *self)
{
g_autoptr(GDateTime) week_start = NULL;
g_autoptr(GDateTime) week_end = NULL;
g_autoptr(GDateTime) now = NULL;
GtkAdjustment *vadjustment;
gdouble minutes, real_value;
gdouble max, page, page_increment, value;
/* While the scrolled window is not mapped, we keep waiting */
if (!gtk_widget_get_mapped (self->scrolled_window))
return G_SOURCE_CONTINUE;
now = g_date_time_new_now_local ();
week_start = get_start_of_week (self->date);
week_end = get_end_of_week (self->date);
/* Don't animate when not today */
if (datetime_compare_date (now, week_start) < 0 || datetime_compare_date (now, week_end) >= 0)
goto out;
vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (self->scrolled_window));
minutes = g_date_time_get_hour (now) * 60 + g_date_time_get_minute (now);
page = gtk_adjustment_get_page_size (vadjustment);
max = gtk_adjustment_get_upper (vadjustment);
real_value = max / MINUTES_PER_DAY * minutes - (page / 2.0);
page_increment = gtk_adjustment_get_page_increment (vadjustment);
value = gtk_adjustment_get_value (vadjustment);
gtk_adjustment_set_page_increment (vadjustment, real_value - value);
g_signal_emit_by_name (self->scrolled_window,
"scroll-child",
GTK_SCROLL_PAGE_FORWARD,
FALSE);
gtk_adjustment_set_page_increment (vadjustment, page_increment);
out:
self->scroll_grid_timeout_id = 0;
return G_SOURCE_REMOVE;
}
static void
schedule_position_scroll (GcalWeekView *self)
{
/* Nothing is scheduled, we should do it now */
if (self->scroll_grid_timeout_id > 0)
g_source_remove (self->scroll_grid_timeout_id);
self->scroll_grid_timeout_id = g_timeout_add (200,
(GSourceFunc) update_grid_scroll_position,
self);
}
/**
* 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)
{
GcalWeekView *self;
icaltimetype *new_date;
g_return_val_if_fail (GCAL_IS_WEEK_VIEW (view), NULL);
self = GCAL_WEEK_VIEW(view);
new_date = g_new0 (icaltimetype, 1);
*new_date = icaltime_from_day_of_year (icaltime_start_doy_week (*(self->date),
self->first_weekday + 1),
self->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, self->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)
{
GcalWeekView *self;
icaltimetype *new_date;
g_return_val_if_fail (GCAL_IS_WEEK_VIEW (view), NULL);
self = GCAL_WEEK_VIEW(view);
new_date = g_new0 (icaltimetype, 1);
*new_date = icaltime_from_day_of_year (icaltime_start_doy_week (*(self->date),
self->first_weekday + 1) + 6,
self->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, self->date->zone);
return new_date;
}
static GList*
gcal_week_view_get_children_by_uuid (GcalView *view,
const gchar *uuid)
{
GcalWeekView *self;
GList *grid, *header;
self = GCAL_WEEK_VIEW (view);
grid = gcal_week_grid_get_children_by_uuid (GCAL_WEEK_GRID (self->week_grid), uuid);
header = gcal_week_header_get_children_by_uuid (GCAL_WEEK_HEADER (self->header), uuid);
return g_list_concat (grid, header);
}
static void
gcal_week_view_clear_marks (GcalView *view)
{
GcalWeekView *self = GCAL_WEEK_VIEW (view);
gcal_week_header_clear_marks (GCAL_WEEK_HEADER (self->header));
gcal_week_grid_clear_marks (GCAL_WEEK_GRID (self->week_grid));
}
static void
update_hours_sidebar_size (GcalWeekView *self)
{
GtkStyleContext *context;
GtkStateFlags state;
GtkSizeGroup *sidebar_sizegroup;
GtkWidget *widget;
GtkBorder padding;
PangoLayout *layout;
PangoFontDescription *font_desc;
gint hours_12_width, hours_24_width, sidebar_width;
gint hours_12_height, hours_24_height, cell_height;
widget = GTK_WIDGET (self);
context = gtk_widget_get_style_context (widget);
state = gtk_style_context_get_state (context);
gtk_style_context_save (context);
gtk_style_context_add_class (context, "hours");
gtk_style_context_get (context, state,
"font", &font_desc,
NULL);
gtk_style_context_get_padding (context, state, &padding);
layout = pango_layout_new (gtk_widget_get_pango_context (widget));
pango_layout_set_font_description (layout, font_desc);
pango_layout_set_text (layout, _("00 AM"), -1);
pango_layout_get_pixel_size (layout, &hours_12_width, &hours_12_height);
pango_layout_set_text (layout, _("00:00"), -1);
pango_layout_get_pixel_size (layout, &hours_24_width, &hours_24_height);
sidebar_width = MAX (hours_12_width, hours_24_width) + padding.left + padding.right;
cell_height = MAX (hours_12_height, hours_24_height) + padding.top + padding.bottom + 1;
gtk_style_context_restore (context);
/* Update the size requests */
gtk_widget_set_size_request (self->hours_bar,
sidebar_width,
48 * cell_height);
/* Sync with the week header sidebar */
sidebar_sizegroup = gcal_week_header_get_sidebar_size_group (GCAL_WEEK_HEADER (self->header));
gtk_size_group_add_widget (sidebar_sizegroup, self->hours_bar);
pango_font_description_free (font_desc);
g_object_unref (layout);
}
static void
gcal_week_view_component_added (ECalDataModelSubscriber *subscriber,
ECalClient *client,
ECalComponent *comp)
{
GcalWeekView *self = GCAL_WEEK_VIEW (subscriber);
GcalEvent *event;
event = gcal_event_new (e_client_get_source (E_CLIENT (client)), comp, NULL);
if (gcal_event_is_multiday (event) || gcal_event_get_all_day (event))
gcal_week_header_add_event (GCAL_WEEK_HEADER (self->header), event);
else
gcal_week_grid_add_event (GCAL_WEEK_GRID (self->week_grid), event);
}
static void
gcal_week_view_component_modified (ECalDataModelSubscriber *subscriber,
ECalClient *client,
ECalComponent *comp)
{
GcalWeekView *self = GCAL_WEEK_VIEW (subscriber);
GcalWeekHeader *header;
gchar *uuid;
header = GCAL_WEEK_HEADER (self->header);
uuid = get_uuid_from_component (e_client_get_source (E_CLIENT (client)), comp);
gcal_week_header_remove_event (header, uuid);
gcal_week_grid_remove_event (GCAL_WEEK_GRID (self->week_grid), uuid);
gcal_week_view_component_added (subscriber, client, comp);
g_free (uuid);
}
static void
gcal_week_view_component_removed (ECalDataModelSubscriber *subscriber,
ECalClient *client,
const gchar *uid,
const gchar *rid)
{
GcalWeekView *self = GCAL_WEEK_VIEW (subscriber);
ESource *source;
gchar *uuid;
source = e_client_get_source (E_CLIENT (client));
if (rid != NULL)
uuid = g_strdup_printf ("%s:%s:%s", e_source_get_uid (source), uid, rid);
else
uuid = g_strdup_printf ("%s:%s", e_source_get_uid (source), uid);
gcal_week_header_remove_event (GCAL_WEEK_HEADER (self->header), uuid);
gcal_week_grid_remove_event (GCAL_WEEK_GRID (self->week_grid), uuid);
g_free (uuid);
}
static void
gcal_week_view_freeze (ECalDataModelSubscriber *subscriber)
{
}
static void
gcal_week_view_thaw (ECalDataModelSubscriber *subscriber)
{
}
static gboolean
gcal_week_view_draw_hours (GcalWeekView *self,
cairo_t *cr,
GtkWidget *widget)
{
GtkStyleContext *context;
GtkStateFlags state;
GtkBorder padding;
GdkRGBA color;
gboolean ltr;
gint i, width, height;
gint font_width;
PangoLayout *layout;
PangoFontDescription *font_desc;
context = gtk_widget_get_style_context (widget);
state = gtk_widget_get_state_flags (widget);
ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
gtk_style_context_add_class (context, "hours");
gtk_style_context_get_color (context, state, &color);
gtk_style_context_get_padding (context, state, &padding);
gtk_style_context_get (context, state, "font", &font_desc, NULL);
layout = pango_cairo_create_layout (cr);
pango_layout_set_font_description (layout, font_desc);
gdk_cairo_set_source_rgba (cr, &color);
/* Gets the size of the widget */
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
/* Draws the hours in the sidebar */
for (i = 0; i < 24; i++)
{
gchar *hours;
if (self->use_24h_format)
{
hours = g_strdup_printf ("%02d:00", i);
}
else
{
hours = g_strdup_printf ("%d %s",
i % 12 == 0 ? 12 : i % 12,
i > 12 ? _("PM") : _("AM"));
}
pango_layout_set_text (layout, hours, -1);
pango_layout_get_pixel_size (layout, &font_width, NULL);
cairo_move_to (cr,
ltr ? padding.left : width - font_width - padding.right,
(height / 24) * i + padding.top);
pango_cairo_show_layout (cr, layout);
g_free (hours);
}
cairo_set_line_width (cr, 0.65);
if (!ltr)
{
cairo_move_to (cr, 0.5, 0);
cairo_rel_line_to (cr, 0, height);
}
/* Draws the horizontal complete lines */
for (i = 1; i < 24; i++)
{
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);
/* Draws the horizontal dashed lines */
for (i = 0; i < 24; i++)
{
cairo_move_to (cr, 0, (height / 24) * i + (height / 48) + 0.4);
cairo_rel_line_to (cr, width, 0);
}
cairo_stroke (cr);
pango_font_description_free (font_desc);
g_object_unref (layout);
return FALSE;
}
static void
gcal_week_view_class_init (GcalWeekViewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
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");
signals[EVENT_ACTIVATED] = g_signal_new ("event-activated",
GCAL_TYPE_WEEK_VIEW,
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE,
1,
GCAL_TYPE_EVENT_WIDGET);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/week-view.ui");
gtk_widget_class_bind_template_child (widget_class, GcalWeekView, header);
gtk_widget_class_bind_template_child (widget_class, GcalWeekView, hours_bar);
gtk_widget_class_bind_template_child (widget_class, GcalWeekView, scrolled_window);
gtk_widget_class_bind_template_child (widget_class, GcalWeekView, week_grid);
gtk_widget_class_bind_template_callback (widget_class, gcal_week_view_draw_hours);
gtk_widget_class_bind_template_callback (widget_class, on_event_activated);
gtk_widget_class_set_css_name (widget_class, "calendar-view");
}
static void
gcal_week_view_init (GcalWeekView *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
update_hours_sidebar_size (self);
}
static void
gcal_view_interface_init (GcalViewInterface *iface)
{
iface->get_initial_date = gcal_week_view_get_initial_date;
iface->get_final_date = gcal_week_view_get_final_date;
iface->get_children_by_uuid = gcal_week_view_get_children_by_uuid;
iface->clear_marks = gcal_week_view_clear_marks;
}
static void
gcal_data_model_subscriber_interface_init (ECalDataModelSubscriberInterface *iface)
{
iface->component_added = gcal_week_view_component_added;
iface->component_modified = gcal_week_view_component_modified;
iface->component_removed = gcal_week_view_component_removed;
iface->freeze = gcal_week_view_freeze;
iface->thaw = gcal_week_view_thaw;
}
static void
gcal_week_view_finalize (GObject *object)
{
GcalWeekView *self;
self = GCAL_WEEK_VIEW (object);
g_clear_pointer (&self->date, g_free);
/* 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)
{
GcalWeekView *self;
self = GCAL_WEEK_VIEW (object);
switch (property_id)
{
case PROP_DATE:
g_clear_pointer (&self->date, g_free);
self->date = g_value_dup_boxed (value);
schedule_position_scroll (self);
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)
{
GcalWeekView *self;
g_return_if_fail (GCAL_IS_WEEK_VIEW (object));
self = GCAL_WEEK_VIEW (object);
switch (property_id)
{
case PROP_DATE:
g_value_set_boxed (value, self->date);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/* Public API */
/**
* gcal_week_view_new:
*
* Create a week-view widget
*
* Returns: (transfer full):
**/
GtkWidget*
gcal_week_view_new (void)
{
return g_object_new (GCAL_TYPE_WEEK_VIEW, NULL);
}
void
gcal_week_view_set_manager (GcalWeekView *self,
GcalManager *manager)
{
g_return_if_fail (GCAL_IS_WEEK_VIEW (self));
self->manager = manager;
gcal_week_grid_set_manager (GCAL_WEEK_GRID (self->week_grid), manager);
gcal_week_header_set_manager (GCAL_WEEK_HEADER (self->header), manager);
}
/**
* gcal_week_view_set_first_weekday:
* @view:
* @day_nr:
*
* Set the first day of the week according to the locale, being
* 0 for Sunday, 1 for Monday and so on.
**/
void
gcal_week_view_set_first_weekday (GcalWeekView *self,
gint day_nr)
{
g_return_if_fail (GCAL_IS_WEEK_VIEW (self));
self->first_weekday = day_nr;
}
/**
* gcal_week_view_set_use_24h_format:
* @view:
* @use_24h:
*
* Whether the view will show time using 24h or 12h format
**/
void
gcal_week_view_set_use_24h_format (GcalWeekView *self,
gboolean use_24h)
{
g_return_if_fail (GCAL_IS_WEEK_VIEW (self));
self->use_24h_format = use_24h;
}
void
gcal_week_view_set_current_date (GcalWeekView *self,
icaltimetype *current_date)
{
g_return_if_fail (GCAL_IS_WEEK_VIEW (self));
g_clear_pointer (&self->current_date, g_free);
self->current_date = current_date;
gcal_week_header_set_current_date (GCAL_WEEK_HEADER (self->header), current_date);
gcal_week_grid_set_current_date (GCAL_WEEK_GRID (self->week_grid), current_date);
}
@@ -21,32 +21,14 @@
#define __GCAL_WEEK_VIEW_H__
#include "gcal-manager.h"
#include "gcal-subscriber-view.h"
#include "gcal-view.h"
G_BEGIN_DECLS
#define GCAL_TYPE_WEEK_VIEW (gcal_week_view_get_type ())
#define GCAL_WEEK_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GCAL_TYPE_WEEK_VIEW, GcalWeekView))
#define GCAL_WEEK_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GCAL_TYPE_WEEK_VIEW, GcalWeekViewClass))
#define GCAL_IS_WEEK_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GCAL_TYPE_WEEK_VIEW))
#define GCAL_IS_WEEK_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GCAL_TYPE_WEEK_VIEW))
#define GCAL_WEEK_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GCAL_TYPE_WEEK_VIEW, GcalWeekViewClass))
#define GCAL_TYPE_WEEK_VIEW (gcal_week_view_get_type ())
typedef struct _GcalWeekView GcalWeekView;
typedef struct _GcalWeekViewClass GcalWeekViewClass;
G_DECLARE_FINAL_TYPE (GcalWeekView, gcal_week_view, GCAL, WEEK_VIEW, GtkBox)
struct _GcalWeekView
{
GcalSubscriberView parent;
};
struct _GcalWeekViewClass
{
GcalSubscriberViewClass parent_class;
};
GType gcal_week_view_get_type (void);
GtkWidget* gcal_week_view_new (void);
void gcal_week_view_set_manager (GcalWeekView *view,
GcalManager *manager);
@@ -54,6 +36,8 @@ void gcal_week_view_set_first_weekday (GcalWeekView *view,
gint day_nr);
void gcal_week_view_set_use_24h_format (GcalWeekView *view,
gboolean use_24h);
void gcal_week_view_set_current_date (GcalWeekView *week_header,
icaltimetype *current_date);
G_END_DECLS