project: Move ui-related classes to gui/

This commit is contained in:
Georges Basile Stavracas Neto
2019-05-04 12:14:05 -03:00
parent d5fbce1385
commit f55b4531ef
24 changed files with 20 additions and 19 deletions
+304
View File
@@ -0,0 +1,304 @@
/* gcal-calendar-popover.c
*
* Copyright 2019 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/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "GcalCalendarPopover"
#include "gcal-calendar.h"
#include "gcal-calendar-popover.h"
#include "gcal-context.h"
#include "gcal-utils.h"
struct _GcalCalendarPopover
{
GtkPopover parent;
GtkWidget *calendar_listbox;
GcalContext *context;
};
G_DEFINE_TYPE (GcalCalendarPopover, gcal_calendar_popover, GTK_TYPE_POPOVER)
enum
{
PROP_0,
PROP_CONTEXT,
N_PROPS
};
static GParamSpec *properties [N_PROPS];
/*
* Auxiliary methods
*/
static GtkWidget*
make_calendar_row (GcalCalendar *calendar)
{
GtkWidget *label, *icon, *checkbox, *box, *row;
GtkStyleContext *context;
cairo_surface_t *surface;
const GdkRGBA *color;
row = gtk_list_box_row_new ();
/* apply some nice styling */
context = gtk_widget_get_style_context (row);
gtk_style_context_add_class (context, "button");
gtk_style_context_add_class (context, "flat");
gtk_style_context_add_class (context, "menuitem");
/* main box */
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (box), 6);
/* source color icon */
color = gcal_calendar_get_color (calendar);
surface = get_circle_surface_from_color (color, 16);
icon = gtk_image_new_from_surface (surface);
gtk_style_context_add_class (gtk_widget_get_style_context (icon), "calendar-color-image");
/* source name label */
label = gtk_label_new (gcal_calendar_get_name (calendar));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_widget_set_hexpand (label, TRUE);
/* checkbox */
checkbox = gtk_check_button_new ();
g_object_bind_property (calendar,
"visible",
checkbox,
"active",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
gtk_container_add (GTK_CONTAINER (box), icon);
gtk_container_add (GTK_CONTAINER (box), label);
gtk_container_add (GTK_CONTAINER (box), checkbox);
gtk_container_add (GTK_CONTAINER (row), box);
g_object_set_data (G_OBJECT (row), "check", checkbox);
g_object_set_data (G_OBJECT (row), "calendar", calendar);
gtk_widget_show_all (row);
g_clear_pointer (&surface, cairo_surface_destroy);
return row;
}
static void
add_calendar (GcalCalendarPopover *self,
GcalCalendar *calendar)
{
GtkWidget *row;
row = make_calendar_row (calendar);
gtk_container_add (GTK_CONTAINER (self->calendar_listbox), row);
}
static void
remove_calendar (GcalCalendarPopover *self,
GcalCalendar *calendar)
{
g_autoptr (GList) children = NULL;
GList *aux;
children = gtk_container_get_children (GTK_CONTAINER (self->calendar_listbox));
for (aux = children; aux != NULL; aux = aux->next)
{
GcalCalendar *row_calendar = g_object_get_data (G_OBJECT (aux->data), "calendar");
if (row_calendar && row_calendar == calendar)
{
gtk_widget_destroy (aux->data);
break;
}
}
}
/*
* Callbacks
*/
static gint
listbox_sort_func (GtkListBoxRow *row1,
GtkListBoxRow *row2,
gpointer user_data)
{
GcalCalendar *calendar1, *calendar2;
calendar1 = g_object_get_data (G_OBJECT (row1), "calendar");
calendar2 = g_object_get_data (G_OBJECT (row2), "calendar");
return g_ascii_strcasecmp (gcal_calendar_get_name (calendar1), gcal_calendar_get_name (calendar2));
}
static void
on_manager_calendar_added_cb (GcalManager *manager,
GcalCalendar *calendar,
GcalCalendarPopover *self)
{
add_calendar (self, calendar);
}
static void
on_manager_calendar_changed_cb (GcalManager *manager,
GcalCalendar *calendar,
GcalCalendarPopover *self)
{
remove_calendar (self, calendar);
add_calendar (self, calendar);
}
static void
on_manager_calendar_removed_cb (GcalManager *manager,
GcalCalendar *calendar,
GcalCalendarPopover *self)
{
remove_calendar (self, calendar);
}
static void
on_listbox_row_activated_cb (GtkListBox *listbox,
GtkListBoxRow *row,
GcalCalendarPopover *self)
{
GtkToggleButton *check;
check = (GtkToggleButton *) g_object_get_data (G_OBJECT (row), "check");
gtk_toggle_button_set_active (check, !gtk_toggle_button_get_active (check));
}
/*
* GObject overrides
*/
static void
gcal_calendar_popover_finalize (GObject *object)
{
GcalCalendarPopover *self = (GcalCalendarPopover *)object;
g_clear_object (&self->context);
G_OBJECT_CLASS (gcal_calendar_popover_parent_class)->finalize (object);
}
static void
gcal_calendar_popover_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GcalCalendarPopover *self = GCAL_CALENDAR_POPOVER (object);
switch (prop_id)
{
case PROP_CONTEXT:
g_value_set_object (value, self->context);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gcal_calendar_popover_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GcalCalendarPopover *self = GCAL_CALENDAR_POPOVER (object);
switch (prop_id)
{
case PROP_CONTEXT:
{
g_autoptr (GList) calendars = NULL;
GcalManager *manager;
GList *l;
g_assert (self->context == NULL);
self->context = g_value_dup_object (value);
manager = gcal_context_get_manager (self->context);
calendars = gcal_manager_get_calendars (manager);
for (l = calendars; l; l = l->next)
add_calendar (self, l->data);
g_signal_connect (manager, "calendar-added", G_CALLBACK (on_manager_calendar_added_cb), object);
g_signal_connect (manager, "calendar-removed", G_CALLBACK (on_manager_calendar_removed_cb), object);
g_signal_connect (manager, "calendar-changed", G_CALLBACK (on_manager_calendar_changed_cb), object);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gcal_calendar_popover_class_init (GcalCalendarPopoverClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = gcal_calendar_popover_finalize;
object_class->get_property = gcal_calendar_popover_get_property;
object_class->set_property = gcal_calendar_popover_set_property;
/**
* GcalCalendarPopover::context:
*
* The #GcalContext of the application.
*/
properties[PROP_CONTEXT] = g_param_spec_object ("context",
"Context of the application",
"The context of the application",
GCAL_TYPE_CONTEXT,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, properties);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/calendar-popover.ui");
gtk_widget_class_bind_template_child (widget_class, GcalCalendarPopover, calendar_listbox);
gtk_widget_class_bind_template_callback (widget_class, on_listbox_row_activated_cb);
}
static void
gcal_calendar_popover_init (GcalCalendarPopover *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
gtk_list_box_set_sort_func (GTK_LIST_BOX (self->calendar_listbox),
(GtkListBoxSortFunc) listbox_sort_func,
self,
NULL);
}
+30
View File
@@ -0,0 +1,30 @@
/* gcal-calendar-popover.h
*
* Copyright 2019 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/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GCAL_TYPE_CALENDAR_POPOVER (gcal_calendar_popover_get_type())
G_DECLARE_FINAL_TYPE (GcalCalendarPopover, gcal_calendar_popover, GCAL, CALENDAR_POPOVER, GtkPopover)
G_END_DECLS
+483
View File
@@ -0,0 +1,483 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#define G_LOG_DOMAIN "GcalDateChooserDay"
#include "gcal-date-chooser-day.h"
#include <stdlib.h>
#include <langinfo.h>
enum {
SELECTED,
LAST_DAY_SIGNAL
};
static guint signals[LAST_DAY_SIGNAL] = { 0, };
struct _GcalDateChooserDay
{
GtkBin parent;
GtkWidget *label;
GDateTime *date;
GdkWindow *event_window;
GtkGesture *multipress_gesture;
};
G_DEFINE_TYPE (GcalDateChooserDay, gcal_date_chooser_day, GTK_TYPE_BIN)
static void
day_pressed (GtkGestureMultiPress *gesture,
gint n_press,
gdouble x,
gdouble y,
GcalDateChooserDay *self)
{
gint button;
button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
if (button == GDK_BUTTON_PRIMARY)
{
if (n_press == 1)
g_signal_emit (self, signals[SELECTED], 0);
}
}
static gboolean
gcal_date_chooser_day_key_press (GtkWidget *widget,
GdkEventKey *event)
{
GcalDateChooserDay *self = GCAL_DATE_CHOOSER_DAY (widget);
if (event->keyval == GDK_KEY_space ||
event->keyval == GDK_KEY_Return ||
event->keyval == GDK_KEY_ISO_Enter||
event->keyval == GDK_KEY_KP_Enter ||
event->keyval == GDK_KEY_KP_Space)
{
g_signal_emit (self, signals[SELECTED], 0);
return TRUE;
}
if (GTK_WIDGET_CLASS (gcal_date_chooser_day_parent_class)->key_press_event (widget, event))
return TRUE;
return FALSE;
}
static void
gcal_date_chooser_day_dispose (GObject *object)
{
GcalDateChooserDay *self = GCAL_DATE_CHOOSER_DAY (object);
g_clear_object (&self->multipress_gesture);
g_clear_pointer (&self->date, g_date_time_unref);
G_OBJECT_CLASS (gcal_date_chooser_day_parent_class)->dispose (object);
}
static gboolean
gcal_date_chooser_day_draw (GtkWidget *widget,
cairo_t *cr)
{
GtkStyleContext *context;
GtkStateFlags state;
gint x, y, width, height;
context = gtk_widget_get_style_context (widget);
state = gtk_style_context_get_state (context);
x = 0;
y = 0;
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
gtk_render_background (context, cr, x, y, width, height);
gtk_render_frame (context, cr, x, y, width, height);
GTK_WIDGET_CLASS (gcal_date_chooser_day_parent_class)->draw (widget, cr);
if (gtk_widget_has_visible_focus (widget))
{
GtkBorder border;
gtk_style_context_get_border (context, state, &border);
gtk_render_focus (context, cr, border.left, border.top,
gtk_widget_get_allocated_width (widget) - border.left - border.right,
gtk_widget_get_allocated_height (widget) - border.top - border.bottom);
}
return FALSE;
}
static void
gcal_date_chooser_day_map (GtkWidget *widget)
{
GcalDateChooserDay *self = GCAL_DATE_CHOOSER_DAY (widget);
GTK_WIDGET_CLASS (gcal_date_chooser_day_parent_class)->map (widget);
gdk_window_show (self->event_window);
}
static void
gcal_date_chooser_day_unmap (GtkWidget *widget)
{
GcalDateChooserDay *self = GCAL_DATE_CHOOSER_DAY (widget);
gdk_window_hide (self->event_window);
GTK_WIDGET_CLASS (gcal_date_chooser_day_parent_class)->unmap (widget);
}
static void
gcal_date_chooser_day_realize (GtkWidget *widget)
{
GcalDateChooserDay *self = GCAL_DATE_CHOOSER_DAY (widget);
GtkAllocation allocation;
GdkWindow *window;
GdkWindowAttr attributes;
gint attributes_mask;
gtk_widget_get_allocation (widget, &allocation);
gtk_widget_set_realized (widget, TRUE);
attributes.window_type = GDK_WINDOW_CHILD;
attributes.x = allocation.x;
attributes.y = allocation.y;
attributes.width = allocation.width;
attributes.height = allocation.height;
attributes.wclass = GDK_INPUT_ONLY;
attributes.event_mask = gtk_widget_get_events (widget);
attributes.event_mask |= GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
| GDK_TOUCH_MASK
| GDK_ENTER_NOTIFY_MASK
| GDK_LEAVE_NOTIFY_MASK;
attributes_mask = GDK_WA_X | GDK_WA_Y;
window = gtk_widget_get_parent_window (widget);
gtk_widget_set_window (widget, window);
g_object_ref (window);
self->event_window = gdk_window_new (window, &attributes, attributes_mask);
gtk_widget_register_window (widget, self->event_window);
}
static void
gcal_date_chooser_day_unrealize (GtkWidget *widget)
{
GcalDateChooserDay *self = GCAL_DATE_CHOOSER_DAY (widget);
if (self->event_window)
{
gtk_widget_unregister_window (widget, self->event_window);
gdk_window_destroy (self->event_window);
self->event_window = NULL;
}
GTK_WIDGET_CLASS (gcal_date_chooser_day_parent_class)->unrealize (widget);
}
static void
gcal_date_chooser_day_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GcalDateChooserDay *self = GCAL_DATE_CHOOSER_DAY (widget);
GTK_WIDGET_CLASS (gcal_date_chooser_day_parent_class)->size_allocate (widget, allocation);
if (gtk_widget_get_realized (widget))
{
gdk_window_move_resize (self->event_window,
allocation->x,
allocation->y,
allocation->width,
allocation->height);
}
}
static void
gcal_date_chooser_day_drag_data_get (GtkWidget *widget,
GdkDragContext *context,
GtkSelectionData *selection_data,
guint info,
guint time)
{
GcalDateChooserDay *self = GCAL_DATE_CHOOSER_DAY (widget);
gchar *text;
text = g_date_time_format (self->date, "%x");
gtk_selection_data_set_text (selection_data, text, -1);
g_free (text);
}
static void
gcal_date_chooser_day_get_preferred_width (GtkWidget *widget,
gint *minimum,
gint *natural)
{
GcalDateChooserDay *self;
GtkStyleContext *context;
GtkStateFlags flags;
GtkBorder border, margin, padding;
gint label_min, label_nat;
gint min_width, min, nat;
self = GCAL_DATE_CHOOSER_DAY (widget);
context = gtk_widget_get_style_context (widget);
flags = gtk_style_context_get_state (context);
gtk_style_context_get_border (context, flags, &border);
gtk_style_context_get_margin (context, flags, &margin);
gtk_style_context_get_padding (context, flags, &padding);
gtk_style_context_get (context,
flags,
"min-width", &min_width,
NULL);
gtk_widget_get_preferred_width (self->label, &label_min, &label_nat);
min = label_min + margin.left + border.left + padding.left + margin.right + border.right + padding.right;
nat = label_nat + margin.left + border.left + padding.left + margin.right + border.right + padding.right;
if (minimum)
*minimum = MAX (min, min_width);
if (natural)
*natural = MAX (nat, min_width);
}
static void
gcal_date_chooser_day_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural)
{
GcalDateChooserDay *self;
GtkStyleContext *context;
GtkStateFlags flags;
GtkBorder border, margin, padding;
gint label_min, label_nat;
gint min_height, min, nat;
self = GCAL_DATE_CHOOSER_DAY (widget);
context = gtk_widget_get_style_context (widget);
flags = gtk_style_context_get_state (context);
gtk_style_context_get_border (context, flags, &border);
gtk_style_context_get_margin (context, flags, &margin);
gtk_style_context_get_padding (context, flags, &padding);
gtk_style_context_get (context,
flags,
"min-height", &min_height,
NULL);
gtk_widget_get_preferred_height (self->label, &label_min, &label_nat);
min = label_min + margin.top + border.top + padding.top + margin.bottom + border.bottom + padding.bottom;
nat = label_nat + margin.top + border.top + padding.top + margin.bottom + border.bottom + padding.bottom;
if (minimum)
*minimum = MAX (min, min_height);
if (natural)
*natural = MAX (nat, min_height);
}
static gboolean
gcal_date_chooser_day_enter_notify_event (GtkWidget *widget,
GdkEventCrossing *event)
{
GtkStyleContext *context;
GtkStateFlags state;
context = gtk_widget_get_style_context (widget);
state = gtk_style_context_get_state (context);
gtk_style_context_set_state (context, state | GTK_STATE_FLAG_PRELIGHT);
return GDK_EVENT_PROPAGATE;
}
static gboolean
gcal_date_chooser_day_leave_notify_event (GtkWidget *widget,
GdkEventCrossing *event)
{
GtkStyleContext *context;
GtkStateFlags state;
context = gtk_widget_get_style_context (widget);
state = gtk_style_context_get_state (context);
gtk_style_context_set_state (context, state & ~GTK_STATE_FLAG_PRELIGHT);
return GDK_EVENT_PROPAGATE;
}
static void
gcal_date_chooser_day_class_init (GcalDateChooserDayClass *class)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = gcal_date_chooser_day_dispose;
widget_class->draw = gcal_date_chooser_day_draw;
widget_class->realize = gcal_date_chooser_day_realize;
widget_class->unrealize = gcal_date_chooser_day_unrealize;
widget_class->map = gcal_date_chooser_day_map;
widget_class->unmap = gcal_date_chooser_day_unmap;
widget_class->key_press_event = gcal_date_chooser_day_key_press;
widget_class->size_allocate = gcal_date_chooser_day_size_allocate;
widget_class->drag_data_get = gcal_date_chooser_day_drag_data_get;
widget_class->get_preferred_width = gcal_date_chooser_day_get_preferred_width;
widget_class->get_preferred_height = gcal_date_chooser_day_get_preferred_height;
widget_class->enter_notify_event = gcal_date_chooser_day_enter_notify_event;
widget_class->leave_notify_event = gcal_date_chooser_day_leave_notify_event;
signals[SELECTED] = g_signal_new ("selected",
GCAL_TYPE_DATE_CHOOSER_DAY,
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE, 0);
gtk_widget_class_set_css_name (widget_class, "day");
}
static void
gcal_date_chooser_day_init (GcalDateChooserDay *self)
{
GtkWidget *widget = GTK_WIDGET (self);
gtk_widget_set_halign (widget, GTK_ALIGN_CENTER);
gtk_widget_set_valign (widget, GTK_ALIGN_CENTER);
gtk_widget_set_can_focus (widget, TRUE);
gtk_style_context_add_class (gtk_widget_get_style_context (widget), "day");
self->label = gtk_label_new ("");
gtk_widget_show (self->label);
gtk_widget_set_halign (self->label, GTK_ALIGN_CENTER);
gtk_widget_set_valign (self->label, GTK_ALIGN_CENTER);
gtk_widget_set_hexpand (self->label, TRUE);
gtk_widget_set_vexpand (self->label, TRUE);
gtk_container_add (GTK_CONTAINER (self), self->label);
self->multipress_gesture = gtk_gesture_multi_press_new (widget);
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (self->multipress_gesture), 0);
g_signal_connect (self->multipress_gesture,
"pressed",
G_CALLBACK (day_pressed),
self);
}
GtkWidget*
gcal_date_chooser_day_new (void)
{
return g_object_new (GCAL_TYPE_DATE_CHOOSER_DAY, NULL);
}
void
gcal_date_chooser_day_set_date (GcalDateChooserDay *self,
GDateTime *date)
{
gchar *text;
g_clear_pointer (&self->date, g_date_time_unref);
self->date = g_date_time_ref (date);
text = g_strdup_printf ("%d", g_date_time_get_day_of_month (date));
gtk_label_set_label (GTK_LABEL (self->label), text);
g_free (text);
}
GDateTime*
gcal_date_chooser_day_get_date (GcalDateChooserDay *self)
{
return self->date;
}
void
gcal_date_chooser_day_set_other_month (GcalDateChooserDay *self,
gboolean other_month)
{
GtkStyleContext *context;
context = gtk_widget_get_style_context (GTK_WIDGET (self));
if (other_month)
{
gtk_style_context_add_class (context, "other-month");
gtk_drag_source_unset (GTK_WIDGET (self));
}
else
{
gtk_style_context_remove_class (context, "other-month");
gtk_drag_source_set (GTK_WIDGET (self),
GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
NULL, 0,
GDK_ACTION_COPY);
gtk_drag_source_add_text_targets (GTK_WIDGET (self));
}
}
void
gcal_date_chooser_day_set_selected (GcalDateChooserDay *self,
gboolean selected)
{
if (selected)
gtk_widget_set_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_SELECTED, FALSE);
else
gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_SELECTED);
}
void
gcal_date_chooser_day_set_options (GcalDateChooserDay *self,
GcalDateChooserDayOptions options)
{
GtkStyleContext *context;
context = gtk_widget_get_style_context (GTK_WIDGET (self));
if (options & GCAL_DATE_CHOOSER_DAY_WEEKEND)
gtk_style_context_add_class (context, "weekend");
else
gtk_style_context_remove_class (context, "weekend");
if (options & GCAL_DATE_CHOOSER_DAY_HOLIDAY)
gtk_style_context_add_class (context, "holiday");
else
gtk_style_context_remove_class (context, "holiday");
if (options & GCAL_DATE_CHOOSER_DAY_MARKED)
gtk_style_context_add_class (context, "marked");
else
gtk_style_context_remove_class (context, "marked");
}
+50
View File
@@ -0,0 +1,50 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GCAL_DATE_CHOOSER_DAY_PRIVATE_H__
#define __GCAL_DATE_CHOOSER_DAY_PRIVATE_H__
#include "gcal-date-chooser.h"
#include <glib-object.h>
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GCAL_TYPE_DATE_CHOOSER_DAY (gcal_date_chooser_day_get_type())
G_DECLARE_FINAL_TYPE (GcalDateChooserDay, gcal_date_chooser_day, GCAL, DATE_CHOOSER_DAY, GtkBin)
GtkWidget* gcal_date_chooser_day_new (void);
GDateTime* gcal_date_chooser_day_get_date (GcalDateChooserDay *day);
void gcal_date_chooser_day_set_date (GcalDateChooserDay *day,
GDateTime *date);
void gcal_date_chooser_day_set_other_month (GcalDateChooserDay *day,
gboolean other_month);
void gcal_date_chooser_day_set_selected (GcalDateChooserDay *day,
gboolean selected);
void gcal_date_chooser_day_set_options (GcalDateChooserDay *day,
GcalDateChooserDayOptions options);
G_END_DECLS
#endif /* __GCAL_DATE_CHOOSER_DAY_PRIVATE_H__ */
+808
View File
@@ -0,0 +1,808 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#define G_LOG_DOMAIN "GcalDateChooser"
#include "gcal-utils.h"
#include "gcal-date-chooser.h"
#include "gcal-date-chooser-day.h"
#include "gcal-multi-choice.h"
#include <stdlib.h>
#include <langinfo.h>
struct _GcalDateChooser
{
GtkBin parent;
GtkWidget *month_choice;
GtkWidget *year_choice;
GtkWidget *grid;
GtkWidget *day_grid;
GtkWidget *corner;
GtkWidget *cols[7];
GtkWidget *rows[6];
GtkWidget *days[6][7];
GDateTime *date;
gint this_year;
gint week_start;
gboolean show_heading;
gboolean show_day_names;
gboolean show_week_numbers;
gboolean no_month_change;
GcalDateChooserDayOptionsCallback day_options_cb;
gpointer day_options_data;
GDestroyNotify day_options_destroy;
};
G_DEFINE_TYPE (GcalDateChooser, gcal_date_chooser, GTK_TYPE_BIN)
enum
{
MONTH_CHANGED,
DAY_SELECTED,
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_DATE,
PROP_SHOW_HEADING,
PROP_SHOW_DAY_NAMES,
PROP_SHOW_WEEK_NUMBERS,
PROP_NO_MONTH_CHANGE,
NUM_PROPERTIES
};
static guint signals[LAST_SIGNAL] = { 0, };
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
static const guint month_length[2][13] =
{
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
static gboolean
leap (guint year)
{
return ((((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0));
}
static void
calendar_compute_days (GcalDateChooser *self)
{
GcalDateChooserDay *d;
GDateTime *date;
gint year, month, day;
gint other_year, other_month;
gint ndays_in_month;
gint ndays_in_prev_month;
gint first_day;
gint row;
gint col;
g_date_time_get_ymd (self->date, &year, &month, NULL);
ndays_in_month = month_length[leap (year)][month];
date = g_date_time_new_local (year, month, 1, 1, 1, 1);
first_day = g_date_time_get_day_of_week (date);
g_date_time_unref (date);
first_day = (first_day + 7 - self->week_start) % 7;
if (first_day == 0)
first_day = 7;
/* Compute days of previous month */
if (month > 1)
ndays_in_prev_month = month_length[leap (year)][month - 1];
else
ndays_in_prev_month = month_length[leap (year - 1)][12];
day = ndays_in_prev_month - first_day + 1;
other_year = year;
other_month = month - 1;
if (other_month == 0)
{
other_month = 12;
other_year -= 1;
}
for (col = 0; col < first_day; col++)
{
d = GCAL_DATE_CHOOSER_DAY (self->days[0][col]);
date = g_date_time_new_local (other_year, other_month, day, 1, 1, 1);
gcal_date_chooser_day_set_date (d, date);
gcal_date_chooser_day_set_other_month (d, TRUE);
g_date_time_unref (date);
day++;
}
/* Compute days of current month */
row = first_day / 7;
col = first_day % 7;
for (day = 1; day <= ndays_in_month; day++)
{
d = GCAL_DATE_CHOOSER_DAY (self->days[row][col]);
date = g_date_time_new_local (year, month, day, 1, 1, 1);
gcal_date_chooser_day_set_date (d, date);
gcal_date_chooser_day_set_other_month (d, FALSE);
g_date_time_unref (date);
col++;
if (col == 7)
{
row++;
col = 0;
}
}
/* Compute days of next month */
other_year = year;
other_month = month + 1;
if (other_month == 13)
{
other_month = 1;
other_year += 1;
}
day = 1;
for (; row < 6; row++)
{
for (; col < 7; col++)
{
d = GCAL_DATE_CHOOSER_DAY (self->days[row][col]);
date = g_date_time_new_local (other_year, other_month, day, 1, 1, 1);
gcal_date_chooser_day_set_date (d, date);
gcal_date_chooser_day_set_other_month (d, TRUE);
g_date_time_unref (date);
day++;
}
col = 0;
}
/* update week numbers */
for (row = 0; row < 6; row++)
{
gchar *text;
d = GCAL_DATE_CHOOSER_DAY (self->days[row][6]);
date = gcal_date_chooser_day_get_date (d);
text = g_strdup_printf ("%d", g_date_time_get_week_of_year (date));
gtk_label_set_label (GTK_LABEL (self->rows[row]), text);
g_free (text);
}
gcal_date_chooser_invalidate_day_options (self);
}
/* 0 == sunday */
static gchar *
calendar_get_weekday_name (gint i)
{
GDateTime *date;
gchar *formatted_date;
gchar *upcased_date;
gchar *text;
date = g_date_time_new_local (2015, 1, 4 + i, 1, 1, 1);
formatted_date = g_date_time_format (date, "%a");
g_date_time_unref (date);
upcased_date = g_utf8_strup (formatted_date, -1);
g_free (formatted_date);
text = g_utf8_substring (upcased_date, 0, 1);
g_free (upcased_date);
return text;
}
static void
calendar_init_weekday_display (GcalDateChooser *self)
{
gint i;
gchar *text;
for (i = 0; i < 7; i++)
{
text = calendar_get_weekday_name ((i + self->week_start) % 7);
gtk_label_set_label (GTK_LABEL (self->cols[i]), text);
g_free (text);
}
}
static gchar *
format_month (GcalMultiChoice *choice,
gint value,
gpointer data)
{
return g_strdup (gcal_get_month_name (value));
}
static void
calendar_init_month_display (GcalDateChooser *self)
{
gchar *months[13];
gchar *month;
gint i;
for (i = 0; i < 12; i++)
{
month = gcal_get_month_name (i);
months[i] = g_strdup (month);
}
months[12] = NULL;
gcal_multi_choice_set_choices (GCAL_MULTI_CHOICE (self->month_choice),
(const gchar**) months);
for (i = 0; i < 12; i++)
g_free (months[i]);
gcal_multi_choice_set_format_callback (GCAL_MULTI_CHOICE (self->month_choice),
format_month,
self,
NULL);
}
static void
calendar_update_selected_day_display (GcalDateChooser *self)
{
GcalDateChooserDay *d;
GDateTime *date;
gint row, col;
for (row = 0; row < 6; row++)
{
for (col = 0; col < 7; col++)
{
d = GCAL_DATE_CHOOSER_DAY (self->days[row][col]);
date = gcal_date_chooser_day_get_date (d);
gcal_date_chooser_day_set_selected (d, gcal_date_time_compare_date (date, self->date) == 0);
}
}
}
static void
calendar_update_selected_day (GcalDateChooser *self)
{
GDateTime *date;
gint month_len;
gint year, month, day;
g_date_time_get_ymd (self->date, &year, &month, &day);
month_len = month_length[leap (year)][month];
if (month_len < day)
{
date = g_date_time_new_local (year, month, month_len, 1, 1, 1);
gcal_date_chooser_set_date (self, date);
g_date_time_unref (date);
}
else
{
calendar_update_selected_day_display (self);
}
}
static void
day_selected_cb (GcalDateChooserDay *d,
GcalDateChooser *self)
{
gcal_date_chooser_set_date (self, gcal_date_chooser_day_get_date (d));
}
static void
calendar_set_property (GObject *obj,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GcalDateChooser *self = GCAL_DATE_CHOOSER (obj);
switch (property_id)
{
case PROP_DATE:
gcal_date_chooser_set_date (self, g_value_get_boxed (value));
break;
case PROP_SHOW_HEADING:
gcal_date_chooser_set_show_heading (self, g_value_get_boolean (value));
break;
case PROP_SHOW_DAY_NAMES:
gcal_date_chooser_set_show_day_names (self, g_value_get_boolean (value));
break;
case PROP_SHOW_WEEK_NUMBERS:
gcal_date_chooser_set_show_week_numbers (self, g_value_get_boolean (value));
break;
case PROP_NO_MONTH_CHANGE:
gcal_date_chooser_set_no_month_change (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
break;
}
}
static void
calendar_get_property (GObject *obj,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GcalDateChooser *self = GCAL_DATE_CHOOSER (obj);
switch (property_id)
{
case PROP_DATE:
g_value_set_boxed (value, self->date);
break;
case PROP_SHOW_HEADING:
g_value_set_boolean (value, self->show_heading);
break;
case PROP_SHOW_DAY_NAMES:
g_value_set_boolean (value, self->show_day_names);
break;
case PROP_SHOW_WEEK_NUMBERS:
g_value_set_boolean (value, self->show_week_numbers);
break;
case PROP_NO_MONTH_CHANGE:
g_value_set_boolean (value, self->no_month_change);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
break;
}
}
static void
multi_choice_changed (GcalDateChooser *self)
{
g_autoptr (GDateTime) date = NULL;
gint year, month, day;
year = gcal_multi_choice_get_value (GCAL_MULTI_CHOICE (self->year_choice));
month = gcal_multi_choice_get_value (GCAL_MULTI_CHOICE (self->month_choice)) + 1;
day = g_date_time_get_day_of_month (self->date);
/* Make sure the day is valid at that month */
day = MIN (day, month_length[leap (year)][month]);
date = g_date_time_new_local (year, month, day, 1, 1, 1);
gcal_date_chooser_set_date (self, date);
}
static void
calendar_drag_data_received (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
GtkSelectionData *selection_data,
guint info,
guint time)
{
GcalDateChooser *self = GCAL_DATE_CHOOSER (widget);
gchar *text;
GDate *gdate;
gint year, month, day;
GDateTime *date;
gdate = g_date_new ();
text = (gchar *)gtk_selection_data_get_text (selection_data);
if (text)
{
g_date_set_parse (gdate, text);
g_free (text);
}
if (!g_date_valid (gdate))
{
g_date_free (gdate);
gtk_drag_finish (context, FALSE, FALSE, time);
return;
}
year = g_date_get_year (gdate);
month = g_date_get_month (gdate);
day = g_date_get_day (gdate);
g_date_free (gdate);
gtk_drag_finish (context, TRUE, FALSE, time);
if (!self->show_heading || self->no_month_change)
g_date_time_get_ymd (self->date, &year, &month, NULL);
date = g_date_time_new_local (year, month, day, 1, 1, 1);
gcal_date_chooser_set_date (self, date);
g_date_time_unref (date);
}
static void
gcal_date_chooser_finalize (GObject *object)
{
GcalDateChooser *self = GCAL_DATE_CHOOSER (object);
g_clear_pointer (&self->date, g_date_time_unref);
G_OBJECT_CLASS (gcal_date_chooser_parent_class)->finalize (object);
}
static void
gcal_date_chooser_dispose (GObject *object)
{
G_OBJECT_CLASS (gcal_date_chooser_parent_class)->dispose (object);
}
static void
gcal_date_chooser_class_init (GcalDateChooserClass *class)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
GObjectClass *object_class = G_OBJECT_CLASS (class);
g_type_ensure (GCAL_TYPE_MULTI_CHOICE);
object_class->dispose = gcal_date_chooser_dispose;
object_class->finalize = gcal_date_chooser_finalize;
object_class->set_property = calendar_set_property;
object_class->get_property = calendar_get_property;
widget_class->drag_data_received = calendar_drag_data_received;
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/date-chooser.ui");
properties[PROP_DATE] = g_param_spec_boxed ("date",
"Date",
"The selected date",
G_TYPE_DATE_TIME,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
properties[PROP_SHOW_HEADING] = g_param_spec_boolean ("show-heading",
"Show Heading",
"If TRUE, a heading is displayed",
TRUE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
properties[PROP_SHOW_DAY_NAMES] = g_param_spec_boolean ("show-day-names",
"Show Day Names",
"If TRUE, day names are displayed",
TRUE,
G_PARAM_READWRITE);
properties[PROP_SHOW_WEEK_NUMBERS] = g_param_spec_boolean ("show-week-numbers",
"Show Week Numbers",
"If TRUE, week numbers are displayed",
TRUE,
G_PARAM_READWRITE);
properties[PROP_NO_MONTH_CHANGE] = g_param_spec_boolean ("no-month-change",
"No Month Change",
"If TRUE, the selected month cannot be changed",
FALSE,
G_PARAM_READWRITE);
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
signals[MONTH_CHANGED] = g_signal_new ("month-changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0,
NULL, NULL,
NULL,
G_TYPE_NONE, 0);
signals[DAY_SELECTED] = g_signal_new ("day-selected",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0,
NULL, NULL,
NULL,
G_TYPE_NONE, 0);
gtk_widget_class_bind_template_child (widget_class, GcalDateChooser, month_choice);
gtk_widget_class_bind_template_child (widget_class, GcalDateChooser, year_choice);
gtk_widget_class_bind_template_child (widget_class, GcalDateChooser, grid);
gtk_widget_class_bind_template_callback (widget_class, multi_choice_changed);
gtk_widget_class_set_css_name (widget_class, "datechooser");
}
static void
gcal_date_chooser_init (GcalDateChooser *self)
{
GtkWidget *label;
gint row, col;
gint year, month;
self->show_heading = TRUE;
self->show_day_names = TRUE;
self->show_week_numbers = TRUE;
self->no_month_change = FALSE;
self->date = g_date_time_new_now_local ();
g_date_time_get_ymd (self->date, &self->this_year, NULL, NULL);
self->week_start = get_first_weekday ();
gtk_widget_init_template (GTK_WIDGET (self));
for (col = 0; col < 7; col++)
{
self->cols[col] = gtk_label_new ("");
g_object_bind_property (self,
"show-day-names",
self->cols[col],
"visible",
G_BINDING_SYNC_CREATE);
gtk_style_context_add_class (gtk_widget_get_style_context (self->cols[col]), "weekday");
gtk_grid_attach (GTK_GRID (self->grid), self->cols[col], col, -1, 1, 1);
}
for (row = 0; row < 6; row++)
{
self->rows[row] = gtk_label_new ("");
g_object_bind_property (self,
"show-week-numbers",
self->rows[row],
"visible",
G_BINDING_SYNC_CREATE);
gtk_widget_show (self->rows[row]);
gtk_style_context_add_class (gtk_widget_get_style_context (self->rows[row]), "weeknum");
gtk_grid_attach (GTK_GRID (self->grid), self->rows[row], -1, row, 1, 1);
}
/* We are using a stack here to keep the week number column from shrinking
* when all the weeks are single-digit
*/
self->corner = gtk_stack_new ();
gtk_grid_attach (GTK_GRID (self->grid), self->corner, -1, -1, 1, 1);
label = gtk_label_new ("");
gtk_widget_show (label);
gtk_style_context_add_class (gtk_widget_get_style_context (label), "weekday");
gtk_container_add (GTK_CONTAINER (self->corner), label);
label = gtk_label_new ("99");
gtk_style_context_add_class (gtk_widget_get_style_context (label), "weeknum");
gtk_container_add (GTK_CONTAINER (self->corner), label);
self->day_grid = g_object_new (GTK_TYPE_GRID,
"valign", GTK_ALIGN_FILL,
"halign", GTK_ALIGN_FILL,
"row-spacing", 2,
"column-spacing", 2,
"visible", TRUE,
NULL);
gtk_grid_attach (GTK_GRID (self->grid), self->day_grid, 0, 0, 7, 6);
for (row = 0; row < 6; row++)
{
for (col = 0; col < 7; col++)
{
self->days[row][col] = gcal_date_chooser_day_new ();
g_signal_connect (self->days[row][col],
"selected",
G_CALLBACK (day_selected_cb),
self);
gtk_widget_show (self->days[row][col]);
gtk_grid_attach (GTK_GRID (self->day_grid), self->days[row][col], col, row, 1, 1);
}
}
calendar_init_month_display (self);
calendar_init_weekday_display (self);
calendar_compute_days (self);
g_date_time_get_ymd (self->date, &year, &month, NULL);
gcal_multi_choice_set_value (GCAL_MULTI_CHOICE (self->year_choice), year);
gcal_multi_choice_set_value (GCAL_MULTI_CHOICE (self->month_choice), month - 1);
calendar_update_selected_day_display (self);
gtk_drag_dest_set (GTK_WIDGET (self), GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY);
gtk_drag_dest_add_text_targets (GTK_WIDGET (self));
}
GtkWidget*
gcal_date_chooser_new (void)
{
return g_object_new (GCAL_TYPE_DATE_CHOOSER, NULL);
}
void
gcal_date_chooser_set_show_heading (GcalDateChooser *self,
gboolean setting)
{
if (self->show_heading == setting)
return;
self->show_heading = setting;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_HEADING]);
}
gboolean
gcal_date_chooser_get_show_heading (GcalDateChooser *self)
{
return self->show_heading;
}
void
gcal_date_chooser_set_show_day_names (GcalDateChooser *self,
gboolean setting)
{
if (self->show_day_names == setting)
return;
self->show_day_names = setting;
gtk_widget_set_visible (self->corner, self->show_day_names && self->show_week_numbers);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_DAY_NAMES]);
}
gboolean
gcal_date_chooser_get_show_day_names (GcalDateChooser *self)
{
return self->show_day_names;
}
void
gcal_date_chooser_set_show_week_numbers (GcalDateChooser *self,
gboolean setting)
{
if (self->show_week_numbers == setting)
return;
self->show_week_numbers = setting;
gtk_widget_set_visible (self->corner, self->show_day_names && self->show_week_numbers);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_WEEK_NUMBERS]);
}
gboolean
gcal_date_chooser_get_show_week_numbers (GcalDateChooser *self)
{
return self->show_week_numbers;
}
void
gcal_date_chooser_set_no_month_change (GcalDateChooser *self,
gboolean setting)
{
if (self->no_month_change == setting)
return;
self->no_month_change = setting;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_NO_MONTH_CHANGE]);
}
gboolean
gcal_date_chooser_get_no_month_change (GcalDateChooser *self)
{
return self->no_month_change;
}
void
gcal_date_chooser_set_date (GcalDateChooser *self,
GDateTime *date)
{
gint y1, m1, d1, y2, m2, d2;
g_object_freeze_notify (G_OBJECT (self));
g_date_time_get_ymd (self->date, &y1, &m1, &d1);
g_date_time_get_ymd (date, &y2, &m2, &d2);
g_date_time_unref (self->date);
self->date = g_date_time_ref (date);
if (y1 != y2 || m1 != m2)
{
gcal_multi_choice_set_value (GCAL_MULTI_CHOICE (self->year_choice), y2);
gcal_multi_choice_set_value (GCAL_MULTI_CHOICE (self->month_choice), m2 - 1);
calendar_compute_days (self);
}
if (y1 != y2 || m1 != m2 || d1 != d2)
{
calendar_update_selected_day (self);
g_signal_emit (self, signals[DAY_SELECTED], 0);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DATE]);
}
g_object_thaw_notify (G_OBJECT (self));
}
GDateTime *
gcal_date_chooser_get_date (GcalDateChooser *self)
{
return self->date;
}
void
gcal_date_chooser_set_day_options_callback (GcalDateChooser *self,
GcalDateChooserDayOptionsCallback callback,
gpointer data,
GDestroyNotify destroy)
{
if (self->day_options_destroy)
self->day_options_destroy (self->day_options_data);
self->day_options_cb = callback;
self->day_options_data = data;
self->day_options_destroy = destroy;
gcal_date_chooser_invalidate_day_options (self);
}
void
gcal_date_chooser_invalidate_day_options (GcalDateChooser *self)
{
GcalDateChooserDayOptions options;
GcalDateChooserDay *d;
GDateTime *date;
gint row, col;
for (row = 0; row < 6; row++)
{
for (col = 0; col < 7; col++)
{
d = GCAL_DATE_CHOOSER_DAY (self->days[row][col]);
date = gcal_date_chooser_day_get_date (d);
if (self->day_options_cb)
options = self->day_options_cb (self, date, self->day_options_data);
else
options = GCAL_DATE_CHOOSER_DAY_NONE;
gcal_date_chooser_day_set_options (d, options);
}
}
}
+77
View File
@@ -0,0 +1,77 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GCAL_DATE_CHOOSER_H__
#define __GCAL_DATE_CHOOSER_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
typedef enum
{
GCAL_DATE_CHOOSER_DAY_NONE = 1 << 0,
GCAL_DATE_CHOOSER_DAY_WEEKEND = 1 << 1,
GCAL_DATE_CHOOSER_DAY_HOLIDAY = 1 << 2,
GCAL_DATE_CHOOSER_DAY_MARKED = 1 << 3
} GcalDateChooserDayOptions;
#define GCAL_TYPE_DATE_CHOOSER (gcal_date_chooser_get_type ())
G_DECLARE_FINAL_TYPE (GcalDateChooser, gcal_date_chooser, GCAL, DATE_CHOOSER, GtkBin)
typedef GcalDateChooserDayOptions (*GcalDateChooserDayOptionsCallback) (GcalDateChooser *self,
GDateTime *date,
gpointer user_data);
GtkWidget* gcal_date_chooser_new (void);
GDateTime* gcal_date_chooser_get_date (GcalDateChooser *self);
void gcal_date_chooser_set_date (GcalDateChooser *self,
GDateTime *date);
void gcal_date_chooser_set_day_options_callback (GcalDateChooser *self,
GcalDateChooserDayOptionsCallback callback,
gpointer data,
GDestroyNotify destroy);
void gcal_date_chooser_invalidate_day_options (GcalDateChooser *self);
gboolean gcal_date_chooser_get_no_month_change (GcalDateChooser *self);
void gcal_date_chooser_set_no_month_change (GcalDateChooser *self,
gboolean setting);
gboolean gcal_date_chooser_get_show_heading (GcalDateChooser *self);
void gcal_date_chooser_set_show_heading (GcalDateChooser *self,
gboolean setting);
gboolean gcal_date_chooser_get_show_day_names (GcalDateChooser *self);
void gcal_date_chooser_set_show_day_names (GcalDateChooser *self,
gboolean setting);
gboolean gcal_date_chooser_get_show_week_numbers (GcalDateChooser *self);
void gcal_date_chooser_set_show_week_numbers (GcalDateChooser *self,
gboolean setting);
G_END_DECLS
#endif /* __GCAL_DATE_CHOOSER_H__ */
+284
View File
@@ -0,0 +1,284 @@
/* gcal-date-selector.c
*
* Copyright (C) 2014 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* gnome-calendar 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.
*
* gnome-calendar 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/>.
*/
#define G_LOG_DOMAIN "GcalDateSelector"
#include "gcal-date-chooser.h"
#include "gcal-date-selector.h"
#include <locale.h>
#include <langinfo.h>
#include <stdlib.h>
#include <glib/gi18n.h>
struct _GcalDateSelector
{
GtkEntry parent;
/* widgets */
GtkWidget *date_chooser;
GtkWidget *date_selector_popover;
GSettings *settings;
};
G_DEFINE_TYPE (GcalDateSelector, gcal_date_selector, GTK_TYPE_ENTRY);
enum
{
PROP_0,
PROP_DATE,
N_PROPS
};
static GParamSpec* properties[N_PROPS] = { NULL, };
static void
update_text (GcalDateSelector *self)
{
GDateTime *date;
gchar *label;
date = gcal_date_chooser_get_date (GCAL_DATE_CHOOSER (self->date_chooser));
/* rebuild the date label */
label = g_date_time_format (date, "%x");
gtk_entry_set_text (GTK_ENTRY (self), label);
g_free (label);
}
static void
calendar_day_selected (GcalDateSelector *self)
{
update_text (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DATE]);
}
static void
parse_date (GcalDateSelector *self)
{
GDateTime *new_date;
GDate parsed_date;
g_date_clear (&parsed_date, 1);
g_date_set_parse (&parsed_date, gtk_entry_get_text (GTK_ENTRY (self)));
if (!g_date_valid (&parsed_date))
{
update_text (self);
return;
}
new_date = g_date_time_new_local (g_date_get_year (&parsed_date),
g_date_get_month (&parsed_date),
g_date_get_day (&parsed_date),
0, 0, 0);
gcal_date_selector_set_date (self, new_date);
g_clear_pointer (&new_date, g_date_time_unref);
}
static void
icon_pressed_cb (GcalDateSelector *self,
GtkEntryIconPosition position,
GdkEvent *event)
{
GdkRectangle icon_bounds;
gtk_entry_get_icon_area (GTK_ENTRY (self), position, &icon_bounds);
gtk_popover_set_relative_to (GTK_POPOVER (self->date_selector_popover), GTK_WIDGET (self));
gtk_popover_set_pointing_to (GTK_POPOVER (self->date_selector_popover), &icon_bounds);
gtk_widget_show (self->date_selector_popover);
}
static void
gcal_date_selector_finalize (GObject *object)
{
GcalDateSelector *self = GCAL_DATE_SELECTOR (object);
g_clear_object (&self->settings);
G_OBJECT_CLASS (gcal_date_selector_parent_class)->finalize (object);
}
static void
gcal_date_selector_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GcalDateSelector *self = (GcalDateSelector*) object;
switch (prop_id)
{
case PROP_DATE:
g_value_set_boxed (value, gcal_date_chooser_get_date (GCAL_DATE_CHOOSER (self->date_chooser)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gcal_date_selector_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GcalDateSelector *self = (GcalDateSelector*) object;
switch (prop_id)
{
case PROP_DATE:
gcal_date_selector_set_date (self, g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static gboolean
gcal_date_selector_focus_in_event (GtkWidget *widget,
GdkEventFocus *event)
{
parse_date (GCAL_DATE_SELECTOR (widget));
return GTK_WIDGET_CLASS (gcal_date_selector_parent_class)->focus_in_event (widget, event);
}
static gboolean
gcal_date_selector_focus_out_event (GtkWidget *widget,
GdkEventFocus *event)
{
parse_date (GCAL_DATE_SELECTOR (widget));
return GTK_WIDGET_CLASS (gcal_date_selector_parent_class)->focus_out_event (widget, event);
}
static void
gcal_date_selector_activate (GtkEntry *entry)
{
parse_date (GCAL_DATE_SELECTOR (entry));
}
static void
gcal_date_selector_class_init (GcalDateSelectorClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GtkEntryClass *entry_class = GTK_ENTRY_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_ensure (GCAL_TYPE_DATE_CHOOSER);
object_class->finalize = gcal_date_selector_finalize;
object_class->get_property = gcal_date_selector_get_property;
object_class->set_property = gcal_date_selector_set_property;
widget_class->focus_in_event = gcal_date_selector_focus_in_event;
widget_class->focus_out_event = gcal_date_selector_focus_out_event;
entry_class->activate = gcal_date_selector_activate;
/**
* GcalDateSelector::date:
*
* The current date of the selector.
*/
properties[PROP_DATE] = g_param_spec_boxed ("date",
"Date of the selector",
"The current date of the selector",
G_TYPE_DATE_TIME,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, properties);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/date-selector.ui");
gtk_widget_class_bind_template_child (widget_class, GcalDateSelector, date_chooser);
gtk_widget_class_bind_template_child (widget_class, GcalDateSelector, date_selector_popover);
gtk_widget_class_bind_template_callback (widget_class, calendar_day_selected);
gtk_widget_class_bind_template_callback (widget_class, icon_pressed_cb);
}
static void
gcal_date_selector_init (GcalDateSelector *self)
{
gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
gtk_widget_init_template (GTK_WIDGET (self));
self->settings = g_settings_new ("org.gnome.desktop.calendar");
g_settings_bind (self->settings,
"show-weekdate",
self->date_chooser,
"show-week-numbers",
G_SETTINGS_BIND_DEFAULT);
}
/* Public API */
GtkWidget*
gcal_date_selector_new (void)
{
return g_object_new (GCAL_TYPE_DATE_SELECTOR, NULL);
}
/**
* gcal_date_selector_set_date:
* @selector: a #GcalDateSelector
* @date: a valid #GDateTime
*
* Set the value of the shown date.
*/
void
gcal_date_selector_set_date (GcalDateSelector *selector,
GDateTime *date)
{
g_return_if_fail (GCAL_IS_DATE_SELECTOR (selector));
/* set calendar's date */
gcal_date_chooser_set_date (GCAL_DATE_CHOOSER (selector->date_chooser), date);
update_text (selector);
/* emit the MODIFIED signal */
g_object_notify_by_pspec (G_OBJECT (selector), properties[PROP_DATE]);
}
/**
* gcal_date_selector_get_date:
* @selector: a #GcalDateSelector
*
* Get the value of the date shown
*
* Returns: (transfer none): the date of the selector.
*/
GDateTime*
gcal_date_selector_get_date (GcalDateSelector *selector)
{
g_return_val_if_fail (GCAL_IS_DATE_SELECTOR (selector), NULL);
return gcal_date_chooser_get_date (GCAL_DATE_CHOOSER (selector->date_chooser));
}
+39
View File
@@ -0,0 +1,39 @@
/* gcal-date-selector.h
*
* Copyright (C) 2015 Erick Pérez Castellanos <erickpc@gnome.org>
*
* gnome-calendar 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.
*
* gnome-calendar 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_DATE_SELECTOR_H__
#define __GCAL_DATE_SELECTOR_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GCAL_TYPE_DATE_SELECTOR (gcal_date_selector_get_type ())
G_DECLARE_FINAL_TYPE (GcalDateSelector, gcal_date_selector, GCAL, DATE_SELECTOR, GtkEntry)
GtkWidget* gcal_date_selector_new (void);
GDateTime* gcal_date_selector_get_date (GcalDateSelector *selector);
void gcal_date_selector_set_date (GcalDateSelector *selector,
GDateTime *date);
G_END_DECLS
#endif /* __GCAL_DATE_SELECTOR_H__ */
File diff suppressed because it is too large Load Diff
+53
View File
@@ -0,0 +1,53 @@
/* gcal-edit-dialog.h
*
* Copyright (C) 2015 Erick Pérez Castellanos <erickpc@gnome.org>
*
* gnome-calendar 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.
*
* gnome-calendar 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_EDIT_DIALOG_H__
#define __GCAL_EDIT_DIALOG_H__
#include "gcal-event.h"
#include "gcal-manager.h"
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GCAL_RESPONSE_DELETE_EVENT 2
#define GCAL_RESPONSE_SAVE_EVENT 4
#define GCAL_RESPONSE_CREATE_EVENT 6
#define GCAL_TYPE_EDIT_DIALOG (gcal_edit_dialog_get_type ())
G_DECLARE_FINAL_TYPE (GcalEditDialog, gcal_edit_dialog, GCAL, EDIT_DIALOG, GtkDialog);
GtkWidget* gcal_edit_dialog_new (void);
void gcal_edit_dialog_set_event_is_new (GcalEditDialog *dialog,
gboolean event_is_new);
GcalEvent* gcal_edit_dialog_get_event (GcalEditDialog *dialog);
void gcal_edit_dialog_set_event (GcalEditDialog *dialog,
GcalEvent *event);
gboolean gcal_edit_dialog_get_recurrence_changed (GcalEditDialog *self);
GcalRecurrenceModType gcal_edit_dialog_get_recurrence_mod_type (GcalEditDialog *self);
G_END_DECLS
#endif /* __GCAL_EDIT_DIALOG_H__ */
File diff suppressed because it is too large Load Diff
+71
View File
@@ -0,0 +1,71 @@
/* gcal-event-widget.h
*
* Copyright (C) 2015 Erick Pérez Castellanos <erickpc@gnome.org>
*
* gnome-calendar 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.
*
* gnome-calendar 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_EVENT_WIDGET_H__
#define __GCAL_EVENT_WIDGET_H__
#include "gcal-event.h"
#include "gcal-context.h"
#include <gtk/gtk.h>
#include <libical/icaltime.h>
G_BEGIN_DECLS
#define GCAL_TYPE_EVENT_WIDGET (gcal_event_widget_get_type ())
G_DECLARE_FINAL_TYPE (GcalEventWidget, gcal_event_widget, GCAL, EVENT_WIDGET, GtkBin)
GtkWidget* gcal_event_widget_new (GcalContext *context,
GcalEvent *event);
GcalEvent* gcal_event_widget_get_event (GcalEventWidget *self);
GDateTime* gcal_event_widget_get_date_start (GcalEventWidget *self);
void gcal_event_widget_set_date_start (GcalEventWidget *self,
GDateTime *date_start);
GDateTime* gcal_event_widget_get_date_end (GcalEventWidget *self);
void gcal_event_widget_set_date_end (GcalEventWidget *self,
GDateTime *date_end);
void gcal_event_widget_set_read_only (GcalEventWidget *event,
gboolean read_only);
/* Utilities */
GtkWidget* gcal_event_widget_clone (GcalEventWidget *widget);
gboolean gcal_event_widget_equal (GcalEventWidget *widget1,
GcalEventWidget *widget2);
gint gcal_event_widget_compare_by_length (GcalEventWidget *widget1,
GcalEventWidget *widget2);
gint gcal_event_widget_compare_by_start_date (GcalEventWidget *widget1,
GcalEventWidget *widget2);
gint gcal_event_widget_sort_events (GcalEventWidget *widget1,
GcalEventWidget *widget2);
G_END_DECLS
#endif /* __GCAL_EVENT_WIDGET_H__ */
+492
View File
@@ -0,0 +1,492 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#define G_LOG_DOMAIN "GcalMultiChoice"
#include "gcal-multi-choice.h"
struct _GcalMultiChoice
{
GtkBox parent;
GtkWidget *down_button;
GtkWidget *stack;
GtkWidget *up_button;
gint value;
gint min_value;
gint max_value;
gboolean wrap;
gboolean animate;
GtkWidget **choices;
gint n_choices;
guint click_id;
GtkWidget *active;
GtkWidget *label1;
GtkWidget *label2;
GcalMultiChoiceFormatCallback format_cb;
gpointer format_data;
GDestroyNotify format_destroy;
};
enum
{
PROP_VALUE = 1,
PROP_MIN_VALUE,
PROP_MAX_VALUE,
PROP_WRAP,
PROP_ANIMATE,
PROP_CHOICES,
NUM_PROPERTIES
};
enum
{
WRAPPED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0, };
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
G_DEFINE_TYPE (GcalMultiChoice, gcal_multi_choice, GTK_TYPE_BOX)
static gchar *
get_value_string (GcalMultiChoice *self,
gint value)
{
if (self->format_cb)
return self->format_cb (self, value, self->format_data);
else if (0 <= value && value < self->n_choices)
return g_strdup (gtk_label_get_label (GTK_LABEL (self->choices[value])));
else
return g_strdup_printf ("%d", value);
}
static void
set_value (GcalMultiChoice *self,
gint value,
GtkStackTransitionType transition)
{
GtkWidget *label;
const gchar *name;
gchar *text;
value = CLAMP (value, self->min_value, self->max_value);
if (self->value == value)
return;
self->value = value;
if (gtk_stack_get_visible_child (GTK_STACK (self->stack)) == self->label1)
{
name = "label2";
label = self->label2;
}
else
{
name = "label1";
label = self->label1;
}
text = get_value_string (self, value);
gtk_label_set_text (GTK_LABEL (label), text);
g_free (text);
if (!self->animate)
transition = GTK_STACK_TRANSITION_TYPE_NONE;
gtk_stack_set_visible_child_full (GTK_STACK (self->stack), name, transition);
gtk_widget_set_sensitive (self->down_button,
self->wrap || self->value > self->min_value);
gtk_widget_set_sensitive (self->up_button,
self->wrap || self->value < self->max_value);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VALUE]);
}
static void
go_up (GcalMultiChoice *self)
{
gboolean wrapped = FALSE;
gint value;
value = self->value + 1;
if (value > self->max_value)
{
if (!self->wrap)
return;
value = self->min_value;
wrapped = TRUE;
}
set_value (self, value, GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT);
if (wrapped)
g_signal_emit (self, signals[WRAPPED], 0);
}
static void
go_down (GcalMultiChoice *self)
{
gint value;
gboolean wrapped = FALSE;
value = self->value - 1;
if (value < self->min_value)
{
if (!self->wrap)
return;
value = self->max_value;
wrapped = TRUE;
}
set_value (self, value, GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT);
if (wrapped)
g_signal_emit (self, signals[WRAPPED], 0);
}
static gboolean
button_activate (GcalMultiChoice *self,
GtkWidget *button)
{
if (button == self->down_button)
go_down (self);
else if (button == self->up_button)
go_up (self);
else
g_assert_not_reached ();
return TRUE;
}
static gboolean
button_timeout (gpointer user_data)
{
GcalMultiChoice *self = GCAL_MULTI_CHOICE (user_data);
gboolean res;
if (self->click_id == 0)
return G_SOURCE_REMOVE;
if (!gtk_widget_get_mapped (self->down_button) && !gtk_widget_get_mapped (self->up_button))
{
if (self->click_id)
g_source_remove (self->click_id);
self->click_id = 0;
self->active = NULL;
return G_SOURCE_REMOVE;
}
res = button_activate (self, self->active);
if (!res)
{
g_source_remove (self->click_id);
self->click_id = 0;
}
return res;
}
static gboolean
button_press_cb (GtkWidget *widget,
GdkEventButton *button,
GcalMultiChoice *self)
{
gint double_click_time;
if (button->type != GDK_BUTTON_PRESS)
return TRUE;
g_object_get (gtk_widget_get_settings (widget),
"gtk-double-click-time", &double_click_time,
NULL);
if (self->click_id != 0)
g_source_remove (self->click_id);
self->active = widget;
self->click_id = gdk_threads_add_timeout (double_click_time,
button_timeout,
self);
g_source_set_name_by_id (self->click_id, "[gtk+] button_timeout");
button_timeout (self);
return TRUE;
}
static gboolean
button_release_cb (GtkWidget *widget,
GdkEventButton *event,
GcalMultiChoice *self)
{
if (self->click_id != 0)
{
g_source_remove (self->click_id);
self->click_id = 0;
}
self->active = NULL;
return TRUE;
}
static void
button_clicked_cb (GtkWidget *button,
GcalMultiChoice *self)
{
if (self->click_id != 0)
return;
button_activate (self, button);
}
static void
gcal_multi_choice_init (GcalMultiChoice *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
}
static void
gcal_multi_choice_dispose (GObject *object)
{
GcalMultiChoice *self = GCAL_MULTI_CHOICE (object);
if (self->click_id != 0)
{
g_source_remove (self->click_id);
self->click_id = 0;
}
g_free (self->choices);
self->choices = NULL;
if (self->format_destroy)
{
self->format_destroy (self->format_data);
self->format_destroy = NULL;
}
G_OBJECT_CLASS (gcal_multi_choice_parent_class)->dispose (object);
}
static void
gcal_multi_choice_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GcalMultiChoice *self = GCAL_MULTI_CHOICE (object);
switch (property_id)
{
case PROP_VALUE:
g_value_set_int (value, self->value);
break;
case PROP_MIN_VALUE:
g_value_set_int (value, self->min_value);
break;
case PROP_MAX_VALUE:
g_value_set_int (value, self->max_value);
break;
case PROP_WRAP:
g_value_set_boolean (value, self->wrap);
break;
case PROP_ANIMATE:
g_value_set_boolean (value, self->animate);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gcal_multi_choice_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GcalMultiChoice *self = GCAL_MULTI_CHOICE (object);
switch (property_id)
{
case PROP_VALUE:
gcal_multi_choice_set_value (self, g_value_get_int (value));
break;
case PROP_MIN_VALUE:
self->min_value = g_value_get_int (value);
g_object_notify_by_pspec (object, properties[PROP_MIN_VALUE]);
gcal_multi_choice_set_value (self, self->value);
break;
case PROP_MAX_VALUE:
self->max_value = g_value_get_int (value);
g_object_notify_by_pspec (object, properties[PROP_MAX_VALUE]);
gcal_multi_choice_set_value (self, self->value);
break;
case PROP_WRAP:
self->wrap = g_value_get_boolean (value);
g_object_notify_by_pspec (object, properties[PROP_WRAP]);
break;
case PROP_ANIMATE:
self->animate = g_value_get_boolean (value);
g_object_notify_by_pspec (object, properties[PROP_ANIMATE]);
break;
case PROP_CHOICES:
gcal_multi_choice_set_choices (self, (const gchar **)g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gcal_multi_choice_class_init (GcalMultiChoiceClass *class)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = gcal_multi_choice_dispose;
object_class->set_property = gcal_multi_choice_set_property;
object_class->get_property = gcal_multi_choice_get_property;
properties[PROP_VALUE] =
g_param_spec_int ("value", "Value", "Value",
G_MININT, G_MAXINT, 0,
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
properties[PROP_MIN_VALUE] =
g_param_spec_int ("min-value", "Minimum Value", "Minimum Value",
G_MININT, G_MAXINT, 0,
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
properties[PROP_MAX_VALUE] =
g_param_spec_int ("max-value", "Maximum Value", "Maximum Value",
G_MININT, G_MAXINT, 0,
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
properties[PROP_WRAP] =
g_param_spec_boolean ("wrap", "Wrap", "Wrap",
FALSE,
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
properties[PROP_ANIMATE] =
g_param_spec_boolean ("animate", "Animate", "Animate",
FALSE,
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
properties[PROP_CHOICES] =
g_param_spec_boxed ("choices", "Choices", "Choices",
G_TYPE_STRV,
G_PARAM_WRITABLE|G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
signals[WRAPPED] =
g_signal_new ("wrapped",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
NULL,
G_TYPE_NONE, 0);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/multi-choice.ui");
gtk_widget_class_bind_template_child (widget_class, GcalMultiChoice, down_button);
gtk_widget_class_bind_template_child (widget_class, GcalMultiChoice, up_button);
gtk_widget_class_bind_template_child (widget_class, GcalMultiChoice, stack);
gtk_widget_class_bind_template_child (widget_class, GcalMultiChoice, label1);
gtk_widget_class_bind_template_child (widget_class, GcalMultiChoice, label2);
gtk_widget_class_bind_template_callback (widget_class, button_clicked_cb);
gtk_widget_class_bind_template_callback (widget_class, button_press_cb);
gtk_widget_class_bind_template_callback (widget_class, button_release_cb);
gtk_widget_class_set_css_name (widget_class, "navigator");
}
GtkWidget *
gcal_multi_choice_new (void)
{
return GTK_WIDGET (g_object_new (GCAL_TYPE_MULTI_CHOICE, NULL));
}
void
gcal_multi_choice_set_value (GcalMultiChoice *self,
gint value)
{
set_value (self, value, GTK_STACK_TRANSITION_TYPE_NONE);
}
gint
gcal_multi_choice_get_value (GcalMultiChoice *self)
{
return self->value;
}
void
gcal_multi_choice_set_choices (GcalMultiChoice *self,
const gchar **choices)
{
gint i;
for (i = 0; i < self->n_choices; i++)
gtk_container_remove (GTK_CONTAINER (self->stack), self->choices[i]);
g_free (self->choices);
self->n_choices = g_strv_length ((gchar **)choices);
self->choices = g_new (GtkWidget *, self->n_choices);
for (i = 0; i < self->n_choices; i++)
{
self->choices[i] = gtk_label_new (choices[i]);
gtk_widget_show (self->choices[i]);
gtk_stack_add_named (GTK_STACK (self->stack),
self->choices[i],
choices[i]);
}
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CHOICES]);
}
void
gcal_multi_choice_set_format_callback (GcalMultiChoice *self,
GcalMultiChoiceFormatCallback callback,
gpointer user_data,
GDestroyNotify destroy)
{
if (self->format_destroy)
self->format_destroy (self->format_data);
self->format_cb = callback;
self->format_data = user_data;
self->format_destroy = destroy;
}
+51
View File
@@ -0,0 +1,51 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GCAL_MULTI_CHOICE_H
#define GCAL_MULTI_CHOICE_H
#include <gtk/gtk.h>
#include <glib-object.h>
G_BEGIN_DECLS
#define GCAL_TYPE_MULTI_CHOICE (gcal_multi_choice_get_type())
G_DECLARE_FINAL_TYPE (GcalMultiChoice, gcal_multi_choice, GCAL, MULTI_CHOICE, GtkBox)
GtkWidget* gcal_multi_choice_new (void);
gint gcal_multi_choice_get_value (GcalMultiChoice *self);
void gcal_multi_choice_set_value (GcalMultiChoice *self,
gint value);
void gcal_multi_choice_set_choices (GcalMultiChoice *self,
const gchar **selfs);
typedef gchar* (*GcalMultiChoiceFormatCallback) (GcalMultiChoice *self,
gint value,
gpointer user_data);
void gcal_multi_choice_set_format_callback (GcalMultiChoice *self,
GcalMultiChoiceFormatCallback callback,
gpointer user_data,
GDestroyNotify notify);
G_END_DECLS
#endif /* GCAL_MULTI_CHOICE_H */
File diff suppressed because it is too large Load Diff
+48
View File
@@ -0,0 +1,48 @@
/* gcal-quick-add-popover.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_QUICK_ADD_POPOVER_H
#define GCAL_QUICK_ADD_POPOVER_H
#include "gcal-context.h"
#include "gcal-event.h"
#include <glib.h>
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GCAL_TYPE_QUICK_ADD_POPOVER (gcal_quick_add_popover_get_type())
G_DECLARE_FINAL_TYPE (GcalQuickAddPopover, gcal_quick_add_popover, GCAL, QUICK_ADD_POPOVER, GtkPopover)
GtkWidget* gcal_quick_add_popover_new (void);
GDateTime* gcal_quick_add_popover_get_date_start (GcalQuickAddPopover *self);
void gcal_quick_add_popover_set_date_start (GcalQuickAddPopover *self,
GDateTime *dt);
GDateTime* gcal_quick_add_popover_get_date_end (GcalQuickAddPopover *self);
void gcal_quick_add_popover_set_date_end (GcalQuickAddPopover *self,
GDateTime *dt);
G_END_DECLS
#endif /* GCAL_QUICK_ADD_POPOVER_H */
File diff suppressed because it is too large Load Diff
+63
View File
@@ -0,0 +1,63 @@
/* gcal-source-manager.h
*
* Copyright (C) 2015 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_SOURCE_DIALOG_H
#define GCAL_SOURCE_DIALOG_H
#include <glib-object.h>
#include "gcal-application.h"
#include "gcal-manager.h"
#include <libecal/libecal.h>
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GCAL_RESPONSE_REMOVE_SOURCE 2
#define GCAL_TYPE_SOURCE_DIALOG (gcal_source_dialog_get_type())
G_DECLARE_FINAL_TYPE (GcalSourceDialog, gcal_source_dialog, GCAL, SOURCE_DIALOG, GtkDialog)
/**
* GcalSourceDialogMode:
* @GCAL_SOURCE_DIALOG_MODE_CREATE: creating a new calendar
* @GCAL_SOURCE_DIALOG_MODE_CREATE_WEB: creating a new web-based calendar
* @GCAL_SOURCE_DIALOG_MODE_EDIT: editing an existing calendar
* @GCAL_SOURCE_DIALOG_MODE_NORMAL: showing the list of calendars and online accounts
*
* The current action of the #GcalSourceDialog
*/
typedef enum
{
GCAL_SOURCE_DIALOG_MODE_CREATE,
GCAL_SOURCE_DIALOG_MODE_CREATE_WEB,
GCAL_SOURCE_DIALOG_MODE_EDIT,
GCAL_SOURCE_DIALOG_MODE_NORMAL
} GcalSourceDialogMode;
void gcal_source_dialog_set_mode (GcalSourceDialog *dialog,
GcalSourceDialogMode mode);
void gcal_source_dialog_set_source (GcalSourceDialog *dialog,
ESource *source);
G_END_DECLS
#endif /* GCAL_SOURCE_DIALOG_H */
+344
View File
@@ -0,0 +1,344 @@
/* gcal-time-selector.c
*
* Copyright (C) 2015 Erick Pérez Castellanos <erickpc@gnome.org>
* 2014 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* gnome-calendar 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.
*
* gnome-calendar 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/>.
*/
#define G_LOG_DOMAIN "GcalTimeSelector"
#include "gcal-time-selector.h"
#include <glib/gi18n.h>
struct _GcalTimeSelector
{
GtkMenuButton parent;
GtkAdjustment *hour_adjustment;
GtkAdjustment *minute_adjustment;
GtkWidget *time_label;
GtkWidget *hour_spin;
GtkWidget *minute_spin;
GtkWidget *period_combo;
GtkWidget *grid;
GDateTime *time;
GcalTimeFormat time_format;
};
enum
{
PROP_0,
PROP_TIME,
LAST_PROP
};
enum
{
AM,
PM
};
static void gcal_time_selector_constructed (GObject *object);
G_DEFINE_TYPE (GcalTimeSelector, gcal_time_selector, GTK_TYPE_MENU_BUTTON);
static void
update_label (GcalTimeSelector *selector)
{
gchar *new_label;
if (selector->time_format == GCAL_TIME_FORMAT_24H)
{
new_label = g_date_time_format (selector->time, "%H:%M");
}
else
{
gchar *time_str;
gint hour, minute, period;
hour = (gint) gtk_adjustment_get_value (selector->hour_adjustment);
minute = (gint) gtk_adjustment_get_value (selector->minute_adjustment);
period = gtk_combo_box_get_active (GTK_COMBO_BOX (selector->period_combo));
time_str = g_strdup_printf ("%.2d:%.2d", hour, minute);
if (period == AM)
new_label = g_strdup_printf (_("%s AM"), time_str);
else
new_label = g_strdup_printf (_("%s PM"), time_str);
g_free (time_str);
}
gtk_label_set_label (GTK_LABEL (selector->time_label), new_label);
g_clear_pointer (&new_label, g_free);
}
static void
update_time (GcalTimeSelector *selector)
{
GDateTime *now, *new_time;
gint hour, minute;
/* Retrieve current time */
hour = (gint) gtk_adjustment_get_value (selector->hour_adjustment);
minute = (gint) gtk_adjustment_get_value (selector->minute_adjustment);
if (selector->time_format == GCAL_TIME_FORMAT_12H)
{
hour = hour % 12;
if (gtk_combo_box_get_active (GTK_COMBO_BOX (selector->period_combo)) == PM)
{
g_signal_handlers_block_by_func (selector->period_combo, update_time, selector);
gtk_combo_box_set_active (GTK_COMBO_BOX (selector->period_combo), hour >= 12);
hour += 12;
g_signal_handlers_unblock_by_func (selector->period_combo, update_time, selector);
}
}
now = g_date_time_new_now_local ();
new_time = g_date_time_new_local (g_date_time_get_year (now),
g_date_time_get_month (now),
g_date_time_get_day_of_month (now),
hour, minute, 0);
/* Set the new time */
gcal_time_selector_set_time (selector, new_time);
g_clear_pointer (&new_time, g_date_time_unref);
g_clear_pointer (&now, g_date_time_unref);
}
static gboolean
on_output (GtkWidget *widget,
GcalTimeSelector *selector)
{
GtkAdjustment *adjustment;
gchar *text;
gint value;
adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (widget));
value = (gint) gtk_adjustment_get_value (adjustment);
text = g_strdup_printf ("%02d", value);
gtk_entry_set_text (GTK_ENTRY (widget), text);
g_free (text);
return TRUE;
}
static void
gcal_time_selector_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GcalTimeSelector *self = (GcalTimeSelector*) object;
switch (prop_id)
{
case PROP_TIME:
g_value_set_boxed (value, self->time);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gcal_time_selector_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GcalTimeSelector *self = (GcalTimeSelector*) object;
switch (prop_id)
{
case PROP_TIME:
gcal_time_selector_set_time (self, g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
void
gcal_time_selector_set_time_format (GcalTimeSelector *selector,
GcalTimeFormat time_format)
{
g_return_if_fail (GCAL_IS_TIME_SELECTOR (selector));
selector->time_format = time_format;
gtk_widget_set_visible (selector->period_combo, time_format == GCAL_TIME_FORMAT_12H);
if (time_format == GCAL_TIME_FORMAT_24H)
{
gtk_adjustment_set_lower (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (selector->hour_spin)), 0.0);
gtk_adjustment_set_upper (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (selector->hour_spin)), 23.0);
}
else
{
gtk_adjustment_set_lower (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (selector->hour_spin)), 1.0);
gtk_adjustment_set_upper (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (selector->hour_spin)), 12.0);
}
}
static void
gcal_time_selector_finalize (GObject *object)
{
GcalTimeSelector *self = GCAL_TIME_SELECTOR (object);
g_clear_pointer (&self->time, g_date_time_unref);
G_OBJECT_CLASS (gcal_time_selector_parent_class)->finalize (object);
}
static void
gcal_time_selector_dispose (GObject *object)
{
G_OBJECT_CLASS (gcal_time_selector_parent_class)->dispose (object);
}
static void
gcal_time_selector_class_init (GcalTimeSelectorClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
object_class->constructed = gcal_time_selector_constructed;
object_class->dispose = gcal_time_selector_dispose;
object_class->finalize = gcal_time_selector_finalize;
object_class->get_property = gcal_time_selector_get_property;
object_class->set_property = gcal_time_selector_set_property;
/**
* GcalTimeSelector::time:
*
* The current time of the selector.
*/
g_object_class_install_property (object_class,
PROP_TIME,
g_param_spec_boxed ("time",
"Time of the selector",
"The current time of the selector",
G_TYPE_DATE_TIME,
G_PARAM_READWRITE));
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass), "/org/gnome/calendar/time-selector.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GcalTimeSelector, time_label);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GcalTimeSelector, hour_adjustment);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GcalTimeSelector, hour_spin);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GcalTimeSelector, minute_adjustment);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GcalTimeSelector, minute_spin);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GcalTimeSelector, period_combo);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GcalTimeSelector, grid);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), on_output);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), update_time);
}
static void
gcal_time_selector_init (GcalTimeSelector *self)
{
self->time = g_date_time_new_now_local ();
gtk_widget_init_template (GTK_WIDGET (self));
}
static void
gcal_time_selector_constructed (GObject *object)
{
GcalTimeSelector *selector = GCAL_TIME_SELECTOR (object);
/* chaining up */
G_OBJECT_CLASS (gcal_time_selector_parent_class)->constructed (object);
gtk_widget_set_direction (selector->grid, GTK_TEXT_DIR_LTR);
}
/* Public API */
GtkWidget*
gcal_time_selector_new (void)
{
return g_object_new (GCAL_TYPE_TIME_SELECTOR, NULL);
}
void
gcal_time_selector_set_time (GcalTimeSelector *selector,
GDateTime *time)
{
g_return_if_fail (GCAL_IS_TIME_SELECTOR (selector));
if (selector->time != time)
{
gint hour, minute;
g_clear_pointer (&selector->time, g_date_time_unref);
selector->time = g_date_time_new_local (g_date_time_get_year (time),
g_date_time_get_month (time),
g_date_time_get_day_of_month (time),
g_date_time_get_hour (time),
g_date_time_get_minute (time),
0);
/* Update the spinners */
g_signal_handlers_block_by_func (selector->hour_adjustment, update_time, selector);
g_signal_handlers_block_by_func (selector->minute_adjustment, update_time, selector);
hour = g_date_time_get_hour (time);
minute = g_date_time_get_minute (time);
if (selector->time_format == GCAL_TIME_FORMAT_12H)
{
g_signal_handlers_block_by_func (selector->period_combo, update_time, selector);
gtk_combo_box_set_active (GTK_COMBO_BOX (selector->period_combo), hour >= 12);
hour = hour % 12;
hour = (hour == 0)? 12 : hour;
g_signal_handlers_unblock_by_func (selector->period_combo, update_time, selector);
}
gtk_adjustment_set_value (selector->hour_adjustment, hour);
gtk_adjustment_set_value (selector->minute_adjustment, minute);
update_label (selector);
g_signal_handlers_unblock_by_func (selector->hour_adjustment, update_time, selector);
g_signal_handlers_unblock_by_func (selector->minute_adjustment, update_time, selector);
g_object_notify (G_OBJECT (selector), "time");
}
}
GDateTime*
gcal_time_selector_get_time (GcalTimeSelector *selector)
{
g_return_val_if_fail (GCAL_IS_TIME_SELECTOR (selector), NULL);
return selector->time;
}
+44
View File
@@ -0,0 +1,44 @@
/* gcal-time-selector.h
*
* Copyright (C) 2015 Erick Pérez Castellanos <erickpc@gnome.org>
*
* gnome-calendar 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.
*
* gnome-calendar 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_TIME_SELECTOR_H__
#define __GCAL_TIME_SELECTOR_H__
#include "gcal-enums.h"
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GCAL_TYPE_TIME_SELECTOR (gcal_time_selector_get_type ())
G_DECLARE_FINAL_TYPE (GcalTimeSelector, gcal_time_selector, GCAL, TIME_SELECTOR, GtkMenuButton)
GtkWidget* gcal_time_selector_new (void);
void gcal_time_selector_set_time_format (GcalTimeSelector *selector,
GcalTimeFormat time_format);
GDateTime* gcal_time_selector_get_time (GcalTimeSelector *selector);
void gcal_time_selector_set_time (GcalTimeSelector *selector,
GDateTime *time);
G_END_DECLS
#endif /* __GCAL_TIME_SELECTOR_H__ */
File diff suppressed because it is too large Load Diff
+46
View File
@@ -0,0 +1,46 @@
/* gcal-window.h
*
* Copyright (C) 2015 Erick Pérez Castellanos <erickpc@gnome.org>
*
* gnome-calendar 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.
*
* gnome-calendar 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_WINDOW_H__
#define __GCAL_WINDOW_H__
#include "gcal-application.h"
#include "gcal-enums.h"
#include "gcal-utils.h"
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GCAL_TYPE_WINDOW (gcal_window_get_type ())
G_DECLARE_FINAL_TYPE (GcalWindow, gcal_window, GCAL, WINDOW, GtkApplicationWindow)
GtkWidget* gcal_window_new_with_date (GcalApplication *app,
GDateTime *date);
void gcal_window_set_search_query (GcalWindow *self,
const gchar *query);
void gcal_window_open_event_by_uuid (GcalWindow *self,
const gchar *uuid);
G_END_DECLS
#endif /* __GCAL_WINDOW_H__ */