about summary refs log tree commit diff
path: root/clients/tui/newt/nmt-newt-stack.c
diff options
context:
space:
mode:
Diffstat (limited to 'clients/tui/newt/nmt-newt-stack.c')
-rw-r--r--clients/tui/newt/nmt-newt-stack.c368
1 files changed, 368 insertions, 0 deletions
diff --git a/clients/tui/newt/nmt-newt-stack.c b/clients/tui/newt/nmt-newt-stack.c
new file mode 100644
index 00000000..d94bdebf
--- /dev/null
+++ b/clients/tui/newt/nmt-newt-stack.c
@@ -0,0 +1,368 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * 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 2 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/>.
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nmt-newt-stack
+ * @short_description: A stack of alternative widgets
+ *
+ * #NmtNewtStack implements a stack of widgets, only one of which is
+ * visible at any time.
+ *
+ * The height and width of the widget is determined only by its
+ * visible child. Likewise, the widget's #NmtNewtWidget:valid is
+ * determined only by the validity of its visible child, not its other
+ * children.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "nmt-newt-stack.h"
+
+G_DEFINE_TYPE (NmtNewtStack, nmt_newt_stack, NMT_TYPE_NEWT_CONTAINER)
+
+#define NMT_NEWT_STACK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_NEWT_STACK, NmtNewtStackPrivate))
+
+typedef struct {
+	GPtrArray *children;
+	GPtrArray *ids;
+
+	guint active;
+} NmtNewtStackPrivate;
+
+enum {
+	PROP_0,
+	PROP_ACTIVE,
+	PROP_ACTIVE_ID,
+
+	LAST_PROP
+};
+
+/**
+ * nmt_newt_stack_new:
+ *
+ * Creates a new #NmtNewtStack
+ *
+ * Returns: a new #NmtNewtStack
+ */
+NmtNewtWidget *
+nmt_newt_stack_new (void)
+{
+	return g_object_new (NMT_TYPE_NEWT_STACK, NULL);
+}
+
+static void
+nmt_newt_stack_init (NmtNewtStack *stack)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack);
+
+	priv->children = g_ptr_array_new ();
+	priv->ids = g_ptr_array_new_with_free_func (g_free);
+}
+
+static void
+nmt_newt_stack_finalize (GObject *object)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (object);
+
+	g_ptr_array_unref (priv->children);
+	g_ptr_array_unref (priv->ids);
+
+	G_OBJECT_CLASS (nmt_newt_stack_parent_class)->finalize (object);
+}
+
+static newtComponent *
+nmt_newt_stack_get_components (NmtNewtWidget *widget)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (widget);
+
+	if (priv->active > priv->children->len)
+		return NULL;
+
+	return nmt_newt_widget_get_components (priv->children->pdata[priv->active]);
+}
+
+static void
+nmt_newt_stack_size_request (NmtNewtWidget *widget,
+                             int           *width,
+                             int           *height)
+{
+	NmtNewtStack *stack = NMT_NEWT_STACK (widget);
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack);
+	int i, child_width, child_height;
+
+	if (priv->active > priv->children->len) {
+		*width = *height = 0;
+		return;
+	}
+
+	/* We size-request all pages so that embedded NmtPageGrids will
+	 * participate in their size-grouping (so that switching pages
+	 * won't result in the column widths changing).
+	 */
+	for (i = 0; i < priv->children->len; i++) {
+		nmt_newt_widget_size_request (priv->children->pdata[i], &child_width, &child_height);
+		if (i == priv->active) {
+			*width = child_width;
+			*height = child_height;
+		}
+	}
+}
+
+static void
+nmt_newt_stack_size_allocate (NmtNewtWidget *widget,
+                              int            x,
+                              int            y,
+                              int            width,
+                              int            height)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (widget);
+
+	if (priv->active > priv->children->len)
+		return;
+
+	nmt_newt_widget_size_allocate (priv->children->pdata[priv->active], x, y, width, height);
+}
+
+/**
+ * nmt_newt_stack_add:
+ * @stack: an #NmtNewtStack
+ * @id: the ID for the new page
+ * @widget: the widget to add
+ *
+ * Adds @widget to @stack with the given @id.
+ */
+void
+nmt_newt_stack_add (NmtNewtStack  *stack,
+                    const char    *id,
+                    NmtNewtWidget *widget)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack);
+
+	g_ptr_array_add (priv->children, widget);
+	g_ptr_array_add (priv->ids, g_strdup (id));
+
+	NMT_NEWT_CONTAINER_CLASS (nmt_newt_stack_parent_class)->add (NMT_NEWT_CONTAINER (stack), widget);
+}
+
+static void
+nmt_newt_stack_remove (NmtNewtContainer *container,
+                       NmtNewtWidget    *widget)
+{
+	NmtNewtStack *stack = NMT_NEWT_STACK (container);
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack);
+	int i;
+
+	NMT_NEWT_CONTAINER_CLASS (nmt_newt_stack_parent_class)->remove (container, widget);
+
+	for (i = 0; i < priv->children->len; i++) {
+		if (priv->children->pdata[i] == widget) {
+			g_ptr_array_remove_index (priv->children, i);
+			g_ptr_array_remove_index (priv->ids, i);
+			return;
+		}
+	}
+}
+
+static void
+nmt_newt_stack_child_validity_changed (NmtNewtContainer *container,
+                                       NmtNewtWidget    *widget)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (container);
+
+	if (priv->active > priv->children->len)
+		return;
+
+	if (priv->children->pdata[priv->active] == (gpointer) widget) {
+		NMT_NEWT_CONTAINER_CLASS (nmt_newt_stack_parent_class)->
+			child_validity_changed (container, widget);
+	}
+}
+
+/**
+ * nmt_newt_stack_set_active:
+ * @stack: an #NmtNewtStack
+ * @active: the index of the new active page
+ *
+ * Sets the active page on @stack to @active.
+ */
+void
+nmt_newt_stack_set_active (NmtNewtStack *stack,
+                           guint         active)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack);
+
+	if (priv->active == active)
+		return;
+
+	priv->active = active;
+	g_object_notify (G_OBJECT (stack), "active");
+	g_object_notify (G_OBJECT (stack), "active-id");
+	nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (stack));
+}
+
+/**
+ * nmt_newt_stack_get_active:
+ * @stack: an #NmtNewtStack
+ *
+ * Gets the index of the active page on @stack
+ *
+ * Returns: the index of the active page on @stack
+ */
+guint
+nmt_newt_stack_get_active (NmtNewtStack *stack)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack);
+
+	return priv->active;
+}
+
+/**
+ * nmt_newt_stack_set_active_id:
+ * @stack: an #NmtNewtStack
+ * @active_id: the ID of the new active page
+ *
+ * Sets the active page on @stack to @active_id.
+ */
+void
+nmt_newt_stack_set_active_id (NmtNewtStack *stack,
+                              const char   *id)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack);
+	int i;
+
+	if (!g_strcmp0 (priv->ids->pdata[priv->active], id))
+		return;
+
+	for (i = 0; i < priv->ids->len; i++) {
+		if (!g_strcmp0 (priv->ids->pdata[i], id)) {
+			priv->active = i;
+			g_object_notify (G_OBJECT (stack), "active");
+			g_object_notify (G_OBJECT (stack), "active-id");
+			nmt_newt_widget_needs_rebuild (NMT_NEWT_WIDGET (stack));
+			return;
+		}
+	}
+}
+
+/**
+ * nmt_newt_stack_get_active_id:
+ * @stack: an #NmtNewtStack
+ *
+ * Gets the ID of the active page on @stack
+ *
+ * Returns: the ID of the active page on @stack
+ */
+const char *
+nmt_newt_stack_get_active_id (NmtNewtStack *stack)
+{
+	NmtNewtStackPrivate *priv = NMT_NEWT_STACK_GET_PRIVATE (stack);
+
+	if (priv->active > priv->children->len)
+		return NULL;
+
+	return priv->ids->pdata[priv->active];
+}
+
+static void
+nmt_newt_stack_set_property (GObject      *object,
+                             guint         prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+	NmtNewtStack *stack = NMT_NEWT_STACK (object);
+
+	switch (prop_id) {
+	case PROP_ACTIVE:
+		nmt_newt_stack_set_active (stack, g_value_get_uint (value));
+		break;
+	case PROP_ACTIVE_ID:
+		nmt_newt_stack_set_active_id (stack, g_value_get_string (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_stack_get_property (GObject    *object,
+                             guint       prop_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+	NmtNewtStack *stack = NMT_NEWT_STACK (object);
+
+	switch (prop_id) {
+	case PROP_ACTIVE:
+		g_value_set_uint (value, nmt_newt_stack_get_active (stack));
+		break;
+	case PROP_ACTIVE_ID:
+		g_value_set_string (value, nmt_newt_stack_get_active_id (stack));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nmt_newt_stack_class_init (NmtNewtStackClass *stack_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (stack_class);
+	NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (stack_class);
+	NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (stack_class);
+
+	g_type_class_add_private (stack_class, sizeof (NmtNewtStackPrivate));
+
+	/* virtual methods */
+	object_class->set_property = nmt_newt_stack_set_property;
+	object_class->get_property = nmt_newt_stack_get_property;
+	object_class->finalize = nmt_newt_stack_finalize;
+
+	widget_class->get_components = nmt_newt_stack_get_components;
+	widget_class->size_request   = nmt_newt_stack_size_request;
+	widget_class->size_allocate  = nmt_newt_stack_size_allocate;
+
+	container_class->remove = nmt_newt_stack_remove;
+	container_class->child_validity_changed = nmt_newt_stack_child_validity_changed;
+
+	/**
+	 * NmtNewtStack:active:
+	 *
+	 * The index of the active page
+	 */
+	g_object_class_install_property
+		(object_class, PROP_ACTIVE,
+		 g_param_spec_uint ("active", "", "",
+		                    0, G_MAXUINT, 0,
+		                    G_PARAM_READWRITE |
+		                    G_PARAM_STATIC_STRINGS));
+	/**
+	 * NmtNewtStack:active-id:
+	 *
+	 * The ID of the active page
+	 */
+	g_object_class_install_property
+		(object_class, PROP_ACTIVE_ID,
+		 g_param_spec_string ("active-id", "", "",
+		                      NULL,
+		                      G_PARAM_READWRITE |
+		                      G_PARAM_STATIC_STRINGS));
+}