Merge branch 'wip/pandusonu/week-view'
This commit is contained in:
+1
-1
@@ -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 ***************************************************************************
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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"><Primary>1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="visible">True</property>
|
||||
|
||||
@@ -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>
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+40
-11
@@ -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");
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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 */
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user