summaryrefslogtreecommitdiff
path: root/tests/interactive
diff options
context:
space:
mode:
authorMatthew Fennell <matthew@fennell.dev>2025-12-27 12:40:20 +0000
committerMatthew Fennell <matthew@fennell.dev>2025-12-27 12:40:20 +0000
commit5d8e439bc597159e3c9f0a8b65c0ae869dead3a8 (patch)
treeed28aefed8add0da1c55c08fdf80b23c4346e0dc /tests/interactive
Import Upstream version 43.0upstream/latest
Diffstat (limited to 'tests/interactive')
-rw-r--r--tests/interactive/test-animation.c288
-rw-r--r--tests/interactive/test-colorbutton.c85
-rw-r--r--tests/interactive/test-filter-sort.c290
-rw-r--r--tests/interactive/test-star-widget.c53
-rw-r--r--tests/interactive/test-task-model.c171
-rw-r--r--tests/interactive/test-widget.c130
6 files changed, 1017 insertions, 0 deletions
diff --git a/tests/interactive/test-animation.c b/tests/interactive/test-animation.c
new file mode 100644
index 0000000..6541551
--- /dev/null
+++ b/tests/interactive/test-animation.c
@@ -0,0 +1,288 @@
+/* test-widget.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-keyframe-transition.h"
+#include "gtd-widget.h"
+
+static const char *css =
+"translated {"
+" background-image: none;"
+" background-color: red;"
+"}\n"
+"wiggler {"
+" background-image: none;"
+" background-color: green;"
+"}\n"
+"rotated {"
+" background-image: none;"
+" background-color: blue;"
+"}\n"
+"mover {"
+" background-image: none;"
+" background-color: pink;"
+"}\n"
+;
+
+static const char *ui =
+"<interface>"
+" <object class='GtkWindow' id='window'>"
+" <property name='default-width'>600</property>"
+" <property name='default-height'>400</property>"
+" <child>"
+" <object class='GtkBox'>"
+" <child>"
+" <object class='GtdWidget'>"
+" <property name='hexpand'>true</property>"
+" <child>"
+" <object class='GtdWidget'>"
+" <property name='halign'>center</property>"
+" <property name='valign'>center</property>"
+" <child>"
+" <object class='GtdWidget' id='translated'>"
+" <property name='css-name'>translated</property>"
+" <property name='width-request'>30</property>"
+" <property name='height-request'>30</property>"
+" </object>"
+" </child>"
+" </object>"
+" </child>"
+" <child>"
+" <object class='GtdWidget'>"
+" <property name='halign'>center</property>"
+" <property name='valign'>start</property>"
+" <child>"
+" <object class='GtdWidget' id='wiggler'>"
+" <property name='css-name'>wiggler</property>"
+" <property name='translation-y'>40</property>"
+" <property name='width-request'>300</property>"
+" <property name='height-request'>40</property>"
+" </object>"
+" </child>"
+" </object>"
+" </child>"
+" <child>"
+" <object class='GtdWidget'>"
+" <property name='halign'>center</property>"
+" <property name='valign'>end</property>"
+" <child>"
+" <object class='GtdWidget' id='rotated'>"
+" <property name='css-name'>rotated</property>"
+" <property name='translation-y'>-80</property>"
+" <property name='width-request'>40</property>"
+" <property name='height-request'>40</property>"
+" </object>"
+" </child>"
+" </object>"
+" </child>"
+" <child>"
+" <object class='GtdWidget'>"
+" <property name='halign'>center</property>"
+" <property name='valign'>end</property>"
+" <child>"
+" <object class='GtdWidget' id='mover'>"
+" <property name='css-name'>mover</property>"
+" <property name='translation-x'>-200</property>"
+" <property name='translation-y'>-40</property>"
+" <property name='width-request'>50</property>"
+" <property name='height-request'>50</property>"
+" </object>"
+" </child>"
+" </object>"
+" </child>"
+" </object>"
+" </child>"
+" <child>"
+" <object class='GtkButton' id='button'>"
+" <property name='label'>Move</property>"
+" <property name='valign'>start</property>"
+" <property name='margin-top'>12</property>"
+" <property name='margin-start'>12</property>"
+" <property name='margin-end'>12</property>"
+" <property name='margin-bottom'>12</property>"
+" </object>"
+" </child>"
+" </object>"
+" </child>"
+" </object>"
+"</interface>";
+
+static gboolean pink_moved = FALSE;
+
+static void
+animate_rotation (GtdWidget *widget)
+{
+ GtdTransition *rotation_z;
+ GtdTransition *scale_x;
+ GtdTransition *scale_y;
+
+ rotation_z = gtd_property_transition_new ("rotation-z");
+ gtd_transition_set_from (rotation_z, G_TYPE_FLOAT, 0.f);
+ gtd_transition_set_to (rotation_z, G_TYPE_FLOAT, 360.f);
+ gtd_timeline_set_duration (GTD_TIMELINE (rotation_z), 750);
+ gtd_timeline_set_repeat_count (GTD_TIMELINE (rotation_z), -1);
+ gtd_timeline_set_auto_reverse (GTD_TIMELINE (rotation_z), TRUE);
+
+ scale_x = gtd_property_transition_new ("scale-x");
+ gtd_transition_set_from (scale_x, G_TYPE_FLOAT, 1.f);
+ gtd_transition_set_to (scale_x, G_TYPE_FLOAT, 2.f);
+ gtd_timeline_set_duration (GTD_TIMELINE (scale_x), 750);
+ gtd_timeline_set_repeat_count (GTD_TIMELINE (scale_x), -1);
+ gtd_timeline_set_auto_reverse (GTD_TIMELINE (scale_x), TRUE);
+
+ scale_y = gtd_property_transition_new ("scale-y");
+ gtd_transition_set_from (scale_y, G_TYPE_FLOAT, 1.f);
+ gtd_transition_set_to (scale_y, G_TYPE_FLOAT, 2.f);
+ gtd_timeline_set_duration (GTD_TIMELINE (scale_y), 750);
+ gtd_timeline_set_repeat_count (GTD_TIMELINE (scale_y), -1);
+ gtd_timeline_set_auto_reverse (GTD_TIMELINE (scale_y), TRUE);
+
+ gtd_widget_add_transition (widget, "loop-rotation-z", rotation_z);
+ gtd_widget_add_transition (widget, "loop-scale-x", scale_x);
+ gtd_widget_add_transition (widget, "loop-scale-y", scale_y);
+}
+
+static void
+animate_translation (GtdWidget *widget)
+{
+ GtdTransition *transition_x;
+
+ transition_x = gtd_property_transition_new ("translation-x");
+ gtd_transition_set_from (transition_x, G_TYPE_FLOAT, -200.f);
+ gtd_transition_set_to (transition_x, G_TYPE_FLOAT, 200.f);
+ gtd_timeline_set_duration (GTD_TIMELINE (transition_x), 2000);
+ gtd_timeline_set_repeat_count (GTD_TIMELINE (transition_x), -1);
+ gtd_timeline_set_auto_reverse (GTD_TIMELINE (transition_x), TRUE);
+
+ gtd_widget_add_transition (widget, "loop-translation-x", transition_x);
+}
+
+static void
+animate_wiggle (GtdWidget *widget)
+{
+ GtdTransition *transition_x;
+
+ g_message ("Adding wiggle");
+
+ gtd_widget_remove_all_transitions (widget);
+
+ transition_x = gtd_keyframe_transition_new ("translation-x");
+ gtd_transition_set_from (transition_x, G_TYPE_FLOAT, 0.f);
+ gtd_transition_set_to (transition_x, G_TYPE_FLOAT, 0.f);
+ gtd_timeline_set_duration (GTD_TIMELINE (transition_x), 350);
+ gtd_timeline_set_delay (GTD_TIMELINE (transition_x), 1000);
+ gtd_keyframe_transition_set (GTD_KEYFRAME_TRANSITION (transition_x),
+ G_TYPE_FLOAT,
+ 5,
+ 0.20, -15.f, GTD_EASE_OUT_QUAD,
+ 0.40, 15.f, GTD_EASE_LINEAR,
+ 0.60, -15.f, GTD_EASE_LINEAR,
+ 0.80, 15.f, GTD_EASE_LINEAR,
+ 1.00, 0.f, GTD_EASE_IN_QUAD);
+
+ gtd_widget_add_transition (widget, "wiggle", transition_x);
+
+ g_signal_connect_swapped (transition_x,
+ "completed",
+ G_CALLBACK (animate_wiggle),
+ widget);
+}
+
+static void
+move_pink_cb (GtkButton *button,
+ GtdWidget *widget)
+{
+ GtdTransition *rotation_y;
+
+ gtd_widget_remove_all_transitions (widget);
+
+ rotation_y = gtd_property_transition_new ("rotation-y");
+ gtd_transition_set_from (rotation_y, G_TYPE_FLOAT, 0.f);
+ gtd_transition_set_to (rotation_y, G_TYPE_FLOAT, 360.f);
+ gtd_timeline_set_duration (GTD_TIMELINE (rotation_y), 500);
+ gtd_timeline_set_repeat_count (GTD_TIMELINE (rotation_y), 3);
+
+ gtd_widget_save_easing_state (widget);
+ gtd_widget_set_easing_duration (widget, 2000);
+ gtd_widget_set_easing_mode (widget, GTD_EASE_LINEAR);
+ gtd_widget_set_translation (widget, pink_moved ? -200.f : 200.f, -40.f, 0.f);
+ gtd_widget_restore_easing_state (widget);
+
+ gtd_widget_add_transition (widget, "loop-rotation-y", rotation_y);
+
+ pink_moved = !pink_moved;
+}
+
+static GtkWidget *
+create_ui (void)
+{
+ g_autoptr (GtkBuilder) builder = NULL;
+ g_autoptr (GError) error = NULL;
+ GtkWidget *win;
+
+ g_type_ensure (GTD_TYPE_WIDGET);
+
+ builder = gtk_builder_new ();
+ if (!gtk_builder_add_from_string (builder, ui, -1, &error))
+ {
+ g_warning ("%s", error->message);
+ return NULL;
+ }
+
+ win = (GtkWidget *)gtk_builder_get_object (builder, "window");
+ g_object_ref (win);
+
+ animate_rotation ((GtdWidget *)gtk_builder_get_object (builder, "rotated"));
+ animate_translation ((GtdWidget *)gtk_builder_get_object (builder, "translated"));
+ animate_wiggle ((GtdWidget *)gtk_builder_get_object (builder, "wiggler"));
+
+ g_signal_connect (gtk_builder_get_object (builder, "button"),
+ "clicked",
+ G_CALLBACK (move_pink_cb),
+ gtk_builder_get_object (builder, "mover"));
+
+ return win;
+}
+
+gint
+main (gint argc,
+ gchar *argv[])
+{
+ g_autoptr (GtkCssProvider) css_provider = NULL;
+ GtkWindow *window;
+
+ g_set_prgname ("test-colorbutton");
+ g_set_application_name ("Endeavour | Widget Test");
+
+ gtk_init ();
+
+ css_provider = gtk_css_provider_new ();
+ gtk_css_provider_load_from_data (css_provider, css, -1);
+ gtk_style_context_add_provider_for_display (gdk_display_get_default (),
+ GTK_STYLE_PROVIDER (css_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+ window = GTK_WINDOW (create_ui ());
+ gtk_window_present (window);
+
+ while (TRUE)
+ g_main_context_iteration (NULL, TRUE);
+
+ return 0;
+}
diff --git a/tests/interactive/test-colorbutton.c b/tests/interactive/test-colorbutton.c
new file mode 100644
index 0000000..065c978
--- /dev/null
+++ b/tests/interactive/test-colorbutton.c
@@ -0,0 +1,85 @@
+/* test-colorbutton.c
+ *
+ * Copyright 2018-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-color-button.h"
+
+static const gchar * const colors[] =
+{
+ "#ffffff",
+ "#dddddd",
+ "#ababab",
+ "#fafa00",
+ "#888888",
+ "#333333",
+ "#000000",
+ "#96ff11",
+ "#03fa95",
+};
+
+gint
+main (gint argc,
+ gchar *argv[])
+{
+ GtkWindow *window = NULL;
+ GtkWidget *grid = NULL;
+ guint columns;
+ guint i;
+
+ g_set_prgname ("test-colorbutton");
+ g_set_application_name ("Endeavour | Color Button Test");
+
+ gtk_init ();
+
+ grid = g_object_new (GTK_TYPE_GRID,
+ "row-homogeneous", TRUE,
+ "column-homogeneous", TRUE,
+ NULL);
+
+ columns = ceil (sqrt (G_N_ELEMENTS (colors)));
+
+ for (i = 0; i < G_N_ELEMENTS (colors); i++)
+ {
+ GtkWidget *color_button = NULL;
+ GdkRGBA color;
+
+ gdk_rgba_parse (&color, colors[i]);
+
+ color_button = g_object_new (GTD_TYPE_COLOR_BUTTON,
+ "color", &color,
+ NULL);
+
+ gtk_grid_attach (GTK_GRID (grid),
+ color_button,
+ i % columns,
+ i / columns,
+ 1,
+ 1);
+ }
+
+ window = GTK_WINDOW (gtk_window_new ());
+ gtk_window_set_child (window, grid);
+ gtk_window_present (window);
+
+ while (TRUE)
+ g_main_context_iteration (NULL, TRUE);
+
+ return 0;
+}
+
diff --git a/tests/interactive/test-filter-sort.c b/tests/interactive/test-filter-sort.c
new file mode 100644
index 0000000..a356e3c
--- /dev/null
+++ b/tests/interactive/test-filter-sort.c
@@ -0,0 +1,290 @@
+/* test-filter-sort.c
+ *
+ * Copyright 2018-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 <gtk/gtk.h>
+
+#include "core/gtd-log.h"
+#include "models/gtd-list-model-filter.h"
+#include "models/gtd-list-model-sort.h"
+#include "models/gtd-task-model.h"
+#include "models/gtd-task-model-private.h"
+#include "dummy-provider.h"
+#include "gtd-manager.h"
+#include "gtd-manager-protected.h"
+#include "gtd-provider.h"
+#include "gtd-task.h"
+#include "gtd-task-list.h"
+#include "gtd-utils.h"
+
+
+/*
+ * Auxiliary methods
+ */
+
+static GtkWidget*
+create_bold_label_for_task_row (GtkListBoxRow *row)
+{
+ g_autofree gchar *markup = NULL;
+ GtdTask *task;
+
+ task = g_object_get_data (G_OBJECT (row), "task");
+ markup = g_strdup_printf ("<big><b>%s</b></big>", gtd_task_list_get_name (gtd_task_get_list (task)));
+
+ return g_object_new (GTK_TYPE_LABEL,
+ "margin", 6,
+ "margin-top", 18,
+ "use-markup", TRUE,
+ "label", markup,
+ "xalign", 0.0,
+ NULL);
+}
+
+static GtkWidget*
+create_label_for_string (const gchar *string)
+{
+ return g_object_new (GTK_TYPE_LABEL,
+ "label", string,
+ "hexpand", TRUE,
+ "xalign", 0.0,
+ "margin", 6,
+ "margin-start", 18,
+ NULL);
+}
+
+
+/*
+ * Callbacks
+ */
+
+static void
+header_func (GtkListBoxRow *row,
+ GtkListBoxRow *before,
+ gpointer user_data)
+{
+ GtkWidget *header = NULL;
+
+ if (!before)
+ {
+ header = create_bold_label_for_task_row (row);
+ }
+ else
+ {
+ GtdTask *before_task;
+ GtdTask *task;
+
+ before_task = g_object_get_data (G_OBJECT (before), "task");
+ task = g_object_get_data (G_OBJECT (row), "task");
+
+ if (gtd_task_get_list (task) != gtd_task_get_list (before_task))
+ header = create_bold_label_for_task_row (row);
+ }
+
+ gtk_list_box_row_set_header (row, header);
+}
+
+static gboolean
+filter_func (GObject *item,
+ gpointer user_data)
+{
+ g_autofree gchar *normalized_entry_text = NULL;
+ g_autofree gchar *normalized_task_name = NULL;
+ GtkEntry *entry;
+ GtdTask *task;
+
+ task = (GtdTask*) item;
+ entry = (GtkEntry*) user_data;
+
+ normalized_entry_text = gtd_normalize_casefold_and_unaccent (gtk_editable_get_text (GTK_EDITABLE (entry)));
+ normalized_task_name = gtd_normalize_casefold_and_unaccent (gtd_task_get_title (task));
+
+ return strstr (normalized_task_name, normalized_entry_text) != NULL;
+}
+
+static GtkWidget*
+create_task_cb (gpointer item,
+ gpointer user_data)
+{
+ GtkWidget *row;
+ GtkWidget *box;
+ GtdTask *task;
+
+ task = item;
+
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 16);
+
+ gtk_box_append (GTK_BOX (box), create_label_for_string (gtd_task_get_title (task)));
+
+ row = gtk_list_box_row_new ();
+ gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box);
+
+ g_object_set_data (G_OBJECT (row), "task", task);
+
+ return row;
+}
+
+static gint
+sort_func (GObject *a,
+ GObject *b,
+ gpointer user_data)
+{
+ GtkCheckButton *check;
+ GtdTask *task_a;
+ GtdTask *task_b;
+
+ check = (GtkCheckButton*) user_data;
+
+ if (gtk_check_button_get_active (check))
+ {
+ task_a = GTD_TASK (a);
+ task_b = GTD_TASK (b);
+ }
+ else
+ {
+ task_a = GTD_TASK (b);
+ task_b = GTD_TASK (a);
+ }
+
+ if (gtd_task_get_list (task_a) == gtd_task_get_list (task_b))
+ {
+ return gtd_task_compare (task_b, task_a);
+ }
+ else
+ {
+ GtdTaskList *list_a = gtd_task_get_list (task_a);
+ GtdTaskList *list_b = gtd_task_get_list (task_b);
+
+ return g_strcmp0 (gtd_task_list_get_name (list_b), gtd_task_list_get_name (list_a));
+ }
+}
+
+static void
+on_check_active_changed_cb (GtkCheckButton *check,
+ GParamSpec *pspec,
+ GtdListModelSort *sort)
+{
+ gtd_list_model_sort_invalidate (sort);
+}
+
+static void
+on_remove_button_clicked_cb (GtkButton *button,
+ DummyProvider *provider)
+{
+ dummy_provider_randomly_remove_task (provider);
+}
+
+static void
+on_search_text_changed_cb (GtkEntry *entry,
+ GParamSpec *pspec,
+ GtdListModelFilter *filter)
+{
+ gtd_list_model_filter_invalidate (filter);
+}
+
+gint
+main (gint argc,
+ gchar *argv[])
+{
+ g_autoptr (GtdListModelFilter) filter = NULL;
+ g_autoptr (GtdListModelSort) sort = NULL;
+ g_autoptr (DummyProvider) dummy_provider = NULL;
+ GtdTaskModel *model = NULL;
+ GtkWidget *scrolledwindow = NULL;
+ GtkWidget *search_entry = NULL;
+ GtkWindow *window = NULL;
+ GtkWidget *listbox = NULL;
+ GtkWidget *button = NULL;
+ GtkWidget *check = NULL;
+ GtkWidget *hbox = NULL;
+ GtkWidget *vbox = NULL;
+
+ g_set_prgname ("test-filter-sort");
+ g_set_application_name ("Endeavour | Filter & Sort Test");
+
+ gtk_init ();
+ gtd_log_init ();
+
+ /* Create a DumbProvider and pre-populate it */
+ dummy_provider = dummy_provider_new ();
+ dummy_provider_generate_task_lists (dummy_provider);
+ dummy_provider_generate_task_lists (dummy_provider);
+ gtd_manager_add_provider (gtd_manager_get_default (), GTD_PROVIDER (dummy_provider));
+
+ /* Models */
+ model = _gtd_task_model_new (gtd_manager_get_default ());
+ filter = gtd_list_model_filter_new (G_LIST_MODEL (model));
+ sort = gtd_list_model_sort_new (G_LIST_MODEL (filter));
+
+ /* Listbox */
+ listbox = gtk_list_box_new ();
+ gtk_list_box_bind_model (GTK_LIST_BOX (listbox),
+ G_LIST_MODEL (sort),
+ create_task_cb,
+ NULL,
+ NULL);
+
+ gtk_list_box_set_header_func (GTK_LIST_BOX (listbox), header_func, NULL, NULL);
+
+ /* Scrolled window */
+ scrolledwindow = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
+ "propagate-natural-height", TRUE,
+ "max-content-height", 600,
+ "hscrollbar-policy", GTK_POLICY_NEVER,
+ NULL);
+ gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), listbox);
+
+ /* Search entry */
+ search_entry = gtk_search_entry_new ();
+ gtd_list_model_filter_set_filter_func (filter, filter_func, search_entry, NULL);
+
+ g_signal_connect_object (search_entry, "notify::text", G_CALLBACK (on_search_text_changed_cb), filter, 0);
+
+ /* Reverse order checkbox */
+ check = gtk_check_button_new_with_label ("Reverse Order");
+ gtd_list_model_sort_set_sort_func (sort, sort_func, check, NULL);
+
+ g_signal_connect_object (check, "notify::active", G_CALLBACK (on_check_active_changed_cb), sort, 0);
+
+ /* Remove Tasks button */
+ button = gtk_button_new_with_label ("Randomly Remove Tasks");
+ g_signal_connect_object (button, "clicked", G_CALLBACK (on_remove_button_clicked_cb), dummy_provider, 0);
+
+ /* Horizontal box */
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_box_append (GTK_BOX (hbox), search_entry);
+ gtk_box_append (GTK_BOX (hbox), check);
+ gtk_box_append (GTK_BOX (hbox), button);
+
+ /* Box */
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ gtk_box_append (GTK_BOX (vbox), hbox);
+ gtk_box_append (GTK_BOX (vbox), scrolledwindow);
+
+ /* Window */
+ window = GTK_WINDOW (gtk_window_new ());
+ gtk_window_set_default_size (window, 800, 600);
+ gtk_window_set_child (GTK_WINDOW (window), vbox);
+ gtk_window_present (window);
+
+ while (TRUE)
+ g_main_context_iteration (NULL, TRUE);
+
+ return 0;
+}
diff --git a/tests/interactive/test-star-widget.c b/tests/interactive/test-star-widget.c
new file mode 100644
index 0000000..cfb102c
--- /dev/null
+++ b/tests/interactive/test-star-widget.c
@@ -0,0 +1,53 @@
+/* test-star-widget.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 <gtk/gtk.h>
+
+#include "gtd-log.h"
+#include "gtd-star-widget.h"
+
+gint
+main (gint argc,
+ gchar *argv[])
+{
+ GtkWidget *start_widget = NULL;
+ GtkWindow *window = NULL;
+
+ g_set_prgname ("test-star-widget");
+ g_set_application_name ("Endeavour | Star Widget");
+
+ gtk_init ();
+ gtd_log_init ();
+
+ /* Box */
+ start_widget = gtd_star_widget_new ();
+
+ /* Window */
+ window = GTK_WINDOW (gtk_window_new ());
+ gtk_window_set_default_size (window, 200, 150);
+ gtk_window_set_child (window, start_widget);
+ gtk_window_present (window);
+
+ while (TRUE)
+ g_main_context_iteration (NULL, TRUE);
+
+ return 0;
+}
diff --git a/tests/interactive/test-task-model.c b/tests/interactive/test-task-model.c
new file mode 100644
index 0000000..aa61ba9
--- /dev/null
+++ b/tests/interactive/test-task-model.c
@@ -0,0 +1,171 @@
+/* test-task-model.c
+ *
+ * Copyright 2018-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 <gtk/gtk.h>
+
+#include "models/gtd-task-model.h"
+#include "models/gtd-task-model-private.h"
+#include "dummy-provider.h"
+#include "gtd-log.h"
+#include "gtd-manager.h"
+#include "gtd-manager-protected.h"
+#include "gtd-provider.h"
+#include "gtd-task.h"
+#include "gtd-task-list.h"
+
+static GtkWidget*
+create_bold_label_for_task_row (GtkListBoxRow *row)
+{
+ g_autofree gchar *markup = NULL;
+ GtdTask *task;
+
+ task = g_object_get_data (G_OBJECT (row), "task");
+ markup = g_strdup_printf ("<big><b>%s</b></big>", gtd_task_list_get_name (gtd_task_get_list (task)));
+
+ return g_object_new (GTK_TYPE_LABEL,
+ "margin", 6,
+ "margin-top", 18,
+ "use-markup", TRUE,
+ "label", markup,
+ "xalign", 0.0,
+ NULL);
+}
+
+static void
+header_func (GtkListBoxRow *row,
+ GtkListBoxRow *before,
+ gpointer user_data)
+{
+ GtkWidget *header = NULL;
+
+ if (!before)
+ {
+ header = create_bold_label_for_task_row (row);
+ }
+ else
+ {
+ GtdTask *before_task;
+ GtdTask *task;
+
+ before_task = g_object_get_data (G_OBJECT (before), "task");
+ task = g_object_get_data (G_OBJECT (row), "task");
+
+ if (gtd_task_get_list (task) != gtd_task_get_list (before_task))
+ header = create_bold_label_for_task_row (row);
+ }
+
+ gtk_list_box_row_set_header (row, header);
+}
+
+static GtkWidget*
+create_label_for_string (const gchar *string)
+{
+ return g_object_new (GTK_TYPE_LABEL,
+ "label", string,
+ "hexpand", TRUE,
+ "xalign", 0.0,
+ "margin", 6,
+ "margin-start", 18,
+ NULL);
+}
+
+static GtkWidget*
+create_task_cb (gpointer item,
+ gpointer user_data)
+{
+ GtkWidget *row;
+ GtkWidget *box;
+ GtdTask *task;
+
+ task = item;
+
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 16);
+
+ gtk_box_append (GTK_BOX (box), create_label_for_string (gtd_task_get_title (task)));
+
+ row = gtk_list_box_row_new ();
+ gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box);
+
+ g_object_set_data (G_OBJECT (row), "task", task);
+
+ return row;
+}
+
+gint
+main (gint argc,
+ gchar *argv[])
+{
+ g_autoptr (DummyProvider) dummy_provider = NULL;
+ GtdTaskModel *model = NULL;
+ GtkWidget *scrolledwindow = NULL;
+ GtkWindow *window = NULL;
+ GtkWidget *listbox = NULL;
+
+ g_set_prgname ("test-task-model");
+ g_set_application_name ("Endeavour | Task Model Test");
+
+ gtk_init ();
+ gtd_log_init ();
+
+ /* Create a DumbProvider and pre-populate it */
+ dummy_provider = dummy_provider_new ();
+ dummy_provider_generate_task_lists (dummy_provider);
+
+ /* Inject a dumb fake provider */
+ gtd_manager_add_provider (gtd_manager_get_default (), GTD_PROVIDER (dummy_provider));
+
+ /* Now create the model - the initial providers must be there already */
+ model = _gtd_task_model_new (gtd_manager_get_default ());
+
+ /* Listbox */
+ listbox = gtk_list_box_new ();
+ gtk_list_box_bind_model (GTK_LIST_BOX (listbox),
+ G_LIST_MODEL (model),
+ create_task_cb,
+ NULL,
+ NULL);
+
+ gtk_list_box_set_header_func (GTK_LIST_BOX (listbox), header_func, NULL, NULL);
+
+ /* Scrolled window */
+ scrolledwindow = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
+ "propagate-natural-height", TRUE,
+ "max-content-height", 600,
+ "hscrollbar-policy", GTK_POLICY_NEVER,
+ NULL);
+ gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), listbox);
+
+ /* Window */
+ window = GTK_WINDOW (gtk_window_new ());
+ gtk_window_set_default_size (window, 800, 600);
+ gtk_window_set_child (GTK_WINDOW (window), scrolledwindow);
+ gtk_window_present (window);
+
+ /* Now, generate more tasks and lists after injecting to the manager */
+ dummy_provider_generate_task_lists (dummy_provider);
+
+ /* Schedule a live removal of tasks */
+ dummy_provider_schedule_remove_task (dummy_provider);
+
+ while (TRUE)
+ g_main_context_iteration (NULL, TRUE);
+
+ return 0;
+}
diff --git a/tests/interactive/test-widget.c b/tests/interactive/test-widget.c
new file mode 100644
index 0000000..32c1d2d
--- /dev/null
+++ b/tests/interactive/test-widget.c
@@ -0,0 +1,130 @@
+/* test-widget.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-widget.h"
+
+static const char *css =
+"translated {"
+" background-image: none;"
+" background-color: red;"
+"}\n"
+"scaled {"
+" background-image: none;"
+" background-color: green;"
+"}\n"
+"rotated {"
+" background-image: none;"
+" background-color: blue;"
+"}\n"
+;
+
+static const char *ui =
+"<interface>"
+" <object class='GtkWindow' id='window'>"
+" <property name='default-width'>400</property>"
+" <property name='default-height'>300</property>"
+" <child>"
+" <object class='GtdWidget'>"
+" <child>"
+" <object class='GtdWidget' id='translated'>"
+" <property name='css-name'>translated</property>"
+" <property name='translation-x'>30.0</property>"
+" <property name='translation-y'>15.0</property>"
+" <property name='translation-z'>0.0</property>"
+" <property name='valign'>start</property>"
+" <property name='width-request'>30</property>"
+" <property name='height-request'>30</property>"
+" </object>"
+" </child>"
+" <child>"
+" <object class='GtdWidget' id='scaled'>"
+" <property name='css-name'>scaled</property>"
+" <property name='scale-x'>0.75</property>"
+" <property name='scale-y'>1.25</property>"
+" <property name='scale-z'>1.0</property>"
+" <property name='valign'>center</property>"
+" <property name='width-request'>30</property>"
+" <property name='height-request'>30</property>"
+" </object>"
+" </child>"
+" <child>"
+" <object class='GtdWidget' id='rotated'>"
+" <property name='css-name'>rotated</property>"
+" <property name='rotation-x'>30.0</property>"
+" <property name='rotation-y'>-15.0</property>"
+" <property name='rotation-z'>0</property>"
+" <property name='valign'>end</property>"
+" <property name='width-request'>30</property>"
+" <property name='height-request'>30</property>"
+" </object>"
+" </child>"
+" </object>"
+" </child>"
+" </object>"
+"</interface>";
+
+static GtkWidget *
+create_ui (void)
+{
+ g_autoptr (GtkBuilder) builder = NULL;
+ g_autoptr (GError) error = NULL;
+ GtkWidget *win;
+
+ g_type_ensure (GTD_TYPE_WIDGET);
+
+ builder = gtk_builder_new ();
+ if (!gtk_builder_add_from_string (builder, ui, -1, &error))
+ {
+ g_warning ("%s", error->message);
+ return NULL;
+ }
+
+ win = (GtkWidget *)gtk_builder_get_object (builder, "window");
+ g_object_ref (win);
+
+ return win;
+}
+
+gint
+main (gint argc,
+ gchar *argv[])
+{
+ g_autoptr (GtkCssProvider) css_provider = NULL;
+ GtkWindow *window;
+
+ g_set_prgname ("test-colorbutton");
+ g_set_application_name ("Endeavour | Widget Test");
+
+ gtk_init ();
+
+ css_provider = gtk_css_provider_new ();
+ gtk_css_provider_load_from_data (css_provider, css, -1);
+ gtk_style_context_add_provider_for_display (gdk_display_get_default (),
+ GTK_STYLE_PROVIDER (css_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+ window = GTK_WINDOW (create_ui ());
+ gtk_window_present (window);
+
+ while (TRUE)
+ g_main_context_iteration (NULL, TRUE);
+
+ return 0;
+}