diff options
Diffstat (limited to 'clients/tui/newt/nmt-newt-stack.c')
| -rw-r--r-- | clients/tui/newt/nmt-newt-stack.c | 368 |
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)); +} |