summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2020-09-27 14:43:04 -0300
committerGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2020-09-27 14:43:04 -0300
commite6b4270fcfa00b2947cfff61cba8137131bb722c (patch)
tree77edfa94c19ee1129f9cff9c556b1467792f390c
parent75f289de59ed9897f40c4e23647e80c6e037ca21 (diff)
downloadgnome-todo-gbsneto/listview2.tar.gz
Initial port to GtkListViewgbsneto/listview2
Various APIs needed to be revisited or simply removed to support this.
-rw-r--r--src/gui/gtd-edit-pane.c10
-rw-r--r--src/gui/gtd-new-task-row.ui11
-rw-r--r--src/gui/gtd-task-list-popover.c4
-rw-r--r--src/gui/gtd-task-list-view-model.c210
-rw-r--r--src/gui/gtd-task-list-view-model.h43
-rw-r--r--src/gui/gtd-task-list-view.c885
-rw-r--r--src/gui/gtd-task-list-view.h22
-rw-r--r--src/gui/gtd-task-list-view.ui102
-rw-r--r--src/gui/gtd-task-row.c91
-rw-r--r--src/gui/gtd-task-row.h10
-rw-r--r--src/gui/gtd-task-row.ui14
-rw-r--r--src/meson.build1
-rw-r--r--src/plugins/inbox-panel/gtd-inbox-panel.c2
13 files changed, 483 insertions, 922 deletions
diff --git a/src/gui/gtd-edit-pane.c b/src/gui/gtd-edit-pane.c
index 9f9dabc5..07612fca 100644
--- a/src/gui/gtd-edit-pane.c
+++ b/src/gui/gtd-edit-pane.c
@@ -74,25 +74,25 @@ static void
update_date_widgets (GtdEditPane *self)
{
g_autoptr (GDateTime) dt = NULL;
- gchar *text;
+ g_autofree gchar *text = NULL;
g_return_if_fail (GTD_IS_EDIT_PANE (self));
- dt = self->task ? g_date_time_ref (gtd_task_get_due_date (self->task)) : NULL;
- text = dt ? g_date_time_format (dt, "%x") : NULL;
+ dt = self->task ? gtd_task_get_due_date (self->task) : NULL;
g_signal_handlers_block_by_func (self->calendar, on_date_selected_cb, self);
if (!dt)
dt = g_date_time_new_now_local ();
+ else
+ g_date_time_ref (dt);
gtk_calendar_select_day (self->calendar, dt);
g_signal_handlers_unblock_by_func (self->calendar, on_date_selected_cb, self);
+ text = dt ? g_date_time_format (dt, "%x") : NULL;
gtk_label_set_label (self->date_label, text ? text : _("No date set"));
-
- g_free (text);
}
diff --git a/src/gui/gtd-new-task-row.ui b/src/gui/gtd-new-task-row.ui
index b28a1267..12a0df01 100644
--- a/src/gui/gtd-new-task-row.ui
+++ b/src/gui/gtd-new-task-row.ui
@@ -3,9 +3,18 @@
<requires lib="gtk+" version="3.16"/>
<template class="GtdNewTaskRow" parent="GtkWidget">
<property name="can_focus">1</property>
- <property name="margin-top">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-end">12</property>
+ <property name="margin-top">6</property>
+ <property name="margin-bottom">6</property>
<property name="height-request">42</property>
<property name="css-name">newtaskrow</property>
+ <property name="halign">center</property>
+ <property name="layout-manager">
+ <object class="GtdMaxSizeLayout">
+ <property name="max-width">700</property>
+ </object>
+ </property>
<child>
<object class="GtkEntry" id="entry">
<property name="can_focus">1</property>
diff --git a/src/gui/gtd-task-list-popover.c b/src/gui/gtd-task-list-popover.c
index 176c0e5b..a81d4618 100644
--- a/src/gui/gtd-task-list-popover.c
+++ b/src/gui/gtd-task-list-popover.c
@@ -243,12 +243,12 @@ gtd_task_list_popover_init (GtdTaskListPopover *self)
GtdManager *manager = gtd_manager_get_default ();
GtkCustomFilter *filter;
+ gtk_widget_init_template (GTK_WIDGET (self));
+
filter = gtk_custom_filter_new (filter_listbox_cb, self, NULL);
self->filter_model = gtk_filter_list_model_new (gtd_manager_get_task_lists_model (manager),
GTK_FILTER (filter));
- gtk_widget_init_template (GTK_WIDGET (self));
-
gtk_list_box_bind_model (self->listbox,
G_LIST_MODEL (self->filter_model),
create_list_row_cb,
diff --git a/src/gui/gtd-task-list-view-model.c b/src/gui/gtd-task-list-view-model.c
new file mode 100644
index 00000000..87b6f41d
--- /dev/null
+++ b/src/gui/gtd-task-list-view-model.c
@@ -0,0 +1,210 @@
+/* gtd-task-list-view-model.c
+ *
+ * Copyright 2020 Georges Basile Stavracas Neto <georges.stavracas@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
+ */
+
+#include "gtd-task-list-view-model.h"
+
+
+/*
+ * Sentinel
+ */
+
+struct _GtdSentinel
+{
+ GObject parent_instance;
+};
+
+G_DEFINE_TYPE (GtdSentinel, gtd_sentinel, G_TYPE_OBJECT);
+
+static void
+gtd_sentinel_init (GtdSentinel *self)
+{
+}
+
+static void
+gtd_sentinel_class_init (GtdSentinelClass *klass)
+{
+}
+
+
+
+struct _GtdTaskListViewModel
+{
+ GObject parent_instance;
+
+ GtdSentinel *sentinel;
+
+ GListModel *model;
+ guint n_items;
+};
+
+static void g_list_model_iface_init (GListModelInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GtdTaskListViewModel, gtd_task_list_view_model, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, g_list_model_iface_init))
+
+
+/*
+ * Auxiliary methods
+ */
+
+static void
+update_n_items (GtdTaskListViewModel *self,
+ guint position,
+ guint removed,
+ guint added)
+{
+ self->n_items = self->n_items - removed + added;
+ g_list_model_items_changed (G_LIST_MODEL (self), position, removed, added);
+}
+
+
+/*
+ * Callbacks
+ */
+
+static void
+on_model_items_changed_cb (GListModel *model,
+ guint position,
+ guint removed,
+ guint added,
+ GtdTaskListViewModel *self)
+{
+ update_n_items (self, position, removed, added);
+}
+
+
+/*
+ * GListModel interface
+ */
+
+static guint
+gtd_task_list_view_model_get_n_items (GListModel *model)
+{
+ GtdTaskListViewModel *self = (GtdTaskListViewModel *)model;
+
+ return self->n_items + 1;
+}
+
+static GType
+gtd_task_list_view_model_get_item_type (GListModel *model)
+{
+ return G_TYPE_OBJECT;
+}
+
+static gpointer
+gtd_task_list_view_model_get_item (GListModel *model,
+ guint position)
+{
+ GtdTaskListViewModel *self = (GtdTaskListViewModel *)model;
+
+ if (gtd_task_list_view_model_is_sentinel (self, position))
+ return g_object_ref (self->sentinel);
+
+ return g_list_model_get_item (self->model, position);
+}
+
+static void
+g_list_model_iface_init (GListModelInterface *iface)
+{
+ iface->get_n_items = gtd_task_list_view_model_get_n_items;
+ iface->get_item_type = gtd_task_list_view_model_get_item_type;
+ iface->get_item = gtd_task_list_view_model_get_item;
+}
+
+
+/*
+ * GObject overrides
+ */
+
+static void
+gtd_task_list_view_model_finalize (GObject *object)
+{
+ GtdTaskListViewModel *self = (GtdTaskListViewModel *)object;
+
+ g_clear_object (&self->model);
+ g_clear_object (&self->sentinel);
+
+ G_OBJECT_CLASS (gtd_task_list_view_model_parent_class)->finalize (object);
+}
+
+static void
+gtd_task_list_view_model_class_init (GtdTaskListViewModelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gtd_task_list_view_model_finalize;
+}
+
+static void
+gtd_task_list_view_model_init (GtdTaskListViewModel *self)
+{
+ self->sentinel = g_object_new (GTD_TYPE_SENTINEL, NULL);
+}
+
+GtdTaskListViewModel *
+gtd_task_list_view_model_new (void)
+{
+ return g_object_new (GTD_TYPE_TASK_LIST_VIEW_MODEL, NULL);
+}
+
+GListModel *
+gtd_task_list_view_model_get_model (GtdTaskListViewModel *self)
+{
+ return self->model;
+}
+
+void
+gtd_task_list_view_model_set_model (GtdTaskListViewModel *self,
+ GListModel *model)
+{
+ guint old_n_items = self->n_items;
+ guint new_n_items = 0;
+
+ if (self->model)
+ {
+ g_signal_handlers_disconnect_by_func (self->model,
+ on_model_items_changed_cb,
+ self);
+ }
+
+ g_clear_object (&self->model);
+
+ if (model)
+ {
+ self->model = g_object_ref (model);
+
+ g_signal_connect_object (model,
+ "items-changed",
+ G_CALLBACK (on_model_items_changed_cb),
+ self,
+ 0);
+
+ new_n_items = g_list_model_get_n_items (model);
+ }
+
+ update_n_items (self, 0, old_n_items, new_n_items);
+}
+
+gboolean
+gtd_task_list_view_model_is_sentinel (GtdTaskListViewModel *self,
+ guint position)
+{
+ return position == self->n_items;
+}
diff --git a/src/gui/gtd-task-list-view-model.h b/src/gui/gtd-task-list-view-model.h
new file mode 100644
index 00000000..7323f3ac
--- /dev/null
+++ b/src/gui/gtd-task-list-view-model.h
@@ -0,0 +1,43 @@
+/* gtd-task-list-view-model.h
+ *
+ * Copyright 2020 Georges Basile Stavracas Neto <georges.stavracas@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 <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define GTD_TYPE_SENTINEL (gtd_sentinel_get_type ())
+G_DECLARE_FINAL_TYPE (GtdSentinel, gtd_sentinel, GTD, SENTINEL, GObject)
+
+#define GTD_TYPE_TASK_LIST_VIEW_MODEL (gtd_task_list_view_model_get_type())
+G_DECLARE_FINAL_TYPE (GtdTaskListViewModel, gtd_task_list_view_model, GTD, TASK_LIST_VIEW_MODEL, GObject)
+
+GtdTaskListViewModel* gtd_task_list_view_model_new (void);
+
+GListModel* gtd_task_list_view_model_get_model (GtdTaskListViewModel *self);
+
+void gtd_task_list_view_model_set_model (GtdTaskListViewModel *self,
+ GListModel *model);
+
+gboolean gtd_task_list_view_model_is_sentinel (GtdTaskListViewModel *self,
+ guint position);
+
+G_END_DECLS
diff --git a/src/gui/gtd-task-list-view.c b/src/gui/gtd-task-list-view.c
index bf89e022..d76edf5f 100644
--- a/src/gui/gtd-task-list-view.c
+++ b/src/gui/gtd-task-list-view.c
@@ -30,6 +30,7 @@
#include "gtd-provider.h"
#include "gtd-task.h"
#include "gtd-task-list.h"
+#include "gtd-task-list-view-model.h"
#include "gtd-task-row.h"
#include "gtd-utils-private.h"
#include "gtd-widget.h"
@@ -58,9 +59,6 @@
*
* gtd_task_list_view_set_model (view, model);
*
- * // Hide the '+ New task' row
- * gtd_task_list_view_set_show_new_task_row (view, FALSE);
- *
* // Date which tasks will be automatically assigned
* gtd_task_list_view_set_default_date (view, now);
* ]|
@@ -69,8 +67,7 @@
typedef struct
{
- GtkListBox *listbox;
- GtkListBoxRow *new_task_row;
+ GtkListView *listview;
GtkWidget *scrolled_window;
GtkStack *stack;
@@ -79,12 +76,13 @@ typedef struct
gboolean show_due_date;
gboolean show_list_name;
gboolean handle_subtasks;
- GListModel *model;
GDateTime *default_date;
- guint scroll_to_bottom_handler_id;
+ GtdTaskListViewModel *model;
+ gpointer active_item;
+ gint64 active_position;
- GHashTable *task_to_row;
+ guint scroll_to_bottom_handler_id;
/* Markup renderer*/
GtdMarkdownRenderer *renderer;
@@ -94,10 +92,6 @@ typedef struct
guint scroll_timeout_id;
gboolean scroll_up;
- /* color provider */
- GtkCssProvider *color_provider;
- GdkRGBA *color;
-
/* action */
GActionGroup *action_group;
@@ -105,10 +99,8 @@ typedef struct
GtdTaskListViewHeaderFunc header_func;
gpointer header_user_data;
- GtdTaskRow *active_row;
GtkSizeGroup *due_date_sizegroup;
GtkSizeGroup *tasklist_name_sizegroup;
- GtdTaskListSelectorBehavior task_list_selector_behavior;
} GtdTaskListViewPrivate;
struct _GtdTaskListView
@@ -119,23 +111,6 @@ struct _GtdTaskListView
GtdTaskListViewPrivate *priv;
};
-typedef enum
-{
- GTD_IDLE_STATE_STARTED,
- GTD_IDLE_STATE_LOADING,
- GTD_IDLE_STATE_COMPLETE,
- GTD_IDLE_STATE_FINISHED,
-} GtdIdleState;
-
-typedef struct
-{
- GtdTaskListView *self;
- GtdIdleState state;
- GPtrArray *added;
- GPtrArray *removed;
- guint32 current_item;
-} GtdIdleData;
-
#define COLOR_TEMPLATE "tasklistview {background-color: %s;}"
#define DND_SCROLL_OFFSET 24 //px
#define LUMINANCE(c) (0.299 * c->red + 0.587 * c->green + 0.114 * c->blue)
@@ -149,12 +124,6 @@ static void on_clear_completed_tasks_activated_cb (GSimpleAction
static void on_remove_task_row_cb (GtdTaskRow *row,
GtdTaskListView *self);
-static void on_task_row_entered_cb (GtdTaskListView *self,
- GtdTaskRow *row);
-
-static void on_task_row_exited_cb (GtdTaskListView *self,
- GtdTaskRow *row);
-
static gboolean scroll_to_bottom_cb (gpointer data);
@@ -172,49 +141,19 @@ typedef struct
enum {
PROP_0,
- PROP_COLOR,
PROP_HANDLE_SUBTASKS,
PROP_SHOW_LIST_NAME,
PROP_SHOW_DUE_DATE,
- PROP_SHOW_NEW_TASK_ROW,
LAST_PROP
};
typedef gboolean (*IterateSubtaskFunc) (GtdTaskListView *self,
GtdTask *task);
-
/*
* Auxiliary methods
*/
-static inline GtdTaskRow*
-task_row_from_row (GtkListBoxRow *row)
-{
- return GTD_TASK_ROW (gtk_list_box_row_get_child (row));
-}
-
-static void
-set_active_row (GtdTaskListView *self,
- GtdTaskRow *row)
-{
- GtdTaskListViewPrivate *priv = gtd_task_list_view_get_instance_private (self);
-
- if (priv->active_row == row)
- return;
-
- if (priv->active_row)
- gtd_task_row_set_active (priv->active_row, FALSE);
-
- priv->active_row = row;
-
- if (row)
- {
- gtd_task_row_set_active (row, TRUE);
- gtk_widget_grab_focus (GTK_WIDGET (row));
- }
-}
-
static gboolean
iterate_subtasks (GtdTaskListView *self,
GtdTask *task,
@@ -237,35 +176,6 @@ iterate_subtasks (GtdTaskListView *self,
}
static void
-update_font_color (GtdTaskListView *self)
-{
- GtdTaskListViewPrivate *priv;
- GtkStyleContext *context;
- GdkRGBA *color;
-
- priv = gtd_task_list_view_get_instance_private (self);
-
- if (!priv->model || !GTD_IS_TASK_LIST (priv->model))
- return;
-
- context = gtk_widget_get_style_context (GTK_WIDGET (self));
- color = gtd_task_list_get_color (GTD_TASK_LIST (priv->model));
-
- if (LUMINANCE (color) < 0.5)
- {
- gtk_style_context_add_class (context, "dark");
- gtk_style_context_remove_class (context, "light");
- }
- else
- {
- gtk_style_context_add_class (context, "light");
- gtk_style_context_remove_class (context, "dark");
- }
-
- gdk_rgba_free (color);
-}
-
-static void
schedule_scroll_to_bottom (GtdTaskListView *self)
{
GtdTaskListViewPrivate *priv = gtd_task_list_view_get_instance_private (self);
@@ -276,24 +186,13 @@ schedule_scroll_to_bottom (GtdTaskListView *self)
priv->scroll_to_bottom_handler_id = g_timeout_add (250, scroll_to_bottom_cb, self);
}
-
-/*
- * Callbacks
- */
-
static GtkWidget*
-create_row_for_task_cb (gpointer item,
- gpointer user_data)
+create_task_row (GtdTaskListView *self)
{
- GtdTaskListViewPrivate *priv;
- GtdTaskListView *self;
- GtkWidget *listbox_row;
+ GtdTaskListViewPrivate *priv = gtd_task_list_view_get_instance_private (self);
GtkWidget *row;
- self = GTD_TASK_LIST_VIEW (user_data);
- priv = gtd_task_list_view_get_instance_private (self);
-
- row = gtd_task_row_new (item, priv->renderer);
+ row = gtd_task_row_new (NULL, priv->renderer);
g_object_bind_property (self,
"handle-subtasks",
@@ -303,21 +202,19 @@ create_row_for_task_cb (gpointer item,
gtd_task_row_set_list_name_visible (GTD_TASK_ROW (row), priv->show_list_name);
gtd_task_row_set_due_date_visible (GTD_TASK_ROW (row), priv->show_due_date);
-
- g_signal_connect_swapped (row, "enter", G_CALLBACK (on_task_row_entered_cb), self);
- g_signal_connect_swapped (row, "exit", G_CALLBACK (on_task_row_exited_cb), self);
+ gtd_task_row_set_sizegroups (GTD_TASK_ROW (row),
+ priv->tasklist_name_sizegroup,
+ priv->due_date_sizegroup);
g_signal_connect (row, "remove-task", G_CALLBACK (on_remove_task_row_cb), self);
- listbox_row = gtk_list_box_row_new ();
- gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (listbox_row), row);
-
- g_object_bind_property (row, "visible", listbox_row, "visible", G_BINDING_BIDIRECTIONAL);
+ return row;
+}
- g_hash_table_insert (priv->task_to_row, item, row);
- return listbox_row;
-}
+/*
+ * Callbacks
+ */
static gboolean
scroll_to_bottom_cb (gpointer data)
@@ -346,7 +243,6 @@ scroll_to_bottom_cb (gpointer data)
{
gboolean ignored;
- gtk_widget_grab_focus (GTK_WIDGET (priv->new_task_row));
g_signal_emit_by_name (priv->scrolled_window, "scroll-child", GTK_SCROLL_END, FALSE, &ignored);
}
@@ -388,7 +284,7 @@ on_clear_completed_tasks_activated_cb (GSimpleAction *simple,
guint i;
self = GTD_TASK_LIST_VIEW (user_data);
- model = self->priv->model;
+ model = gtd_task_list_view_model_get_model (self->priv->model);
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
@@ -483,86 +379,36 @@ on_remove_task_row_cb (GtdTaskRow *row,
/* Clear the active row */
- set_active_row (self, NULL);
+ gtd_task_row_set_active (row, FALSE);
}
static void
-on_task_list_color_changed_cb (GtdTaskListView *self)
-{
- GtdTaskListViewPrivate *priv = GTD_TASK_LIST_VIEW (self)->priv;
- gchar *color_str;
- gchar *parsed_css;
-
- /* Add the color to provider */
- if (priv->color)
- {
- color_str = gdk_rgba_to_string (priv->color);
- }
- else
- {
- GdkRGBA *color;
-
- color = gtd_task_list_get_color (GTD_TASK_LIST (priv->model));
- color_str = gdk_rgba_to_string (color);
-
- gdk_rgba_free (color);
- }
-
- parsed_css = g_strdup_printf (COLOR_TEMPLATE, color_str);
-
- gtk_css_provider_load_from_data (priv->color_provider, parsed_css, -1);
-
- update_font_color (self);
-
- g_free (color_str);
-}
-static void
-on_new_task_row_entered_cb (GtdTaskListView *self,
- GtdNewTaskRow *row)
-{
- set_active_row (self, NULL);
-}
-
-static void
-on_new_task_row_exited_cb (GtdTaskListView *self,
- GtdNewTaskRow *row)
+on_listview_activate_cb (GtkListBox *listbox,
+ guint position,
+ GtdTaskListView *self)
{
+ GtdTaskListViewPrivate *priv = gtd_task_list_view_get_instance_private (self);
+ gpointer item;
+ gint64 old_active_position;
-}
+ GTD_ENTRY;
-static void
-on_task_row_entered_cb (GtdTaskListView *self,
- GtdTaskRow *row)
-{
- set_active_row (self, row);
-}
+ if (priv->active_position == position)
+ GTD_RETURN ();
-static void
-on_task_row_exited_cb (GtdTaskListView *self,
- GtdTaskRow *row)
-{
- GtdTaskListViewPrivate *priv = self->priv;
+ item = g_list_model_get_item (G_LIST_MODEL (priv->model), position);
- if (row == priv->active_row)
- set_active_row (self, NULL);
-}
+ old_active_position = priv->active_position;
-static void
-on_listbox_row_activated_cb (GtkListBox *listbox,
- GtkListBoxRow *row,
- GtdTaskListView *self)
-{
- GtdTaskRow *task_row;
+ priv->active_item = item;
+ priv->active_position = position;
- GTD_ENTRY;
+ GTD_TRACE_MSG ("Activating %s at %u", G_OBJECT_TYPE_NAME (item), position);
- task_row = task_row_from_row (row);
+ if (old_active_position != -1)
+ g_list_model_items_changed (G_LIST_MODEL (priv->model), old_active_position, 1, 1);
- /* Toggle the row */
- if (gtd_task_row_get_active (task_row))
- set_active_row (self, NULL);
- else
- set_active_row (self, task_row);
+ g_clear_object (&item);
GTD_EXIT;
}
@@ -573,362 +419,76 @@ on_listbox_row_activated_cb (GtkListBox *listbox,
*/
static void
-internal_header_func (GtkListBoxRow *row,
- GtkListBoxRow *before,
- GtdTaskListView *view)
-{
- GtkWidget *header;
- GtdTask *row_task;
- GtdTask *before_task;
-
- if (!view->priv->header_func)
- return;
-
- row_task = before_task = NULL;
-
- if (row)
- row_task = gtd_task_row_get_task (task_row_from_row (row));
-
- if (before)
- before_task = gtd_task_row_get_task (task_row_from_row (before));
-
- header = view->priv->header_func (row_task, before_task, view->priv->header_user_data);
-
- if (header)
- {
- GtkWidget *real_header = gtd_widget_new ();
- gtk_widget_insert_before (header, real_header, NULL);
-
- header = real_header;
- }
-
- gtk_list_box_row_set_header (row, header);
-}
-
-
-/*
- * Drag n' Drop functions
- */
-
-static gboolean
-row_is_subtask_of (GtdTaskRow *row_a,
- GtdTaskRow *row_b)
+on_listview_setup_cb (GtkSignalListItemFactory *factory,
+ GtkListItem *list_item,
+ GtdTaskListView *self)
{
- GtdTask *task_a;
- GtdTask *task_b;
+ GtkWidget *row;
- task_a = gtd_task_row_get_task (row_a);
- task_b = gtd_task_row_get_task (row_b);
+ /* Use a task row here, even if it's the sentinel */
+ row = create_task_row (self);
- return gtd_task_is_subtask (task_a, task_b);
+ gtk_list_item_set_child (list_item, row);
}
-static GtkListBoxRow*
-get_drop_row_at_y (GtdTaskListView *self,
- gdouble y)
+static void
+on_listview_bind_cb (GtkSignalListItemFactory *factory,
+ GtkListItem *list_item,
+ GtdTaskListView *self)
{
- GtdTaskListViewPrivate *priv;
- GtkListBoxRow *hovered_row;
- GtkListBoxRow *task_row;
- GtkListBoxRow *drop_row;
- gdouble row_y, row_height;
-
- priv = gtd_task_list_view_get_instance_private (self);
-
- hovered_row = gtk_list_box_get_row_at_y (priv->listbox, y);
-
- /* Small optimization when hovering the first row */
- if (gtk_list_box_row_get_index (hovered_row) == 0)
- return hovered_row;
+ GtdTaskListViewPrivate *priv = gtd_task_list_view_get_instance_private (self);
+ GtkWidget *row;
+ gpointer item;
- drop_row = NULL;
- task_row = hovered_row;
- row_height = gtk_widget_get_allocated_height (GTK_WIDGET (hovered_row));
- gtk_widget_translate_coordinates (GTK_WIDGET (priv->listbox),
- GTK_WIDGET (hovered_row),
- 0,
- y,
- NULL,
- &row_y);
+ item = gtk_list_item_get_item (list_item);
+ row = gtk_list_item_get_child (list_item);
- /*
- * If the pointer if in the top part of the row, move the DnD row to
- * the previous row.
- */
- if (row_y < row_height / 2)
+ if (GTD_IS_TASK (item))
{
- gint row_index, i;
+ GtdTaskRow *task_row;
- row_index = gtk_list_box_row_get_index (hovered_row);
-
- /* Search for a valid task row */
- for (i = row_index - 1; i >= 0; i--)
+ if (!GTD_IS_TASK_ROW (row))
{
- GtkListBoxRow *aux;
-
- aux = gtk_list_box_get_row_at_index (GTK_LIST_BOX (priv->listbox), i);
-
- /* Skip DnD, New task and hidden rows */
- if (aux && !gtk_widget_get_visible (GTK_WIDGET (aux)))
- continue;
-
- drop_row = aux;
- break;
+ row = create_task_row (self);
+ gtk_list_item_set_child (list_item, GTK_WIDGET (row));
}
- }
- else
- {
- drop_row = task_row;
- }
-
- return drop_row ? drop_row : NULL;
-}
-
-static void
-unset_previously_highlighted_row (GtdTaskListView *self)
-{
- GtdTaskListViewPrivate *priv = gtd_task_list_view_get_instance_private (self);
- if (priv->highlighted_row)
- {
- gtd_task_row_unset_drag_offset (task_row_from_row (priv->highlighted_row));
- priv->highlighted_row = NULL;
- }
-}
-static inline gboolean
-scroll_to_dnd (gpointer user_data)
-{
- GtdTaskListViewPrivate *priv;
- GtkAdjustment *vadjustment;
- gint value;
+ task_row = GTD_TASK_ROW (row);
- priv = gtd_task_list_view_get_instance_private (user_data);
- vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scrolled_window));
- value = gtk_adjustment_get_value (vadjustment) + (priv->scroll_up ? -6 : 6);
-
- gtk_adjustment_set_value (vadjustment,
- CLAMP (value, 0, gtk_adjustment_get_upper (vadjustment)));
-
- return G_SOURCE_CONTINUE;
-}
+ gtd_task_row_set_task (task_row, GTD_TASK (item));
-static void
-check_dnd_scroll (GtdTaskListView *self,
- gboolean should_cancel,
- gdouble y)
-{
- GtdTaskListViewPrivate *priv = gtd_task_list_view_get_instance_private (self);
- gdouble current_y, height;
+ if (gtk_list_item_get_item (list_item) == priv->active_item)
+ {
+ gboolean active;
- if (should_cancel)
- {
- if (priv->scroll_timeout_id > 0)
+ /* Toggle the active state if this is the active item */
+ active = gtd_task_row_get_active (task_row);
+ g_message ("Row active: %d", active);
+ gtd_task_row_set_active (task_row, !active);
+ }
+ else
{
- g_source_remove (priv->scroll_timeout_id);
- priv->scroll_timeout_id = 0;
+ gtd_task_row_set_active (task_row, FALSE);
}
- return;
}
-
- height = gtk_widget_get_allocated_height (priv->scrolled_window);
- gtk_widget_translate_coordinates (GTK_WIDGET (priv->listbox),
- priv->scrolled_window,
- 0, y,
- NULL, &current_y);
-
- if (current_y < DND_SCROLL_OFFSET || current_y > height - DND_SCROLL_OFFSET)
- {
- if (priv->scroll_timeout_id > 0)
- return;
-
- /* Start the autoscroll */
- priv->scroll_up = current_y < DND_SCROLL_OFFSET;
- priv->scroll_timeout_id = g_timeout_add (25,
- scroll_to_dnd,
- self);
- }
- else
+ else if (GTD_IS_SENTINEL (item))
{
- if (priv->scroll_timeout_id == 0)
- return;
-
- /* Cancel the autoscroll */
- g_source_remove (priv->scroll_timeout_id);
- priv->scroll_timeout_id = 0;
- }
-}
-
-static void
-on_drop_target_drag_leave_cb (GtkDropTarget *drop_target,
- GtdTaskListView *self)
-{
- unset_previously_highlighted_row (self);
- check_dnd_scroll (self, TRUE, -1);
-}
-
-static GdkDragAction
-on_drop_target_drag_motion_cb (GtkDropTarget *drop_target,
- gdouble x,
- gdouble y,
- GtdTaskListView *self)
-{
- GtdTaskListViewPrivate *priv;
- GtkListBoxRow *highlighted_row;
- GtdTaskRow *highlighted_task_row;
- GtdTaskRow *source_task_row;
- const GValue *value;
- GdkDrop *drop;
- GtdTask *task;
- GdkDrag *drag;
- gdouble x_offset;
-
- GTD_ENTRY;
-
- priv = gtd_task_list_view_get_instance_private (self);
- drop = gtk_drop_target_get_drop (drop_target);
- drag = gdk_drop_get_drag (drop);
-
- if (!drag)
- {
- g_info ("Only dragging task rows is supported");
- GTD_GOTO (fail);
- }
-
- value = gtk_drop_target_get_value (drop_target);
- task = g_value_get_object (value);
-
- source_task_row = g_hash_table_lookup (priv->task_to_row, task);
-
- /* Update the x value according to the current offset */
- if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL)
- x += gtd_task_row_get_x_offset (source_task_row);
- else
- x -= gtd_task_row_get_x_offset (source_task_row);
+ GListModel *model = gtd_task_list_view_model_get_model (priv->model);
- unset_previously_highlighted_row (self);
-
- highlighted_row = get_drop_row_at_y (self, y);
- if (!highlighted_row)
- GTD_GOTO (success);
-
- highlighted_task_row = task_row_from_row (highlighted_row);
-
- /* Forbid dropping a row over a subtask row */
- if (row_is_subtask_of (source_task_row, highlighted_task_row))
- GTD_GOTO (fail);
-
- gtk_widget_translate_coordinates (GTK_WIDGET (priv->listbox),
- GTK_WIDGET (highlighted_task_row),
- x,
- 0,
- &x_offset,
- NULL);
-
- gtd_task_row_set_drag_offset (highlighted_task_row, source_task_row, x_offset);
- priv->highlighted_row = highlighted_row;
-
-success:
- check_dnd_scroll (self, FALSE, y);
- GTD_RETURN (GDK_ACTION_MOVE);
-
-fail:
- GTD_RETURN (0);
-}
-
-static gboolean
-on_drop_target_drag_drop_cb (GtkDropTarget *drop_target,
- const GValue *value,
- gdouble x,
- gdouble y,
- GtdTaskListView *self)
-{
- GtdTaskListViewPrivate *priv;
- GtkListBoxRow *drop_row;
- GtdProvider *provider;
- GtdTaskRow *hovered_row;
- GtkWidget *row;
- GtdTask *new_parent_task;
- GtdTask *hovered_task;
- GtdTask *source_task;
- GdkDrop *drop;
- GdkDrag *drag;
- gint64 current_position;
- gint64 new_position;
-
- GTD_ENTRY;
-
- priv = gtd_task_list_view_get_instance_private (self);
- drop = gtk_drop_target_get_drop (drop_target);
- drag = gdk_drop_get_drag (drop);
-
- if (!drag)
- {
- g_info ("Only dragging task rows is supported");
- GTD_RETURN (FALSE);
- }
-
- unset_previously_highlighted_row (self);
-
- source_task = g_value_get_object (value);
-
- /*
- * When the drag operation began, the source row was hidden. Now is the time
- * to show it again.
- */
- row = g_hash_table_lookup (priv->task_to_row, source_task);
- gtk_widget_show (row);
-
- drop_row = get_drop_row_at_y (self, y);
- hovered_row = task_row_from_row (drop_row);
- hovered_task = gtd_task_row_get_task (hovered_row);
- new_parent_task = gtd_task_row_get_dnd_drop_task (hovered_row);
-
- g_assert (source_task != NULL);
- g_assert (source_task != new_parent_task);
-
- if (new_parent_task)
- {
- /* Forbid adding the parent task as a subtask */
- if (gtd_task_is_subtask (source_task, new_parent_task))
+ if (!GTD_IS_NEW_TASK_ROW (row))
{
- gdk_drop_finish (drop, 0);
- GTD_RETURN (FALSE);
+ row = gtd_new_task_row_new ();
+ gtk_list_item_set_child (list_item, GTK_WIDGET (row));
}
- GTD_TRACE_MSG ("Making '%s' (%s) subtask of '%s' (%s)",
- gtd_task_get_title (source_task),
- gtd_object_get_uid (GTD_OBJECT (source_task)),
- gtd_task_get_title (new_parent_task),
- gtd_object_get_uid (GTD_OBJECT (new_parent_task)));
-
- gtd_task_add_subtask (new_parent_task, source_task);
+ gtd_new_task_row_set_show_list_selector (GTD_NEW_TASK_ROW (row),
+ !GTD_IS_TASK_LIST (model));
}
else
{
- GtdTask *current_parent_task = gtd_task_get_parent (source_task);
- if (current_parent_task)
- gtd_task_remove_subtask (current_parent_task, source_task);
+ g_assert_not_reached ();
}
-
- /*
- * FIXME: via DnD, we only support moving the task to below another
- * task, thus the "+ 1"
- */
- new_position = gtd_task_get_position (hovered_task) + 1;
- current_position = gtd_task_get_position (source_task);
-
- if (new_position != current_position)
- gtd_task_list_move_task_to_position (GTD_TASK_LIST (priv->model), source_task, new_position);
-
- /* Finally, save the task */
- provider = gtd_task_list_get_provider (gtd_task_get_list (source_task));
- gtd_provider_update_task (provider, source_task, NULL, NULL, NULL);
-
- check_dnd_scroll (self, TRUE, -1);
- gdk_drop_finish (drop, GDK_ACTION_MOVE);
-
- GTD_RETURN (TRUE);
}
@@ -942,7 +502,6 @@ gtd_task_list_view_finalize (GObject *object)
GtdTaskListViewPrivate *priv = GTD_TASK_LIST_VIEW (object)->priv;
g_clear_handle_id (&priv->scroll_to_bottom_handler_id, g_source_remove);
- g_clear_pointer (&priv->task_to_row, g_hash_table_destroy);
g_clear_pointer (&priv->default_date, g_date_time_unref);
g_clear_object (&priv->renderer);
g_clear_object (&priv->model);
@@ -960,10 +519,6 @@ gtd_task_list_view_get_property (GObject *object,
switch (prop_id)
{
- case PROP_COLOR:
- g_value_set_boxed (value, self->priv->color);
- break;
-
case PROP_HANDLE_SUBTASKS:
g_value_set_boolean (value, self->priv->handle_subtasks);
break;
@@ -976,10 +531,6 @@ gtd_task_list_view_get_property (GObject *object,
g_value_set_boolean (value, self->priv->show_list_name);
break;
- case PROP_SHOW_NEW_TASK_ROW:
- g_value_set_boolean (value, gtk_widget_get_visible (GTK_WIDGET (self->priv->new_task_row)));
- break;
-
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -995,10 +546,6 @@ gtd_task_list_view_set_property (GObject *object,
switch (prop_id)
{
- case PROP_COLOR:
- gtd_task_list_view_set_color (self, g_value_get_boxed (value));
- break;
-
case PROP_HANDLE_SUBTASKS:
gtd_task_list_view_set_handle_subtasks (self, g_value_get_boolean (value));
break;
@@ -1011,10 +558,6 @@ gtd_task_list_view_set_property (GObject *object,
gtd_task_list_view_set_show_list_name (self, g_value_get_boolean (value));
break;
- case PROP_SHOW_NEW_TASK_ROW:
- gtd_task_list_view_set_show_new_task_row (self, g_value_get_boolean (value));
- break;
-
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -1034,13 +577,6 @@ gtd_task_list_view_constructed (GObject *object)
gtd_task_list_view_entries,
G_N_ELEMENTS (gtd_task_list_view_entries),
object);
-
- /* css provider */
- self->priv->color_provider = gtk_css_provider_new ();
-
- gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (self)),
- GTK_STYLE_PROVIDER (self->priv->color_provider),
- GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + 2);
}
@@ -1086,21 +622,6 @@ gtd_task_list_view_class_init (GtdTaskListViewClass *klass)
g_type_ensure (GTD_TYPE_EMPTY_LIST_WIDGET);
/**
- * GtdTaskListView::color:
- *
- * The custom color of this list. If there is a custom color set,
- * the tasklist's color is ignored.
- */
- g_object_class_install_property (
- object_class,
- PROP_COLOR,
- g_param_spec_boxed ("color",
- "Color of the task list view",
- "The custom color of this task list view",
- GDK_TYPE_RGBA,
- G_PARAM_READWRITE));
-
- /**
* GtdTaskListView::handle-subtasks:
*
* Whether the list is able to handle subtasks.
@@ -1115,20 +636,6 @@ gtd_task_list_view_class_init (GtdTaskListViewClass *klass)
G_PARAM_READWRITE));
/**
- * GtdTaskListView::show-new-task-row:
- *
- * Whether the list shows the "New Task" row or not.
- */
- g_object_class_install_property (
- object_class,
- PROP_SHOW_NEW_TASK_ROW,
- g_param_spec_boolean ("show-new-task-row",
- "Whether it shows the New Task row",
- "Whether the list shows the New Task row, or not",
- TRUE,
- G_PARAM_READWRITE));
-
- /**
* GtdTaskListView::show-list-name:
*
* Whether the task rows should show the list name.
@@ -1159,17 +666,14 @@ gtd_task_list_view_class_init (GtdTaskListViewClass *klass)
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/todo/ui/gtd-task-list-view.ui");
gtk_widget_class_bind_template_child_private (widget_class, GtdTaskListView, due_date_sizegroup);
- gtk_widget_class_bind_template_child_private (widget_class, GtdTaskListView, listbox);
- gtk_widget_class_bind_template_child_private (widget_class, GtdTaskListView, new_task_row);
+ gtk_widget_class_bind_template_child_private (widget_class, GtdTaskListView, listview);
gtk_widget_class_bind_template_child_private (widget_class, GtdTaskListView, tasklist_name_sizegroup);
gtk_widget_class_bind_template_child_private (widget_class, GtdTaskListView, scrolled_window);
gtk_widget_class_bind_template_child_private (widget_class, GtdTaskListView, stack);
- gtk_widget_class_bind_template_callback (widget_class, on_listbox_row_activated_cb);
- gtk_widget_class_bind_template_callback (widget_class, on_new_task_row_entered_cb);
- gtk_widget_class_bind_template_callback (widget_class, on_new_task_row_exited_cb);
- gtk_widget_class_bind_template_callback (widget_class, on_task_row_entered_cb);
- gtk_widget_class_bind_template_callback (widget_class, on_task_row_exited_cb);
+ gtk_widget_class_bind_template_callback (widget_class, on_listview_activate_cb);
+ gtk_widget_class_bind_template_callback (widget_class, on_listview_setup_cb);
+ gtk_widget_class_bind_template_callback (widget_class, on_listview_bind_cb);
gtk_widget_class_set_css_name (widget_class, "tasklistview");
}
@@ -1178,15 +682,13 @@ static void
gtd_task_list_view_init (GtdTaskListView *self)
{
GtdTaskListViewPrivate *priv;
- GtkDropTarget *target;
+ GtkNoSelection *no_selection;
priv = gtd_task_list_view_get_instance_private (self);
self->priv = priv;
- priv->task_list_selector_behavior = GTD_TASK_LIST_SELECTOR_BEHAVIOR_AUTOMATIC;
- priv->task_to_row = g_hash_table_new (NULL, NULL);
-
+ priv->active_position = -1;
priv->can_toggle = TRUE;
priv->handle_subtasks = TRUE;
priv->show_due_date = TRUE;
@@ -1194,15 +696,11 @@ gtd_task_list_view_init (GtdTaskListView *self)
gtk_widget_init_template (GTK_WIDGET (self));
- target = gtk_drop_target_new (GTD_TYPE_TASK, GDK_ACTION_MOVE);
- gtk_drop_target_set_preload (target, TRUE);
- g_signal_connect (target, "drop", G_CALLBACK (on_drop_target_drag_drop_cb), self);
- g_signal_connect (target, "leave", G_CALLBACK (on_drop_target_drag_leave_cb), self);
- g_signal_connect (target, "motion", G_CALLBACK (on_drop_target_drag_motion_cb), self);
-
- gtk_widget_add_controller (GTK_WIDGET (priv->listbox), GTK_EVENT_CONTROLLER (target));
-
priv->renderer = gtd_markdown_renderer_new ();
+
+ priv->model = gtd_task_list_view_model_new ();
+ no_selection = gtk_no_selection_new (G_LIST_MODEL (priv->model));
+ gtk_list_view_set_model (priv->listview, GTK_SELECTION_MODEL (no_selection));
}
/**
@@ -1219,38 +717,6 @@ gtd_task_list_view_new (void)
}
/**
- * gtd_task_list_view_get_show_new_task_row:
- * @view: a #GtdTaskListView
- *
- * Gets whether @view shows the new task row or not.
- *
- * Returns: %TRUE if @view is shows the new task row, %FALSE otherwise
- */
-gboolean
-gtd_task_list_view_get_show_new_task_row (GtdTaskListView *self)
-{
- g_return_val_if_fail (GTD_IS_TASK_LIST_VIEW (self), FALSE);
-
- return gtk_widget_get_visible (GTK_WIDGET (self->priv->new_task_row));
-}
-
-/**
- * gtd_task_list_view_set_show_new_task_row:
- * @view: a #GtdTaskListView
- *
- * Sets the #GtdTaskListView:show-new-task-mode property of @view.
- */
-void
-gtd_task_list_view_set_show_new_task_row (GtdTaskListView *view,
- gboolean show_new_task_row)
-{
- g_return_if_fail (GTD_IS_TASK_LIST_VIEW (view));
-
- gtk_widget_set_visible (GTK_WIDGET (view->priv->new_task_row), show_new_task_row);
- g_object_notify (G_OBJECT (view), "show-new-task-row");
-}
-
-/**
* gtd_task_list_view_get_model:
* @view: a #GtdTaskListView
*
@@ -1262,9 +728,12 @@ gtd_task_list_view_set_show_new_task_row (GtdTaskListView *view,
GListModel*
gtd_task_list_view_get_model (GtdTaskListView *view)
{
+ GtdTaskListViewPrivate *priv;
+
g_return_val_if_fail (GTD_IS_TASK_LIST_VIEW (view), NULL);
- return view->priv->model;
+ priv = gtd_task_list_view_get_instance_private (view);
+ return gtd_task_list_view_model_get_model (priv->model);
}
/**
@@ -1280,45 +749,17 @@ gtd_task_list_view_set_model (GtdTaskListView *view,
GListModel *model)
{
GtdTaskListViewPrivate *priv;
- g_autoptr (GdkRGBA) color = NULL;
- g_autofree gchar *parsed_css = NULL;
- g_autofree gchar *color_str = NULL;
- GtdTaskList *list;
g_return_if_fail (GTD_IS_TASK_LIST_VIEW (view));
g_return_if_fail (G_IS_LIST_MODEL (model));
priv = gtd_task_list_view_get_instance_private (view);
- if (!g_set_object (&priv->model, model))
- return;
-
- gtk_list_box_bind_model (priv->listbox,
- model,
- create_row_for_task_cb,
- view,
- NULL);
+ priv->active_item = NULL;
+ priv->active_position = -1;
+ gtd_task_list_view_model_set_model (priv->model, model);
schedule_scroll_to_bottom (view);
-
- if (priv->task_list_selector_behavior == GTD_TASK_LIST_SELECTOR_BEHAVIOR_AUTOMATIC)
- gtd_new_task_row_set_show_list_selector (GTD_NEW_TASK_ROW (priv->new_task_row), !GTD_IS_TASK_LIST (model));
-
- if (!GTD_IS_TASK_LIST (model))
- return;
-
- list = GTD_TASK_LIST (model);
-
- g_debug ("%p: Setting task list to '%s'", view, gtd_task_list_get_name (list));
-
- /* Add the color to provider */
- color = gtd_task_list_get_color (list);
- color_str = gdk_rgba_to_string (color);
- parsed_css = g_strdup_printf (COLOR_TEMPLATE, color_str);
-
- //gtk_css_provider_load_from_data (priv->color_provider, parsed_css, -1);
-
- update_font_color (view);
}
/**
@@ -1352,22 +793,7 @@ gtd_task_list_view_set_show_list_name (GtdTaskListView *view,
if (view->priv->show_list_name != show_list_name)
{
- GtkWidget *child;
-
view->priv->show_list_name = show_list_name;
-
- for (child = gtk_widget_get_first_child (GTK_WIDGET (view->priv->listbox));
- child;
- child = gtk_widget_get_next_sibling (child))
- {
- GtkWidget *row_child = gtk_list_box_row_get_child (GTK_LIST_BOX_ROW (child));
-
- if (!GTD_IS_TASK_ROW (row_child))
- continue;
-
- gtd_task_row_set_list_name_visible (GTD_TASK_ROW (row_child), show_list_name);
- }
-
g_object_notify (G_OBJECT (view), "show-list-name");
}
}
@@ -1401,7 +827,6 @@ gtd_task_list_view_set_show_due_date (GtdTaskListView *self,
gboolean show_due_date)
{
GtdTaskListViewPrivate *priv;
- GtkWidget *child;
g_return_if_fail (GTD_IS_TASK_LIST_VIEW (self));
@@ -1411,19 +836,6 @@ gtd_task_list_view_set_show_due_date (GtdTaskListView *self,
return;
priv->show_due_date = show_due_date;
-
- for (child = gtk_widget_get_first_child (GTK_WIDGET (priv->listbox));
- child;
- child = gtk_widget_get_next_sibling (child))
- {
- GtkWidget *row_child = gtk_list_box_row_get_child (GTK_LIST_BOX_ROW (child));
-
- if (!GTD_IS_TASK_ROW (row_child))
- continue;
-
- gtd_task_row_set_due_date_visible (GTD_TASK_ROW (row_child), show_due_date);
- }
-
g_object_notify (G_OBJECT (self), "show-due-date");
}
@@ -1453,21 +865,11 @@ gtd_task_list_view_set_header_func (GtdTaskListView *view,
{
priv->header_func = func;
priv->header_user_data = user_data;
-
- gtk_list_box_set_header_func (priv->listbox,
- (GtkListBoxUpdateHeaderFunc) internal_header_func,
- view,
- NULL);
}
else
{
priv->header_func = NULL;
priv->header_user_data = NULL;
-
- gtk_list_box_set_header_func (priv->listbox,
- NULL,
- NULL,
- NULL);
}
}
@@ -1516,57 +918,6 @@ gtd_task_list_view_set_default_date (GtdTaskListView *self,
}
/**
- * gtd_task_list_view_get_color:
- * @self: a #GtdTaskListView
- *
- * Retrieves the custom color of @self.
- *
- * Returns: (nullable): a #GdkRGBA, or %NULL if none is set.
- */
-GdkRGBA*
-gtd_task_list_view_get_color (GtdTaskListView *self)
-{
- GtdTaskListViewPrivate *priv;
-
- g_return_val_if_fail (GTD_IS_TASK_LIST_VIEW (self), NULL);
-
- priv = gtd_task_list_view_get_instance_private (self);
-
- return priv->color;
-}
-
-/**
- * gtd_task_list_view_set_color:
- * @self: a #GtdTaskListView
- * @color: (nullable): a #GdkRGBA
- *
- * Sets the custom color of @self to @color. If a custom color is set,
- * the tasklist's color is ignored. Passing %NULL makes the tasklist's
- * color apply again.
- */
-void
-gtd_task_list_view_set_color (GtdTaskListView *self,
- GdkRGBA *color)
-{
- GtdTaskListViewPrivate *priv;
-
- g_return_if_fail (GTD_IS_TASK_LIST_VIEW (self));
-
- priv = gtd_task_list_view_get_instance_private (self);
-
- if (priv->color != color ||
- (color && priv->color && !gdk_rgba_equal (color, priv->color)))
- {
- g_clear_pointer (&priv->color, gdk_rgba_free);
- priv->color = gdk_rgba_copy (color);
-
- on_task_list_color_changed_cb (self);
-
- g_object_notify (G_OBJECT (self), "color");
- }
-}
-
-/**
* gtd_task_list_view_get_handle_subtasks:
* @self: a #GtdTaskListView
*
@@ -1616,51 +967,3 @@ gtd_task_list_view_set_handle_subtasks (GtdTaskListView *self,
g_object_notify (G_OBJECT (self), "handle-subtasks");
}
-
-
-GtdTaskListSelectorBehavior
-gtd_task_list_view_get_task_list_selector_behavior (GtdTaskListView *self)
-{
- GtdTaskListViewPrivate *priv;
-
- g_return_val_if_fail (GTD_IS_TASK_LIST_VIEW (self), -1);
-
- priv = gtd_task_list_view_get_instance_private (self);
-
- return priv->task_list_selector_behavior;
-}
-
-void
-gtd_task_list_view_set_task_list_selector_behavior (GtdTaskListView *self,
- GtdTaskListSelectorBehavior behavior)
-{
- GtdTaskListViewPrivate *priv;
-
- g_return_if_fail (GTD_IS_TASK_LIST_VIEW (self));
-
- priv = gtd_task_list_view_get_instance_private (self);
-
- if (priv->task_list_selector_behavior == behavior)
- return;
-
- priv->task_list_selector_behavior = behavior;
-
- switch (behavior)
- {
- case GTD_TASK_LIST_SELECTOR_BEHAVIOR_AUTOMATIC:
- if (priv->model)
- {
- gtd_new_task_row_set_show_list_selector (GTD_NEW_TASK_ROW (priv->new_task_row),
- !GTD_IS_TASK_LIST (priv->model));
- }
- break;
-
- case GTD_TASK_LIST_SELECTOR_BEHAVIOR_ALWAYS_SHOW:
- gtd_new_task_row_set_show_list_selector (GTD_NEW_TASK_ROW (priv->new_task_row), TRUE);
- break;
-
- case GTD_TASK_LIST_SELECTOR_BEHAVIOR_ALWAYS_HIDE:
- gtd_new_task_row_set_show_list_selector (GTD_NEW_TASK_ROW (priv->new_task_row), FALSE);
- break;
- }
-}
diff --git a/src/gui/gtd-task-list-view.h b/src/gui/gtd-task-list-view.h
index 92f7b60f..f69c8f1a 100644
--- a/src/gui/gtd-task-list-view.h
+++ b/src/gui/gtd-task-list-view.h
@@ -29,13 +29,6 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GtdTaskListView, gtd_task_list_view, GTD, TASK_LIST_VIEW, GtkBox)
-typedef enum
-{
- GTD_TASK_LIST_SELECTOR_BEHAVIOR_AUTOMATIC,
- GTD_TASK_LIST_SELECTOR_BEHAVIOR_ALWAYS_SHOW,
- GTD_TASK_LIST_SELECTOR_BEHAVIOR_ALWAYS_HIDE,
-} GtdTaskListSelectorBehavior;
-
/**
* GtdTaskListViewHeaderFunc:
* @task: the #GtdTask that @row represents
@@ -71,31 +64,16 @@ void gtd_task_list_view_set_header_func (GtdTaskListView
GtdTaskListViewHeaderFunc func,
gpointer user_data);
-gboolean gtd_task_list_view_get_show_new_task_row (GtdTaskListView *view);
-
-void gtd_task_list_view_set_show_new_task_row (GtdTaskListView *view,
- gboolean show_new_task_row);
-
GDateTime* gtd_task_list_view_get_default_date (GtdTaskListView *self);
void gtd_task_list_view_set_default_date (GtdTaskListView *self,
GDateTime *default_date);
-GdkRGBA* gtd_task_list_view_get_color (GtdTaskListView *self);
-
-void gtd_task_list_view_set_color (GtdTaskListView *self,
- GdkRGBA *color);
-
gboolean gtd_task_list_view_get_handle_subtasks (GtdTaskListView *self);
void gtd_task_list_view_set_handle_subtasks (GtdTaskListView *self,
gboolean handle_subtasks);
-GtdTaskListSelectorBehavior gtd_task_list_view_get_task_list_selector_behavior (GtdTaskListView *self);
-
-void gtd_task_list_view_set_task_list_selector_behavior (GtdTaskListView *self,
- GtdTaskListSelectorBehavior behavior);
-
G_END_DECLS
#endif /* GTD_TASK_LIST_VIEW_H */
diff --git a/src/gui/gtd-task-list-view.ui b/src/gui/gtd-task-list-view.ui
index 2497f70b..cd22cbfd 100644
--- a/src/gui/gtd-task-list-view.ui
+++ b/src/gui/gtd-task-list-view.ui
@@ -2,76 +2,68 @@
<interface>
<requires lib="gtk+" version="3.16"/>
<template class="GtdTaskListView" parent="GtkBox">
- <property name="vexpand">1</property>
+ <property name="vexpand">true</property>
<property name="orientation">vertical</property>
<child>
- <object class="GtkScrolledWindow" id="scrolled_window">
- <property name="can_focus">1</property>
- <property name="hexpand">1</property>
- <property name="vexpand">1</property>
- <property name="min-content-height">320</property>
- <property name="hscrollbar-policy">never</property>
+ <object class="GtkStack" id="stack">
+ <property name="hexpand">true</property>
+ <property name="vexpand">true</property>
+ <property name="transition-type">crossfade</property>
<child>
- <object class="GtkStack" id="stack">
- <property name="hexpand">true</property>
- <property name="vexpand">true</property>
- <property name="transition-type">crossfade</property>
- <child>
- <object class="GtkStackPage">
- <property name="name">listbox</property>
- <property name="child">
- <object class="GtdWidget">
- <property name="hexpand">1</property>
- <property name="vexpand">1</property>
- <property name="halign">center</property>
- <property name="layout-manager">
- <object class="GtdMaxSizeLayout">
- <property name="max-width">700</property>
- </object>
- </property>
+ <object class="GtkStackPage">
+ <property name="name">listview</property>
+ <property name="child">
+ <object class="GtdWidget">
+ <property name="hexpand">true</property>
+ <property name="vexpand">true</property>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
<child>
- <object class="GtkBox">
- <property name="margin-top">6</property>
- <property name="margin-bottom">64</property>
- <property name="margin-start">18</property>
- <property name="margin-end">18</property>
- <property name="orientation">vertical</property>
+ <object class="GtkScrolledWindow" id="scrolled_window">
+ <property name="can_focus">true</property>
+ <property name="hexpand">true</property>
+ <property name="vexpand">true</property>
+ <property name="min-content-height">320</property>
+ <property name="hscrollbar-policy">never</property>
<child>
- <object class="GtkListBox" id="listbox">
- <property name="hexpand">1</property>
- <property name="selection_mode">none</property>
- <signal name="row-activated" handler="on_listbox_row_activated_cb" object="GtdTaskListView" swapped="no"/>
+ <object class="GtkListView" id="listview">
+ <property name="margin-top">6</property>
+ <property name="margin-start">18</property>
+ <property name="margin-end">18</property>
+ <property name="hexpand">true</property>
+ <property name="single-click-activate">true</property>
+ <property name="factory">
+ <object class="GtkSignalListItemFactory">
+ <signal name="setup" handler="on_listview_setup_cb" object="GtdTaskListView" swapped="no" />
+ <signal name="bind" handler="on_listview_bind_cb" object="GtdTaskListView" swapped="no" />
+ </object>
+ </property>
+ <signal name="activate" handler="on_listview_activate_cb" object="GtdTaskListView" swapped="no" />
<style>
<class name="transparent"/>
</style>
</object>
</child>
- <child>
- <object class="GtdNewTaskRow" id="new_task_row">
- <property name="margin-bottom">24</property>
- <signal name="enter" handler="on_new_task_row_entered_cb" object="GtdTaskListView" swapped="yes"/>
- <signal name="exit" handler="on_new_task_row_exited_cb" object="GtdTaskListView" swapped="yes"/>
- </object>
- </child>
</object>
</child>
</object>
-
- </property>
+ </child>
</object>
- </child>
- <child>
- <object class="GtkStackPage">
- <property name="name">loading</property>
- <property name="child">
- <object class="GtkSpinner">
- <property name="spinning">true</property>
- <property name="width-request">96</property>
- <property name="height-request">96</property>
- </object>
- </property>
+
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStackPage">
+ <property name="name">loading</property>
+ <property name="child">
+ <object class="GtkSpinner">
+ <property name="spinning">true</property>
+ <property name="width-request">96</property>
+ <property name="height-request">96</property>
</object>
- </child>
+ </property>
</object>
</child>
</object>
diff --git a/src/gui/gtd-task-row.c b/src/gui/gtd-task-row.c
index 876df1bd..ae6c2a0a 100644
--- a/src/gui/gtd-task-row.c
+++ b/src/gui/gtd-task-row.c
@@ -72,6 +72,7 @@ struct _GtdTaskRow
gboolean active;
gboolean changed;
+ gboolean pressed;
};
#define PRIORITY_ICON_SIZE 8
@@ -293,8 +294,6 @@ on_drag_end_cb (GtkDragSource *source,
{
GTD_ENTRY;
- gtd_task_row_unset_drag_offset (self);
-
gtk_widget_set_cursor_from_name (GTK_WIDGET (self), NULL);
gtk_widget_show (GTK_WIDGET (self));
@@ -309,8 +308,6 @@ on_drag_cancelled_cb (GtkDragSource *source,
{
GTD_ENTRY;
- gtd_task_row_unset_drag_offset (self);
-
gtk_widget_set_cursor_from_name (GTK_WIDGET (self), NULL);
gtk_widget_show (GTK_WIDGET (self));
@@ -426,6 +423,54 @@ on_task_changed_cb (GtdTaskRow *self)
self->changed = TRUE;
}
+static void
+on_click_gesture_pressed_cb (GtkGestureClick *gesture,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ GtdTaskRow *self)
+{
+ GTD_ENTRY;
+
+ if (self->pressed || n_press != 1)
+ GTD_RETURN ();
+
+ self->pressed = TRUE;
+
+ GTD_EXIT;
+}
+
+
+static void
+on_click_gesture_released_cb (GtkGestureClick *gesture,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ GtdTaskRow *self)
+{
+ GTD_ENTRY;
+
+ if (!self->pressed || n_press != 1)
+ GTD_RETURN ();
+
+ gtd_task_row_set_active (self, !self->active);
+
+ self->pressed = FALSE;
+
+ GTD_EXIT;
+}
+
+static void
+on_click_gesture_stopped_cb (GtkGestureClick *gesture,
+ GtdTaskRow *self)
+{
+ GTD_ENTRY;
+
+ self->pressed = FALSE;
+
+ GTD_EXIT;
+}
+
/*
* GObject overrides
@@ -642,6 +687,9 @@ gtd_task_row_class_init (GtdTaskRowClass *klass)
gtk_widget_class_bind_template_child (widget_class, GtdTaskRow, title_entry);
gtk_widget_class_bind_template_callback (widget_class, on_button_press_event_cb);
+ gtk_widget_class_bind_template_callback (widget_class, on_click_gesture_pressed_cb);
+ gtk_widget_class_bind_template_callback (widget_class, on_click_gesture_released_cb);
+ gtk_widget_class_bind_template_callback (widget_class, on_click_gesture_stopped_cb);
gtk_widget_class_bind_template_callback (widget_class, on_complete_check_toggled_cb);
gtk_widget_class_bind_template_callback (widget_class, on_key_pressed_cb);
gtk_widget_class_bind_template_callback (widget_class, on_remove_task_cb);
@@ -695,6 +743,9 @@ gtd_task_row_set_task (GtdTaskRow *self,
g_return_if_fail (GTD_IS_TASK_ROW (self));
+ if (task == self->task)
+ return;
+
old_task = self->task;
if (old_task)
@@ -845,7 +896,8 @@ gtd_task_row_set_handle_subtasks (GtdTaskRow *self,
gtk_widget_set_visible (self->dnd_box, handle_subtasks);
gtk_widget_set_visible (self->dnd_icon, handle_subtasks);
- on_depth_changed_cb (self, NULL, self->task);
+ if (self->task)
+ on_depth_changed_cb (self, NULL, self->task);
g_object_notify (G_OBJECT (self), "handle-subtasks");
}
@@ -962,32 +1014,3 @@ gtd_task_row_set_drag_offset (GtdTaskRow *self,
gtk_widget_show (self->dnd_frame);
}
-
-void
-gtd_task_row_unset_drag_offset (GtdTaskRow *self)
-{
- g_return_if_fail (GTD_IS_TASK_ROW (self));
-
- gtk_widget_hide (self->dnd_frame);
-}
-
-GtdTask*
-gtd_task_row_get_dnd_drop_task (GtdTaskRow *self)
-{
- GtdTask *task;
- gint task_depth;
- gint depth;
- gint i;
-
- g_return_val_if_fail (GTD_IS_TASK_ROW (self), NULL);
-
- task = self->task;
- task_depth = gtd_task_get_depth (task);
- depth = (gtk_widget_get_margin_start (self->dnd_frame) - 12) / 32;
-
- /* Find the real parent */
- for (i = task_depth - depth; i >= 0; i--)
- task = gtd_task_get_parent (task);
-
- return task;
-}
diff --git a/src/gui/gtd-task-row.h b/src/gui/gtd-task-row.h
index b51099ba..851c652f 100644
--- a/src/gui/gtd-task-row.h
+++ b/src/gui/gtd-task-row.h
@@ -54,16 +54,6 @@ void gtd_task_row_set_sizegroups (GtdTaskRow
GtkSizeGroup *name_group,
GtkSizeGroup *date_group);
-gint gtd_task_row_get_x_offset (GtdTaskRow *self);
-
-void gtd_task_row_set_drag_offset (GtdTaskRow *self,
- GtdTaskRow *source_row,
- gint x_offset);
-
-void gtd_task_row_unset_drag_offset (GtdTaskRow *self);
-
-GtdTask* gtd_task_row_get_dnd_drop_task (GtdTaskRow *self);
-
G_END_DECLS
#endif /* GTD_TASK_ROW_H */
diff --git a/src/gui/gtd-task-row.ui b/src/gui/gtd-task-row.ui
index ffa6860e..c50349bb 100644
--- a/src/gui/gtd-task-row.ui
+++ b/src/gui/gtd-task-row.ui
@@ -3,6 +3,12 @@
<requires lib="gtk+" version="3.16"/>
<template class="GtdTaskRow" parent="GtdWidget">
<property name="hexpand">true</property>
+ <property name="halign">center</property>
+ <property name="layout-manager">
+ <object class="GtdMaxSizeLayout">
+ <property name="max-width">700</property>
+ </object>
+ </property>
<child>
<object class="GtkEventControllerKey">
<property name="propagation-phase">capture</property>
@@ -10,6 +16,14 @@
</object>
</child>
<child>
+ <object class="GtkGestureClick">
+ <property name="propagation-phase">bubble</property>
+ <signal name="pressed" handler="on_click_gesture_pressed_cb" object="GtdTaskRow" swapped="no"/>
+ <signal name="released" handler="on_click_gesture_released_cb" object="GtdTaskRow" swapped="no"/>
+ <signal name="stopped" handler="on_click_gesture_stopped_cb" object="GtdTaskRow" swapped="no"/>
+ </object>
+ </child>
+ <child>
<object class="GtkBox" id="main_box">
<property name="orientation">vertical</property>
<child>
diff --git a/src/meson.build b/src/meson.build
index bea40f5b..e8df5685 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -141,6 +141,7 @@ sources += files(
'gui/gtd-new-task-row.c',
'gui/gtd-task-list-popover.c',
'gui/gtd-task-list-view.c',
+ 'gui/gtd-task-list-view-model.c',
'gui/gtd-task-row.c',
'gui/gtd-color-button.c',
'gui/gtd-empty-list-widget.c',
diff --git a/src/plugins/inbox-panel/gtd-inbox-panel.c b/src/plugins/inbox-panel/gtd-inbox-panel.c
index 62272780..04e61bea 100644
--- a/src/plugins/inbox-panel/gtd-inbox-panel.c
+++ b/src/plugins/inbox-panel/gtd-inbox-panel.c
@@ -254,8 +254,6 @@ gtd_inbox_panel_init (GtdInboxPanel *self)
gtd_task_list_view_set_handle_subtasks (GTD_TASK_LIST_VIEW (self->view), FALSE);
gtd_task_list_view_set_show_list_name (GTD_TASK_LIST_VIEW (self->view), FALSE);
gtd_task_list_view_set_show_due_date (GTD_TASK_LIST_VIEW (self->view), FALSE);
- gtd_task_list_view_set_task_list_selector_behavior (GTD_TASK_LIST_VIEW (self->view),
- GTD_TASK_LIST_SELECTOR_BEHAVIOR_ALWAYS_HIDE);
gtk_widget_set_hexpand (GTK_WIDGET (self->view), TRUE);
gtk_widget_set_vexpand (GTK_WIDGET (self->view), TRUE);