project: Move GcalEditDialog and friends to src/gui/event-editor/
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/org/gnome/calendar/ui/event-editor">
|
||||
<file compressed="true">gcal-alarm-row.ui</file>
|
||||
<file compressed="true">gcal-date-chooser.ui</file>
|
||||
<file compressed="true">gcal-date-selector.ui</file>
|
||||
<file compressed="true">gcal-edit-dialog.ui</file>
|
||||
<file compressed="true">gcal-multi-choice.ui</file>
|
||||
<file compressed="true">gcal-time-selector.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
@@ -0,0 +1,367 @@
|
||||
/* gcal-alarm-row.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 "GcalAlarmRow"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "gcal-alarm-row.h"
|
||||
|
||||
struct _GcalAlarmRow
|
||||
{
|
||||
HdyActionRow parent;
|
||||
|
||||
GtkToggleButton *volume_button;
|
||||
GtkImage *volume_icon;
|
||||
|
||||
ECalComponentAlarm *alarm;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GcalAlarmRow, gcal_alarm_row, HDY_TYPE_ACTION_ROW)
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_ALARM,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
REMOVE_ALARM,
|
||||
N_SIGNALS,
|
||||
};
|
||||
|
||||
static guint signals [N_SIGNALS] = { 0, };
|
||||
static GParamSpec *properties [N_PROPS] = { NULL, };
|
||||
|
||||
/*
|
||||
* Auxiliary methods
|
||||
*/
|
||||
|
||||
static gchar*
|
||||
format_alarm_duration (ICalDuration *duration)
|
||||
{
|
||||
guint minutes;
|
||||
guint hours;
|
||||
guint days;
|
||||
|
||||
days = i_cal_duration_get_weeks (duration) * 7 + i_cal_duration_get_days (duration);
|
||||
hours = i_cal_duration_get_hours (duration);
|
||||
minutes = i_cal_duration_get_minutes (duration);
|
||||
|
||||
if (days > 0)
|
||||
{
|
||||
if (hours > 0)
|
||||
{
|
||||
if (minutes > 0)
|
||||
{
|
||||
/*
|
||||
* Translators: %1$u is days (in numbers), %2$u is hours (in numbers), and %3$u is minutes (in numbers).
|
||||
* The full sentence would be "X days, X hours, and X minutes before the event starts".
|
||||
*/
|
||||
const gchar *format = g_dngettext (GETTEXT_PACKAGE,
|
||||
g_dngettext (GETTEXT_PACKAGE,
|
||||
g_dngettext (GETTEXT_PACKAGE,
|
||||
"%1$u day, %2$u hour, and %3$u minute before",
|
||||
"%1$u day, %2$u hour, and %3$u minutes before",
|
||||
minutes),
|
||||
g_dngettext (GETTEXT_PACKAGE,
|
||||
"%1$u day, %2$u hours, and %3$u minute before",
|
||||
"%1$u day, %2$u hours, and %3$u minutes before",
|
||||
minutes),
|
||||
hours),
|
||||
g_dngettext (GETTEXT_PACKAGE,
|
||||
g_dngettext (GETTEXT_PACKAGE,
|
||||
"%1$u days, %2$u hour, and %3$u minute before",
|
||||
"%1$u days, %2$u hour, and %3$u minutes before",
|
||||
minutes),
|
||||
g_dngettext (GETTEXT_PACKAGE,
|
||||
"%1$u days, %2$u hours, and %3$u minute before",
|
||||
"%1$u days, %2$u hours, and %3$u minutes before",
|
||||
minutes),
|
||||
hours),
|
||||
days);
|
||||
return g_strdup_printf (format, days, hours, minutes);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Translators: %1$u is days (in numbers) and %2$u is hours (in numbers). The full sentence would be "X
|
||||
* days and X hours before the event starts".
|
||||
*/
|
||||
const gchar *format = g_dngettext (GETTEXT_PACKAGE,
|
||||
g_dngettext (GETTEXT_PACKAGE,
|
||||
"%1$u day and %2$u hour before",
|
||||
"%1$u day and %2$u hours before",
|
||||
hours),
|
||||
g_dngettext (GETTEXT_PACKAGE,
|
||||
"%1$u days and %2$u hour before",
|
||||
"%1$u days and %2$u hours before",
|
||||
hours),
|
||||
days);
|
||||
return g_strdup_printf (format, days, hours);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (minutes > 0)
|
||||
{
|
||||
/* Translators: %1$u is days (in numbers) and %2$u is minutes (in numbers). The full sentence would be "X
|
||||
* days and X hours before the event starts".
|
||||
*/
|
||||
const gchar *format = g_dngettext (GETTEXT_PACKAGE,
|
||||
g_dngettext (GETTEXT_PACKAGE,
|
||||
"%1$u day and %2$u minute before",
|
||||
"%1$u day and %2$u minutes before",
|
||||
minutes),
|
||||
g_dngettext (GETTEXT_PACKAGE,
|
||||
"%1$u days and %2$u minute before",
|
||||
"%1$u days and %2$u minutes before",
|
||||
minutes),
|
||||
days);
|
||||
return g_strdup_printf (format, days, minutes);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Translators: %1$u is days (in numbers). The full sentence would be "X days before the event starts". */
|
||||
const gchar *format = g_dngettext (GETTEXT_PACKAGE,
|
||||
"%1$u day before",
|
||||
"%1$u days before",
|
||||
days);
|
||||
return g_strdup_printf (format, days);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hours > 0)
|
||||
{
|
||||
if (minutes > 0)
|
||||
{
|
||||
/*
|
||||
* Translators: %1$u is hours (in numbers), and %2$u is minutes (in numbers). The full sentence would be
|
||||
* "X hours and X minutes before the event starts". */
|
||||
const gchar *format = g_dngettext (GETTEXT_PACKAGE,
|
||||
g_dngettext (GETTEXT_PACKAGE,
|
||||
"%1$u hour and %2$u minute before",
|
||||
"%1$u hour and %2$u minutes before",
|
||||
minutes),
|
||||
g_dngettext (GETTEXT_PACKAGE,
|
||||
"%1$u hours and %2$u minute before",
|
||||
"%1$u hours and %2$u minutes before",
|
||||
minutes),
|
||||
hours);
|
||||
return g_strdup_printf (format, hours, minutes);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Translators: %1$u is hours (in numbers). The full sentence would be "X hours before the event starts". */
|
||||
const gchar *format = g_dngettext (GETTEXT_PACKAGE,
|
||||
"%1$u hour before",
|
||||
"%1$u hours before",
|
||||
hours);
|
||||
return g_strdup_printf (format, hours);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (minutes > 0)
|
||||
{
|
||||
/* Translators: %1$u is minutes (in numbers). The full sentence would be "X minutes before the event starts". */
|
||||
const gchar *format = g_dngettext (GETTEXT_PACKAGE,
|
||||
"%1$u minute before",
|
||||
"%1$u minutes before",
|
||||
minutes);
|
||||
return g_strdup_printf (format, minutes);
|
||||
}
|
||||
else
|
||||
{
|
||||
return g_strdup (_("Event start time"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
setup_alarm (GcalAlarmRow *self)
|
||||
{
|
||||
g_autofree gchar *formatted_duration = NULL;
|
||||
ECalComponentAlarmTrigger *trigger;
|
||||
ECalComponentAlarmAction action;
|
||||
ICalDuration *duration;
|
||||
|
||||
trigger = e_cal_component_alarm_get_trigger (self->alarm);
|
||||
duration = e_cal_component_alarm_trigger_get_duration (trigger);
|
||||
formatted_duration = format_alarm_duration (duration);
|
||||
|
||||
hdy_preferences_row_set_title (HDY_PREFERENCES_ROW (self), formatted_duration);
|
||||
|
||||
action = e_cal_component_alarm_get_action (self->alarm);
|
||||
gtk_toggle_button_set_active (self->volume_button, action == E_CAL_COMPONENT_ALARM_AUDIO);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Callbacks
|
||||
*/
|
||||
|
||||
static void
|
||||
on_remove_button_clicked_cb (GtkButton *button,
|
||||
GcalAlarmRow *self)
|
||||
{
|
||||
g_signal_emit (self, signals[REMOVE_ALARM], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
on_sound_toggle_changed_cb (GtkToggleButton *button,
|
||||
GParamSpec *pspec,
|
||||
GcalAlarmRow *self)
|
||||
{
|
||||
ECalComponentAlarmAction action;
|
||||
gboolean has_sound;
|
||||
|
||||
has_sound = gtk_toggle_button_get_active (button);
|
||||
|
||||
/* Setup the alarm action */
|
||||
action = has_sound ? E_CAL_COMPONENT_ALARM_AUDIO : E_CAL_COMPONENT_ALARM_DISPLAY;
|
||||
|
||||
e_cal_component_alarm_set_action (self->alarm, action);
|
||||
|
||||
/* Update the volume icon */
|
||||
gtk_image_set_from_icon_name (self->volume_icon,
|
||||
has_sound ? "audio-volume-high-symbolic" : "audio-volume-muted-symbolic",
|
||||
GTK_ICON_SIZE_BUTTON);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* GObject overrides
|
||||
*/
|
||||
|
||||
static void
|
||||
gcal_alarm_row_finalize (GObject *object)
|
||||
{
|
||||
GcalAlarmRow *self = (GcalAlarmRow *)object;
|
||||
|
||||
g_clear_pointer (&self->alarm, e_cal_component_alarm_free);
|
||||
|
||||
G_OBJECT_CLASS (gcal_alarm_row_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gcal_alarm_row_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GcalAlarmRow *self = GCAL_ALARM_ROW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ALARM:
|
||||
g_value_set_pointer (value, self->alarm);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gcal_alarm_row_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GcalAlarmRow *self = GCAL_ALARM_ROW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ALARM:
|
||||
g_assert (self->alarm == NULL);
|
||||
self->alarm = e_cal_component_alarm_copy (g_value_get_pointer (value));
|
||||
setup_alarm (self);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gcal_alarm_row_class_init (GcalAlarmRowClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->finalize = gcal_alarm_row_finalize;
|
||||
object_class->get_property = gcal_alarm_row_get_property;
|
||||
object_class->set_property = gcal_alarm_row_set_property;
|
||||
|
||||
properties[PROP_ALARM] = g_param_spec_pointer ("alarm",
|
||||
"Alarm",
|
||||
"Alarm",
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
|
||||
signals[REMOVE_ALARM] = g_signal_new ("remove-alarm",
|
||||
GCAL_TYPE_ALARM_ROW,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/ui/event-editor/gcal-alarm-row.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (widget_class, GcalAlarmRow, volume_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, GcalAlarmRow, volume_icon);
|
||||
|
||||
gtk_widget_class_bind_template_callback (widget_class, on_remove_button_clicked_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, on_sound_toggle_changed_cb);
|
||||
}
|
||||
|
||||
static void
|
||||
gcal_alarm_row_init (GcalAlarmRow *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
GtkWidget*
|
||||
gcal_alarm_row_new (ECalComponentAlarm *alarm)
|
||||
{
|
||||
return g_object_new (GCAL_TYPE_ALARM_ROW,
|
||||
"alarm", alarm,
|
||||
NULL);
|
||||
}
|
||||
|
||||
ECalComponentAlarm*
|
||||
gcal_alarm_row_get_alarm (GcalAlarmRow *self)
|
||||
{
|
||||
g_return_val_if_fail (GCAL_IS_ALARM_ROW (self), NULL);
|
||||
|
||||
return self->alarm;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/* gcal-alarm-row.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 <handy.h>
|
||||
#include <libecal/libecal.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GCAL_TYPE_ALARM_ROW (gcal_alarm_row_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GcalAlarmRow, gcal_alarm_row, GCAL, ALARM_ROW, HdyActionRow)
|
||||
|
||||
GtkWidget* gcal_alarm_row_new (ECalComponentAlarm *alarm);
|
||||
|
||||
ECalComponentAlarm* gcal_alarm_row_get_alarm (GcalAlarmRow *self);
|
||||
|
||||
G_END_DECLS
|
||||
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GcalAlarmRow" parent="HdyActionRow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="volume_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="relief">none</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Toggles the sound of the alarm</property>
|
||||
<signal name="notify::active" handler="on_sound_toggle_changed_cb" object="GcalAlarmRow" swapped="no" />
|
||||
<child>
|
||||
<object class="GtkImage" id="volume_icon">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">audio-volume-high-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="remove_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="relief">none</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Remove the alarm</property>
|
||||
<signal name="clicked" handler="on_remove_button_clicked_cb" object="GcalAlarmRow" swapped="no" />
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">edit-delete-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@@ -0,0 +1,484 @@
|
||||
/* 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_object (self->multipress_gesture,
|
||||
"pressed",
|
||||
G_CALLBACK (day_pressed),
|
||||
self,
|
||||
0);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
@@ -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__ */
|
||||
@@ -0,0 +1,809 @@
|
||||
/* 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/ui/event-editor/gcal-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_object (self->days[row][col],
|
||||
"selected",
|
||||
G_CALLBACK (day_selected_cb),
|
||||
self,
|
||||
0);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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__ */
|
||||
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.16"/>
|
||||
<template class="GcalDateChooser" parent="GtkBin">
|
||||
<child>
|
||||
<object class="GtkGrid">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GcalMultiChoice" id="month_choice">
|
||||
<property name="visible" bind-source="GcalDateChooser" bind-property="show-heading" bind-flags="sync-create"/>
|
||||
<property name="halign">fill</property>
|
||||
<property name="min-value">0</property>
|
||||
<property name="max-value">11</property>
|
||||
<property name="animate">False</property>
|
||||
<property name="value">0</property>
|
||||
<signal name="notify::value" handler="multi_choice_changed" swapped="yes"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GcalMultiChoice" id="year_choice">
|
||||
<property name="visible" bind-source="GcalDateChooser" bind-property="show-heading" bind-flags="sync-create"/>
|
||||
<property name="halign">fill</property>
|
||||
<property name="min-value">0</property>
|
||||
<property name="max-value">120000</property>
|
||||
<property name="animate">False</property>
|
||||
<property name="value">0</property>
|
||||
<signal name="notify::value" handler="multi_choice_changed" swapped="yes"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid">
|
||||
<property name="visible">True</property>
|
||||
<property name="row-homogeneous">True</property>
|
||||
<property name="column-homogeneous">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@@ -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/ui/event-editor/gcal-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));
|
||||
}
|
||||
@@ -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__ */
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.12"/>
|
||||
<template class="GcalDateSelector" parent="GtkEntry">
|
||||
<property name="visible">True</property>
|
||||
<property name="width-chars">11</property>
|
||||
<property name="max-width-chars">11</property>
|
||||
<property name="secondary-icon-name">pan-down-symbolic</property>
|
||||
<property name="input-hints">no-emoji</property>
|
||||
<signal name="icon-press" handler="icon_pressed_cb" object="GcalDateSelector" swapped="no"/>
|
||||
</template>
|
||||
<object class="GtkPopover" id="date_selector_popover">
|
||||
<property name="position">bottom</property>
|
||||
<property name="border_width">12</property>
|
||||
<child>
|
||||
<object class="GcalDateChooser" id="date_chooser">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="show_week_numbers">True</property>
|
||||
<signal name="day-selected" handler="calendar_day_selected" object="GcalDateSelector" swapped="yes"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,52 @@
|
||||
/* 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"
|
||||
|
||||
|
||||
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__ */
|
||||
@@ -0,0 +1,666 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GcalEditDialog" parent="GtkDialog">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="resizable">False</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="default-width">450</property>
|
||||
<property name="window_position">center-on-parent</property>
|
||||
<property name="use_header_bar">1</property>
|
||||
<property name="destroy_with_parent">True</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="titlebar">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="cancel_button">
|
||||
<property name="label" translatable="yes">Cancel</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<signal name="clicked" handler="on_action_button_clicked_cb" object="GcalEditDialog" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage" id="lock">
|
||||
<property name="visible" bind-source="GcalEditDialog" bind-property="writable" bind-flags="default|invert-boolean" />
|
||||
<property name="icon_name">changes-prevent-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="title">
|
||||
<object class="GtkMenuButton" id="sources_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="popover">sources_popover</property>
|
||||
<property name="sensitive" bind-source="GcalEditDialog" bind-property="writable" bind-flags="default" />
|
||||
<property name="tooltip-text" translatable="yes">Click to select the calendar</property>
|
||||
<style>
|
||||
<class name="flat"/>
|
||||
<class name="sources-button"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="title_label_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="title_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="ellipsize">middle</property>
|
||||
<property name="max_width_chars">40</property>
|
||||
<property name="label" bind-source="summary_entry" bind-property="text" bind-flags="default" />
|
||||
<style>
|
||||
<class name="title"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="subtitle_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">horizontal</property>
|
||||
<property name="halign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="source_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<style>
|
||||
<class name="calendar-color-image"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="subtitle_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<style>
|
||||
<class name="subtitle"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="subtitle"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage" id="pan_down_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">pan-down-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="done_button">
|
||||
<property name="label" translatable="yes">Done</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<signal name="clicked" handler="on_action_button_clicked_cb" object="GcalEditDialog" swapped="no"/>
|
||||
<style>
|
||||
<class name="suggested-action"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkBox" id="dialog-vbox">
|
||||
<property name="visible">true</property>
|
||||
<property name="spacing">0</property>
|
||||
<property name="border_width">0</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolled_window">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hscrollbar_policy">never</property>
|
||||
<property name="min_content_height">400</property>
|
||||
<property name="propagate_natural_height">true</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="margin">18</property>
|
||||
<property name="spacing">12</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkListBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="selection-mode">none</property>
|
||||
<property name="sensitive" bind-source="GcalEditDialog" bind-property="writable" bind-flags="default" />
|
||||
|
||||
<style>
|
||||
<class name="frame" />
|
||||
</style>
|
||||
|
||||
<!-- Summary -->
|
||||
<child>
|
||||
<object class="HdyActionRow">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes">Title</property>
|
||||
<property name="activatable-widget">summary_entry</property>
|
||||
|
||||
<child>
|
||||
<object class="GtkEntry" id="summary_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="editable" bind-source="GcalEditDialog" bind-property="writable" bind-flags="default" />
|
||||
<property name="sensitive" bind-source="GcalEditDialog" bind-property="writable" bind-flags="default" />
|
||||
<signal name="notify::text" handler="on_summary_entry_changed_cb" object="GcalEditDialog" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- Location -->
|
||||
<child>
|
||||
<object class="HdyActionRow">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes">Location</property>
|
||||
<property name="activatable-widget">location_entry</property>
|
||||
|
||||
<child>
|
||||
<object class="GtkEntry" id="location_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="secondary_icon_name">find-location-symbolic</property>
|
||||
<property name="editable" bind-source="GcalEditDialog" bind-property="writable" bind-flags="default" />
|
||||
<property name="sensitive" bind-source="GcalEditDialog" bind-property="writable" bind-flags="default" />
|
||||
<signal name="notify::text" handler="on_location_entry_changed_cb" object="GcalEditDialog" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="margin-top">12</property>
|
||||
<property name="xalign">0.0</property>
|
||||
<property name="label" translatable="yes">Schedule</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold" />
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkListBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="selection-mode">none</property>
|
||||
<property name="sensitive" bind-source="GcalEditDialog" bind-property="writable" bind-flags="default" />
|
||||
|
||||
<style>
|
||||
<class name="frame" />
|
||||
</style>
|
||||
|
||||
<!-- All Day -->
|
||||
<child>
|
||||
<object class="HdyActionRow">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes">All Day</property>
|
||||
<property name="activatable-widget">all_day_switch</property>
|
||||
|
||||
<child>
|
||||
<object class="GtkSwitch" id="all_day_switch">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="sensitive" bind-source="GcalEditDialog" bind-property="writable" bind-flags="default" />
|
||||
<signal name="notify::active" handler="on_all_day_switch_active_changed_cb" object="GcalEditDialog" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- Start -->
|
||||
<child>
|
||||
<object class="HdyExpanderRow">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes">Starts</property>
|
||||
|
||||
<child>
|
||||
<object class="GtkLabel" id="event_start_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">1.0</property>
|
||||
<property name="label" translatable="yes">Check this out!</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="margin">12</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<object class="GcalDateSelector" id="start_date_selector">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="input-hints">no-emoji</property>
|
||||
<signal name="notify::date" handler="sync_datetimes" object="GcalEditDialog" swapped="yes" />
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GcalTimeSelector" id="start_time_selector">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<signal name="notify::time" handler="sync_datetimes" object="GcalEditDialog" swapped="yes" />
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- End -->
|
||||
<child>
|
||||
<object class="HdyExpanderRow">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes">Ends</property>
|
||||
|
||||
<child>
|
||||
<object class="GtkLabel" id="event_end_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">1.0</property>
|
||||
<property name="label" translatable="yes">Check this out!</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="margin">12</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<object class="GcalDateSelector" id="end_date_selector">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="input-hints">no-emoji</property>
|
||||
<signal name="notify::date" handler="sync_datetimes" object="GcalEditDialog" swapped="yes" />
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GcalTimeSelector" id="end_time_selector">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<signal name="notify::time" handler="sync_datetimes" object="GcalEditDialog" swapped="yes" />
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- Repeat -->
|
||||
<child>
|
||||
<object class="HdyActionRow">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes">Repeat</property>
|
||||
<property name="activatable-widget">repeat_combo</property>
|
||||
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="repeat_combo">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="valign">center</property>
|
||||
<signal name="changed" handler="on_repeat_type_changed_cb" object="GcalEditDialog" swapped="no"/>
|
||||
<property name="sensitive" bind-source="GcalEditDialog" bind-property="writable" bind-flags="default" />
|
||||
<items>
|
||||
<item translatable="yes" id="no_repeat">No Repeat</item>
|
||||
<item translatable="yes" id="daily">Daily</item>
|
||||
<item translatable="yes" id="mon_fri">Monday – Friday</item>
|
||||
<item translatable="yes" id="weekly">Weekly</item>
|
||||
<item translatable="yes" id="monthly">Monthly</item>
|
||||
<item translatable="yes" id="yearly">Yearly</item>
|
||||
</items>
|
||||
<property name="active_id">no_repeat</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- End Repeat -->
|
||||
<child>
|
||||
<object class="HdyActionRow">
|
||||
<property name="visible" bind-source="repeat_duration_combo" bind-property="visible" bind-flags="default" />
|
||||
<property name="title" translatable="yes">End Repeat</property>
|
||||
<property name="activatable-widget">repeat_combo</property>
|
||||
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="repeat_duration_combo">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="valign">center</property>
|
||||
<signal name="changed" handler="on_repeat_duration_changed_cb" object="GcalEditDialog" swapped="no"/>
|
||||
<items>
|
||||
<item translatable="yes" id="forever">Forever</item>
|
||||
<item translatable="yes" id="number_of_occurrences_spin">No. of occurrences</item>
|
||||
<item translatable="yes" id="until_date">Until Date</item>
|
||||
</items>
|
||||
<property name="active_id">forever</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- Number of Occurrences -->
|
||||
<child>
|
||||
<object class="HdyActionRow">
|
||||
<property name="visible" bind-source="number_of_occurrences_spin" bind-property="visible" bind-flags="default" />
|
||||
<property name="title" translatable="yes">Number of Occurrences</property>
|
||||
<property name="activatable-widget">number_of_occurrences_spin</property>
|
||||
|
||||
<child>
|
||||
<object class = "GtkSpinButton" id="number_of_occurrences_spin">
|
||||
<property name="input_purpose">number</property>
|
||||
<property name="input-hints">no-emoji</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- End Repeat Date -->
|
||||
<child>
|
||||
<object class="HdyActionRow">
|
||||
<property name="visible" bind-source="until_date_selector" bind-property="visible" bind-flags="default" />
|
||||
<property name="title" translatable="yes">End Repeat Date</property>
|
||||
<property name="activatable-widget">until_date_selector</property>
|
||||
|
||||
<child>
|
||||
<object class = "GcalDateSelector" id="until_date_selector">
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="margin-top">12</property>
|
||||
<property name="xalign">0.0</property>
|
||||
<property name="label" translatable="yes">Reminders</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold" />
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- Reminders -->
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
|
||||
<style>
|
||||
<class name="frame" />
|
||||
</style>
|
||||
|
||||
<child>
|
||||
<object class="GtkListBox" id="alarms_listbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="selection_mode">none</property>
|
||||
<signal name="row-activated" handler="on_alarms_listbox_row_activated_cb" object="GcalEditDialog" swapped="no" />
|
||||
<property name="sensitive" bind-source="GcalEditDialog" bind-property="writable" bind-flags="default" />
|
||||
|
||||
<child>
|
||||
<object class="GtkListBoxRow" id="new_alarm_row">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive" bind-source="GcalEditDialog" bind-property="writable" bind-flags="default" />
|
||||
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="margin">12</property>
|
||||
<property name="label" translatable="yes">Add a Reminder…</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- Notes -->
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="margin-top">12</property>
|
||||
<property name="xalign">0.0</property>
|
||||
<property name="label" translatable="yes">Notes</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold" />
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="min_content_height">120</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkTextView" id="notes_text">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="top_margin">6</property>
|
||||
<property name="bottom_margin">6</property>
|
||||
<property name="left_margin">6</property>
|
||||
<property name="right_margin">6</property>
|
||||
<property name="sensitive">True</property>
|
||||
<property name="editable" bind-source="GcalEditDialog" bind-property="writable" bind-flags="default" />
|
||||
<property name="cursor_visible" bind-source="GcalEditDialog" bind-property="writable" bind-flags="default" />
|
||||
<property name="wrap_mode">GTK_WRAP_WORD_CHAR</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
|
||||
<!-- Delete Button -->
|
||||
<child>
|
||||
<object class="GtkButton" id="delete_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="can_focus">True</property>
|
||||
<signal name="clicked" handler="on_action_button_clicked_cb" object="GcalEditDialog" swapped="no"/>
|
||||
<property name="sensitive" bind-source="GcalEditDialog" bind-property="writable" bind-flags="default" />
|
||||
<child>
|
||||
<object class="GtkLabel" id="delete_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Delete Event</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="destructive-action"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
<object class="GtkPopover" id="sources_popover">
|
||||
</object>
|
||||
<object class="GtkPopoverMenu" id="alarms_popover">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="width_request">175</property>
|
||||
<property name="relative-to">new_alarm_row</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">12</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkModelButton" id="five_minutes_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="text" translatable="yes">5 minutes</property>
|
||||
<signal name="clicked" handler="on_add_alarm_button_clicked_cb" object="GcalEditDialog" swapped="no" />
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkModelButton" id="ten_minutes_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="text" translatable="yes">10 minutes</property>
|
||||
<signal name="clicked" handler="on_add_alarm_button_clicked_cb" object="GcalEditDialog" swapped="no" />
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkModelButton" id="thirty_minutes_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="text" translatable="yes">30 minutes</property>
|
||||
<signal name="clicked" handler="on_add_alarm_button_clicked_cb" object="GcalEditDialog" swapped="no" />
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkModelButton" id="one_hour_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="text" translatable="yes">1 hour</property>
|
||||
<signal name="clicked" handler="on_add_alarm_button_clicked_cb" object="GcalEditDialog" swapped="no" />
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkModelButton" id="one_day_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="text" translatable="yes">1 day</property>
|
||||
<signal name="clicked" handler="on_add_alarm_button_clicked_cb" object="GcalEditDialog" swapped="no" />
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkModelButton" id="two_days_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="text" translatable="yes">2 days</property>
|
||||
<signal name="clicked" handler="on_add_alarm_button_clicked_cb" object="GcalEditDialog" swapped="no" />
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkModelButton" id="three_days_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="text" translatable="yes">3 days</property>
|
||||
<signal name="clicked" handler="on_add_alarm_button_clicked_cb" object="GcalEditDialog" swapped="no" />
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkModelButton" id="one_week_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="text" translatable="yes">1 week</property>
|
||||
<signal name="clicked" handler="on_add_alarm_button_clicked_cb" object="GcalEditDialog" swapped="no" />
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkSizeGroup">
|
||||
<property name="mode">vertical</property>
|
||||
<widgets>
|
||||
<widget name="cancel_button" />
|
||||
<widget name="done_button" />
|
||||
<widget name="sources_button" />
|
||||
</widgets>
|
||||
</object>
|
||||
<object class="GtkSizeGroup">
|
||||
<property name="mode">vertical</property>
|
||||
<widgets>
|
||||
<widget name="pan_down_image" />
|
||||
<widget name="title_label_box" />
|
||||
</widgets>
|
||||
</object>
|
||||
<object class="GtkSizeGroup">
|
||||
<property name="mode">horizontal</property>
|
||||
<widgets>
|
||||
<widget name="end_date_selector" />
|
||||
<widget name="end_time_selector" />
|
||||
<widget name="start_date_selector" />
|
||||
<widget name="start_time_selector" />
|
||||
</widgets>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -0,0 +1,501 @@
|
||||
/* 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
|
||||
apply_value (GcalMultiChoice *self,
|
||||
GtkStackTransitionType transition)
|
||||
{
|
||||
GtkWidget *label;
|
||||
const gchar *name;
|
||||
gchar *text;
|
||||
|
||||
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, 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);
|
||||
}
|
||||
|
||||
static void
|
||||
set_value (GcalMultiChoice *self,
|
||||
gint value,
|
||||
GtkStackTransitionType transition)
|
||||
{
|
||||
value = CLAMP (value, self->min_value, self->max_value);
|
||||
|
||||
if (self->value == value)
|
||||
return;
|
||||
|
||||
self->value = value;
|
||||
|
||||
apply_value (self, transition);
|
||||
|
||||
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/ui/event-editor/gcal-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;
|
||||
|
||||
apply_value (self, GTK_STACK_TRANSITION_TYPE_NONE);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface domain="gtk30">
|
||||
<requires lib="gtk+" version="3.16"/>
|
||||
<template class="GcalMultiChoice" parent="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="down_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="relief">none</property>
|
||||
<signal name="button-press-event" handler="button_press_cb"/>
|
||||
<signal name="button-release-event" handler="button_release_cb"/>
|
||||
<signal name="clicked" handler="button_clicked_cb"/>
|
||||
<style>
|
||||
<class name="image-button"/>
|
||||
<class name="back-button"/>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="icon_name">pan-start-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">label1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">label2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="up_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="relief">none</property>
|
||||
<signal name="button-press-event" handler="button_press_cb"/>
|
||||
<signal name="button-release-event" handler="button_release_cb"/>
|
||||
<signal name="clicked" handler="button_clicked_cb"/>
|
||||
<style>
|
||||
<class name="image-button"/>
|
||||
<class name="forward-button"/>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="icon_name">pan-end-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@@ -0,0 +1,290 @@
|
||||
/* 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
|
||||
{
|
||||
GtkBox parent;
|
||||
|
||||
GtkAdjustment *hour_adjustment;
|
||||
GtkAdjustment *minute_adjustment;
|
||||
|
||||
GtkWidget *hour_spin;
|
||||
GtkWidget *minute_spin;
|
||||
GtkWidget *period_combo;
|
||||
|
||||
GDateTime *time;
|
||||
|
||||
GcalTimeFormat time_format;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_TIME,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
AM,
|
||||
PM
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GcalTimeSelector, gcal_time_selector, GTK_TYPE_BOX);
|
||||
|
||||
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->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/ui/event-editor/gcal-time-selector.ui");
|
||||
|
||||
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_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));
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/* 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, GtkBox)
|
||||
|
||||
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__ */
|
||||
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GcalTimeSelector" parent="GtkBox">
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<!-- Hour -->
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="hour_spin">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="input_purpose">number</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="adjustment">hour_adjustment</property>
|
||||
<signal name="output" handler="on_output" object="GcalTimeSelector" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">:</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!-- Minute -->
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="minute_spin">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="input_purpose">number</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="adjustment">minute_adjustment</property>
|
||||
<signal name="output" handler="on_output" object="GcalTimeSelector" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
|
||||
<!-- AM/PM -->
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="period_combo">
|
||||
<property name="valign">center</property>
|
||||
<property name="active">0</property>
|
||||
<signal name="changed" handler="update_time" object="GcalTimeSelector" swapped="yes"/>
|
||||
<items>
|
||||
<item translatable="yes">AM</item>
|
||||
<item translatable="yes">PM</item>
|
||||
</items>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
|
||||
<object class="GtkAdjustment" id="hour_adjustment">
|
||||
<property name="upper">23</property>
|
||||
<property name="step_increment">1</property>
|
||||
<property name="page_increment">5</property>
|
||||
<signal name="value-changed" handler="update_time" object="GcalTimeSelector" swapped="yes"/>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="minute_adjustment">
|
||||
<property name="upper">59</property>
|
||||
<property name="step_increment">1</property>
|
||||
<property name="page_increment">10</property>
|
||||
<signal name="value-changed" handler="update_time" object="GcalTimeSelector" swapped="yes"/>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -0,0 +1,17 @@
|
||||
calendar_incs += include_directories('.')
|
||||
|
||||
built_sources += gnome.compile_resources(
|
||||
'event-editor-resources',
|
||||
'event-editor.gresource.xml',
|
||||
c_name: 'event_editor',
|
||||
)
|
||||
|
||||
sources += files(
|
||||
'gcal-alarm-row.c',
|
||||
'gcal-date-chooser.c',
|
||||
'gcal-date-chooser-day.c',
|
||||
'gcal-date-selector.c',
|
||||
'gcal-edit-dialog.c',
|
||||
'gcal-multi-choice.c',
|
||||
'gcal-time-selector.c',
|
||||
)
|
||||
Reference in New Issue
Block a user