/* -*- 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 . * * 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 "nm-default.h" #include #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)); }