drop-overlay: Introduce GcalDropOverlay

A new widget to perform drag and drop operations, for example,
dropping ICS files to the GcalWindow. It allows to overlay
a child for visual feedback when a DnD operation is done.

either in the main window or in the import dialog,
depending on whether none could be imported, or just some
of them.

It is based on Loupe's DragOverlay widget.

Closes #1257
This commit is contained in:
Diego Iván
2024-08-05 12:31:31 -03:00
committed by Georges Basile Stavracas Neto
parent 75ad1425e7
commit dfc5a9b970
6 changed files with 622 additions and 156 deletions
+184
View File
@@ -0,0 +1,184 @@
/* gcal-drop-overlay.c
*
* Copyright 2024 Diego Iván <diegoivan.mae@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
// A drop overlay widget, based on Loupe's LpDragOverlay
// https://gitlab.gnome.org/GNOME/loupe/-/blob/692997ff0ee10ea187469c9da328010e1733dd6f/src/widgets/drag_overlay.rs
#define G_LOG_DOMAIN "GcalDropOverlay"
#include "gcal-debug.h"
#include "gcal-drop-overlay.h"
struct _GcalDropOverlay
{
AdwBin parent;
GtkOverlay *overlay;
GtkRevealer *revealer;
GtkDropTarget *drop_target;
};
static void on_current_drop_notify_cb (GcalDropOverlay *self);
G_DEFINE_TYPE (GcalDropOverlay, gcal_drop_overlay, ADW_TYPE_BIN)
enum
{
PROP_0,
PROP_CHILD,
PROP_OVERLAYED,
N_PROPS
};
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
on_current_drop_notify_cb (GcalDropOverlay *self)
{
GdkDrop *current_drop;
GCAL_ENTRY;
current_drop = gtk_drop_target_get_current_drop (self->drop_target);
if (current_drop != NULL)
{
gtk_revealer_set_reveal_child (self->revealer, TRUE);
gtk_widget_add_css_class (gtk_overlay_get_child (self->overlay), "blurred");
}
else
{
gtk_revealer_set_reveal_child (self->revealer, FALSE);
gtk_widget_remove_css_class (gtk_overlay_get_child (self->overlay), "blurred");
}
gtk_revealer_set_reveal_child (self->revealer, current_drop != NULL);
GCAL_EXIT;
}
static void
gcal_drop_overlay_dispose (GObject *object)
{
GcalDropOverlay *self = GCAL_DROP_OVERLAY (object);
g_clear_object (&self->drop_target);
G_OBJECT_CLASS (gcal_drop_overlay_parent_class)->dispose (object);
}
static void
gcal_drop_overlay_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GcalDropOverlay *self = GCAL_DROP_OVERLAY (object);
switch (prop_id)
{
case PROP_CHILD:
g_value_set_object (value, gtk_overlay_get_child (self->overlay));
break;
case PROP_OVERLAYED:
g_value_set_object (value, gtk_revealer_get_child (self->revealer));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gcal_drop_overlay_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GcalDropOverlay *self = GCAL_DROP_OVERLAY (object);
switch (prop_id)
{
case PROP_CHILD:
gtk_overlay_set_child (self->overlay, g_value_get_object (value));
break;
case PROP_OVERLAYED:
gtk_revealer_set_child (self->revealer, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gcal_drop_overlay_class_init (GcalDropOverlayClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gcal_drop_overlay_dispose;
object_class->get_property = gcal_drop_overlay_get_property;
object_class->set_property = gcal_drop_overlay_set_property;
properties[PROP_CHILD] = g_param_spec_object ("child", NULL, NULL,
GTK_TYPE_WIDGET,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
properties[PROP_OVERLAYED] = g_param_spec_object ("overlayed", NULL, NULL,
GTK_TYPE_WIDGET,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
gcal_drop_overlay_init (GcalDropOverlay *self)
{
self->overlay = GTK_OVERLAY (gtk_overlay_new ());
self->revealer = GTK_REVEALER (gtk_revealer_new ());
gtk_overlay_add_overlay (self->overlay, GTK_WIDGET (self->revealer));
gtk_widget_set_can_target (GTK_WIDGET (self->revealer), FALSE);
gtk_revealer_set_transition_type (self->revealer, GTK_REVEALER_TRANSITION_TYPE_CROSSFADE);
gtk_revealer_set_reveal_child (self->revealer, FALSE);
adw_bin_set_child (ADW_BIN (self), GTK_WIDGET (self->overlay));
}
void
gcal_drop_overlay_set_drop_target (GcalDropOverlay *self,
GtkDropTarget *drop_target)
{
GCAL_ENTRY;
g_return_if_fail (GCAL_IS_DROP_OVERLAY (self));
g_return_if_fail (GTK_IS_DROP_TARGET (drop_target));
g_set_object (&self->drop_target, drop_target);
g_signal_connect_object (self->drop_target,
"notify::current-drop",
G_CALLBACK (on_current_drop_notify_cb),
self,
G_CONNECT_SWAPPED);
GCAL_EXIT;
}
+36
View File
@@ -0,0 +1,36 @@
/* gcal-drop-overlay.h
*
* Copyright 2024 Diego Iván M.E <diegoivan.mae@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include "gcal-context.h"
#include "gcal-event.h"
#include <adwaita.h>
G_BEGIN_DECLS
#define GCAL_TYPE_DROP_OVERLAY (gcal_drop_overlay_get_type())
G_DECLARE_FINAL_TYPE (GcalDropOverlay, gcal_drop_overlay, GCAL, DROP_OVERLAY, AdwBin)
void gcal_drop_overlay_set_drop_target (GcalDropOverlay *self,
GtkDropTarget *drop_target);
G_END_DECLS
+198
View File
@@ -25,6 +25,7 @@
#include "config.h"
#include "gcal-date-chooser.h"
#include "gcal-debug.h"
#include "gcal-drop-overlay.h"
#include "gcal-event-editor-dialog.h"
#include "gcal-event-widget.h"
#include "gcal-context.h"
@@ -90,6 +91,12 @@ typedef struct
gchar *uuid;
} OpenEditDialogData;
typedef struct
{
GList *ics_files;
GList *invalid_files;
} FileFilterResult;
struct _GcalWindow
{
AdwApplicationWindow parent;
@@ -158,6 +165,11 @@ struct _GcalWindow
/* Window states */
gboolean in_key_press;
/* File drop */
GcalDropOverlay *drop_overlay;
AdwStatusPage *drop_status_page;
GtkDropTarget *drop_target;
};
enum
@@ -340,6 +352,86 @@ content_title (GcalWindow *self,
return g_strdup (_("Month"));
}
static inline void
free_file_filter_result (FileFilterResult *self)
{
g_list_free_full (self->ics_files, g_object_unref);
g_list_free_full (self->invalid_files, g_object_unref);
}
static inline gboolean
is_ics_file (GFile *file)
{
g_autoptr (GFileInfo) file_info = NULL;
g_autoptr (GError) error = NULL;
file_info = g_file_query_info (file,
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
G_FILE_QUERY_INFO_NONE,
NULL,
&error);
if (error)
return FALSE;
return g_strcmp0 (g_file_info_get_content_type (file_info), "text/calendar") == 0;
}
static inline void
free_file_slist_full (GSList *files)
{
g_slist_free_full (files, g_object_unref);
}
static void
filter_ics_files_thread (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
FileFilterResult *result;
GSList *files;
files = task_data;
result = g_new0 (FileFilterResult, 1);
for (GSList *iter = files; iter != NULL; iter = iter->next)
{
GFile *file = G_FILE (iter->data);
if (is_ics_file (file))
result->ics_files = g_list_prepend (result->ics_files, g_object_ref (file));
else
result->invalid_files = g_list_prepend (result->invalid_files, g_object_ref (file));
}
g_task_return_pointer (task, result, NULL);
}
static FileFilterResult*
filter_ics_files_finish (GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
return g_task_propagate_pointer (G_TASK (result), error);
}
static void
filter_ics_files (GcalWindow *self,
GSList *files,
GAsyncReadyCallback callback)
{
g_autoslist (GFile) files_copy = NULL;
g_autoptr (GTask) task = NULL;
files_copy = g_slist_copy_deep (files, (GCopyFunc) g_object_ref, NULL);
task = g_task_new (NULL, NULL, callback, self);
g_task_set_task_data (task, g_steal_pointer (&files_copy), (GDestroyNotify) free_file_slist_full);
g_task_set_source_tag (task, filter_ics_files);
g_task_run_in_thread (task, filter_ics_files_thread);
}
/*
* Callbacks
*/
@@ -763,6 +855,99 @@ on_event_editor_dialog_remove_event_cb (GcalEventEditorDialog *edit_dialog,
GCAL_EXIT;
}
static gboolean
on_drop_target_accept_cb (GtkDropTarget *target,
GdkDrop *drop,
gpointer user_data)
{
GdkDrag *drag;
GdkContentFormats *formats;
drag = gdk_drop_get_drag (drop);
formats = gdk_drop_get_formats (drop);
// If drag is NULL, it means we are not receiving the from an external application/window,
// but from internal sources, i.e, dragging events
gboolean is_external = drag == NULL;
return is_external && gdk_content_formats_contain_gtype (formats, GDK_TYPE_FILE_LIST);
}
static void
on_ics_files_filtered_cb (GObject *source_object,
GAsyncResult *result,
gpointer data)
{
g_autoptr (GError) error = NULL;
g_autofree gchar* toast_title = NULL;
AdwToast *error_toast = NULL;
GcalWindow *self;
FileFilterResult *filter_result;
GCAL_ENTRY;
self = GCAL_WINDOW (data);
filter_result = filter_ics_files_finish (result, &error);
if (error)
return;
// Creates an error toast if it's needed
if (filter_result->invalid_files)
{
if (filter_result->invalid_files->next)
{
toast_title = g_strdup(_("Could not import some files: Not ICS files"));
}
else
{
g_autofree gchar *basename = g_file_get_basename (filter_result->invalid_files->data);
toast_title = g_strdup_printf (_("Could not import “%s”: Not an ICS file"), basename);
}
error_toast = adw_toast_new (toast_title);
}
if (filter_result->ics_files)
{
g_clear_pointer (&self->import_dialog, gtk_widget_unparent);
self->import_dialog = gcal_import_dialog_new_for_file_list (self->context, filter_result->ics_files);
adw_dialog_present (ADW_DIALOG (self->import_dialog), GTK_WIDGET (self));
g_object_add_weak_pointer (G_OBJECT (self->import_dialog), (gpointer *)&self->import_dialog);
if (error_toast)
gcal_import_dialog_add_toast (GCAL_IMPORT_DIALOG (self->import_dialog), error_toast);
}
else
{
adw_toast_overlay_add_toast (self->overlay, error_toast);
}
g_clear_pointer (&filter_result, free_file_filter_result);
GCAL_EXIT;
}
static gboolean
on_drop_target_drop_cb (GtkDropTarget *target,
const GValue *value,
gdouble x,
gdouble y,
gpointer user_data)
{
g_autoptr (GSList) files = NULL;
GdkFileList *file_list;
GcalWindow *self;
GCAL_ENTRY;
self = GCAL_WINDOW (user_data);
file_list = g_value_get_boxed (value);
files = gdk_file_list_get_files (file_list);
filter_ics_files (self, files, on_ics_files_filtered_cb);
GCAL_RETURN (TRUE);
}
static gboolean
schedule_open_edit_dialog_by_uuid (OpenEditDialogData *edit_dialog_data)
{
@@ -1023,6 +1208,7 @@ gcal_window_class_init (GcalWindowClass *klass)
g_type_ensure (GCAL_TYPE_TOOLBAR_END);
g_type_ensure (GCAL_TYPE_WEATHER_SETTINGS);
g_type_ensure (GCAL_TYPE_WEEK_VIEW);
g_type_ensure (GCAL_TYPE_DROP_OVERLAY);
object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gcal_window_finalize;
@@ -1085,6 +1271,8 @@ gcal_window_class_init (GcalWindowClass *klass)
gtk_widget_class_bind_template_child (widget_class, GcalWindow, views_switcher);
gtk_widget_class_bind_template_child (widget_class, GcalWindow, weather_settings);
gtk_widget_class_bind_template_child (widget_class, GcalWindow, week_view);
gtk_widget_class_bind_template_child (widget_class, GcalWindow, drop_overlay);
gtk_widget_class_bind_template_child (widget_class, GcalWindow, drop_target);
gtk_widget_class_bind_template_callback (widget_class, view_changed);
@@ -1099,6 +1287,10 @@ gcal_window_class_init (GcalWindowClass *klass)
/* Edit dialog related */
gtk_widget_class_bind_template_callback (widget_class, on_event_editor_dialog_remove_event_cb);
/* Drop Target related */
gtk_widget_class_bind_template_callback (widget_class, on_drop_target_accept_cb);
gtk_widget_class_bind_template_callback (widget_class, on_drop_target_drop_cb);
}
static void
@@ -1135,6 +1327,12 @@ gcal_window_init (GcalWindow *self)
gtk_widget_add_css_class (GTK_WIDGET (self), "devel");
gtk_widget_set_parent (self->quick_add_popover, GTK_WIDGET (self));
GType drop_types[] = { GDK_TYPE_FILE_LIST };
gtk_drop_target_set_gtypes (self->drop_target, drop_types,
G_N_ELEMENTS(drop_types));
gcal_drop_overlay_set_drop_target(self->drop_overlay, self->drop_target);
}
/**
+182 -156
View File
@@ -117,174 +117,200 @@
<child>
<object class="AdwToastOverlay" id="overlay">
<child>
<object class="AdwNavigationSplitView" id="split_view">
<!-- Sidebar -->
<property name="sidebar">
<object class="AdwNavigationPage">
<property name="title" translatable="yes">Calendar</property>
<property name="child">
<object class="AdwToolbarView">
<child type="top">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="AdwHeaderBar">
<child type="start">
<object class="GcalSyncIndicator" id="sync_indicator" />
</child>
<property name="title-widget">
<object class="GcalCalendarButton" id="calendars_button" />
</property>
<child type="end">
<object class="GtkMenuButton" id="menu_button">
<property name="icon-name">open-menu-symbolic</property>
<property name="popover">win_menu</property>
<property name="tooltip-text" translatable="yes">Main Menu</property>
<property name="primary">True</property>
</object>
</child>
</object>
</child>
<child>
<object class="GcalDateChooser" id="date_chooser">
<property name="split-month-year">False</property>
<property name="vexpand">False</property>
<property name="active-date" bind-source="GcalWindow" bind-property="active-date" bind-flags="bidirectional"/>
<signal name="day-selected" handler="day_selected" object="GcalWindow" swapped="yes"/>
</object>
</child>
</object>
</child>
<property name="content">
<object class="GcalAgendaView" id="agenda_view">
<property name="vexpand">True</property>
<property name="active-date" bind-source="GcalWindow" bind-property="active-date" bind-flags="bidirectional"/>
<signal name="create-event" handler="show_new_event_widget" object="GcalWindow" swapped="no"/>
<signal name="event-activated" handler="event_activated" object="GcalWindow" swapped="no"/>
</object>
</property>
<child type="bottom">
<object class="GtkActionBar" id="action_bar">
<property name="revealed">False</property>
<child type="start">
<object class="GtkButton">
<property name="action-name">win.today</property>
<property name="child">
<object class="AdwButtonContent">
<property name="label" translatable="yes">_Today</property>
<property name="use-underline">True</property>
<property name="icon-name">calendar-today-symbolic</property>
<property name="can-shrink">True</property>
</object>
</property>
</object>
</child>
<child type="end">
<object class="GcalToolbarEnd" id="sidebar_toolbar_end"/>
</child>
</object>
</child>
</object>
</property>
<object class="GcalDropOverlay" id="drop_overlay">
<property name="overlayed">
<object class="AdwStatusPage" id="drop_status_page">
<property name="title" translatable="yes">Drop Event Files to Import</property>
<property name="icon-name">calendar-month-symbolic</property>
<style>
<class name="drop-overlay-area"/>
<class name="compact"/>
</style>
</object>
</property>
<property name="child">
<object class="AdwNavigationSplitView" id="split_view">
<child>
<object class="GtkDropTarget" id="drop_target">
<property name="actions">copy</property>
<property name="propagation-phase">capture</property>
<signal name="accept" handler="on_drop_target_accept_cb" object="GcalWindow" swapped="no"/>
<signal name="drop" handler="on_drop_target_drop_cb" object="GcalWindow" swapped="no"/>
</object>
</child>
<style>
<class name="drop-target"/>
</style>
<!-- Sidebar -->
<property name="sidebar">
<object class="AdwNavigationPage">
<property name="title" translatable="yes">Calendar</property>
<property name="child">
<object class="AdwToolbarView">
<child type="top">
<object class="GtkBox">
<property name="orientation">vertical</property>
<!-- Main content -->
<property name="content">
<object class="AdwNavigationPage" id="content_page">
<binding name="title">
<closure type="gchararray" function="content_title">
<lookup type="GcalWindow" name="active-view"/>
</closure>
</binding>
<property name="child">
<object class="AdwToolbarView">
<style>
<class name="view" />
</style>
<child type="top">
<object class="AdwHeaderBar" id="header_bar">
<child>
<object class="GtkButton">
<property name="action-name">win.today</property>
<property name="child">
<object class="AdwButtonContent">
<property name="label" translatable="yes">_Today</property>
<property name="use-underline">True</property>
<property name="icon-name">calendar-today-symbolic</property>
<property name="can-shrink">True</property>
</object>
</property>
</object>
</child>
<child type="title">
<object class="AdwViewSwitcher" id="views_switcher">
<property name="stack">views_stack</property>
<property name="policy">wide</property>
</object>
</child>
<child type="end">
<object class="GcalToolbarEnd" id="toolbar_end" />
</child>
</object>
</child>
<property name="content">
<object class="GtkBox" id="main_box">
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<child>
<object class="AdwViewStack" id="views_stack">
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<signal name="notify::visible-child" handler="view_changed" object="GcalWindow" swapped="no"/>
<style>
<class name="view"/>
</style>
<child>
<object class="AdwViewStackPage">
<property name="name">week</property>
<property name="title" translatable="yes">_Week</property>
<property name="use-underline">True</property>
<property name="icon_name">calendar-week-symbolic</property>
<object class="AdwHeaderBar">
<child type="start">
<object class="GcalSyncIndicator" id="sync_indicator" />
</child>
<property name="title-widget">
<object class="GcalCalendarButton" id="calendars_button" />
</property>
<child type="end">
<object class="GtkMenuButton" id="menu_button">
<property name="icon-name">open-menu-symbolic</property>
<property name="popover">win_menu</property>
<property name="tooltip-text" translatable="yes">Main Menu</property>
<property name="primary">True</property>
</object>
</child>
</object>
</child>
<child>
<object class="GcalDateChooser" id="date_chooser">
<property name="split-month-year">False</property>
<property name="vexpand">False</property>
<property name="active-date" bind-source="GcalWindow" bind-property="active-date" bind-flags="bidirectional"/>
<signal name="day-selected" handler="day_selected" object="GcalWindow" swapped="yes"/>
</object>
</child>
</object>
</child>
<property name="content">
<object class="GcalAgendaView" id="agenda_view">
<property name="vexpand">True</property>
<property name="active-date" bind-source="GcalWindow" bind-property="active-date" bind-flags="bidirectional"/>
<signal name="create-event" handler="show_new_event_widget" object="GcalWindow" swapped="no"/>
<signal name="event-activated" handler="event_activated" object="GcalWindow" swapped="no"/>
</object>
</property>
<child type="bottom">
<object class="GtkActionBar" id="action_bar">
<property name="revealed">False</property>
<child type="start">
<object class="GtkButton">
<property name="action-name">win.today</property>
<property name="child">
<object class="GcalWeekView" id="week_view">
<property name="active-date" bind-source="GcalWindow" bind-property="active-date" bind-flags="bidirectional"/>
<signal name="create-event" handler="show_new_event_widget" object="GcalWindow" swapped="no"/>
<signal name="event-activated" handler="event_activated" object="GcalWindow" swapped="no"/>
<object class="AdwButtonContent">
<property name="label" translatable="yes">_Today</property>
<property name="use-underline">True</property>
<property name="icon-name">calendar-today-symbolic</property>
<property name="can-shrink">True</property>
</object>
</property>
</object>
</child>
<child>
<object class="AdwViewStackPage">
<property name="name">month</property>
<property name="title" translatable="yes">_Month</property>
<property name="use-underline">True</property>
<property name="icon_name">calendar-month-symbolic</property>
<property name="child">
<object class="GcalMonthView" id="month_view">
<property name="active-date" bind-source="GcalWindow" bind-property="active-date" bind-flags="bidirectional"/>
<signal name="create-event" handler="show_new_event_widget" object="GcalWindow" swapped="no"/>
<signal name="create-event-detailed" handler="create_event_detailed_cb" object="GcalWindow" swapped="no"/>
<signal name="event-activated" handler="event_activated" object="GcalWindow" swapped="no"/>
</object>
</property>
</object>
<child type="end">
<object class="GcalToolbarEnd" id="sidebar_toolbar_end"/>
</child>
</object>
</child>
</object>
</property>
</object>
</property>
<!-- Main content -->
<property name="content">
<object class="AdwNavigationPage" id="content_page">
<binding name="title">
<closure type="gchararray" function="content_title">
<lookup type="GcalWindow" name="active-view"/>
</closure>
</binding>
<property name="child">
<object class="AdwToolbarView">
<style>
<class name="view" />
</style>
<child type="top">
<object class="AdwHeaderBar" id="header_bar">
<child>
<object class="GtkButton">
<property name="action-name">win.today</property>
<property name="child">
<object class="AdwButtonContent">
<property name="label" translatable="yes">_Today</property>
<property name="use-underline">True</property>
<property name="icon-name">calendar-today-symbolic</property>
<property name="can-shrink">True</property>
</object>
</property>
</object>
</child>
<child type="title">
<object class="AdwViewSwitcher" id="views_switcher">
<property name="stack">views_stack</property>
<property name="policy">wide</property>
</object>
</child>
<child type="end">
<object class="GcalToolbarEnd" id="toolbar_end" />
</child>
</object>
</child>
<property name="content">
<object class="GtkBox" id="main_box">
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<child>
<object class="AdwViewStack" id="views_stack">
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<signal name="notify::visible-child" handler="view_changed" object="GcalWindow" swapped="no"/>
<style>
<class name="view"/>
</style>
<child>
<object class="AdwViewStackPage">
<property name="name">week</property>
<property name="title" translatable="yes">_Week</property>
<property name="use-underline">True</property>
<property name="icon_name">calendar-week-symbolic</property>
<property name="child">
<object class="GcalWeekView" id="week_view">
<property name="active-date" bind-source="GcalWindow" bind-property="active-date" bind-flags="bidirectional"/>
<signal name="create-event" handler="show_new_event_widget" object="GcalWindow" swapped="no"/>
<signal name="event-activated" handler="event_activated" object="GcalWindow" swapped="no"/>
</object>
</property>
</object>
</child>
<child>
<object class="AdwViewStackPage">
<property name="name">month</property>
<property name="title" translatable="yes">_Month</property>
<property name="use-underline">True</property>
<property name="icon_name">calendar-month-symbolic</property>
<property name="child">
<object class="GcalMonthView" id="month_view">
<property name="active-date" bind-source="GcalWindow" bind-property="active-date" bind-flags="bidirectional"/>
<signal name="create-event" handler="show_new_event_widget" object="GcalWindow" swapped="no"/>
<signal name="create-event-detailed" handler="create_event_detailed_cb" object="GcalWindow" swapped="no"/>
<signal name="event-activated" handler="event_activated" object="GcalWindow" swapped="no"/>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</property>
</object>
</property>
</object>
@@ -314,7 +340,7 @@
<object class="GcalEventEditorDialog" id="event_editor">
<signal name="remove-event" handler="on_event_editor_dialog_remove_event_cb" object="GcalWindow" swapped="no"/>
</object>
<menu id='menu'>
<section>
<item>
@@ -346,11 +372,11 @@
<object class="GtkPopoverMenu" id="win_menu">
<property name="menu-model">menu</property>
<!-- Weather submenu -->
<child type="weather">
<object class="GcalWeatherSettings" id="weather_settings" />
</child>
</object>
</interface>
+1
View File
@@ -16,6 +16,7 @@ built_sources += gnome.compile_resources(
sources += files(
'gcal-application.c',
'gcal-calendar-button.c',
'gcal-drop-overlay.c',
'gcal-event-popover.c',
'gcal-event-widget.c',
'gcal-meeting-row.c',