[gnome-calendar] year-view: add navigator drawing
- From: Erick Pérez Castellanos <erickpc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-calendar] year-view: add navigator drawing
- Date: Tue, 20 Jan 2015 18:16:09 +0000 (UTC)
commit e49418a26d392463afa131f9dcef78d9a93bfdb2
Author: Erick Pérez Castellanos <erick red gmail com>
Date: Sun Jan 18 17:43:09 2015 -0500
year-view: add navigator drawing
data/theme/gtk-styles.css | 51 ++++++
data/ui/year-view.ui | 13 +-
src/gcal-window.c | 2 +
src/gcal-year-view.c | 397 +++++++++++++++++++++++++++++++++++++++++++--
src/gcal-year-view.h | 13 +-
5 files changed, 455 insertions(+), 21 deletions(-)
---
diff --git a/data/theme/gtk-styles.css b/data/theme/gtk-styles.css
index a7b07ef..d82bb94 100644
--- a/data/theme/gtk-styles.css
+++ b/data/theme/gtk-styles.css
@@ -57,6 +57,57 @@
color: alpha(@theme_fg_color, 0.4);
}
+.calendar-view.first-view-header {
+ font: bold 18;
+ color: @theme_selected_bg_color;
+ padding: 12px;
+}
+
+.calendar-view.second-view-header {
+ font: bold 18;
+ padding: 12px;
+}
+
+/* Header the padding if for sizing, on drawing the spacing between cells,
+ * and the padding will be automatically calculated
+ * Because of year-view widget internals, the color property should be the same
+ * of .calendar-view.first-view-header selector */
+.year-navigator {
+ padding: 6px 12px;
+ color: @theme_selected_bg_color;
+}
+
+.year-navigator.header {
+ color: @theme_selected_bg_color;
+ font-weight: bold;
+}
+
+.year-navigator.lines {
+ color: alpha(@theme_fg_color, 0.4);
+}
+
+.year-navigator.days {
+ color: @theme_fg_color;
+ font: 9;
+}
+
+.year-navigator.sunday {
+ color: alpha(@theme_fg_color, 0.5);
+}
+
+.year-navigator.week-numbers {
+ color: alpha(@theme_fg_color, 0.2);
+ font: 6;
+}
+
+/* this is supposed be changed in sync with .calendar-view.current */
+.year-navigator.current {
+ background-color: @theme_fg_color;
+ border-radius: 2px;
+ color: white;
+ font: bold;
+}
+
GcalEventWidget {
border-radius: 6px;
margin-top: 2px;
diff --git a/data/ui/year-view.ui b/data/ui/year-view.ui
index 3654386..276cbdc 100644
--- a/data/ui/year-view.ui
+++ b/data/ui/year-view.ui
@@ -2,12 +2,15 @@
<interface>
<!-- interface-requires gtk+ 3.10 -->
<template class="GcalYearView" parent="GtkBox">
- <property name="visible">True</property>
<child>
- <object class="GtkDrawingArea" id="year_view_navigator">
+ <object class="GtkDrawingArea" id="navigator">
<property name="visible">True</property>
+ <property name="hexpand">True</property>
<signal name="draw" handler="draw_navigator" object="GcalYearView" swapped="yes" />
- <!-- FIXME: add some other necessary signals -->
+ <style>
+ <class name="year-navigator" />
+ </style>
+ <!-- FIXME: add some other signals handlers -->
</object>
<packing>
<property name="position">0</property>
@@ -15,12 +18,12 @@
</child>
<child>
<object class="GtkOverlay" id="sidebar">
- <property name="visible">True</property>
+ <property name="width_request">200</property>
<child type="overlay">
<object class="GtkButton" id="add_event_button">
<property name="visible">True</property>
<property name="valign">end</property>
- <property name="label" translatable="yes">Add new event...</property>
+ <property name="label" translatable="yes">Add new event…</property>
<signal name="clicked" handler="add_event_clicked_cb" object="GcalYearView" swapped="yes" />
</object>
</child>
diff --git a/src/gcal-window.c b/src/gcal-window.c
index b7844ce..cca2167 100644
--- a/src/gcal-window.c
+++ b/src/gcal-window.c
@@ -1291,6 +1291,8 @@ gcal_window_constructed (GObject *object)
priv->views[GCAL_WINDOW_VIEW_YEAR] = g_object_new (GCAL_TYPE_YEAR_VIEW, NULL);
gcal_year_view_set_manager (GCAL_YEAR_VIEW (priv->views[GCAL_WINDOW_VIEW_YEAR]), priv->manager);
+ gcal_year_view_set_first_weekday (GCAL_YEAR_VIEW (priv->views[GCAL_WINDOW_VIEW_YEAR]), get_first_weekday
());
+ gcal_year_view_set_use_24h_format (GCAL_YEAR_VIEW (priv->views[GCAL_WINDOW_VIEW_YEAR]), use_24h_format);
gtk_stack_add_titled (GTK_STACK (priv->views_stack), priv->views[GCAL_WINDOW_VIEW_YEAR], "year",
_("Year"));
/* search view */
diff --git a/src/gcal-year-view.c b/src/gcal-year-view.c
index cbbb8e6..9d48c1a 100644
--- a/src/gcal-year-view.c
+++ b/src/gcal-year-view.c
@@ -19,11 +19,18 @@
#include "gcal-year-view.h"
#include "gcal-view.h"
+#include "gcal-utils.h"
+
+#include <math.h>
+
+#define NAVIGATOR_CELL_WIDTH (210 + 15)
+#define NAVIGATOR_CELL_HEIGHT 210
+#define SIDEBAR_PREFERRED_WIDTH 200
struct _GcalYearViewPrivate
{
/* composite, GtkBuilder's widgets */
- GtkWidget *year_view_navigator;
+ GtkWidget *navigator;
GtkWidget *sidebar;
GtkWidget *add_event_button;
GtkWidget *events_listbox;
@@ -31,6 +38,25 @@ struct _GcalYearViewPrivate
/* manager singleton */
GcalManager *manager;
+ /* state flags */
+ gboolean popover_mode;
+
+ /**
+ * 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;
+
+ /* text direction factors */
+ gint k;
+
+ /* weak ref to current date */
+ icaltimetype *current_date;
+
/* date property */
icaltimetype *date;
};
@@ -56,10 +82,193 @@ update_date (GcalYearView *year_view,
{
GcalYearViewPrivate *priv = year_view->priv;
- /* FIXME: add updating subscribe range */
+ /* FIXME: add updating subscribe range, only when needed */
if (priv->date != NULL)
g_free (priv->date);
priv->date = new_date;
+
+ gtk_widget_queue_draw (GTK_WIDGET (year_view));
+}
+
+static void
+draw_month_grid (GcalYearView *year_view,
+ GtkWidget *widget,
+ cairo_t *cr,
+ gint month_nr,
+ gint *weeks_counter,
+ gint block_side,
+ gdouble x,
+ gdouble y)
+{
+ GcalYearViewPrivate *priv = year_view->priv;
+
+ GtkStyleContext *context;
+ GtkStateFlags state_flags;
+
+ PangoLayout *layout;
+ PangoFontDescription *font_desc;
+
+ GdkRGBA color;
+ gint layout_width, layout_height, i, j, sw;
+ gint column, row, box_padding_top, box_padding_start;
+ gint days_delay, days, shown_rows, sunday_idx;
+ gchar *str, *nr_day, *nr_week;
+
+ cairo_save (cr);
+ context = gtk_widget_get_style_context (widget);
+ state_flags = gtk_widget_get_state_flags (widget);
+ sw = 1 - 2 * priv->k;
+
+ /* header */
+ gtk_style_context_save (context);
+ gtk_style_context_add_class (context, "header");
+
+ str = g_strdup (gcal_get_month_name (month_nr));
+ gtk_style_context_get (context, state_flags, "font", &font_desc, NULL);
+
+ layout = gtk_widget_create_pango_layout (widget, str);
+ pango_layout_set_font_description (layout, font_desc);
+ pango_layout_get_pixel_size (layout, &layout_width, &layout_height);
+ gtk_render_layout (context, cr, x + (block_side * 8 - layout_width) / 2, y + (block_side - layout_height)
/ 2,
+ layout);
+
+ gtk_render_background (context, cr,
+ x + (block_side * 8 - layout_width) / 2, y + (block_side - layout_height) / 2,
+ layout_width, layout_width);
+
+ pango_font_description_free (font_desc);
+ g_free (str);
+ gtk_style_context_restore (context);
+
+ /* separator line */
+ gtk_style_context_save (context);
+ gtk_style_context_add_class (context, "lines");
+
+ gtk_style_context_get_color (context, state_flags, &color);
+ cairo_set_line_width (cr, 0.2);
+ gdk_cairo_set_source_rgba (cr, &color);
+ cairo_move_to (cr, x + block_side / 2, y + block_side + 0.4);
+ cairo_rel_line_to (cr, 7 * block_side, 0);
+ cairo_stroke (cr);
+
+ gtk_style_context_restore (context);
+
+ /* days */
+ gtk_style_context_save (context);
+ gtk_style_context_add_class (context, "days");
+
+ gtk_style_context_get (context, state_flags, "font", &font_desc, NULL);
+ pango_layout_set_font_description (layout, font_desc);
+
+ days_delay = (time_day_of_week (1, month_nr, priv->date->year) - priv->first_weekday + 7) % 7;
+ days = days_delay + icaltime_days_in_month (month_nr + 1, priv->date->year);
+ shown_rows = ceil (days / 7.0);
+ sunday_idx = priv->k * 6 + sw * ((7 - priv->first_weekday) % 7);
+
+ for (i = 0; i < 7 * shown_rows; i++)
+ {
+ column = i % 7;
+ row = i / 7;
+
+ j = 7 * ((i + 7 * priv->k) / 7) + sw * (i % 7) + (1 - priv->k);
+ if (j <= days_delay)
+ continue;
+ else if (j > days)
+ continue;
+ j -= days_delay;
+
+ nr_day = g_strdup_printf ("%d", j);
+ pango_layout_set_text (layout, nr_day, -1);
+ pango_layout_get_pixel_size (layout, &layout_width, &layout_height);
+ box_padding_top = (block_side - layout_height) / 2 > 0 ? (block_side - layout_height) / 2 : 0;
+ box_padding_start = (block_side - layout_width) / 2 > 0 ? (block_side - layout_width) / 2 : 0;
+
+ if (priv->date->year == priv->current_date->year && month_nr + 1 == priv->current_date->month &&
+ j == priv->current_date->day)
+ {
+ PangoLayout *clayout;
+ PangoFontDescription *cfont_desc;
+
+ gtk_style_context_save (context);
+ gtk_style_context_add_class (context, "current");
+
+ clayout = gtk_widget_create_pango_layout (widget, nr_day);
+ gtk_style_context_get (context, state_flags, "font", &cfont_desc, NULL);
+ pango_layout_set_font_description (clayout, cfont_desc);
+ pango_layout_get_pixel_size (clayout, &layout_width, &layout_height);
+
+ /* FIXME: hardcoded padding of the number background */
+ gtk_render_background (context, cr,
+ block_side * (column + 0.5 + priv->k) + x + sw * box_padding_start -
priv->k * layout_width - 2.0,
+ block_side * (row + 1) + y + box_padding_top - 1.0,
+ layout_width + 4.0, layout_height + 2.0);
+ gtk_render_layout (context, cr,
+ block_side * (column + 0.5 + priv->k) + x + sw * box_padding_start - priv->k *
layout_width,
+ block_side * (row + 1) + y + box_padding_top,
+ clayout);
+
+ gtk_style_context_restore (context);
+ pango_font_description_free (cfont_desc);
+ g_object_unref (clayout);
+ }
+ else if (column == sunday_idx)
+ {
+ gtk_style_context_add_class (context, "sunday");
+ gtk_render_layout (context, cr,
+ block_side * (column + 0.5 + priv->k) + x + sw * box_padding_start - priv->k *
layout_width,
+ block_side * (row + 1) + y + box_padding_top,
+ layout);
+ gtk_style_context_remove_class (context, "sunday");
+ }
+ else
+ {
+ gtk_render_layout (context, cr,
+ block_side * (column + 0.5 + priv->k) + x + sw * box_padding_start - priv->k *
layout_width,
+ block_side * (row + 1) + y + box_padding_top,
+ layout);
+ }
+
+ g_free (nr_day);
+ }
+ pango_font_description_free (font_desc);
+ gtk_style_context_restore (context);
+
+ /* week numbers */
+ gtk_style_context_save (context);
+ gtk_style_context_add_class (context, "week-numbers");
+
+ gtk_style_context_get (context, state_flags, "font", &font_desc, NULL);
+ pango_layout_set_font_description (layout, font_desc);
+
+ for (i = 0; i < shown_rows; i++)
+ {
+ if (i == 0)
+ {
+ if (days_delay == 0)
+ *weeks_counter = *weeks_counter + 1;
+ }
+ else
+ *weeks_counter = *weeks_counter + 1;
+
+ nr_week = g_strdup_printf ("%d", *weeks_counter);
+
+ pango_layout_set_text (layout, nr_week, -1);
+ pango_layout_get_pixel_size (layout, &layout_width, &layout_height);
+ box_padding_top = (block_side - layout_height) / 2 > 0 ? (block_side - layout_height) / 2 : 0;
+ box_padding_start = ((block_side / 2) - layout_width) / 2 > 0 ? ((block_side / 2) - layout_width) / 2
: 0;
+
+ gtk_render_layout (context, cr,
+ x + sw * box_padding_start + priv->k * (8 * block_side - layout_width),
+ block_side * (i + 1) + y + box_padding_top,
+ layout);
+
+ g_free (nr_week);
+ }
+ pango_font_description_free (font_desc);
+ gtk_style_context_restore (context);
+
+ g_object_unref (layout);
+ cairo_restore (cr);
}
static gboolean
@@ -67,18 +276,79 @@ draw_navigator (GcalYearView *year_view,
cairo_t *cr,
GtkWidget *widget)
{
- /* FIXME: draw navigator */
- guint width, height;
+ GcalYearViewPrivate *priv;
+
+ GtkStyleContext *context;
+ GtkStateFlags state_flags;
+
+ gint header_padding_left, header_padding_top, header_height, layout_width, layout_height;
+ gint width, height, real_padding_left, real_padding_top, block_side, i, sw, weeks_counter;
+
+ gchar *header_str;
+
+ PangoLayout *header_layout;
+ PangoFontDescription *font_desc;
+
GdkRGBA color;
+ priv = year_view->priv;
+ context = gtk_widget_get_style_context (GTK_WIDGET (year_view));
+ state_flags = gtk_widget_get_state_flags (GTK_WIDGET (year_view));
+ sw = 1 - 2 * priv->k;
width = gtk_widget_get_allocated_width (widget);
- height = gtk_widget_get_allocated_height (widget);
- cairo_arc (cr, width / 2.0, height / 2.0, MIN (width, height) / 2.0, 0, 2 * G_PI);
- gtk_style_context_get_color (gtk_widget_get_style_context (widget), 0, &color);
- gdk_cairo_set_source_rgba (cr, &color);
+ /* read header from CSS code related to the view */
+ gtk_style_context_save (context);
+ gtk_style_context_add_class (context, "first-view-header");
+
+ header_str = g_strdup_printf ("%d", priv->date->year);
+ gtk_style_context_get (context, state_flags,
+ "padding-left", &header_padding_left, "padding-top", &header_padding_top,
+ "font", &font_desc, NULL);
+
+ gtk_style_context_restore (context);
+
+ /* draw header on navigator */
+ context = gtk_widget_get_style_context (widget);
+ state_flags = gtk_widget_get_state_flags (GTK_WIDGET (year_view));
+
+ header_layout = gtk_widget_create_pango_layout (widget, header_str);
+ pango_layout_set_font_description (header_layout, font_desc);
+ pango_layout_get_pixel_size (header_layout, &layout_width, &layout_height);
+ /* XXX: here the color of the text isn't read from year-view but from navigator widget,
+ * which has the same color on the CSS file */
+ gtk_render_layout (context, cr,
+ priv->k * (width - layout_width) + sw * header_padding_left, header_padding_top,
header_layout);
+
+ pango_font_description_free (font_desc);
+ g_object_unref (header_layout);
+ g_free (header_str);
+
+ header_height = header_padding_top * 2 + layout_height;
- cairo_fill (cr);
+ /* FIXME: debug statement, drawing frame */
+ gtk_style_context_get_color (context, state_flags, &color);
+
+ height = gtk_widget_get_allocated_height (widget) - header_height;
+
+ if (((width / 4) / 8) < ((height / 3) / 7))
+ block_side = (width / 4) / 8;
+ else
+ block_side = (height / 3) / 7;
+
+ real_padding_left = (width - (8 * 4 * block_side)) / 5;
+ real_padding_top = (height - (7 * 3 * block_side)) / 5;
+
+ weeks_counter = 1;
+ for (i = 0; i < 12; i++)
+ {
+ gint row = i / 4;
+ gint column = priv->k * 3 + sw * (i % 4);
+
+ draw_month_grid (year_view, widget, cr, i, &weeks_counter, block_side,
+ (column + 1) * real_padding_left + column * block_side * 8,
+ (row + 1) * real_padding_top + row * block_side * 7 + header_height);
+ }
return FALSE;
}
@@ -98,6 +368,10 @@ gcal_year_view_finalize (GObject *object)
if (priv->date != NULL)
g_free (priv->date);
+ /* FIXME: move into window */
+ if (priv->current_date != NULL)
+ g_free (priv->current_date);
+
G_OBJECT_CLASS (gcal_year_view_parent_class)->finalize (object);
}
@@ -137,6 +411,76 @@ gcal_year_view_set_property (GObject *object,
}
}
+static void
+gcal_year_view_get_preferred_width (GtkWidget *widget,
+ gint *minimum,
+ gint *natural)
+{
+ GcalYearViewPrivate *priv = GCAL_YEAR_VIEW (widget)->priv;
+ gint padding_left;
+
+ gtk_style_context_get (gtk_widget_get_style_context (priv->navigator),
+ gtk_widget_get_state_flags (priv->navigator),
+ "padding-left", &padding_left, NULL);
+
+ if (minimum != NULL)
+ *minimum = NAVIGATOR_CELL_WIDTH * 4 + padding_left * 8;
+ if (natural != NULL)
+ *natural = NAVIGATOR_CELL_WIDTH * 4 + padding_left * 8 + SIDEBAR_PREFERRED_WIDTH;
+}
+
+static void
+gcal_year_view_get_preferred_height_for_width (GtkWidget *widget,
+ gint width,
+ gint *minimum,
+ gint *natural)
+{
+ GcalYearViewPrivate *priv = GCAL_YEAR_VIEW (widget)->priv;
+ gint padding_top;
+
+ gtk_style_context_get (gtk_widget_get_style_context (priv->navigator),
+ gtk_widget_get_state_flags (priv->navigator),
+ "padding-top", &padding_top, NULL);
+
+ if (minimum != NULL)
+ *minimum = NAVIGATOR_CELL_HEIGHT * 3 + padding_top * 6;
+ if (natural != NULL)
+ *natural = NAVIGATOR_CELL_HEIGHT * 3 + padding_top * 6;
+}
+
+static void
+gcal_year_view_size_allocate (GtkWidget *widget,
+ GtkAllocation *alloc)
+{
+ GcalYearViewPrivate *priv = GCAL_YEAR_VIEW (widget)->priv;
+ GtkStyleContext *context;
+ gint padding_left;
+
+ context = gtk_widget_get_style_context (widget);
+ gtk_style_context_save (context);
+ gtk_style_context_add_class (context, "year-navigator");
+ gtk_style_context_get (context, gtk_widget_get_state_flags (widget), "padding-left", &padding_left, NULL);
+ gtk_style_context_restore (context);
+
+ priv->popover_mode = (alloc->width < NAVIGATOR_CELL_WIDTH * 4 + padding_left * 8 +
SIDEBAR_PREFERRED_WIDTH);
+ if (gtk_widget_get_visible (priv->sidebar) == priv->popover_mode)
+ gtk_widget_set_visible (priv->sidebar, !priv->popover_mode);
+
+ GTK_WIDGET_CLASS (gcal_year_view_parent_class)->size_allocate (widget, alloc);
+}
+
+static void
+gcal_year_view_direction_changed (GtkWidget *widget,
+ GtkTextDirection previous_direction)
+{
+ GcalYearViewPrivate *priv = GCAL_YEAR_VIEW (widget)->priv;
+
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+ priv->k = 0;
+ else if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+ priv->k = 1;
+}
+
static gchar*
gcal_year_view_get_left_header (GcalView *view)
{
@@ -161,11 +505,16 @@ gcal_year_view_class_init (GcalYearViewClass *klass)
object_class->get_property = gcal_year_view_get_property;
object_class->set_property = gcal_year_view_set_property;
+ widget_class->get_preferred_width = gcal_year_view_get_preferred_width;
+ widget_class->get_preferred_height_for_width = gcal_year_view_get_preferred_height_for_width;
+ widget_class->size_allocate = gcal_year_view_size_allocate;
+ widget_class->direction_changed = gcal_year_view_direction_changed;
+
g_object_class_override_property (object_class, PROP_DATE, "active-date");
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/year-view.ui");
- gtk_widget_class_bind_template_child_private (widget_class, GcalYearView, year_view_navigator);
+ gtk_widget_class_bind_template_child_private (widget_class, GcalYearView, navigator);
gtk_widget_class_bind_template_child_private (widget_class, GcalYearView, sidebar);
gtk_widget_class_bind_template_child_private (widget_class, GcalYearView, add_event_button);
gtk_widget_class_bind_template_child_private (widget_class, GcalYearView, events_listbox);
@@ -181,6 +530,11 @@ gcal_year_view_init (GcalYearView *self)
gtk_widget_init_template (GTK_WIDGET (self));
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (self)), "calendar-view");
+
+ if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_LTR)
+ self->priv->k = 0;
+ else if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL)
+ self->priv->k = 1;
}
static void
@@ -213,7 +567,26 @@ void
gcal_year_view_set_manager (GcalYearView *year_view,
GcalManager *manager)
{
- GcalYearViewPrivate *priv = year_view->priv;
+ year_view->priv->manager = manager;
+
+ /* FIXME: move into window */
+ year_view->priv->current_date = g_new0 (icaltimetype, 1);
+ *(year_view->priv->current_date) =
+ icaltime_current_time_with_zone (gcal_manager_get_system_timezone (year_view->priv->manager));
+ *(year_view->priv->current_date) = icaltime_set_timezone (year_view->priv->current_date,
+ gcal_manager_get_system_timezone
(year_view->priv->manager));
+}
+
+void
+gcal_year_view_set_first_weekday (GcalYearView *year_view,
+ gint nr_day)
+{
+ year_view->priv->first_weekday = nr_day;
+}
- priv->manager = manager;
+void
+gcal_year_view_set_use_24h_format (GcalYearView *year_view,
+ gboolean use_24h_format)
+{
+ year_view->priv->use_24h_format = use_24h_format;
}
diff --git a/src/gcal-year-view.h b/src/gcal-year-view.h
index 68acf1a..6bba292 100644
--- a/src/gcal-year-view.h
+++ b/src/gcal-year-view.h
@@ -50,10 +50,15 @@ struct _GcalYearViewClass
GtkBoxClass parent;
};
-GType gcal_year_view_get_type (void);
-GcalYearView *gcal_year_view_new (void);
-void gcal_year_view_set_manager (GcalYearView *year_view,
- GcalManager *manager);
+GType gcal_year_view_get_type (void);
+GcalYearView *gcal_year_view_new (void);
+void gcal_year_view_set_manager (GcalYearView *year_view,
+ GcalManager *manager);
+void gcal_year_view_set_first_weekday (GcalYearView *year_view,
+ gint nr_day);
+void gcal_year_view_set_use_24h_format (GcalYearView *year_view,
+ gboolean use_24h_format);
+
G_END_DECLS
#endif /* GCAL_YEAR_VIEW_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]