[gtk+/wip/matthiasc/calendar: 1/2] wip: date chooser widget
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/matthiasc/calendar: 1/2] wip: date chooser widget
- Date: Mon, 31 Aug 2015 04:59:08 +0000 (UTC)
commit 26ab45a3e0f88f814b3f34a43f2dffd48ef3cb40
Author: Matthias Clasen <mclasen redhat com>
Date: Sun Aug 30 21:40:38 2015 -0400
wip: date chooser widget
gtk/Makefile.am | 5 +
gtk/gtk.h | 1 +
gtk/gtkdatechooserday.c | 359 ++++++++++++++
gtk/gtkdatechooserdayprivate.h | 53 +++
gtk/gtkdatechooserwidget.c | 1005 ++++++++++++++++++++++++++++++++++++++++
gtk/gtkdatechooserwidget.h | 93 ++++
gtk/ui/gtkdatechooserwidget.ui | 153 ++++++
7 files changed, 1669 insertions(+), 0 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 4fd509c..799c0b0 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -164,6 +164,7 @@ gtk_public_h_sources = \
gtkcontainer.h \
gtkcssprovider.h \
gtkcsssection.h \
+ gtkdatechooserwidget.h \
gtkdebug.h \
gtkdialog.h \
gtkdnd.h \
@@ -424,6 +425,7 @@ gtk_private_h_sources = \
gtkcssvalueprivate.h \
gtkcsswidgetnodeprivate.h \
gtkcustompaperunixdialog.h \
+ gtkdatechooserdayprivate.h \
gtkdialogprivate.h \
gtkdndprivate.h \
gtkentryprivate.h \
@@ -668,6 +670,8 @@ gtk_base_c_sources = \
gtkcsstypes.c \
gtkcssvalue.c \
gtkcsswidgetnode.c \
+ gtkdatechooserday.c \
+ gtkdatechooserwidget.c \
gtkdialog.c \
gtkdrawingarea.c \
gtkeditable.c \
@@ -1080,6 +1084,7 @@ templates = \
ui/gtkcolorchooserdialog.ui \
ui/gtkcoloreditor.ui \
ui/gtkcombobox.ui \
+ ui/gtkdatechooserwidget.ui \
ui/gtkdialog.ui \
ui/gtkfilechooserbutton.ui \
ui/gtkfilechooserwidget.ui \
diff --git a/gtk/gtk.h b/gtk/gtk.h
index 3cbd13f..0d85e4a 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -81,6 +81,7 @@
#include <gtk/gtkcontainer.h>
#include <gtk/gtkcssprovider.h>
#include <gtk/gtkcsssection.h>
+#include <gtk/gtkdatechooserwidget.h>
#include <gtk/gtkdebug.h>
#include <gtk/gtkdialog.h>
#include <gtk/gtkdnd.h>
diff --git a/gtk/gtkdatechooserday.c b/gtk/gtkdatechooserday.c
new file mode 100644
index 0000000..5e7c500
--- /dev/null
+++ b/gtk/gtkdatechooserday.c
@@ -0,0 +1,359 @@
+/* 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"
+
+#include "gtkdatechooserdayprivate.h"
+#include "gtklabel.h"
+#include "gtkgesturemultipress.h"
+#include "gtkrender.h"
+#include "gtkwidgetprivate.h"
+#include "gtkselection.h"
+#include "gtkdnd.h"
+
+#include "gtkintl.h"
+#include "gtkprivate.h"
+
+#include <stdlib.h>
+#include <langinfo.h>
+
+enum {
+ SELECTED,
+ LAST_DAY_SIGNAL
+};
+
+static guint day_signals[LAST_DAY_SIGNAL] = { 0, };
+
+struct _GtkDateChooserDay
+{
+ GtkBin parent;
+ GtkWidget *label;
+ guint day;
+ guint month;
+ guint year;
+ GdkWindow *event_window;
+ GtkGesture *multipress_gesture;
+};
+
+struct _GtkDateChooserDayClass
+{
+ GtkBinClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkDateChooserDay, gtk_date_chooser_day, GTK_TYPE_BIN)
+
+static void
+day_pressed (GtkGestureMultiPress *gesture,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ GtkDateChooserDay *day)
+{
+ 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 (day, day_signals[SELECTED], 0);
+ }
+}
+
+static gboolean
+gtk_date_chooser_day_key_press (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ GtkDateChooserDay *day = GTK_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 (day, day_signals[SELECTED], 0);
+ return TRUE;
+ }
+
+ if (GTK_WIDGET_CLASS (gtk_date_chooser_day_parent_class)->key_press_event (widget, event))
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+gtk_date_chooser_day_init (GtkDateChooserDay *day)
+{
+ GtkWidget *widget = GTK_WIDGET (day);
+
+ gtk_widget_set_can_focus (widget, TRUE);
+ gtk_style_context_add_class (gtk_widget_get_style_context (widget), "day");
+
+ day->label = gtk_label_new ("");
+ gtk_widget_show (day->label);
+ gtk_widget_set_hexpand (day->label, TRUE);
+ gtk_widget_set_vexpand (day->label, TRUE);
+ gtk_label_set_xalign (GTK_LABEL (day->label), 1.0);
+
+ gtk_container_add (GTK_CONTAINER (day), day->label);
+
+ day->multipress_gesture = gtk_gesture_multi_press_new (widget);
+ gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (day->multipress_gesture), 0);
+ g_signal_connect (day->multipress_gesture, "pressed",
+ G_CALLBACK (day_pressed), day);
+}
+
+static void
+gtk_date_chooser_day_dispose (GObject *object)
+{
+ GtkDateChooserDay *day = GTK_DATE_CHOOSER_DAY (object);
+
+ g_clear_object (&day->multipress_gesture);
+
+ G_OBJECT_CLASS (gtk_date_chooser_day_parent_class)->dispose (object);
+}
+
+static gboolean
+gtk_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_widget_get_state_flags (widget);
+
+ 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 (gtk_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
+gtk_date_chooser_day_map (GtkWidget *widget)
+{
+ GtkDateChooserDay *day = GTK_DATE_CHOOSER_DAY (widget);
+
+ GTK_WIDGET_CLASS (gtk_date_chooser_day_parent_class)->map (widget);
+
+ gdk_window_show (day->event_window);
+}
+
+static void
+gtk_date_chooser_day_unmap (GtkWidget *widget)
+{
+ GtkDateChooserDay *day = GTK_DATE_CHOOSER_DAY (widget);
+
+ gdk_window_hide (day->event_window);
+
+ GTK_WIDGET_CLASS (gtk_date_chooser_day_parent_class)->unmap (widget);
+}
+
+static void
+gtk_date_chooser_day_realize (GtkWidget *widget)
+{
+ GtkDateChooserDay *day = GTK_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;
+
+ 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);
+
+ day->event_window = gdk_window_new (window, &attributes, attributes_mask);
+ gtk_widget_register_window (widget, day->event_window);
+}
+
+static void
+gtk_date_chooser_day_unrealize (GtkWidget *widget)
+{
+ GtkDateChooserDay *day = GTK_DATE_CHOOSER_DAY (widget);
+
+ if (day->event_window)
+ {
+ gtk_widget_unregister_window (widget, day->event_window);
+ gdk_window_destroy (day->event_window);
+ day->event_window = NULL;
+ }
+
+ GTK_WIDGET_CLASS (gtk_date_chooser_day_parent_class)->unrealize (widget);
+}
+
+static void
+gtk_date_chooser_day_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GtkDateChooserDay *day = GTK_DATE_CHOOSER_DAY (widget);
+
+ GTK_WIDGET_CLASS (gtk_date_chooser_day_parent_class)->size_allocate (widget, allocation);
+
+ if (gtk_widget_get_realized (widget))
+ gdk_window_move_resize (day->event_window,
+ allocation->x,
+ allocation->y,
+ allocation->width,
+ allocation->height);
+}
+
+static void
+gtk_date_chooser_day_drag_data_get (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ GtkDateChooserDay *day = GTK_DATE_CHOOSER_DAY (widget);
+ GDateTime *dt;
+ gchar *text;
+
+ dt = g_date_time_new_local (day->year, day->month + 1 , day->day, 1, 1, 1);
+ text = g_date_time_format (dt, "%x");
+ gtk_selection_data_set_text (selection_data, text, -1);
+ g_free (text);
+ g_date_time_unref (dt);
+}
+
+static void
+gtk_date_chooser_day_class_init (GtkDateChooserDayClass *class)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->dispose = gtk_date_chooser_day_dispose;
+
+ widget_class->draw = gtk_date_chooser_day_draw;
+ widget_class->realize = gtk_date_chooser_day_realize;
+ widget_class->unrealize = gtk_date_chooser_day_unrealize;
+ widget_class->map = gtk_date_chooser_day_map;
+ widget_class->unmap = gtk_date_chooser_day_unmap;
+ widget_class->key_press_event = gtk_date_chooser_day_key_press;
+ widget_class->size_allocate = gtk_date_chooser_day_size_allocate;
+ widget_class->drag_data_get = gtk_date_chooser_day_drag_data_get;
+
+ day_signals[SELECTED] = g_signal_new (I_("selected"),
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+}
+
+GtkWidget *
+gtk_date_chooser_day_new (void)
+{
+ return GTK_WIDGET (g_object_new (GTK_TYPE_DATE_CHOOSER_DAY, NULL));
+}
+
+void
+gtk_date_chooser_day_set_date (GtkDateChooserDay *day,
+ guint y,
+ guint m,
+ guint d)
+{
+ gchar *text;
+
+ day->year = y;
+ day->month = m;
+ day->day = d;
+
+ text = g_strdup_printf ("%d", day->day);
+ gtk_label_set_label (GTK_LABEL (day->label), text);
+ g_free (text);
+}
+
+void
+gtk_date_chooser_day_get_date (GtkDateChooserDay *day,
+ guint *y,
+ guint *m,
+ guint *d)
+{
+ *y = day->year;
+ *m = day->month;
+ *d = day->day;
+}
+
+void
+gtk_date_chooser_day_set_other_month (GtkDateChooserDay *day,
+ gboolean other_month)
+{
+ GtkStyleContext *context;
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (day));
+ if (other_month)
+ {
+ gtk_style_context_add_class (context, "other-month");
+ gtk_drag_source_unset (GTK_WIDGET (day));
+ }
+ else
+ {
+ gtk_style_context_remove_class (context, "other-month");
+ gtk_drag_source_set (GTK_WIDGET (day),
+ GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
+ NULL, 0,
+ GDK_ACTION_COPY);
+ gtk_drag_source_add_text_targets (GTK_WIDGET (day));
+ }
+}
+
+void
+gtk_date_chooser_day_set_selected (GtkDateChooserDay *day,
+ gboolean selected)
+{
+ if (selected)
+ gtk_widget_set_state_flags (GTK_WIDGET (day), GTK_STATE_FLAG_SELECTED, FALSE);
+ else
+ gtk_widget_unset_state_flags (GTK_WIDGET (day), GTK_STATE_FLAG_SELECTED);
+}
diff --git a/gtk/gtkdatechooserdayprivate.h b/gtk/gtkdatechooserdayprivate.h
new file mode 100644
index 0000000..768dd74
--- /dev/null
+++ b/gtk/gtkdatechooserdayprivate.h
@@ -0,0 +1,53 @@
+/* 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 __GTK_DATE_CHOOSER_DAY_PRIVATE_H__
+#define __GTK_DATE_CHOOSER_DAY_PRIVATE_H__
+
+#include <gtk/gtkbin.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_DATE_CHOOSER_DAY (gtk_date_chooser_day_get_type ())
+#define GTK_DATE_CHOOSER_DAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
GTK_TYPE_DATE_CHOOSER_DAY, GtkDateChooserDay))
+#define GTK_DATE_CHOOSER_DAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),
GTK_TYPE_DATE_CHOOSER_DAY, GtkDateChooserDayClass))
+#define GTK_IS_DATE_CHOOSER_DAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
GTK_TYPE_DATE_CHOOSER_DAY))
+#define GTK_IS_DATE_CHOOSER_DAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),
GTK_TYPE_DATE_CHOOSER_DAY))
+#define GTK_DATE_CHOOSER_DAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
GTK_TYPE_DATE_CHOOSER_DAY, GtkDateChooserDayClass))
+
+
+typedef struct _GtkDateChooserDay GtkDateChooserDay;
+typedef struct _GtkDateChooserDayClass GtkDateChooserDayClass;
+
+GType gtk_date_chooser_day_get_type (void) G_GNUC_CONST;
+GtkWidget * gtk_date_chooser_day_new (void);
+void gtk_date_chooser_day_set_date (GtkDateChooserDay *widget,
+ guint year,
+ guint month,
+ guint day);
+void gtk_date_chooser_day_get_date (GtkDateChooserDay *widget,
+ guint *year,
+ guint *month,
+ guint *day);
+void gtk_date_chooser_day_set_other_month (GtkDateChooserDay *day,
+ gboolean other_month);
+void gtk_date_chooser_day_set_selected (GtkDateChooserDay *day,
+ gboolean selected);
+
+G_END_DECLS
+
+#endif /* __GTK_DATE_CHOOSER_DAY_PRIVATE_H__ */
diff --git a/gtk/gtkdatechooserwidget.c b/gtk/gtkdatechooserwidget.c
new file mode 100644
index 0000000..b834c61
--- /dev/null
+++ b/gtk/gtkdatechooserwidget.c
@@ -0,0 +1,1005 @@
+/* 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"
+
+#include "gtkdatechooserwidget.h"
+#include "gtkdatechooserdayprivate.h"
+#include "gtkstack.h"
+#include "gtklabel.h"
+#include "gtkgrid.h"
+#include "gtkselection.h"
+#include "gtkdnd.h"
+
+#include "gtkintl.h"
+#include "gtkprivate.h"
+
+#include <stdlib.h>
+#include <langinfo.h>
+
+
+enum {
+ MONTH_CHANGED,
+ DAY_SELECTED,
+ LAST_SIGNAL
+};
+
+static guint calendar_signals[LAST_SIGNAL] = { 0, };
+
+enum {
+ PROP_YEAR = 1,
+ PROP_MONTH,
+ PROP_DAY,
+ PROP_SHOW_HEADING,
+ PROP_SHOW_DAY_NAMES,
+ PROP_SHOW_WEEK_NUMBERS,
+ PROP_NO_MONTH_CHANGE,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *calendar_properties[NUM_PROPERTIES] = { NULL, };
+
+struct _GtkDateChooserWidget
+{
+ GtkBin parent;
+
+ GtkWidget *month_down_button;
+ GtkWidget *month_stack;
+ GtkWidget *month_up_button;
+ GtkWidget *year_down_button;
+ GtkWidget *year_stack;
+ GtkWidget *odd_year_label;
+ GtkWidget *even_year_label;
+ GtkWidget *year_up_button;
+ GtkWidget *grid;
+
+ guint click_id;
+ GtkWidget *active_button;
+
+ guint year_id;
+ GtkWidget *active_year_button;
+
+ GtkWidget *day_grid;
+ GtkWidget *corner;
+ GtkWidget *cols[7];
+ GtkWidget *rows[6];
+ GtkWidget *days[6][7];
+
+ guint month;
+ guint year;
+ guint day;
+
+ gint week_start;
+
+ gboolean show_heading;
+ gboolean show_day_names;
+ gboolean show_week_numbers;
+ gboolean no_month_change;
+};
+
+struct _GtkDateChooserWidgetClass
+{
+ GtkBinClass parent_class;
+};
+
+
+G_DEFINE_TYPE (GtkDateChooserWidget, gtk_date_chooser_widget, GTK_TYPE_BIN)
+
+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 guint
+day_of_week (guint year, guint mm, guint dd)
+{
+ GDateTime *dt;
+ guint days;
+
+ dt = g_date_time_new_local (year, mm, dd, 1, 1, 1);
+ if (dt == NULL)
+ return 0;
+
+ days = g_date_time_get_day_of_week (dt);
+ g_date_time_unref (dt);
+
+ return days;
+}
+
+static guint
+week_of_year (guint year, guint mm, guint dd)
+{
+ GDateTime *dt;
+ guint week;
+
+ dt = g_date_time_new_local (year, mm, dd, 1, 1, 1);
+ if (dt == NULL)
+ return 1;
+
+ week = g_date_time_get_week_of_year (dt);
+ g_date_time_unref (dt);
+
+ return week;
+}
+
+static void
+calendar_compute_days (GtkDateChooserWidget *calendar)
+{
+ guint year, month, day;
+ gint ndays_in_month;
+ gint ndays_in_prev_month;
+ gint first_day;
+ gint row;
+ gint col;
+ GtkDateChooserDay *d;
+
+ year = calendar->year;
+ month = calendar->month + 1;
+
+ ndays_in_month = month_length[leap (year)][month];
+
+ first_day = day_of_week (year, month, 1);
+ first_day = (first_day + 7 - calendar->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;
+
+ month = (calendar->month + 11) % 12;
+ year = calendar->year - (month == 11);
+
+ for (col = 0; col < first_day; col++)
+ {
+ d = GTK_DATE_CHOOSER_DAY (calendar->days[0][col]);
+ gtk_date_chooser_day_set_date (d, year, month, day);
+ gtk_date_chooser_day_set_other_month (d, TRUE);
+ day++;
+ }
+
+ /* Compute days of current month */
+ row = first_day / 7;
+ col = first_day % 7;
+
+ month = calendar->month;
+ year = calendar->year;
+
+ for (day = 1; day <= ndays_in_month; day++)
+ {
+ d = GTK_DATE_CHOOSER_DAY (calendar->days[row][col]);
+ gtk_date_chooser_day_set_date (d, year, month, day);
+ gtk_date_chooser_day_set_other_month (d, FALSE);
+
+ col++;
+ if (col == 7)
+ {
+ row++;
+ col = 0;
+ }
+ }
+
+ /* Compute days of next month */
+
+ month = (calendar->month + 1) % 12;
+ year = calendar->year + (month == 0);
+
+ day = 1;
+ for (; row < 6; row++)
+ {
+ for (; col < 7; col++)
+ {
+ d = GTK_DATE_CHOOSER_DAY (calendar->days[row][col]);
+ gtk_date_chooser_day_set_date (d, year, month, day);
+ gtk_date_chooser_day_set_other_month (d, TRUE);
+ day++;
+ }
+ col = 0;
+ }
+
+ /* update week numbers */
+ for (row = 0; row < 6; row++)
+ {
+ gchar *text;
+ guint week;
+
+ d = GTK_DATE_CHOOSER_DAY (calendar->days[row][6]);
+ gtk_date_chooser_day_get_date (d, &year, &month, &day);
+
+ week = week_of_year (year, month + 1, day);
+ text = g_strdup_printf ("%d", week);
+ gtk_label_set_label (GTK_LABEL (calendar->rows[row]), text);
+ g_free (text);
+ }
+}
+
+static const gchar *months[] = {
+ "jan", "feb", "mar", "apr",
+ "may", "jun", "jul", "aug",
+ "sep", "oct", "nov", "dec"
+};
+
+static void
+calendar_update_year_display (GtkDateChooserWidget *calendar)
+{
+ GtkWidget *label;
+ gchar *text;
+ GtkWidget *vis;
+
+ vis = gtk_stack_get_visible_child (GTK_STACK (calendar->year_stack));
+ if (vis == calendar->odd_year_label)
+ label = calendar->even_year_label;
+ else
+ label = calendar->odd_year_label;
+
+ text = g_strdup_printf ("%d", calendar->year);
+ gtk_label_set_label (GTK_LABEL (label), text);
+ g_free (text);
+
+ gtk_stack_set_visible_child (GTK_STACK (calendar->year_stack), label);
+}
+
+static void
+calendar_update_month_display (GtkDateChooserWidget *calendar,
+ GtkStackTransitionType transition)
+{
+ gtk_stack_set_visible_child_full (GTK_STACK (calendar->month_stack),
+ months[calendar->month],
+ transition);
+}
+
+static gchar *
+calendar_get_weekday_name (gint i)
+{
+ time_t time;
+ gchar buffer[128];
+
+ time = (i + 3) * 86400;
+ strftime (buffer, sizeof (buffer), "%a", gmtime (&time));
+ return g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
+}
+
+static gchar *
+calendar_get_month_name (gint i)
+{
+ time_t time;
+ gchar buffer[128];
+
+ time = i * 2764800;
+ strftime (buffer, sizeof (buffer), "%B", gmtime (&time));
+ return g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
+}
+
+static void
+calendar_init_weekday_display (GtkDateChooserWidget *calendar)
+{
+ gint i;
+ gchar *text;
+
+ for (i = 0; i < 7; i++)
+ {
+ text = calendar_get_weekday_name ((i + calendar->week_start) % 7);
+ gtk_label_set_label (GTK_LABEL (calendar->cols[i]), text);
+ g_free (text);
+ }
+}
+
+static void
+calendar_init_month_display (GtkDateChooserWidget *calendar)
+{
+ gint i;
+ GtkWidget *label;
+ gchar *text;
+
+ for (i = 0; i < 12; i++)
+ {
+ text = calendar_get_month_name (i);
+ label = gtk_label_new (text);
+ gtk_widget_show (label);
+ gtk_stack_add_named (GTK_STACK (calendar->month_stack), label, months[i]);
+ g_free (text);
+ }
+}
+
+static void
+calendar_update_selected_day_display (GtkDateChooserWidget *calendar)
+{
+ gint row, col;
+ GtkDateChooserDay *d;
+ guint year, month, day;
+
+ for (row = 0; row < 6; row++)
+ for (col = 0; col < 7; col++)
+ {
+ d = GTK_DATE_CHOOSER_DAY (calendar->days[row][col]);
+ gtk_date_chooser_day_get_date (d, &year, &month, &day);
+ gtk_date_chooser_day_set_selected (d, day == calendar->day &&
+ month == calendar->month &&
+ year == calendar->year);
+ }
+}
+
+static void
+calendar_update_selected_day (GtkDateChooserWidget *calendar)
+{
+ gint month_len;
+
+ month_len = month_length[leap (calendar->year)][calendar->month + 1];
+
+ if (month_len < calendar->day)
+ gtk_date_chooser_widget_select_day (calendar, month_len);
+ else
+ calendar_update_selected_day_display (calendar);
+}
+
+static void
+calendar_set_year_prev (GtkDateChooserWidget *calendar)
+{
+ if (calendar->no_month_change)
+ return;
+
+ calendar->year -= 1;
+ calendar_update_year_display (calendar);
+
+ calendar_compute_days (calendar);
+
+ g_signal_emit (calendar, calendar_signals[MONTH_CHANGED], 0);
+
+ calendar_update_selected_day (calendar);
+}
+
+static void
+calendar_set_year_next (GtkDateChooserWidget *calendar)
+{
+ if (calendar->no_month_change)
+ return;
+
+ calendar->year += 1;
+ calendar_update_year_display (calendar);
+
+ calendar_compute_days (calendar);
+
+ g_signal_emit (calendar, calendar_signals[MONTH_CHANGED], 0);
+
+ calendar_update_selected_day (calendar);
+}
+
+static void
+calendar_set_month_prev (GtkDateChooserWidget *calendar)
+{
+ if (calendar->no_month_change)
+ return;
+
+ calendar->month = (calendar->month + 11) % 12;
+ calendar_update_month_display (calendar, GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT);
+
+ if (calendar->month == 11)
+ {
+ calendar->year -= 1;
+ calendar_update_year_display (calendar);
+ }
+
+ calendar_compute_days (calendar);
+
+ g_signal_emit (calendar, calendar_signals[MONTH_CHANGED], 0);
+
+ calendar_update_selected_day (calendar);
+}
+
+static void
+calendar_set_month_next (GtkDateChooserWidget *calendar)
+{
+ if (calendar->no_month_change)
+ return;
+
+ calendar->month = (calendar->month + 1) % 12;
+ calendar_update_month_display (calendar, GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT);
+
+ if (calendar->month == 0)
+ {
+ calendar->year += 1;
+ calendar_update_year_display (calendar);
+ }
+
+ calendar_compute_days (calendar);
+
+ g_signal_emit (calendar, calendar_signals[MONTH_CHANGED], 0);
+
+ calendar_update_selected_day (calendar);
+}
+
+static gint
+calendar_get_week_start (void)
+{
+ union { unsigned int word; char *string; } langinfo;
+ gint week_1stday = 0;
+ gint first_weekday = 1;
+ guint week_origin;
+
+ langinfo.string = nl_langinfo (_NL_TIME_FIRST_WEEKDAY);
+ first_weekday = langinfo.string[0];
+ langinfo.string = nl_langinfo (_NL_TIME_WEEK_1STDAY);
+ week_origin = langinfo.word;
+ if (week_origin == 19971130) /* Sunday */
+ week_1stday = 0;
+ else if (week_origin == 19971201) /* Monday */
+ week_1stday = 1;
+ else
+ g_warning ("Unknown value of _NL_TIME_WEEK_1STDAY.\n");
+
+ return (week_1stday + first_weekday - 1) % 7;
+}
+
+static void
+day_selected_cb (GtkDateChooserDay *d,
+ GtkDateChooserWidget *calendar)
+{
+ guint year, month, day;
+
+ gtk_date_chooser_day_get_date (d, &year, &month, &day);
+
+ if ((month + 1) % 12 == calendar->month)
+ calendar_set_month_prev (calendar);
+ else if ((calendar->month + 1) % 12 == month)
+ calendar_set_month_next (calendar);
+
+ gtk_date_chooser_widget_select_day (calendar, day);
+}
+
+static void
+gtk_date_chooser_widget_init (GtkDateChooserWidget *calendar)
+{
+ gint row, col;
+ GDateTime *now;
+
+ calendar->show_heading = TRUE;
+ calendar->show_day_names = TRUE;
+ calendar->show_week_numbers = TRUE;
+ calendar->no_month_change = FALSE;
+
+ now = g_date_time_new_now_local ();
+ calendar->year = g_date_time_get_year (now);
+ calendar->month = g_date_time_get_month (now) - 1;
+ calendar->day = g_date_time_get_day_of_month (now);
+ g_date_time_unref (now);
+
+ calendar->week_start = calendar_get_week_start ();
+
+ gtk_widget_init_template (GTK_WIDGET (calendar));
+
+ for (col = 0; col < 7; col++)
+ {
+ calendar->cols[col] = gtk_label_new ("");
+ g_object_bind_property (calendar, "show-day-names",
+ calendar->cols[col], "visible",
+ G_BINDING_SYNC_CREATE);
+ gtk_style_context_add_class (gtk_widget_get_style_context (calendar->cols[col]), "weekday");
+ gtk_grid_attach (GTK_GRID (calendar->grid), calendar->cols[col], col, -1, 1, 1);
+ }
+
+ for (row = 0; row < 6; row++)
+ {
+ calendar->rows[row] = gtk_label_new ("");
+ g_object_bind_property (calendar, "show-week-numbers",
+ calendar->rows[row], "visible",
+ G_BINDING_SYNC_CREATE);
+ gtk_label_set_xalign (GTK_LABEL (calendar->rows[row]), 1.0);
+ gtk_widget_show (calendar->rows[row]);
+ gtk_style_context_add_class (gtk_widget_get_style_context (calendar->rows[row]), "weeknum");
+ gtk_grid_attach (GTK_GRID (calendar->grid), calendar->rows[row], -1, row, 1, 1);
+ }
+
+ calendar->corner = gtk_label_new ("");
+ gtk_style_context_add_class (gtk_widget_get_style_context (calendar->corner), "weekday");
+ gtk_grid_attach (GTK_GRID (calendar->grid), calendar->corner, -1, -1, 1, 1);
+
+ calendar->day_grid = gtk_grid_new ();
+ gtk_widget_show (calendar->day_grid);
+ gtk_widget_set_halign (calendar->day_grid, GTK_ALIGN_FILL);
+ gtk_widget_set_valign (calendar->day_grid, GTK_ALIGN_FILL);
+ gtk_grid_attach (GTK_GRID (calendar->grid), calendar->day_grid, 0, 0, 7, 6);
+
+ for (row = 0; row < 6; row++)
+ for (col = 0; col < 7; col++)
+ {
+ calendar->days[row][col] = gtk_date_chooser_day_new ();
+ g_signal_connect (calendar->days[row][col], "selected", G_CALLBACK (day_selected_cb), calendar);
+ gtk_widget_show (calendar->days[row][col]);
+ gtk_grid_attach (GTK_GRID (calendar->day_grid), calendar->days[row][col], col, row, 1, 1);
+ }
+
+ calendar_init_month_display (calendar);
+ calendar_init_weekday_display (calendar);
+
+ calendar_compute_days (calendar);
+ calendar_update_month_display (calendar, GTK_STACK_TRANSITION_TYPE_NONE);
+ calendar_update_year_display (calendar);
+ calendar_update_selected_day_display (calendar);
+
+ gtk_drag_dest_set (GTK_WIDGET (calendar), GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY);
+ gtk_drag_dest_add_text_targets (GTK_WIDGET (calendar));
+}
+
+static void
+calendar_set_property (GObject *obj,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkDateChooserWidget *calendar = GTK_DATE_CHOOSER_WIDGET (obj);
+
+ switch (property_id)
+ {
+ case PROP_YEAR:
+ gtk_date_chooser_widget_set_date (calendar, g_value_get_int (value), calendar->month, calendar->day);
+ break;
+ case PROP_MONTH:
+ gtk_date_chooser_widget_set_date (calendar, calendar->year, g_value_get_int (value), calendar->day);
+ break;
+ case PROP_DAY:
+ gtk_date_chooser_widget_set_date (calendar, calendar->year, calendar->month, g_value_get_int (value));
+ break;
+ case PROP_SHOW_HEADING:
+ gtk_date_chooser_widget_set_show_heading (calendar, g_value_get_boolean (value));
+ break;
+ case PROP_SHOW_DAY_NAMES:
+ gtk_date_chooser_widget_set_show_day_names (calendar, g_value_get_boolean (value));
+ break;
+ case PROP_SHOW_WEEK_NUMBERS:
+ gtk_date_chooser_widget_set_show_week_numbers (calendar, g_value_get_boolean (value));
+ break;
+ case PROP_NO_MONTH_CHANGE:
+ gtk_date_chooser_widget_set_no_month_change (calendar, 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)
+{
+ GtkDateChooserWidget *calendar = GTK_DATE_CHOOSER_WIDGET (obj);
+
+ switch (property_id)
+ {
+ case PROP_YEAR:
+ g_value_set_int (value, calendar->year);
+ break;
+ case PROP_MONTH:
+ g_value_set_int (value, calendar->month);
+ break;
+ case PROP_DAY:
+ g_value_set_int (value, calendar->day);
+ break;
+ case PROP_SHOW_HEADING:
+ g_value_set_boolean (value, calendar->show_heading);
+ break;
+ case PROP_SHOW_DAY_NAMES:
+ g_value_set_boolean (value, calendar->show_day_names);
+ break;
+ case PROP_SHOW_WEEK_NUMBERS:
+ g_value_set_boolean (value, calendar->show_week_numbers);
+ break;
+ case PROP_NO_MONTH_CHANGE:
+ g_value_set_boolean (value, calendar->no_month_change);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+calendar_button_activate (GtkDateChooserWidget *calendar,
+ GtkWidget *button)
+{
+ if (button == calendar->month_down_button)
+ calendar_set_month_prev (calendar);
+ else if (button == calendar->month_up_button)
+ calendar_set_month_next (calendar);
+ else if (button == calendar->year_down_button)
+ calendar_set_year_prev (calendar);
+ else if (button == calendar->year_up_button)
+ calendar_set_year_next (calendar);
+ else
+ g_assert_not_reached ();
+
+ return TRUE;
+}
+
+static gboolean
+calendar_button_timeout (gpointer user_data)
+{
+ GtkDateChooserWidget *calendar = GTK_DATE_CHOOSER_WIDGET (user_data);
+ gboolean res;
+
+ if (calendar->click_id == 0)
+ return G_SOURCE_REMOVE;
+
+ res = calendar_button_activate (calendar, calendar->active_button);
+ if (!res)
+ {
+ g_source_remove (calendar->click_id);
+ calendar->click_id = 0;
+ }
+
+ return res;
+}
+
+static gboolean
+calendar_button_press_cb (GtkWidget *widget,
+ GdkEventButton *button,
+ GtkDateChooserWidget *calendar)
+{
+ gint double_click_time;
+
+ g_object_get (gtk_widget_get_settings (widget),
+ "gtk-double-click-time", &double_click_time,
+ NULL);
+
+ if (calendar->click_id != 0)
+ g_source_remove (calendar->click_id);
+
+ calendar->active_button = widget;
+
+ calendar->click_id = gdk_threads_add_timeout (double_click_time,
+ calendar_button_timeout,
+ calendar);
+ g_source_set_name_by_id (calendar->click_id, "[gtk+] calendar_button_timeout");
+ calendar_button_timeout (calendar);
+
+ return TRUE;
+}
+
+static gboolean
+calendar_button_release_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ GtkDateChooserWidget *calendar)
+{
+ if (calendar->click_id != 0)
+ {
+ g_source_remove (calendar->click_id);
+ calendar->click_id = 0;
+ }
+
+ calendar->active_button = NULL;
+
+ return TRUE;
+}
+
+static void
+calendar_clicked_cb (GtkWidget *widget,
+ GtkDateChooserWidget *calendar)
+{
+ if (calendar->click_id != 0)
+ return;
+
+ calendar_button_activate (calendar, widget);
+}
+
+static void
+calendar_dispose (GObject *object)
+{
+ GtkDateChooserWidget *calendar = GTK_DATE_CHOOSER_WIDGET (object);
+
+ if (calendar->click_id != 0)
+ {
+ g_source_remove (calendar->click_id);
+ calendar->click_id = 0;
+ }
+
+ G_OBJECT_CLASS (gtk_date_chooser_widget_parent_class)->dispose (object);
+}
+
+static void
+calendar_drag_data_received (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ GtkDateChooserWidget *calendar = GTK_DATE_CHOOSER_WIDGET (widget);
+ gchar *text;
+ GDate *date;
+ guint year, month, day;
+
+ date = g_date_new ();
+ text = (gchar *)gtk_selection_data_get_text (selection_data);
+ if (text)
+ {
+ g_date_set_parse (date, text);
+ g_free (text);
+ }
+ if (!g_date_valid (date))
+ {
+ g_date_free (date);
+ gtk_drag_finish (context, FALSE, FALSE, time);
+ return;
+ }
+
+ year = g_date_get_year (date);
+ month = g_date_get_month (date) - 1;
+ day = g_date_get_day (date);
+
+ g_date_free (date);
+
+ gtk_drag_finish (context, TRUE, FALSE, time);
+
+ if (!calendar->show_heading || calendar->no_month_change)
+ {
+ year = calendar->year;
+ month = calendar->month;
+ }
+ gtk_date_chooser_widget_set_date (calendar, year, month, day);
+}
+
+static void
+gtk_date_chooser_widget_class_init (GtkDateChooserWidgetClass *class)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->dispose = calendar_dispose;
+ 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/gtk/libgtk/ui/gtkdatechooserwidget.ui");
+
+ calendar_properties[PROP_YEAR] =
+ g_param_spec_int ("year", P_("Year"), P_("The selected year"),
+ 0, G_MAXINT >> 9, 0,
+ G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+ calendar_properties[PROP_MONTH] =
+ g_param_spec_int ("month", P_("Month"), P_("The selected month (as a number between 0 and 11)"),
+ 0, 11, 0,
+ G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+ calendar_properties[PROP_DAY] =
+ g_param_spec_int ("day", P_("Day"), P_("The selected day (as a number between 1 and 31, or 0 to
unselect the currently selected day)"),
+ 0, 31, 0,
+ G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+ calendar_properties[PROP_SHOW_HEADING] =
+ g_param_spec_boolean ("show-heading", P_("Show Heading"), P_("If TRUE, a heading is displayed"),
+ TRUE, G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+ calendar_properties[PROP_SHOW_DAY_NAMES] =
+ g_param_spec_boolean ("show-day-names", P_("Show Day Names"), P_("If TRUE, day names are displayed"),
+ TRUE, G_PARAM_READWRITE);
+ calendar_properties[PROP_SHOW_WEEK_NUMBERS] =
+ g_param_spec_boolean ("show-week-numbers", P_("Show Week Numbers"), P_("If TRUE, week numbers are
displayed"),
+ TRUE, G_PARAM_READWRITE);
+ calendar_properties[PROP_NO_MONTH_CHANGE] =
+ g_param_spec_boolean ("no-month-change", P_("No Month Change"), P_("If TRUE, the selected month cannot
be changed"),
+ FALSE, G_PARAM_READWRITE);
+ g_object_class_install_properties (object_class, NUM_PROPERTIES, calendar_properties);
+
+ calendar_signals[MONTH_CHANGED] = g_signal_new (I_("month-changed"),
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+ calendar_signals[DAY_SELECTED] = g_signal_new (I_("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, GtkDateChooserWidget, month_down_button);
+ gtk_widget_class_bind_template_child (widget_class, GtkDateChooserWidget, month_stack);
+ gtk_widget_class_bind_template_child (widget_class, GtkDateChooserWidget, month_up_button);
+ gtk_widget_class_bind_template_child (widget_class, GtkDateChooserWidget, year_down_button);
+ gtk_widget_class_bind_template_child (widget_class, GtkDateChooserWidget, year_stack);
+ gtk_widget_class_bind_template_child (widget_class, GtkDateChooserWidget, odd_year_label);
+ gtk_widget_class_bind_template_child (widget_class, GtkDateChooserWidget, even_year_label);
+ gtk_widget_class_bind_template_child (widget_class, GtkDateChooserWidget, year_up_button);
+ gtk_widget_class_bind_template_child (widget_class, GtkDateChooserWidget, grid);
+
+ gtk_widget_class_bind_template_callback (widget_class, calendar_button_press_cb);
+ gtk_widget_class_bind_template_callback (widget_class, calendar_button_release_cb);
+ gtk_widget_class_bind_template_callback (widget_class, calendar_clicked_cb);
+}
+
+GtkWidget *
+gtk_date_chooser_widget_new (void)
+{
+ return GTK_WIDGET (g_object_new (GTK_TYPE_DATE_CHOOSER_WIDGET, NULL));
+}
+
+void
+gtk_date_chooser_widget_set_show_heading (GtkDateChooserWidget *calendar,
+ gboolean setting)
+{
+ if (calendar->show_heading == setting)
+ return;
+
+ calendar->show_heading = setting;
+
+ g_object_notify_by_pspec (G_OBJECT (calendar),
+ calendar_properties[PROP_SHOW_HEADING]);
+}
+
+gboolean
+gtk_date_chooser_widget_get_show_heading (GtkDateChooserWidget *calendar)
+{
+ return calendar->show_heading;
+}
+
+void
+gtk_date_chooser_widget_set_show_day_names (GtkDateChooserWidget *calendar,
+ gboolean setting)
+{
+ if (calendar->show_day_names == setting)
+ return;
+
+ calendar->show_day_names = setting;
+
+ gtk_widget_set_visible (calendar->corner, calendar->show_day_names && calendar->show_week_numbers);
+
+ g_object_notify_by_pspec (G_OBJECT (calendar),
+ calendar_properties[PROP_SHOW_DAY_NAMES]);
+}
+
+gboolean
+gtk_date_chooser_widget_get_show_day_names (GtkDateChooserWidget *calendar)
+{
+ return calendar->show_day_names;
+}
+
+void
+gtk_date_chooser_widget_set_show_week_numbers (GtkDateChooserWidget *calendar,
+ gboolean setting)
+{
+ if (calendar->show_week_numbers == setting)
+ return;
+
+ calendar->show_week_numbers = setting;
+
+ gtk_widget_set_visible (calendar->corner, calendar->show_day_names && calendar->show_week_numbers);
+
+ g_object_notify_by_pspec (G_OBJECT (calendar),
+ calendar_properties[PROP_SHOW_WEEK_NUMBERS]);
+}
+
+gboolean
+gtk_date_chooser_widget_get_show_week_numbers (GtkDateChooserWidget *calendar)
+{
+ return calendar->show_week_numbers;
+}
+
+void
+gtk_date_chooser_widget_set_no_month_change (GtkDateChooserWidget *calendar,
+ gboolean setting)
+{
+ if (calendar->no_month_change == setting)
+ return;
+
+ calendar->no_month_change = setting;
+
+ g_object_notify_by_pspec (G_OBJECT (calendar),
+ calendar_properties[PROP_NO_MONTH_CHANGE]);
+}
+
+gboolean
+gtk_date_chooser_widget_get_no_month_change (GtkDateChooserWidget *calendar)
+{
+ return calendar->no_month_change;
+}
+
+void
+gtk_date_chooser_widget_set_date (GtkDateChooserWidget *calendar,
+ guint year,
+ guint month,
+ guint day)
+{
+ gboolean month_changed = FALSE;
+ gboolean day_changed = FALSE;
+ g_object_freeze_notify (G_OBJECT (calendar));
+
+ if (calendar->year != year)
+ {
+ month_changed = TRUE;
+ calendar->year = year;
+ g_object_notify_by_pspec (G_OBJECT (calendar),
+ calendar_properties[PROP_YEAR]);
+ calendar_update_year_display (calendar);
+ }
+
+ if (calendar->month != month)
+ {
+ month_changed = TRUE;
+ calendar->month = month;
+ g_object_notify_by_pspec (G_OBJECT (calendar),
+ calendar_properties[PROP_MONTH]);
+ calendar_update_month_display (calendar, GTK_STACK_TRANSITION_TYPE_NONE);
+ }
+
+ if (calendar->day != day)
+ {
+ day_changed = TRUE;
+ calendar->day = day;
+ g_object_notify_by_pspec (G_OBJECT (calendar),
+ calendar_properties[PROP_DAY]);
+ }
+
+ if (month_changed)
+ calendar_compute_days (calendar);
+
+ if (month_changed || day_changed)
+ {
+ calendar_update_selected_day (calendar);
+ g_signal_emit (calendar, calendar_signals[DAY_SELECTED], 0);
+ }
+
+ g_object_thaw_notify (G_OBJECT (calendar));
+}
+
+void
+gtk_date_chooser_widget_select_month (GtkDateChooserWidget *calendar,
+ guint year,
+ guint month)
+{
+ gtk_date_chooser_widget_set_date (calendar, year, month, calendar->day);
+}
+
+void
+gtk_date_chooser_widget_select_day (GtkDateChooserWidget *calendar,
+ guint day)
+{
+ if (calendar->day == day)
+ return;
+
+ calendar->day = day;
+
+ calendar_update_selected_day_display (calendar);
+
+ g_signal_emit (calendar, calendar_signals[DAY_SELECTED], 0);
+ g_object_notify_by_pspec (G_OBJECT (calendar),
+ calendar_properties[PROP_DAY]);
+}
+
+void
+gtk_date_chooser_widget_get_date (GtkDateChooserWidget *calendar,
+ guint *year,
+ guint *month,
+ guint *day)
+{
+ *year = calendar->year;
+ *month = calendar->month;
+ *day = calendar->day;
+}
diff --git a/gtk/gtkdatechooserwidget.h b/gtk/gtkdatechooserwidget.h
new file mode 100644
index 0000000..9cd9f8f
--- /dev/null
+++ b/gtk/gtkdatechooserwidget.h
@@ -0,0 +1,93 @@
+/* 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 __GTK_DATE_CHOOSER_WIDGET_H__
+#define __GTK_DATE_CHOOSER_WIDGET_H__
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtkwidget.h>
+
+#ifndef GDK_AVAILABLE_IN_3_20
+#define GDK_AVAILABLE_IN_3_20 _GDK_EXTERN
+#endif
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_DATE_CHOOSER_WIDGET (gtk_date_chooser_widget_get_type ())
+#define GTK_DATE_CHOOSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
GTK_TYPE_DATE_CHOOSER_WIDGET, GtkDateChooserWidget))
+#define GTK_DATE_CHOOSER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),
GTK_TYPE_DATE_CHOOSER_WIDGET, GtkDateChooserWidgetClass))
+#define GTK_IS_DATE_CHOOSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
GTK_TYPE_DATE_CHOOSER_WIDGET))
+#define GTK_IS_DATE_CHOOSER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),
GTK_TYPE_DATE_CHOOSER_WIDGET))
+#define GTK_DATE_CHOOSER_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
GTK_TYPE_DATE_CHOOSER_WIDGET, GtkDateChooserWidgetClass))
+
+typedef struct _GtkDateChooserWidget GtkDateChooserWidget;
+typedef struct _GtkDateChooserWidgetClass GtkDateChooserWidgetClass;
+
+GDK_AVAILABLE_IN_3_20
+GType gtk_date_chooser_widget_get_type (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_3_20
+GtkWidget * gtk_date_chooser_widget_new (void);
+
+
+GDK_AVAILABLE_IN_3_20
+void gtk_date_chooser_widget_select_month (GtkDateChooserWidget *chooser,
+ guint year,
+ guint month);
+
+GDK_AVAILABLE_IN_3_20
+void gtk_date_chooser_widget_select_day (GtkDateChooserWidget *chooser,
+ guint day);
+
+GDK_AVAILABLE_IN_3_20
+void gtk_date_chooser_widget_set_date (GtkDateChooserWidget *chooser,
+ guint year,
+ guint month,
+ guint day);
+GDK_AVAILABLE_IN_3_20
+void gtk_date_chooser_widget_get_date (GtkDateChooserWidget *chooser,
+ guint *year,
+ guint *month,
+ guint *day);
+
+
+void gtk_date_chooser_widget_set_no_month_change (GtkDateChooserWidget *chooser,
+ gboolean setting);
+
+GDK_AVAILABLE_IN_3_20
+void gtk_date_chooser_widget_set_show_heading (GtkDateChooserWidget *chooser,
+ gboolean setting);
+GDK_AVAILABLE_IN_3_20
+gboolean gtk_date_chooser_widget_get_show_heading (GtkDateChooserWidget *chooser);
+GDK_AVAILABLE_IN_3_20
+void gtk_date_chooser_widget_set_show_day_names (GtkDateChooserWidget *chooser,
+ gboolean setting);
+GDK_AVAILABLE_IN_3_20
+gboolean gtk_date_chooser_widget_get_show_day_names (GtkDateChooserWidget *chooser);
+
+GDK_AVAILABLE_IN_3_20
+void gtk_date_chooser_widget_set_show_week_numbers (GtkDateChooserWidget *chooser,
+ gboolean setting);
+GDK_AVAILABLE_IN_3_20
+gboolean gtk_date_chooser_widget_get_show_week_numbers (GtkDateChooserWidget *chooser);
+
+G_END_DECLS
+
+#endif /* __GTK_DATE_CHOOSER_WIDGET_H__ */
diff --git a/gtk/ui/gtkdatechooserwidget.ui b/gtk/ui/gtkdatechooserwidget.ui
new file mode 100644
index 0000000..3dc7e9f
--- /dev/null
+++ b/gtk/ui/gtkdatechooserwidget.ui
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.1 -->
+<interface>
+ <requires lib="gtk+" version="3.16"/>
+ <template class="GtkDateChooserWidget" parent="GtkBin">
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible" bind-source="GtkDateChooserWidget" bind-property="show-heading"
bind-flags="sync-create"/>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="halign">start</property>
+ <child>
+ <object class="GtkButton" id="month_down_button">
+ <property name="visible" bind-source="GtkDateChooserWidget"
bind-property="no-month-change" bind-flags="sync-create|invert-boolean"/>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ <signal name="button-press-event" handler="calendar_button_press_cb"/>
+ <signal name="button-release-event" handler="calendar_button_release_cb"/>
+ <signal name="clicked" handler="calendar_clicked_cb"/>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon_name">pan-start-symbolic</property>
+ </object>
+ </child>
+ <style>
+ <class name="image-button"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStack" id="month_stack">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="month_up_button">
+ <property name="visible" bind-source="GtkDateChooserWidget"
bind-property="no-month-change" bind-flags="sync-create|invert-boolean"/>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ <signal name="button-press-event" handler="calendar_button_press_cb"/>
+ <signal name="button-release-event" handler="calendar_button_release_cb"/>
+ <signal name="clicked" handler="calendar_clicked_cb"/>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon_name">pan-end-symbolic</property>
+ </object>
+ </child>
+ <style>
+ <class name="image-button"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="halign">end</property>
+ <child>
+ <object class="GtkButton" id="year_down_button">
+ <property name="visible" bind-source="GtkDateChooserWidget"
bind-property="no-month-change" bind-flags="sync-create|invert-boolean"/>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ <signal name="button-press-event" handler="calendar_button_press_cb"/>
+ <signal name="button-release-event" handler="calendar_button_release_cb"/>
+ <signal name="clicked" handler="calendar_clicked_cb"/>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon_name">pan-start-symbolic</property>
+ </object>
+ </child>
+ <style>
+ <class name="image-button"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStack" id="year_stack">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="odd_year_label">
+ <property name="visible">True</property>
+ <property name="label">2015</property>
+ </object>
+ <packing>
+ <property name="name">odd</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="even_year_label">
+ <property name="visible">True</property>
+ <property name="label">2016</property>
+ </object>
+ <packing>
+ <property name="name">even</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="year_up_button">
+ <property name="visible" bind-source="GtkDateChooserWidget"
bind-property="no-month-change" bind-flags="sync-create|invert-boolean"/>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ <signal name="button-press-event" handler="calendar_button_press_cb"/>
+ <signal name="button-release-event" handler="calendar_button_release_cb"/>
+ <signal name="clicked" handler="calendar_clicked_cb"/>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon_name">pan-end-symbolic</property>
+ </object>
+ </child>
+ <style>
+ <class name="image-button"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkGrid" id="grid">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]