diff --git a/data/calendar.gresource.xml b/data/calendar.gresource.xml index 6b5397e4..4921985a 100644 --- a/data/calendar.gresource.xml +++ b/data/calendar.gresource.xml @@ -6,6 +6,7 @@ ui/date-chooser.ui ui/date-selector.ui ui/edit-dialog.ui + ui/event-widget.ui ui/multi-choice.ui ui/online-account-row.ui ui/quick-add-popover.ui diff --git a/data/theme/gtk-styles.css b/data/theme/gtk-styles.css index 6f614c14..abaa206a 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 00000000..68bc3eef --- /dev/null +++ b/data/ui/event-widget.ui @@ -0,0 +1,66 @@ + + + + diff --git a/src/css-code.h b/src/css-code.h index a0786145..e1e9061c 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 bee13f2b..6025fc17 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)) + switch (type) { - display_text = escaped_text; - } - else - { - 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 ("%s\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; -} + gdk_window_set_cursor (gtk_widget_get_window (widget), cursor); + gdk_display_flush (display); -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); - - 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,7 +419,199 @@ gcal_event_widget_set_event_internal (GcalEventWidget *self, G_CALLBACK (gtk_widget_queue_draw), self); + /* Tooltip */ gcal_event_widget_set_event_tooltip (self, event); + + /* Alarm icon */ + gtk_widget_set_visible (self->alarm_icon, gcal_event_has_alarms (event)); + + /* Hour label */ + hour_str = get_hour_label (self); + + gtk_widget_set_visible (self->hour_label, !gcal_event_get_all_day (event)); + gtk_label_set_label (GTK_LABEL (self->hour_label), hour_str); + + /* Summary label */ + g_object_bind_property (event, + "summary", + self->summary_label, + "label", + G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); +} + + +/* + * Callbacks + */ + +static gboolean +enter_notify_event_cb (GtkWidget *event_box, + GdkEvent *event, + GtkWidget *widget) +{ + set_cursor (widget, CURSOR_GRAB); + return GDK_EVENT_PROPAGATE; +} + + +static gboolean +leave_notify_event_cb (GtkWidget *event_box, + GdkEvent *event, + GtkWidget *widget) +{ + set_cursor (widget, CURSOR_NONE); + return GDK_EVENT_PROPAGATE; +} + + +/* + * GtkWidget overrides + */ + +static gboolean +gcal_event_widget_draw (GtkWidget *widget, + cairo_t *cr) +{ + GtkStyleContext *context; + guint width, height; + + context = gtk_widget_get_style_context (widget); + + width = gtk_widget_get_allocated_width (widget); + height = gtk_widget_get_allocated_height (widget); + + gtk_render_background (context, cr, 0, 0, width, height); + gtk_render_frame (context, cr, 0, 0, width, height); + + return GTK_WIDGET_CLASS (gcal_event_widget_parent_class)->draw (widget, cr); +} + +static gboolean +gcal_event_widget_button_press_event (GtkWidget *widget, + GdkEventButton *event) +{ + GcalEventWidget *self; + + self = GCAL_EVENT_WIDGET (widget); + self->button_pressed = TRUE; + + return GDK_EVENT_STOP; +} + +static gboolean +gcal_event_widget_button_release_event (GtkWidget *widget, + GdkEventButton *event) +{ + GcalEventWidget *self; + + self = GCAL_EVENT_WIDGET (widget); + + if (self->button_pressed) + { + set_cursor (widget, CURSOR_NONE); + + self->button_pressed = FALSE; + g_signal_emit (widget, signals[ACTIVATE], 0); + + return GDK_EVENT_STOP; + } + + 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* +get_dnd_icon (GtkWidget *widget) +{ + cairo_surface_t *surface; + cairo_t *cr; + + /* Make it transparent */ + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + gtk_widget_get_allocated_width (widget), + gtk_widget_get_allocated_height (widget)); + + cr = cairo_create (surface); + + gtk_widget_draw (widget, cr); + cairo_destroy (cr); + + return surface; +} + +static void +gcal_event_widget_drag_begin (GtkWidget *widget, + GdkDragContext *context) +{ + GcalEventWidget *self = GCAL_EVENT_WIDGET (widget); + cairo_surface_t *surface; + + if (self->read_only) + { + gtk_drag_cancel (context); + return; + } + + /* Setup the drag n' drop icon */ + surface = get_dnd_icon (widget); + + gtk_drag_set_icon_surface (context, surface); + set_cursor (widget, CURSOR_GRABBING); + + g_clear_pointer (&surface, cairo_surface_destroy); +} + +static gboolean +gcal_event_widget_scroll_event (GtkWidget *widget, + GdkEventScroll *scroll_event) +{ + return GDK_EVENT_PROPAGATE; } @@ -524,407 +702,7 @@ gcal_event_widget_finalize (GObject *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); -} - -static void -gcal_event_widget_unrealize (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); -} - -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) -{ - 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); -} - -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); - } -} - -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; - - 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); - - 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 ("%s", 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); -} - -static gboolean -gcal_event_widget_button_press_event (GtkWidget *widget, - GdkEventButton *event) -{ - GcalEventWidget *self; - - self = GCAL_EVENT_WIDGET (widget); - self->button_pressed = TRUE; - return TRUE; -} - -static gboolean -gcal_event_widget_button_release_event (GtkWidget *widget, - GdkEventButton *event) -{ - GcalEventWidget *self; - - self = GCAL_EVENT_WIDGET (widget); - - if (self->button_pressed) - { - self->button_pressed = FALSE; - g_signal_emit (widget, signals[ACTIVATE], 0); - return TRUE; - } - - return FALSE; -} - -static cairo_surface_t* -get_dnd_icon (GtkWidget *widget) -{ - cairo_surface_t *surface; - cairo_t *cr; - - /* Make it transparent */ - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - gtk_widget_get_allocated_width (widget), - gtk_widget_get_allocated_height (widget)); - - cr = cairo_create (surface); - - gtk_widget_draw (widget, cr); - cairo_destroy (cr); - - return surface; -} - -static void -gcal_event_widget_drag_begin (GtkWidget *widget, - GdkDragContext *context) -{ - GcalEventWidget *self = GCAL_EVENT_WIDGET (widget); - cairo_surface_t *surface; - - if (self->read_only) - { - gtk_drag_cancel (context); - return; - } - - /* Setup the drag n' drop icon */ - surface = get_dnd_icon (widget); - - gtk_drag_set_icon_surface (context, surface); - - g_clear_pointer (&surface, cairo_surface_destroy); -} - -static gboolean -gcal_event_widget_scroll_event (GtkWidget *widget, - GdkEventScroll *scroll_event) -{ - return GDK_EVENT_PROPAGATE; -} - -static void -gcal_event_widget_class_init(GcalEventWidgetClass *klass) +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 b4034bda..f54216d5 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 7b80348e..2bc25f66 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 a070a3d5..a8eddea8 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;