[gtk] calendar: Use widgets for the header
- From: Timm Bäder <baedert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk] calendar: Use widgets for the header
- Date: Mon, 27 Jan 2020 12:38:55 +0000 (UTC)
commit baeadea342a01d971e4b291cbbf7ecac4459283d
Author: Timm Bäder <mail baedert org>
Date: Mon Jan 27 10:28:42 2020 +0100
calendar: Use widgets for the header
This is not meant to be a full GtkCalendar conversion to use widgets
instead of custom drawing, but we lost the arrows in the calendar header
when builtin icons were removed. Using proper button for the year/month
buttons brings them back.
gtk/gtkcalendar.c | 387 +++++++++++++++--------------------------
gtk/theme/Adwaita/_common.scss | 11 ++
2 files changed, 151 insertions(+), 247 deletions(-)
---
diff --git a/gtk/gtkcalendar.c b/gtk/gtkcalendar.c
index e3862a3bfc..4a3e8f3b0a 100644
--- a/gtk/gtkcalendar.c
+++ b/gtk/gtkcalendar.c
@@ -90,6 +90,10 @@
#include "gtknative.h"
#include "gtkicontheme.h"
#include "gtkdragicon.h"
+#include "gtkbutton.h"
+#include "gtkbox.h"
+#include "gtklabel.h"
+#include "gtkstack.h"
#define TIMEOUT_INITIAL 500
#define TIMEOUT_REPEAT 50
@@ -212,6 +216,11 @@ struct _GtkCalendarPrivate
{
GtkCalendarDisplayOptions display_flags;
+ GtkWidget *header_box;
+ GtkWidget *year_label;
+ GtkWidget *month_name_stack;
+ GtkWidget *arrow_widgets[4];
+
gint month;
gint year;
gint selected_day;
@@ -364,11 +373,27 @@ static gboolean gtk_calendar_scroll_controller_scroll (GtkEventControllerScroll
gdouble dy,
GtkWidget *widget);
+static void calendar_set_month_prev (GtkCalendar *calendar);
+static void calendar_set_month_next (GtkCalendar *calendar);
+static void calendar_set_year_prev (GtkCalendar *calendar);
+static void calendar_set_year_next (GtkCalendar *calendar);
+
+
static char *default_abbreviated_dayname[7];
static char *default_monthname[12];
G_DEFINE_TYPE_WITH_PRIVATE (GtkCalendar, gtk_calendar, GTK_TYPE_WIDGET)
+static void
+gtk_calendar_dispose (GObject *object)
+{
+ GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (GTK_CALENDAR (object));
+
+ g_clear_pointer (&priv->header_box, gtk_widget_unparent);
+
+ G_OBJECT_CLASS (gtk_calendar_parent_class)->dispose (object);
+}
+
static void
gtk_calendar_class_init (GtkCalendarClass *class)
{
@@ -378,6 +403,7 @@ gtk_calendar_class_init (GtkCalendarClass *class)
gobject_class = (GObjectClass*) class;
widget_class = (GtkWidgetClass*) class;
+ gobject_class->dispose = gtk_calendar_dispose;
gobject_class->set_property = gtk_calendar_set_property;
gobject_class->get_property = gtk_calendar_get_property;
@@ -637,12 +663,59 @@ gtk_calendar_class_init (GtkCalendarClass *class)
gtk_widget_class_set_css_name (widget_class, I_("calendar"));
}
+static void
+set_year (GtkCalendar *calendar,
+ int new_year)
+{
+ GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
+ char buffer[255];
+ char *str;
+ time_t tmp_time;
+ struct tm *tm;
+
+ priv->year = new_year;
+
+ tmp_time = 1; /* Jan 1 1970, 00:00:01 UTC */
+ tm = gmtime (&tmp_time);
+ tm->tm_year = priv->year - 1900;
+
+ /* Translators: This dictates how the year is displayed in
+ * gtkcalendar widget. See strftime() manual for the format.
+ * Use only ASCII in the translation.
+ *
+ * Also look for the msgid "2000".
+ * Translate that entry to a year with the widest output of this
+ * msgid.
+ *
+ * "%Y" is appropriate for most locales.
+ */
+ strftime (buffer, sizeof (buffer), C_("calendar year format", "%Y"), tm);
+ str = g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
+ gtk_label_set_label (GTK_LABEL (priv->year_label), str);
+ g_free (str);
+}
+
+static void
+set_month (GtkCalendar *calendar,
+ int new_month)
+{
+ GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
+
+ g_return_if_fail (new_month >= 0);
+ g_return_if_fail (new_month < 12);
+
+ priv->month = new_month;
+ gtk_stack_set_visible_child_name (GTK_STACK (priv->month_name_stack),
+ default_monthname[priv->month]);
+}
+
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
static void
gtk_calendar_init (GtkCalendar *calendar)
{
+ GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
GtkWidget *widget = GTK_WIDGET (calendar);
GtkEventController *controller;
GtkGesture *gesture;
@@ -656,7 +729,6 @@ gtk_calendar_init (GtkCalendar *calendar)
char buffer[255];
time_t tmp_time;
#endif
- GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
gchar *year_before;
#ifdef HAVE__NL_TIME_FIRST_WEEKDAY
union { unsigned int word; char *string; } langinfo;
@@ -674,6 +746,33 @@ gtk_calendar_init (GtkCalendar *calendar)
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (calendar)),
GTK_STYLE_CLASS_VIEW);
+ priv->header_box = g_object_new (GTK_TYPE_BOX,
+ "css-name", "header",
+ NULL);
+ priv->year_label = gtk_label_new ("");
+ gtk_style_context_add_class (gtk_widget_get_style_context (priv->year_label), "year");
+ priv->month_name_stack = gtk_stack_new ();
+ gtk_style_context_add_class (gtk_widget_get_style_context (priv->month_name_stack), "month");
+ priv->arrow_widgets[0] = gtk_button_new_from_icon_name ("pan-start-symbolic");
+ g_signal_connect_swapped (priv->arrow_widgets[0], "clicked", G_CALLBACK (calendar_set_month_prev),
calendar);
+ priv->arrow_widgets[1] = gtk_button_new_from_icon_name ("pan-end-symbolic");
+ g_signal_connect_swapped (priv->arrow_widgets[1], "clicked", G_CALLBACK (calendar_set_month_next),
calendar);
+ gtk_widget_set_hexpand (priv->arrow_widgets[1], TRUE);
+ gtk_widget_set_halign (priv->arrow_widgets[1], GTK_ALIGN_START);
+ priv->arrow_widgets[2] = gtk_button_new_from_icon_name ("pan-start-symbolic");
+ g_signal_connect_swapped (priv->arrow_widgets[2], "clicked", G_CALLBACK (calendar_set_year_prev),
calendar);
+ priv->arrow_widgets[3] = gtk_button_new_from_icon_name ("pan-end-symbolic");
+ g_signal_connect_swapped (priv->arrow_widgets[3], "clicked", G_CALLBACK (calendar_set_year_next),
calendar);
+
+ gtk_container_add (GTK_CONTAINER (priv->header_box), priv->arrow_widgets[0]);
+ gtk_container_add (GTK_CONTAINER (priv->header_box), priv->month_name_stack);
+ gtk_container_add (GTK_CONTAINER (priv->header_box), priv->arrow_widgets[1]);
+ gtk_container_add (GTK_CONTAINER (priv->header_box), priv->arrow_widgets[2]);
+ gtk_container_add (GTK_CONTAINER (priv->header_box), priv->year_label);
+ gtk_container_add (GTK_CONTAINER (priv->header_box), priv->arrow_widgets[3]);
+
+ gtk_widget_set_parent (priv->header_box, GTK_WIDGET (calendar));
+
gesture = gtk_gesture_click_new ();
g_signal_connect (gesture, "pressed", G_CALLBACK (gtk_calendar_button_press), calendar);
g_signal_connect (gesture, "released", G_CALLBACK (gtk_calendar_button_release), calendar);
@@ -750,11 +849,19 @@ gtk_calendar_init (GtkCalendar *calendar)
#endif
}
+ for (i = 0; i < 12; i ++)
+ {
+ GtkWidget *month_label = gtk_label_new (default_monthname[i]);
+
+ gtk_stack_add_named (GTK_STACK (priv->month_name_stack), month_label, default_monthname[i]);
+ }
+
/* Set defaults */
secs = time (NULL);
tm = localtime (&secs);
- priv->month = tm->tm_mon;
- priv->year = 1900 + tm->tm_year;
+ set_month (calendar, tm->tm_mon);
+ set_year (calendar, 1900 + tm->tm_year);
+
for (i=0;i<31;i++)
priv->marked_date[i] = FALSE;
@@ -894,11 +1001,11 @@ calendar_set_month_next (GtkCalendar *calendar)
if (priv->month == 11)
{
- priv->month = 0;
- priv->year++;
+ set_month (calendar, 0);
+ set_year (calendar, priv->year + 1);
}
else
- priv->month++;
+ set_month (calendar, priv->month + 1);
calendar_compute_days (calendar);
g_signal_emit (calendar,
@@ -927,7 +1034,8 @@ calendar_set_year_prev (GtkCalendar *calendar)
GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
gint month_len;
- priv->year--;
+ set_year (calendar, priv->year - 1);
+
calendar_compute_days (calendar);
g_signal_emit (calendar,
gtk_calendar_signals[PREV_YEAR_SIGNAL],
@@ -955,7 +1063,8 @@ calendar_set_year_next (GtkCalendar *calendar)
GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
gint month_len;
- priv->year++;
+ set_year (calendar, priv->year + 1);
+
calendar_compute_days (calendar);
g_signal_emit (calendar,
gtk_calendar_signals[NEXT_YEAR_SIGNAL],
@@ -1229,51 +1338,9 @@ calendar_arrow_rectangle (GtkCalendar *calendar,
GdkRectangle *rect)
{
GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
- GtkWidget *widget = GTK_WIDGET (calendar);
- int width;
- gboolean year_left;
-
- width = gtk_widget_get_width (widget);
-
- if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
- year_left = priv->year_before;
- else
- year_left = !priv->year_before;
-
- rect->y = 3;
- rect->width = priv->arrow_width;
- rect->height = priv->header_h - 7;
- switch (arrow)
- {
- case ARROW_MONTH_LEFT:
- if (year_left)
- rect->x = (width - (3 + 2 * priv->arrow_width + priv->max_month_width));
- else
- rect->x = 3;
- break;
- case ARROW_MONTH_RIGHT:
- if (year_left)
- rect->x = width - 3 - priv->arrow_width;
- else
- rect->x = priv->arrow_width + priv->max_month_width;
- break;
- case ARROW_YEAR_LEFT:
- if (year_left)
- rect->x = 3;
- else
- rect->x = width - (3 + 2 * priv->arrow_width + priv->max_year_width);
- break;
- case ARROW_YEAR_RIGHT:
- if (year_left)
- rect->x = (priv->arrow_width + priv->max_year_width);
- else
- rect->x = width - 3 - priv->arrow_width;
- break;
-
- default:
- g_assert_not_reached();
- }
+ gtk_widget_get_allocation (priv->arrow_widgets[arrow],
+ rect);
}
static void
@@ -1301,11 +1368,11 @@ calendar_set_month_prev (GtkCalendar *calendar)
if (priv->month == 0)
{
- priv->month = 11;
- priv->year--;
+ set_month (calendar, 11);
+ set_year (calendar, priv->year - 1);
}
else
- priv->month--;
+ set_month (calendar, priv->month - 1);
month_len = month_length[leap (priv->year)][priv->month + 1];
@@ -1628,35 +1695,14 @@ gtk_calendar_size_request (GtkWidget *widget,
layout = gtk_widget_create_pango_layout (widget, NULL);
- /*
- * Calculate the requisition width for the widget.
- */
-
/* Header width */
if (priv->display_flags & GTK_CALENDAR_SHOW_HEADING)
{
- priv->max_month_width = 0;
- for (i = 0; i < 12; i++)
- {
- pango_layout_set_text (layout, default_monthname[i], -1);
- pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
- priv->max_month_width = MAX (priv->max_month_width,
- logical_rect.width + 8);
- max_header_height = MAX (max_header_height, logical_rect.height);
- }
-
- priv->max_year_width = 0;
- /* Translators: This is a text measurement template.
- * Translate it to the widest year text
- *
- * If you don't understand this, leave it as "2000"
- */
- pango_layout_set_text (layout, C_("year measurement template", "2000"), -1);
- pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
- priv->max_year_width = MAX (priv->max_year_width,
- logical_rect.width + 8);
- max_header_height = MAX (max_header_height, logical_rect.height);
+ gtk_widget_measure (priv->header_box, GTK_ORIENTATION_HORIZONTAL, -1,
+ &header_width, NULL, NULL, NULL);
+ gtk_widget_measure (priv->header_box, GTK_ORIENTATION_VERTICAL, -1,
+ &max_header_height, NULL, NULL, NULL);
}
else
{
@@ -1664,15 +1710,6 @@ gtk_calendar_size_request (GtkWidget *widget,
priv->max_year_width = 0;
}
- if (priv->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
- header_width = (priv->max_month_width
- + priv->max_year_width
- + 3 * 3);
- else
- header_width = (priv->max_month_width
- + priv->max_year_width
- + 4 * priv->arrow_width + 3 * 3);
-
/* Mainwindow labels width */
priv->max_day_char_width = 0;
@@ -1875,6 +1912,7 @@ gtk_calendar_size_allocate (GtkWidget *widget,
GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
gint inner_border = calendar_get_inner_border (calendar);
gint calendar_xsep = calendar_get_xsep (calendar);
+ int header_height;
if (priv->display_flags & GTK_CALENDAR_SHOW_WEEK_NUMBERS)
{
@@ -1894,6 +1932,11 @@ gtk_calendar_size_allocate (GtkWidget *widget,
- (DAY_XSEP * 6))/7;
priv->week_width = 0;
}
+
+ gtk_widget_measure (priv->header_box, GTK_ORIENTATION_VERTICAL, width,
+ &header_height, NULL, NULL, NULL);
+ gtk_widget_size_allocate (priv->header_box,
+ &(GtkAllocation){ 0, 0, width, header_height }, -1);
}
@@ -1901,114 +1944,6 @@ gtk_calendar_size_allocate (GtkWidget *widget,
* Repainting *
****************************************/
-static void
-calendar_snapshot_header (GtkCalendar *calendar,
- GtkSnapshot *snapshot)
-{
- GtkWidget *widget = GTK_WIDGET (calendar);
- GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
- GtkStyleContext *context;
- GtkStateFlags state;
- char buffer[255];
- gint x, y;
- gint header_width;
- gint max_month_width;
- gint max_year_width;
- PangoLayout *layout;
- PangoRectangle logical_rect;
- gboolean year_left;
- time_t tmp_time;
- struct tm *tm;
- gchar *str;
-
- context = gtk_widget_get_style_context (widget);
-
- if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
- year_left = priv->year_before;
- else
- year_left = !priv->year_before;
-
- header_width = gtk_widget_get_width (widget);
-
- max_month_width = priv->max_month_width;
- max_year_width = priv->max_year_width;
-
- state = gtk_style_context_get_state (context);
- state &= ~GTK_STATE_FLAG_DROP_ACTIVE;
-
- gtk_style_context_save (context);
-
- gtk_style_context_set_state (context, state);
- gtk_style_context_add_class (context, GTK_STYLE_CLASS_HEADER);
-
- gtk_snapshot_render_background (snapshot, context, 0, 0, header_width, priv->header_h);
- gtk_snapshot_render_frame (snapshot, context, 0, 0, header_width, priv->header_h);
-
- tmp_time = 1; /* Jan 1 1970, 00:00:01 UTC */
- tm = gmtime (&tmp_time);
- tm->tm_year = priv->year - 1900;
-
- /* Translators: This dictates how the year is displayed in
- * gtkcalendar widget. See strftime() manual for the format.
- * Use only ASCII in the translation.
- *
- * Also look for the msgid "2000".
- * Translate that entry to a year with the widest output of this
- * msgid.
- *
- * "%Y" is appropriate for most locales.
- */
- strftime (buffer, sizeof (buffer), C_("calendar year format", "%Y"), tm);
- str = g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
- layout = gtk_widget_create_pango_layout (widget, str);
- g_free (str);
-
- pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
-
- /* Draw title */
- y = (priv->header_h - logical_rect.height) / 2;
-
- /* Draw year and its arrows */
-
- if (priv->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
- if (year_left)
- x = 3 + (max_year_width - logical_rect.width)/2;
- else
- x = header_width - (3 + max_year_width
- - (max_year_width - logical_rect.width)/2);
- else
- if (year_left)
- x = 3 + priv->arrow_width + (max_year_width - logical_rect.width)/2;
- else
- x = header_width - (3 + priv->arrow_width + max_year_width
- - (max_year_width - logical_rect.width)/2);
-
- gtk_snapshot_render_layout (snapshot, context, x, y, layout);
-
- /* Draw month */
- g_snprintf (buffer, sizeof (buffer), "%s", default_monthname[priv->month]);
- pango_layout_set_text (layout, buffer, -1);
- pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
-
- if (priv->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
- if (year_left)
- x = header_width - (3 + max_month_width
- - (max_month_width - logical_rect.width)/2);
- else
- x = 3 + (max_month_width - logical_rect.width) / 2;
- else
- if (year_left)
- x = header_width - (3 + priv->arrow_width + max_month_width
- - (max_month_width - logical_rect.width)/2);
- else
- x = 3 + priv->arrow_width + (max_month_width - logical_rect.width)/2;
-
- gtk_snapshot_render_layout (snapshot, context, x, y, layout);
- g_object_unref (layout);
-
- gtk_style_context_restore (context);
-}
-
static void
calendar_snapshot_day_names (GtkCalendar *calendar,
GtkSnapshot *snapshot)
@@ -2387,61 +2322,16 @@ calendar_snapshot_main (GtkCalendar *calendar,
calendar_snapshot_day (calendar, snapshot, row, col);
}
-static void
-calendar_snapshot_arrow (GtkCalendar *calendar,
- GtkSnapshot *snapshot,
- guint arrow)
-{
- GtkWidget *widget = GTK_WIDGET (calendar);
- GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
- GtkStyleContext *context;
- GtkStateFlags state;
- GdkRectangle rect;
-
- calendar_arrow_rectangle (calendar, arrow, &rect);
-
- context = gtk_widget_get_style_context (widget);
- state = gtk_widget_get_state_flags (widget);
-
- if (priv->arrow_prelight & (1 << arrow))
- state |= GTK_STATE_FLAG_PRELIGHT;
- else
- state &= ~(GTK_STATE_FLAG_PRELIGHT);
-
- gtk_style_context_save (context);
- gtk_style_context_set_state (context, state);
- gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
-
- gtk_snapshot_render_background (snapshot, context,
- rect.x, rect.y,
- rect.width, rect.height);
-
- gtk_snapshot_save (snapshot);
- gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT(
- rect.x + (rect.width - 8) / 2,
- rect.y + (rect.height - 8) / 2));
- gtk_css_style_snapshot_icon (gtk_style_context_lookup_style (context), snapshot, 8, 8);
- gtk_snapshot_restore (snapshot);
-
- gtk_style_context_restore (context);
-}
-
static void
gtk_calendar_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkCalendar *calendar = GTK_CALENDAR (widget);
GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
- int i;
calendar_snapshot_main (calendar, snapshot);
- if (priv->display_flags & GTK_CALENDAR_SHOW_HEADING)
- {
- calendar_snapshot_header (calendar, snapshot);
- for (i = 0; i < 4; i++)
- calendar_snapshot_arrow (calendar, snapshot, i);
- }
+ gtk_widget_snapshot_child (widget, priv->header_box, snapshot);
if (priv->display_flags & GTK_CALENDAR_SHOW_DAY_NAMES)
calendar_snapshot_day_names (calendar, snapshot);
@@ -3149,11 +3039,14 @@ gtk_calendar_set_display_options (GtkCalendar *calendar,
if ((flags ^ priv->display_flags) & GTK_CALENDAR_SHOW_HEADING)
{
- resize++;
-
if (flags & GTK_CALENDAR_SHOW_HEADING)
{
priv->display_flags |= GTK_CALENDAR_SHOW_HEADING;
+ gtk_widget_show (priv->header_box);
+ }
+ else
+ {
+ gtk_widget_hide (priv->header_box);
}
}
@@ -3217,12 +3110,12 @@ gtk_calendar_select_month (GtkCalendar *calendar,
if (priv->month != month)
{
- priv->month = month;
+ set_month (calendar, month);
g_object_notify (G_OBJECT (calendar), "month");
}
if (priv->year != year)
{
- priv->year = year;
+ set_year (calendar, year);
g_object_notify (G_OBJECT (calendar), "year");
}
diff --git a/gtk/theme/Adwaita/_common.scss b/gtk/theme/Adwaita/_common.scss
index abe6843756..96c068d154 100644
--- a/gtk/theme/Adwaita/_common.scss
+++ b/gtk/theme/Adwaita/_common.scss
@@ -3458,6 +3458,17 @@ calendar {
color: $text_color;
border: 1px solid $borders_color;
+ > header {
+ border-bottom: 1px solid $borders_color;
+
+ > button {
+ border: none;
+ box-shadow: none;
+ background: none;
+ border-radius: 0;
+ }
+ }
+
&:selected {
@extend %selected_items;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]