[gnome-calendar] event-widget: turn into a GtkBin subclass
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-calendar] event-widget: turn into a GtkBin subclass
- Date: Thu, 14 Sep 2017 16:32:09 +0000 (UTC)
commit a85337662925fa15b5b4ee4192ff4d27998341df
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Thu Sep 14 01:56:45 2017 -0300
event-widget: turn into a GtkBin subclass
The current GcalEventWidget implementation is a direct
GtkWidget subclass, which means we have to take care of
all the implementation details such as raising GdkWindows
and managing the drawing all by ourselves.
The event widget, however, can be easily described through
a GtkBuilder file. This would simplify the implementation
and makes us maintain less code.
Fix that by making GcalEventWidget a GtkBin subclass.
data/calendar.gresource.xml | 1 +
data/theme/gtk-styles.css | 18 +-
data/ui/event-widget.ui | 66 ++++
src/css-code.h | 7 +-
src/gcal-event-widget.c | 726 +++++++++++++++----------------------------
src/gcal-event-widget.h | 2 +-
src/views/gcal-month-view.c | 6 +
src/views/gcal-week-grid.c | 10 +-
8 files changed, 354 insertions(+), 482 deletions(-)
---
diff --git a/data/calendar.gresource.xml b/data/calendar.gresource.xml
index 6b5397e..4921985 100644
--- a/data/calendar.gresource.xml
+++ b/data/calendar.gresource.xml
@@ -6,6 +6,7 @@
<file alias="date-chooser.ui" compressed="true" preprocess="xml-stripblanks">ui/date-chooser.ui</file>
<file alias="date-selector.ui" compressed="true" preprocess="xml-stripblanks">ui/date-selector.ui</file>
<file alias="edit-dialog.ui" compressed="true" preprocess="xml-stripblanks">ui/edit-dialog.ui</file>
+ <file alias="event-widget.ui" compressed="true" preprocess="xml-stripblanks">ui/event-widget.ui</file>
<file alias="multi-choice.ui" compressed="true" preprocess="xml-stripblanks">ui/multi-choice.ui</file>
<file alias="online-account-row.ui" compressed="true"
preprocess="xml-stripblanks">ui/online-account-row.ui</file>
<file alias="quick-add-popover.ui" compressed="true"
preprocess="xml-stripblanks">ui/quick-add-popover.ui</file>
diff --git a/data/theme/gtk-styles.css b/data/theme/gtk-styles.css
index 6f614c1..abaa206 100644
--- a/data/theme/gtk-styles.css
+++ b/data/theme/gtk-styles.css
@@ -212,28 +212,32 @@ popover.events button {
box-shadow: none;
}
-event-widget {
+
+/*
+ * Event widget
+ */
+
+event {
border-radius: 2px;
- margin: 2px 2px 1px;
- padding: 3px 4px;
+ margin: 1px 1px 0 2px;
font-size: 9pt;
}
-event-widget.color-dark {
+event.color-dark {
color: white;
outline-color: rgba(0, 0, 0, 0.3);
}
-event-widget.color-dark:backdrop {
+event.color-dark:backdrop {
color: rgba(255, 255, 255, 0.3);
}
-event-widget.color-light {
+event.color-light {
color: black;
outline-color: rgba(255, 255, 255, 0.5);
}
-event-widget.color-light:backdrop {
+event.color-light:backdrop {
color: rgba(0, 0, 0, 0.3);
}
diff --git a/data/ui/event-widget.ui b/data/ui/event-widget.ui
new file mode 100644
index 0000000..68bc3ee
--- /dev/null
+++ b/data/ui/event-widget.ui
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GcalEventWidget" parent="GtkBin">
+ <child>
+ <object class="GtkEventBox" id="event_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="above_child">True</property>
+ <signal name="enter-notify-event" handler="enter_notify_event_cb" object="GcalEventWidget"
swapped="no" />
+ <signal name="leave-notify-event" handler="leave_notify_event_cb" object="GcalEventWidget"
swapped="no" />
+ <child>
+ <object class="GtkGrid" id="main_grid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="column_spacing">6</property>
+ <property name="margin-top">1</property>
+ <property name="margin-bottom">1</property>
+ <property name="margin-start">4</property>
+ <property name="margin-end">4</property>
+ <property name="hexpand">False</property>
+ <child>
+ <object class="GtkLabel" id="hour_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0.0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="alarm_icon">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">alarm-symbolic</property>
+ <property name="pixel_size">12</property>
+ <property name="valign">center</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="summary_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="xalign">0</property>
+ <property name="ellipsize">end</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/css-code.h b/src/css-code.h
index a078614..e1e9061 100644
--- a/src/css-code.h
+++ b/src/css-code.h
@@ -257,7 +257,12 @@
" alpha(%2$s, 0) 10px,"\
" alpha(%2$s, 0) 16px,"\
" %2$s 17px);"\
-"}"
+"}"\
+".color-%1$d.slanted box { margin: 0 16px 0 16px; }"\
+".color-%1$d.slanted-start box { margin-left: 16px; }"\
+".color-%1$d.slanted-start:dir(rtl) box { margin-right: 16px; }"\
+".color-%1$d.slanted-end box { margin-right: 16px; }"\
+".color-%1$d.slanted-end:dir(rtl) box { margin-left: 16px; }"
#endif /* CSS_CODE_H */
diff --git a/src/gcal-event-widget.c b/src/gcal-event-widget.c
index bee13f2..6025fc1 100644
--- a/src/gcal-event-widget.c
+++ b/src/gcal-event-widget.c
@@ -31,12 +31,19 @@
struct _GcalEventWidget
{
- GtkWidget parent;
+ GtkBin parent;
/* properties */
GDateTime *dt_start;
GDateTime *dt_end;
+ /* widgets */
+ GtkWidget *alarm_icon;
+ GtkWidget *event_box;
+ GtkWidget *hour_label;
+ GtkWidget *main_grid;
+ GtkWidget *summary_label;
+
/* internal data */
gboolean clock_format_24h : 1;
gboolean read_only : 1;
@@ -46,7 +53,6 @@ struct _GcalEventWidget
GtkOrientation orientation;
- GdkWindow *event_window;
gboolean button_pressed;
};
@@ -66,98 +72,59 @@ enum
NUM_SIGNALS
};
+
+
+typedef enum
+{
+ CURSOR_NONE,
+ CURSOR_GRAB,
+ CURSOR_GRABBING
+} CursorType;
+
static guint signals[NUM_SIGNALS] = { 0, };
-G_DEFINE_TYPE_WITH_CODE (GcalEventWidget, gcal_event_widget, GTK_TYPE_WIDGET,
+G_DEFINE_TYPE_WITH_CODE (GcalEventWidget, gcal_event_widget, GTK_TYPE_BIN,
G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL));
/*
* Auxiliary methods
*/
-static gchar*
-get_visible_text (GtkWidget *widget,
- GtkOrientation orientation)
+
+static void
+set_cursor (GtkWidget *widget,
+ CursorType type)
{
- GcalEventWidget *self;
- gboolean is_ltr;
- gchar *display_text;
- gchar *escaped_text;
+ GdkDisplay *display;
+ GdkCursor *cursor;
- self = GCAL_EVENT_WIDGET (widget);
- is_ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
+ if (!gtk_widget_get_realized (widget))
+ return;
- /*
- * Since we set markup labels, we have to escape text before
- * using it, or we get empty event widgets.
- */
- escaped_text = g_markup_escape_text (gcal_event_get_summary (self->event), -1);
+ display = gtk_widget_get_display (widget);
- /*
- * The text displayed in the widget includes the time when the event
- * is timed, or not if the event is all day.
- */
- if (gcal_event_get_all_day (self->event))
- {
- display_text = escaped_text;
- }
- else
+ switch (type)
{
- GDateTime *local_start_time;
- gchar *start_time;
- local_start_time = g_date_time_to_local (gcal_event_get_date_start (self->event));
+ case CURSOR_NONE:
+ cursor = NULL;
+ break;
- if (self->clock_format_24h)
- start_time = g_date_time_format (local_start_time, "%R");
- else
- start_time = g_date_time_format (local_start_time, "%I:%M %P");
+ case CURSOR_GRAB:
+ cursor = gdk_cursor_new_from_name (display, "grab");
+ break;
- /*
- * When in horizontal, draw the elements sequentially; otherwise,
- * draw the time in the first line, and the title in subsequent
- * lines.
- */
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- if (is_ltr)
- display_text = g_strdup_printf ("(%s) %s", start_time, escaped_text);
- else
- display_text = g_strdup_printf ("%s (%s)", escaped_text, start_time);
- }
- else
- {
- display_text = g_strdup_printf ("<b>%s</b>\n%s", start_time, escaped_text);
- }
+ case CURSOR_GRABBING:
+ cursor = gdk_cursor_new_from_name (display, "grabbing");
+ break;
- g_clear_pointer (&local_start_time, g_date_time_unref);
- g_clear_pointer (&escaped_text, g_free);
- g_clear_pointer (&start_time, g_free);
+ default:
+ cursor = NULL;
}
- return display_text;
-}
-
-static gint
-get_vertical_text_height (GtkWidget *widget)
-{
- GtkBorder border, padding;
- GtkStyleContext *context;
- PangoLayout *layout;
- gint layout_height;
- gchar* display_text;
-
- context = gtk_widget_get_style_context (widget);
- display_text = get_visible_text (widget, GTK_ORIENTATION_VERTICAL);
- layout = gtk_widget_create_pango_layout (widget, display_text);
- pango_layout_get_pixel_size (layout, NULL, &layout_height);
- g_object_unref (layout);
-
- gtk_style_context_get_border (context, gtk_style_context_get_state (context), &border);
- gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
-
- g_clear_pointer(&display_text, g_free);
+ gdk_window_set_cursor (gtk_widget_get_window (widget), cursor);
+ gdk_display_flush (display);
- return layout_height + padding.top + padding.bottom + border.top + border.bottom;
+ g_clear_object (&cursor);
}
static void
@@ -192,6 +159,10 @@ gcal_event_widget_update_style (GcalEventWidget *self)
gtk_style_context_add_class (context, "slanted-start");
else if (slanted_end)
gtk_style_context_add_class (context, "slanted-end");
+
+ /* TODO: adjust margins based on the CSS gradients sizes, not hardcoded */
+ gtk_widget_set_margin_start (self->main_grid, slanted_start ? 20 : 4);
+ gtk_widget_set_margin_end (self->main_grid, slanted_end ? 20 : 4);
}
static void
@@ -397,10 +368,25 @@ gcal_event_widget_set_event_tooltip (GcalEventWidget *self,
g_string_free (tooltip_mesg, TRUE);
}
+static gchar*
+get_hour_label (GcalEventWidget *self)
+{
+ g_autoptr (GDateTime) local_start_time;
+
+ local_start_time = g_date_time_to_local (gcal_event_get_date_start (self->event));
+
+ if (self->clock_format_24h)
+ return g_date_time_format (local_start_time, "%R");
+ else
+ return g_date_time_format (local_start_time, "%I:%M %P");
+}
+
static void
gcal_event_widget_set_event_internal (GcalEventWidget *self,
GcalEvent *event)
{
+ g_autofree gchar *hour_str = NULL;
+
/*
* This function is called only once, since the property is
* set as CONSTRUCT_ONLY. Any other attempt to set an event
@@ -433,285 +419,63 @@ gcal_event_widget_set_event_internal (GcalEventWidget *self,
G_CALLBACK (gtk_widget_queue_draw),
self);
+ /* Tooltip */
gcal_event_widget_set_event_tooltip (self, event);
-}
-
-
-/*
- * GObject overrides
- */
-
-static void
-gcal_event_widget_set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- GcalEventWidget *self = GCAL_EVENT_WIDGET (object);
-
- switch (property_id)
- {
- case PROP_DATE_END:
- gcal_event_widget_set_date_end (self, g_value_get_boxed (value));
- break;
-
- case PROP_DATE_START:
- gcal_event_widget_set_date_start (self, g_value_get_boxed (value));
- break;
-
- case PROP_EVENT:
- gcal_event_widget_set_event_internal (self, g_value_get_object (value));
- break;
-
- case PROP_ORIENTATION:
- self->orientation = g_value_get_enum (value);
- gtk_widget_queue_draw (GTK_WIDGET (object));
- g_object_notify (object, "orientation");
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- }
-}
-
-static void
-gcal_event_widget_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec)
-{
- GcalEventWidget *self = GCAL_EVENT_WIDGET (object);
-
- switch (property_id)
- {
- case PROP_DATE_END:
- g_value_set_boxed (value, self->dt_end);
- break;
- case PROP_DATE_START:
- g_value_set_boxed (value, self->dt_start);
- break;
+ /* Alarm icon */
+ gtk_widget_set_visible (self->alarm_icon, gcal_event_has_alarms (event));
- case PROP_EVENT:
- g_value_set_object (value, self->event);
- break;
+ /* Hour label */
+ hour_str = get_hour_label (self);
- case PROP_ORIENTATION:
- g_value_set_enum (value, self->orientation);
- break;
+ gtk_widget_set_visible (self->hour_label, !gcal_event_get_all_day (event));
+ gtk_label_set_label (GTK_LABEL (self->hour_label), hour_str);
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- }
+ /* Summary label */
+ g_object_bind_property (event,
+ "summary",
+ self->summary_label,
+ "label",
+ G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
}
-static void
-gcal_event_widget_finalize (GObject *object)
-{
- GcalEventWidget *self;
-
- self = GCAL_EVENT_WIDGET (object);
-
- /* disconnect signals */
- g_signal_handlers_disconnect_by_func (self->event, update_color, self);
- g_signal_handlers_disconnect_by_func (self->event, gtk_widget_queue_draw, self);
-
- /* releasing properties */
- g_clear_pointer (&self->css_class, g_free);
- g_clear_object (&self->event);
- G_OBJECT_CLASS (gcal_event_widget_parent_class)->finalize (object);
-}
-
-static void
-gcal_event_widget_get_preferred_width (GtkWidget *widget,
- gint *minimum,
- gint *natural)
-{
- GtkBorder border, padding;
- GtkStyleContext *context;
- PangoLayout *layout;
- gint layout_width;
-
- context = gtk_widget_get_style_context (widget);
- layout = gtk_widget_create_pango_layout (widget, "00:00:00 00:00");
- pango_layout_get_pixel_size (layout, &layout_width, NULL);
- g_object_unref (layout);
-
- gtk_style_context_get_border (context, gtk_style_context_get_state (context), &border);
- gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
-
- if (minimum != NULL)
- *minimum = layout_width + padding.left + padding.right + border.left + border.right;
- if (natural != NULL)
- *natural = layout_width + padding.left + padding.right + border.left + border.right;
-}
-
-static void
-gcal_event_widget_get_preferred_height (GtkWidget *widget,
- gint *minimum,
- gint *natural)
-{
- GcalEventWidget *self;
- GtkBorder border, padding;
- GtkStyleContext *context;
- PangoLayout *layout;
- gint layout_height;
- gchar* display_text;
-
- self = GCAL_EVENT_WIDGET (widget);
- context = gtk_widget_get_style_context (widget);
- display_text = get_visible_text (widget, self->orientation);
- layout = gtk_widget_create_pango_layout (widget, display_text);
- pango_layout_get_pixel_size (layout, NULL, &layout_height);
- g_object_unref (layout);
-
- gtk_style_context_get_border (context, gtk_style_context_get_state (context), &border);
- gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
-
- if (minimum != NULL)
- *minimum = layout_height + padding.top + padding.bottom + border.top + border.bottom;
- if (natural != NULL)
- *natural = layout_height + padding.top + padding.bottom + border.top + border.bottom;
-
- g_clear_pointer(&display_text, g_free);
-}
-
-static void
-gcal_event_widget_realize (GtkWidget *widget)
-{
- GcalEventWidget *self;
- GdkWindow *parent_window;
- GdkWindowAttr attributes;
- gint attributes_mask;
- GtkAllocation allocation;
-
- GdkCursor* pointer_cursor;
-
- self = GCAL_EVENT_WIDGET (widget);
- gtk_widget_set_realized (widget, TRUE);
-
- parent_window = gtk_widget_get_parent_window (widget);
- gtk_widget_set_window (widget, parent_window);
- g_object_ref (parent_window);
-
- gtk_widget_get_allocation (widget, &allocation);
-
- attributes.window_type = GDK_WINDOW_CHILD;
- attributes.wclass = GDK_INPUT_ONLY;
- attributes.x = allocation.x;
- attributes.y = allocation.y;
- attributes.width = allocation.width;
- attributes.height = allocation.height;
- attributes.event_mask = gtk_widget_get_events (widget);
- attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK |
- GDK_BUTTON1_MOTION_MASK |
- GDK_POINTER_MOTION_HINT_MASK |
- GDK_POINTER_MOTION_MASK |
- GDK_ENTER_NOTIFY_MASK |
- GDK_LEAVE_NOTIFY_MASK |
- GDK_SMOOTH_SCROLL_MASK |
- GDK_SCROLL_MASK);
- attributes_mask = GDK_WA_X | GDK_WA_Y;
-
- self->event_window = gdk_window_new (parent_window,
- &attributes,
- attributes_mask);
- gtk_widget_register_window (widget, self->event_window);
- gdk_window_show (self->event_window);
-
- pointer_cursor = gdk_cursor_new_for_display (gdk_display_get_default (),
- GDK_HAND1);
- gdk_window_set_cursor (self->event_window, pointer_cursor);
-}
+/*
+ * Callbacks
+ */
-static void
-gcal_event_widget_unrealize (GtkWidget *widget)
+static gboolean
+enter_notify_event_cb (GtkWidget *event_box,
+ GdkEvent *event,
+ GtkWidget *widget)
{
- GcalEventWidget *self;
-
- self = GCAL_EVENT_WIDGET (widget);
-
- if (self->event_window != NULL)
- {
- gtk_widget_unregister_window (widget, self->event_window);
- gdk_window_destroy (self->event_window);
- self->event_window = NULL;
- }
-
- GTK_WIDGET_CLASS (gcal_event_widget_parent_class)->unrealize (widget);
+ set_cursor (widget, CURSOR_GRAB);
+ return GDK_EVENT_PROPAGATE;
}
-static void
-gcal_event_widget_map (GtkWidget *widget)
-{
- GcalEventWidget *self;
-
- self = GCAL_EVENT_WIDGET (widget);
-
- GTK_WIDGET_CLASS (gcal_event_widget_parent_class)->map (widget);
-
- if (self->event_window != NULL)
- gdk_window_show (self->event_window);
-}
-static void
-gcal_event_widget_unmap (GtkWidget *widget)
+static gboolean
+leave_notify_event_cb (GtkWidget *event_box,
+ GdkEvent *event,
+ GtkWidget *widget)
{
- GcalEventWidget *self;
-
- self = GCAL_EVENT_WIDGET (widget);
-
- GTK_WIDGET_CLASS (gcal_event_widget_parent_class)->unmap (widget);
-
- if (self->event_window != NULL)
- gdk_window_hide (self->event_window);
+ set_cursor (widget, CURSOR_NONE);
+ return GDK_EVENT_PROPAGATE;
}
-static void
-gcal_event_widget_size_allocate (GtkWidget *widget,
- GtkAllocation *allocation)
-{
- GcalEventWidget *self;
-
- self = GCAL_EVENT_WIDGET (widget);
- gtk_widget_set_allocation (widget, allocation);
- if (gtk_widget_get_realized (widget))
- {
- gdk_window_move_resize (self->event_window,
- allocation->x,
- allocation->y,
- allocation->width,
- allocation->height);
- }
-}
+/*
+ * GtkWidget overrides
+ */
static gboolean
gcal_event_widget_draw (GtkWidget *widget,
cairo_t *cr)
{
- GcalEventWidget *self;
-
GtkStyleContext *context;
- GtkStateFlags state;
- GtkBorder padding;
-
- gint width, height, layout_height, x;
- gint end_gap, icon_size = 0;
- gboolean is_ltr;
+ guint width, height;
- PangoLayout *layout;
- PangoFontDescription *font_desc;
- gchar *display_text;
-
- self = GCAL_EVENT_WIDGET (widget);
context = gtk_widget_get_style_context (widget);
- state = gtk_style_context_get_state (context);
- is_ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
-
- gtk_style_context_get_padding (context, state, &padding);
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
@@ -719,131 +483,6 @@ gcal_event_widget_draw (GtkWidget *widget,
gtk_render_background (context, cr, 0, 0, width, height);
gtk_render_frame (context, cr, 0, 0, width, height);
- /* Set the text to be displayed */
- if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
- display_text = get_visible_text (widget, GTK_ORIENTATION_HORIZONTAL);
- else
- {
- if (get_vertical_text_height (widget) >= height)
- display_text = get_visible_text (widget, GTK_ORIENTATION_HORIZONTAL);
- else
- display_text = get_visible_text (widget, GTK_ORIENTATION_VERTICAL);
- }
-
- /* Retrieve the font description */
- gtk_style_context_get (context, state, "font", &font_desc, NULL);
- layout = gtk_widget_create_pango_layout (widget, "");
- pango_layout_set_markup (layout, display_text, -1);
- pango_layout_set_font_description (layout, font_desc);
- pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
-
- /* Icon size */
- icon_size = ICON_SIZE;
- end_gap = 0;
-
- if (gcal_event_has_alarms (self->event))
- end_gap += icon_size + (is_ltr ? padding.left : padding.right);
-
- if (self->read_only)
- end_gap += icon_size + (is_ltr ? padding.left : padding.right);
-
- x = is_ltr ? padding.left : padding.left + end_gap;
-
- pango_layout_set_width (layout, (width - (padding.left + padding.right + end_gap)) * PANGO_SCALE);
- pango_layout_get_pixel_size (layout, NULL, &layout_height);
- gtk_render_layout (context, cr, x, padding.top, layout);
-
-#if 0
- /* TODO: find out a good way to handle this */
- /*
- * On vertical event widgets, we assume we might have space to draw the
- * event's detail (or at least part of it).
- */
- if (self->orientation == GTK_ORIENTATION_VERTICAL &&
- 2 * padding.top + layout_height + padding.bottom < height &&
- strlen (gcal_event_get_description (self->event)) > 0)
- {
- g_autofree gchar *description;
-
- description = g_strdup_printf ("<small>%s</small>", gcal_event_get_description (self->event));
- pango_layout_set_markup (layout, description, -1);
- pango_layout_set_width (layout, (width - (padding.left + padding.right) ) * PANGO_SCALE);
- pango_layout_set_height (layout, (height - (2 * padding.top + layout_height + padding.bottom) ) *
PANGO_SCALE);
- pango_layout_set_font_description (layout, font_desc);
- pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
-
- gtk_render_layout (context,
- cr,
- x,
- 2 * padding.top + layout_height + padding.bottom,
- layout);
- }
-#endif
-
- x += is_ltr ? (width - end_gap - padding.left - padding.right) : (- padding.right - padding.left -
icon_size);
-
- /* render reminder icon */
- if (gcal_event_has_alarms (self->event))
- {
- GtkIconTheme *icon_theme;
- GtkIconInfo *icon_info;
- GdkPixbuf *pixbuf;
- gboolean was_symbolic;
-
- icon_theme = gtk_icon_theme_get_default ();
- icon_info = gtk_icon_theme_lookup_icon (icon_theme,
- "alarm-symbolic",
- icon_size,
- 0);
- pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info,
- context,
- &was_symbolic,
- NULL);
-
- gtk_render_icon (context,
- cr,
- pixbuf,
- x + padding.left,
- padding.top);
-
- x += is_ltr ? (padding.left + icon_size) : (- padding.right - icon_size);
-
- g_object_unref (pixbuf);
- cairo_paint (cr);
- }
-
- /* render locked icon */
- if (self->read_only)
- {
- GtkIconTheme *icon_theme;
- GtkIconInfo *icon_info;
- GdkPixbuf *pixbuf;
- gboolean was_symbolic;
-
- icon_theme = gtk_icon_theme_get_default ();
- icon_info = gtk_icon_theme_lookup_icon (icon_theme,
- "changes-prevent-symbolic",
- icon_size,
- 0);
- pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info,
- context,
- &was_symbolic,
- NULL);
-
- gtk_render_icon (context,
- cr,
- pixbuf,
- x + padding.left,
- padding.top);
-
- g_object_unref (pixbuf);
- cairo_paint (cr);
- }
-
- pango_font_description_free (font_desc);
- g_object_unref (layout);
- g_free (display_text);
-
return GTK_WIDGET_CLASS (gcal_event_widget_parent_class)->draw (widget, cr);
}
@@ -855,7 +494,8 @@ gcal_event_widget_button_press_event (GtkWidget *widget,
self = GCAL_EVENT_WIDGET (widget);
self->button_pressed = TRUE;
- return TRUE;
+
+ return GDK_EVENT_STOP;
}
static gboolean
@@ -868,12 +508,62 @@ gcal_event_widget_button_release_event (GtkWidget *widget,
if (self->button_pressed)
{
+ set_cursor (widget, CURSOR_NONE);
+
self->button_pressed = FALSE;
g_signal_emit (widget, signals[ACTIVATE], 0);
- return TRUE;
+
+ return GDK_EVENT_STOP;
}
- return FALSE;
+ return GDK_EVENT_PROPAGATE;
+}
+
+static void
+gcal_event_widget_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GcalEventWidget *self;
+
+ self = GCAL_EVENT_WIDGET (widget);
+
+ /* Try to put the summary label below if the orientation is vertical */
+ if (self->orientation == GTK_ORIENTATION_VERTICAL && !gcal_event_get_all_day (self->event))
+ {
+ gint minimum_grid_height;
+
+ gtk_label_set_line_wrap (GTK_LABEL (self->summary_label), TRUE);
+ /* This is needed to push the alarm icon to the end of the widget */
+ gtk_widget_set_hexpand (self->hour_label, TRUE);
+
+ gtk_container_child_set (GTK_CONTAINER (self->main_grid),
+ self->summary_label,
+ "left-attach", 0,
+ "top-attach", 1,
+ "width", 3,
+ NULL);
+
+ gtk_widget_get_preferred_height (self->event_box, &minimum_grid_height, NULL);
+
+ /*
+ * There is no vertical space to put the summary label below the hour label.
+ * Thus, reset the label's original attributes.
+ */
+ if (allocation->height < minimum_grid_height)
+ {
+ gtk_container_child_set (GTK_CONTAINER (self->main_grid),
+ self->summary_label,
+ "left-attach", 1,
+ "top-attach", 0,
+ "width", 1,
+ NULL);
+
+ gtk_label_set_line_wrap (GTK_LABEL (self->summary_label), FALSE);
+ gtk_widget_set_hexpand (self->hour_label, FALSE);
+ }
+ }
+
+ GTK_WIDGET_CLASS (gcal_event_widget_parent_class)->size_allocate (widget, allocation);
}
static cairo_surface_t*
@@ -912,6 +602,7 @@ gcal_event_widget_drag_begin (GtkWidget *widget,
surface = get_dnd_icon (widget);
gtk_drag_set_icon_surface (context, surface);
+ set_cursor (widget, CURSOR_GRABBING);
g_clear_pointer (&surface, cairo_surface_destroy);
}
@@ -923,8 +614,95 @@ gcal_event_widget_scroll_event (GtkWidget *widget,
return GDK_EVENT_PROPAGATE;
}
+
+/*
+ * GObject overrides
+ */
+
+static void
+gcal_event_widget_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GcalEventWidget *self = GCAL_EVENT_WIDGET (object);
+
+ switch (property_id)
+ {
+ case PROP_DATE_END:
+ gcal_event_widget_set_date_end (self, g_value_get_boxed (value));
+ break;
+
+ case PROP_DATE_START:
+ gcal_event_widget_set_date_start (self, g_value_get_boxed (value));
+ break;
+
+ case PROP_EVENT:
+ gcal_event_widget_set_event_internal (self, g_value_get_object (value));
+ break;
+
+ case PROP_ORIENTATION:
+ self->orientation = g_value_get_enum (value);
+ gtk_widget_queue_draw (GTK_WIDGET (object));
+ g_object_notify (object, "orientation");
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
static void
-gcal_event_widget_class_init(GcalEventWidgetClass *klass)
+gcal_event_widget_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GcalEventWidget *self = GCAL_EVENT_WIDGET (object);
+
+ switch (property_id)
+ {
+ case PROP_DATE_END:
+ g_value_set_boxed (value, self->dt_end);
+ break;
+
+ case PROP_DATE_START:
+ g_value_set_boxed (value, self->dt_start);
+ break;
+
+ case PROP_EVENT:
+ g_value_set_object (value, self->event);
+ break;
+
+ case PROP_ORIENTATION:
+ g_value_set_enum (value, self->orientation);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+gcal_event_widget_finalize (GObject *object)
+{
+ GcalEventWidget *self;
+
+ self = GCAL_EVENT_WIDGET (object);
+
+ /* disconnect signals */
+ g_signal_handlers_disconnect_by_func (self->event, update_color, self);
+ g_signal_handlers_disconnect_by_func (self->event, gtk_widget_queue_draw, self);
+
+ /* releasing properties */
+ g_clear_pointer (&self->css_class, g_free);
+ g_clear_object (&self->event);
+
+ G_OBJECT_CLASS (gcal_event_widget_parent_class)->finalize (object);
+}
+
+static void
+gcal_event_widget_class_init (GcalEventWidgetClass *klass)
{
GObjectClass *object_class;
GtkWidgetClass *widget_class;
@@ -935,17 +713,11 @@ gcal_event_widget_class_init(GcalEventWidgetClass *klass)
object_class->finalize = gcal_event_widget_finalize;
widget_class = GTK_WIDGET_CLASS (klass);
- widget_class->get_preferred_width = gcal_event_widget_get_preferred_width;
- widget_class->get_preferred_height = gcal_event_widget_get_preferred_height;
- widget_class->realize = gcal_event_widget_realize;
- widget_class->unrealize = gcal_event_widget_unrealize;
- widget_class->map = gcal_event_widget_map;
- widget_class->unmap = gcal_event_widget_unmap;
- widget_class->size_allocate = gcal_event_widget_size_allocate;
- widget_class->draw = gcal_event_widget_draw;
widget_class->button_press_event = gcal_event_widget_button_press_event;
widget_class->button_release_event = gcal_event_widget_button_release_event;
widget_class->drag_begin = gcal_event_widget_drag_begin;
+ widget_class->draw = gcal_event_widget_draw;
+ widget_class->size_allocate = gcal_event_widget_size_allocate;
widget_class->scroll_event = gcal_event_widget_scroll_event;
/**
@@ -954,7 +726,7 @@ gcal_event_widget_class_init(GcalEventWidgetClass *klass)
* The end date this widget represents. Notice that this may
* differ from the event's end date. For example, if the event
* spans more than one month and we're in Month View, the end
- * date marks the last day this event is visible.
+ * date marks the last day this event widget is visible.
*/
g_object_class_install_property (object_class,
PROP_DATE_END,
@@ -970,7 +742,7 @@ gcal_event_widget_class_init(GcalEventWidgetClass *klass)
* The start date this widget represents. Notice that this may
* differ from the event's start date. For example, if the event
* spans more than one month and we're in Month View, the start
- * date marks the first day this event is visible.
+ * date marks the first day this event widget is visible.
*/
g_object_class_install_property (object_class,
PROP_DATE_START,
@@ -1009,7 +781,18 @@ gcal_event_widget_class_init(GcalEventWidgetClass *klass)
G_TYPE_NONE,
0);
- gtk_widget_class_set_css_name (widget_class, "event-widget");
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/event-widget.ui");
+
+ gtk_widget_class_bind_template_child (widget_class, GcalEventWidget, alarm_icon);
+ gtk_widget_class_bind_template_child (widget_class, GcalEventWidget, event_box);
+ gtk_widget_class_bind_template_child (widget_class, GcalEventWidget, hour_label);
+ gtk_widget_class_bind_template_child (widget_class, GcalEventWidget, main_grid);
+ gtk_widget_class_bind_template_child (widget_class, GcalEventWidget, summary_label);
+
+ gtk_widget_class_bind_template_callback (widget_class, enter_notify_event_cb);
+ gtk_widget_class_bind_template_callback (widget_class, leave_notify_event_cb);
+
+ gtk_widget_class_set_css_name (widget_class, "event");
}
static void
@@ -1021,7 +804,8 @@ gcal_event_widget_init (GcalEventWidget *self)
self->clock_format_24h = is_clock_format_24h ();
self->orientation = GTK_ORIENTATION_HORIZONTAL;
- gtk_widget_set_has_window (widget, FALSE);
+ gtk_widget_init_template (GTK_WIDGET (self));
+
gtk_widget_set_can_focus (widget, TRUE);
/* Setup the event widget as a drag source */
@@ -1048,7 +832,7 @@ gcal_event_widget_set_read_only (GcalEventWidget *event,
{
g_return_if_fail (GCAL_IS_EVENT_WIDGET (event));
- if (read_only)
+ if (!read_only)
{
GtkWidget *widget = GTK_WIDGET (event);
diff --git a/src/gcal-event-widget.h b/src/gcal-event-widget.h
index b4034bd..f54216d 100644
--- a/src/gcal-event-widget.h
+++ b/src/gcal-event-widget.h
@@ -31,7 +31,7 @@ G_BEGIN_DECLS
#define GCAL_TYPE_EVENT_WIDGET (gcal_event_widget_get_type ())
-G_DECLARE_FINAL_TYPE (GcalEventWidget, gcal_event_widget, GCAL, EVENT_WIDGET, GtkWidget)
+G_DECLARE_FINAL_TYPE (GcalEventWidget, gcal_event_widget, GCAL, EVENT_WIDGET, GtkBin)
GtkWidget* gcal_event_widget_new (GcalEvent *event);
diff --git a/src/views/gcal-month-view.c b/src/views/gcal-month-view.c
index 7b80348..2bc25f6 100644
--- a/src/views/gcal-month-view.c
+++ b/src/views/gcal-month-view.c
@@ -1791,6 +1791,9 @@ gcal_month_view_size_allocate (GtkWidget *widget,
pos_x = cell_width * column + margin.left;
pos_y = cell_height * (row + first_row_gap) + start_grid_y + margin.top;
+ /* TODO: find a better way to take the lines into account */
+ pos_y += 2;
+
child_allocation.x = pos_x;
child_allocation.y = pos_y + vertical_cell_space - size_left[cell_idx];
child_allocation.width = cell_width * length - (margin.left + margin.right);
@@ -1865,6 +1868,9 @@ gcal_month_view_size_allocate (GtkWidget *widget,
pos_x = cell_width * (i % 7) + margin.left;
pos_y = cell_height * ((i / 7) + first_row_gap) + start_grid_y + margin.top;
+ /* TODO: find a better way to take the lines into account */
+ pos_y += 2;
+
child_allocation.x = pos_x;
child_allocation.y = pos_y + vertical_cell_space - size_left[i];
child_allocation.width = cell_width - (margin.left + margin.right);
diff --git a/src/views/gcal-week-grid.c b/src/views/gcal-week-grid.c
index a070a3d..a8eddea 100644
--- a/src/views/gcal-week-grid.c
+++ b/src/views/gcal-week-grid.c
@@ -615,8 +615,8 @@ gcal_week_grid_size_allocate (GtkWidget *widget,
gboolean ltr;
gdouble minutes_height;
gdouble column_width;
+ guint x, y;
guint i;
- guint x;
/* No need to relayout stuff if nothing changed */
if (allocation->height == gtk_widget_get_allocated_height (widget) &&
@@ -698,15 +698,21 @@ gcal_week_grid_size_allocate (GtkWidget *widget,
width = column_width / events_at_range - margin.left - margin.right;
height = (data->end - data->start) * minutes_height - margin.top - margin.bottom;
offset = (width + margin.left + margin.right) * widget_index;
+ y = (data->start % MINUTES_PER_DAY) * minutes_height + margin.top;
if (ltr)
x = column_width * i + offset + allocation->x + margin.left + 1;
else
x = allocation->width - width - (column_width * i + offset + allocation->x + margin.left + 1);
+ /* TODO: find a better way to handle line widths */
+ height -= 2;
+ width -= 1;
+ y += 1;
+
/* Setup the child position and size */
child_allocation.x = x;
- child_allocation.y = (data->start % MINUTES_PER_DAY) * minutes_height + margin.top;
+ child_allocation.y = y;
child_allocation.width = width;
child_allocation.height = height;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]