1 /* gcal-time-selector.c
2  *
3  * Copyright (C) 2015 Erick Pérez Castellanos <erickpc@gnome.org>
4  *               2014 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
5  *
6  * gnome-calendar is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * gnome-calendar is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #define G_LOG_DOMAIN "GcalTimeSelector"
21 
22 #include "gcal-time-selector.h"
23 
24 #include <glib/gi18n.h>
25 
26 struct _GcalTimeSelector
27 {
28   GtkBox         parent;
29 
30   GtkAdjustment *hour_adjustment;
31   GtkAdjustment *minute_adjustment;
32 
33   GtkWidget *hour_spin;
34   GtkWidget *minute_spin;
35   GtkWidget *period_combo;
36 
37   GDateTime *time;
38 
39   GcalTimeFormat      time_format;
40 };
41 
42 enum
43 {
44   PROP_0,
45   PROP_TIME,
46   LAST_PROP
47 };
48 
49 enum
50 {
51   AM,
52   PM
53 };
54 
55 G_DEFINE_TYPE (GcalTimeSelector, gcal_time_selector, GTK_TYPE_BOX);
56 
57 static void
update_time(GcalTimeSelector * selector)58 update_time (GcalTimeSelector *selector)
59 {
60   GDateTime *now, *new_time;
61   gint hour, minute;
62 
63   /* Retrieve current time */
64   hour = (gint) gtk_adjustment_get_value (selector->hour_adjustment);
65   minute = (gint) gtk_adjustment_get_value (selector->minute_adjustment);
66 
67   if (selector->time_format == GCAL_TIME_FORMAT_12H)
68     {
69       hour = hour % 12;
70 
71       if (gtk_combo_box_get_active (GTK_COMBO_BOX (selector->period_combo)) == PM)
72         {
73           g_signal_handlers_block_by_func (selector->period_combo, update_time, selector);
74 
75           gtk_combo_box_set_active (GTK_COMBO_BOX (selector->period_combo), hour >= 12);
76           hour += 12;
77 
78           g_signal_handlers_unblock_by_func (selector->period_combo, update_time, selector);
79         }
80     }
81 
82   now = g_date_time_new_now_local ();
83   new_time = g_date_time_new_local (g_date_time_get_year (now),
84                                     g_date_time_get_month (now),
85                                     g_date_time_get_day_of_month (now),
86                                     hour, minute, 0);
87 
88   /* Set the new time */
89   gcal_time_selector_set_time (selector, new_time);
90 
91   g_clear_pointer (&new_time, g_date_time_unref);
92   g_clear_pointer (&now, g_date_time_unref);
93 }
94 
95 static gboolean
on_output(GtkWidget * widget,GcalTimeSelector * selector)96 on_output (GtkWidget        *widget,
97            GcalTimeSelector *selector)
98 {
99   GtkAdjustment *adjustment;
100   gchar *text;
101   gint value;
102 
103   adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (widget));
104   value = (gint) gtk_adjustment_get_value (adjustment);
105   text = g_strdup_printf ("%02d", value);
106   gtk_entry_set_text (GTK_ENTRY (widget), text);
107 
108   g_free (text);
109 
110   return TRUE;
111 }
112 
113 static void
gcal_time_selector_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)114 gcal_time_selector_get_property (GObject    *object,
115                                  guint       prop_id,
116                                  GValue     *value,
117                                  GParamSpec *pspec)
118 {
119   GcalTimeSelector *self = (GcalTimeSelector*) object;
120 
121   switch (prop_id)
122     {
123     case PROP_TIME:
124       g_value_set_boxed (value, self->time);
125       break;
126 
127     default:
128       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
129     }
130 }
131 
132 static void
gcal_time_selector_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)133 gcal_time_selector_set_property (GObject      *object,
134                                  guint         prop_id,
135                                  const GValue *value,
136                                  GParamSpec   *pspec)
137 {
138   GcalTimeSelector *self = (GcalTimeSelector*) object;
139 
140   switch (prop_id)
141     {
142     case PROP_TIME:
143       gcal_time_selector_set_time (self, g_value_get_boxed (value));
144       break;
145 
146     default:
147       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
148     }
149 }
150 
151 void
gcal_time_selector_set_time_format(GcalTimeSelector * selector,GcalTimeFormat time_format)152 gcal_time_selector_set_time_format (GcalTimeSelector *selector,
153                                     GcalTimeFormat    time_format)
154 {
155   g_return_if_fail (GCAL_IS_TIME_SELECTOR (selector));
156 
157   selector->time_format = time_format;
158   gtk_widget_set_visible (selector->period_combo, time_format == GCAL_TIME_FORMAT_12H);
159 
160   if (time_format == GCAL_TIME_FORMAT_24H)
161     {
162       gtk_adjustment_set_lower (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (selector->hour_spin)), 0.0);
163       gtk_adjustment_set_upper (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (selector->hour_spin)), 23.0);
164     }
165   else
166     {
167       gtk_adjustment_set_lower (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (selector->hour_spin)), 1.0);
168       gtk_adjustment_set_upper (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (selector->hour_spin)), 12.0);
169     }
170 }
171 
172 static void
gcal_time_selector_finalize(GObject * object)173 gcal_time_selector_finalize (GObject *object)
174 {
175   GcalTimeSelector *self = GCAL_TIME_SELECTOR (object);
176 
177   g_clear_pointer (&self->time, g_date_time_unref);
178   G_OBJECT_CLASS (gcal_time_selector_parent_class)->finalize (object);
179 }
180 
181 static void
gcal_time_selector_dispose(GObject * object)182 gcal_time_selector_dispose (GObject *object)
183 {
184   G_OBJECT_CLASS (gcal_time_selector_parent_class)->dispose (object);
185 }
186 
187 static void
gcal_time_selector_class_init(GcalTimeSelectorClass * klass)188 gcal_time_selector_class_init (GcalTimeSelectorClass *klass)
189 {
190   GObjectClass *object_class;
191 
192   object_class = G_OBJECT_CLASS (klass);
193   object_class->dispose = gcal_time_selector_dispose;
194   object_class->finalize = gcal_time_selector_finalize;
195   object_class->get_property = gcal_time_selector_get_property;
196   object_class->set_property = gcal_time_selector_set_property;
197 
198   /**
199    * GcalTimeSelector::time:
200    *
201    * The current time of the selector.
202    */
203   g_object_class_install_property (object_class,
204                                    PROP_TIME,
205                                    g_param_spec_boxed ("time",
206                                                        "Time of the selector",
207                                                        "The current time of the selector",
208                                                        G_TYPE_DATE_TIME,
209                                                        G_PARAM_READWRITE));
210 
211   gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass), "/org/gnome/calendar/ui/event-editor/gcal-time-selector.ui");
212 
213   gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GcalTimeSelector, hour_adjustment);
214   gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GcalTimeSelector, hour_spin);
215   gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GcalTimeSelector, minute_adjustment);
216   gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GcalTimeSelector, minute_spin);
217   gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GcalTimeSelector, period_combo);
218 
219   gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), on_output);
220   gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), update_time);
221 }
222 
223 static void
gcal_time_selector_init(GcalTimeSelector * self)224 gcal_time_selector_init (GcalTimeSelector *self)
225 {
226   self->time = g_date_time_new_now_local ();
227 
228   gtk_widget_init_template (GTK_WIDGET (self));
229 }
230 
231 /* Public API */
232 GtkWidget*
gcal_time_selector_new(void)233 gcal_time_selector_new (void)
234 {
235   return g_object_new (GCAL_TYPE_TIME_SELECTOR, NULL);
236 }
237 
238 void
gcal_time_selector_set_time(GcalTimeSelector * selector,GDateTime * time)239 gcal_time_selector_set_time (GcalTimeSelector *selector,
240                              GDateTime        *time)
241 {
242   g_return_if_fail (GCAL_IS_TIME_SELECTOR (selector));
243 
244   if (selector->time != time)
245     {
246       gint hour, minute;
247 
248       g_clear_pointer (&selector->time, g_date_time_unref);
249       selector->time = g_date_time_new_local (g_date_time_get_year (time),
250                                               g_date_time_get_month (time),
251                                               g_date_time_get_day_of_month (time),
252                                               g_date_time_get_hour (time),
253                                               g_date_time_get_minute (time),
254                                               0);
255 
256       /* Update the spinners */
257       g_signal_handlers_block_by_func (selector->hour_adjustment, update_time, selector);
258       g_signal_handlers_block_by_func (selector->minute_adjustment, update_time, selector);
259 
260       hour = g_date_time_get_hour (time);
261       minute = g_date_time_get_minute (time);
262 
263       if (selector->time_format == GCAL_TIME_FORMAT_12H)
264         {
265           g_signal_handlers_block_by_func (selector->period_combo, update_time, selector);
266 
267           gtk_combo_box_set_active (GTK_COMBO_BOX (selector->period_combo), hour >= 12);
268           hour =  hour % 12;
269           hour = (hour == 0)? 12 : hour;
270 
271           g_signal_handlers_unblock_by_func (selector->period_combo, update_time, selector);
272         }
273 
274       gtk_adjustment_set_value (selector->hour_adjustment, hour);
275       gtk_adjustment_set_value (selector->minute_adjustment, minute);
276 
277       g_signal_handlers_unblock_by_func (selector->hour_adjustment, update_time, selector);
278       g_signal_handlers_unblock_by_func (selector->minute_adjustment, update_time, selector);
279 
280       g_object_notify (G_OBJECT (selector), "time");
281     }
282 }
283 
284 GDateTime*
gcal_time_selector_get_time(GcalTimeSelector * selector)285 gcal_time_selector_get_time (GcalTimeSelector *selector)
286 {
287   g_return_val_if_fail (GCAL_IS_TIME_SELECTOR (selector), NULL);
288 
289   return selector->time;
290 }
291