year-view: add event handling to navigator

This commit is contained in:
Erick Pérez Castellanos
2015-01-20 13:11:58 -05:00
parent e49418a26d
commit 0770a12ea9
3 changed files with 268 additions and 42 deletions
+259 -40
View File
@@ -22,11 +22,25 @@
#include "gcal-utils.h"
#include <math.h>
#include <string.h>
#define NAVIGATOR_CELL_WIDTH (210 + 15)
#define NAVIGATOR_CELL_HEIGHT 210
#define SIDEBAR_PREFERRED_WIDTH 200
typedef struct
{
/* month span from 0 to 11 */
gint start_day, start_month;
gint end_day, end_month;
} ButtonData;
typedef struct
{
gint box_side;
GdkPoint coordinates [12];
} GridData;
struct _GcalYearViewPrivate
{
/* composite, GtkBuilder's widgets */
@@ -38,8 +52,13 @@ struct _GcalYearViewPrivate
/* manager singleton */
GcalManager *manager;
/* geometry info */
GridData *navigator_grid;
/* state flags */
gboolean popover_mode;
gboolean button_pressed;
ButtonData *selected_data;
/**
* first day of the week according to user locale, being
@@ -90,34 +109,111 @@ update_date (GcalYearView *year_view,
gtk_widget_queue_draw (GTK_WIDGET (year_view));
}
static gboolean
calculate_day_month_for_coord (GcalYearView *year_view,
gdouble x,
gdouble y,
gint *out_day,
gint *out_month)
{
GcalYearViewPrivate *priv = year_view->priv;
gint row, column, i, sw, box_side, clicked_cell, day, month;
row = -1;
column = -1;
box_side = priv->navigator_grid->box_side;
sw = 1 - 2 * priv->k;
/* y selection */
for (i = 0; i < 4 && ((row == -1) || (column == -1)); i++)
{
if (row == -1 &&
y > priv->navigator_grid->coordinates[i * 4].y + box_side &&
y < priv->navigator_grid->coordinates[i * 4].y + box_side * 7)
{
row = i;
}
if (column == -1 &&
x > priv->navigator_grid->coordinates[i].x + box_side * 0.5 &&
x < priv->navigator_grid->coordinates[i].x + box_side * 7.5)
{
column = i;
}
}
if (row == -1 || column == -1)
return FALSE;
month = row * 4 + column;
row = (y - (priv->navigator_grid->coordinates[month].y + box_side)) / box_side;
column = (x - (priv->navigator_grid->coordinates[month].x + box_side * 0.5)) / box_side;
clicked_cell = row * 7 + column;
day = 7 * ((clicked_cell + 7 * priv->k) / 7) + sw * (clicked_cell % 7) + (1 - priv->k);
day -= ((time_day_of_week (1, month, priv->date->year) - priv->first_weekday + 7) % 7);
if (day < 1 || day > time_days_in_month (priv->date->year, month))
return FALSE;
*out_day = day;
*out_month = month;
return TRUE;
}
static void
order_selected_data (ButtonData *selected_data)
{
gint swap;
if (selected_data->end_month < selected_data->start_month)
{
swap = selected_data->start_month;
selected_data->start_month = selected_data->end_month;
selected_data->end_month = swap;
swap = selected_data->start_day;
selected_data->start_day = selected_data->end_day;
selected_data->end_day = swap;
}
else if (selected_data->start_month == selected_data->end_month && selected_data->end_day < selected_data->start_day)
{
swap = selected_data->start_day;
selected_data->start_day = selected_data->end_day;
selected_data->end_day = swap;
}
}
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)
gint *weeks_counter)
{
GcalYearViewPrivate *priv = year_view->priv;
GtkStyleContext *context;
GtkStateFlags state_flags;
PangoLayout *layout;
PangoFontDescription *font_desc;
PangoLayout *layout, *slayout;
PangoFontDescription *font_desc, *sfont_desc;
GdkRGBA color;
gint layout_width, layout_height, i, j, sw;
gint column, row, box_padding_top, box_padding_start;
gint x, y, column, row, box_side, box_padding_top, box_padding_start;
gint days_delay, days, shown_rows, sunday_idx;
gchar *str, *nr_day, *nr_week;
gboolean selected_day;
cairo_save (cr);
context = gtk_widget_get_style_context (widget);
state_flags = gtk_widget_get_state_flags (widget);
sw = 1 - 2 * priv->k;
box_side = priv->navigator_grid->box_side;
x = priv->navigator_grid->coordinates[month_nr].x;
y = priv->navigator_grid->coordinates[month_nr].y;
gtk_style_context_get (context, state_flags | GTK_STATE_FLAG_SELECTED, "font", &sfont_desc, NULL);
slayout = gtk_widget_create_pango_layout (widget, NULL);
pango_layout_set_font_description (slayout, sfont_desc);
/* header */
gtk_style_context_save (context);
@@ -129,11 +225,11 @@ draw_month_grid (GcalYearView *year_view,
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,
gtk_render_layout (context, cr, x + (box_side * 8 - layout_width) / 2, y + (box_side - layout_height) / 2,
layout);
gtk_render_background (context, cr,
x + (block_side * 8 - layout_width) / 2, y + (block_side - layout_height) / 2,
x + (box_side * 8 - layout_width) / 2, y + (box_side - layout_height) / 2,
layout_width, layout_width);
pango_font_description_free (font_desc);
@@ -147,8 +243,8 @@ draw_month_grid (GcalYearView *year_view,
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_move_to (cr, x + box_side / 2, y + box_side + 0.4);
cairo_rel_line_to (cr, 7 * box_side, 0);
cairo_stroke (cr);
gtk_style_context_restore (context);
@@ -180,8 +276,31 @@ draw_month_grid (GcalYearView *year_view,
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;
box_padding_top = (box_side - layout_height) / 2 > 0 ? (box_side - layout_height) / 2 : 0;
box_padding_start = (box_side - layout_width) / 2 > 0 ? (box_side - layout_width) / 2 : 0;
selected_day = FALSE;
if (priv->selected_data->start_day != 0)
{
ButtonData selected_data = *(priv->selected_data);
order_selected_data (&selected_data);
if (month_nr > selected_data.start_month && month_nr < selected_data.end_month)
{
selected_day = TRUE;
}
else if (month_nr == selected_data.start_month && month_nr == selected_data.end_month)
{
selected_day = j >= selected_data.start_day && j <= selected_data.end_day;
}
else if (month_nr == selected_data.start_month && j >= selected_data.start_day)
{
selected_day = TRUE;
}
else if (month_nr == selected_data.end_month && j <= selected_data.end_day)
{
selected_day = TRUE;
}
}
if (priv->date->year == priv->current_date->year && month_nr + 1 == priv->current_date->month &&
j == priv->current_date->day)
@@ -196,35 +315,53 @@ draw_month_grid (GcalYearView *year_view,
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);
box_padding_top = (box_side - layout_height) / 2 > 0 ? (box_side - layout_height) / 2 : 0;
box_padding_start = (box_side - layout_width) / 2 > 0 ? (box_side - layout_width) / 2 : 0;
/* 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,
box_side * (column + 0.5 + priv->k) + x + sw * box_padding_start - priv->k * layout_width - 2.0,
box_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,
box_side * (column + 0.5 + priv->k) + x + sw * box_padding_start - priv->k * layout_width,
box_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 (selected_day)
{
gtk_style_context_set_state (context, state_flags | GTK_STATE_FLAG_SELECTED);
pango_layout_set_text (slayout, nr_day, -1);
pango_layout_get_pixel_size (slayout, &layout_width, &layout_height);
box_padding_top = (box_side - layout_height) / 2 > 0 ? (box_side - layout_height) / 2 : 0;
box_padding_start = (box_side - layout_width) / 2 > 0 ? (box_side - layout_width) / 2 : 0;
gtk_render_layout (context, cr,
box_side * (column + 0.5 + priv->k) + x + sw * box_padding_start - priv->k * layout_width,
box_side * (row + 1) + y + box_padding_top,
slayout);
gtk_style_context_set_state (context, state_flags);
}
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,
box_side * (column + 0.5 + priv->k) + x + sw * box_padding_start - priv->k * layout_width,
box_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,
box_side * (column + 0.5 + priv->k) + x + sw * box_padding_start - priv->k * layout_width,
box_side * (row + 1) + y + box_padding_top,
layout);
}
@@ -254,19 +391,22 @@ draw_month_grid (GcalYearView *year_view,
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;
box_padding_top = (box_side - layout_height) / 2 > 0 ? (box_side - layout_height) / 2 : 0;
box_padding_start = ((box_side / 2) - layout_width) / 2 > 0 ? ((box_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,
x + sw * box_padding_start + priv->k * (8 * box_side - layout_width),
box_side * (i + 1) + y + box_padding_top,
layout);
g_free (nr_week);
}
pango_font_description_free (font_desc);
gtk_style_context_restore (context);
pango_font_description_free (sfont_desc);
g_object_unref (slayout);
pango_font_description_free (font_desc);
g_object_unref (layout);
cairo_restore (cr);
}
@@ -282,15 +422,13 @@ draw_navigator (GcalYearView *year_view,
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;
gint width, height, box_side, real_padding_left, real_padding_top, 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));
@@ -325,34 +463,106 @@ draw_navigator (GcalYearView *year_view,
g_free (header_str);
header_height = header_padding_top * 2 + layout_height;
/* 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;
box_side = (width / 4) / 8;
else
block_side = (height / 3) / 7;
box_side = (height / 3) / 7;
real_padding_left = (width - (8 * 4 * block_side)) / 5;
real_padding_top = (height - (7 * 3 * block_side)) / 5;
real_padding_left = (width - (8 * 4 * box_side)) / 5;
real_padding_top = (height - (7 * 3 * box_side)) / 4;
priv->navigator_grid->box_side = box_side;
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);
priv->navigator_grid->coordinates[i].x = (column + 1) * real_padding_left + column * box_side * 8;
priv->navigator_grid->coordinates[i].y = (row + 1) * real_padding_top + row * box_side * 7 + header_height;
draw_month_grid (year_view, widget, cr, i, &weeks_counter);
}
return FALSE;
}
static gboolean
navigator_button_press_cb (GcalYearView *year_view,
GdkEventButton *event,
GtkWidget *widget)
{
gint day, month;
if (!calculate_day_month_for_coord (year_view, event->x, event->y, &day, &month))
return FALSE;
year_view->priv->button_pressed = TRUE;
year_view->priv->selected_data->start_day = day;
year_view->priv->selected_data->start_month = month;
return TRUE;
}
static gboolean
navigator_button_release_cb (GcalYearView *year_view,
GdkEventButton *event,
GtkWidget *widget)
{
GcalYearViewPrivate *priv = year_view->priv;
gint day, month;
if (!priv->button_pressed)
return FALSE;
if (!calculate_day_month_for_coord (year_view, event->x, event->y, &day, &month))
goto fail;
priv->button_pressed = FALSE;
priv->selected_data->end_day = day;
priv->selected_data->end_month = month;
gtk_widget_queue_draw (widget);
/* FIXME: */
//update events on listbox
return TRUE;
fail:
priv->button_pressed = FALSE;
memset (priv->selected_data, 0, sizeof (ButtonData));
gtk_widget_queue_draw (widget);
/* FIXME: */
//reset listbox to today
return TRUE;
}
static gboolean
navigator_motion_notify_cb (GcalYearView *year_view,
GdkEventMotion *event,
GtkWidget *widget)
{
GcalYearViewPrivate *priv = year_view->priv;
gint day, month;
if (!priv->button_pressed)
return FALSE;
if (!calculate_day_month_for_coord (year_view, event->x, event->y, &day, &month))
goto fail;
priv->selected_data->end_day = day;
priv->selected_data->end_month = month;
gtk_widget_queue_draw (widget);
return TRUE;
fail:
priv->selected_data->end_day = priv->selected_data->start_day;
priv->selected_data->end_month = priv->selected_data->start_month;
gtk_widget_queue_draw (widget);
return TRUE;
}
static void
add_event_clicked_cb (GcalYearView *year_view,
GtkButton *button)
@@ -365,6 +575,9 @@ gcal_year_view_finalize (GObject *object)
{
GcalYearViewPrivate *priv = GCAL_YEAR_VIEW (object)->priv;
g_free (priv->navigator_grid);
g_free (priv->selected_data);
if (priv->date != NULL)
g_free (priv->date);
@@ -520,6 +733,9 @@ gcal_year_view_class_init (GcalYearViewClass *klass)
gtk_widget_class_bind_template_child_private (widget_class, GcalYearView, events_listbox);
gtk_widget_class_bind_template_callback (widget_class, draw_navigator);
gtk_widget_class_bind_template_callback (widget_class, navigator_button_press_cb);
gtk_widget_class_bind_template_callback (widget_class, navigator_button_release_cb);
gtk_widget_class_bind_template_callback (widget_class, navigator_motion_notify_cb);
gtk_widget_class_bind_template_callback (widget_class, add_event_clicked_cb);
}
@@ -535,6 +751,9 @@ gcal_year_view_init (GcalYearView *self)
self->priv->k = 0;
else if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL)
self->priv->k = 1;
self->priv->navigator_grid = g_new0 (GridData, 1);
self->priv->selected_data = g_new0 (ButtonData, 1);
}
static void