mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-05 07:40:49 +00:00
8bace23beb
- All internal source files (except "examples", which are not internal) should include "config.h" first. As also all internal source files should include "nm-default.h", let "config.h" be included by "nm-default.h" and include "nm-default.h" as first in every source file. We already wanted to include "nm-default.h" before other headers because it might contains some fixes (like "nm-glib.h" compatibility) that is required first. - After including "nm-default.h", we optinally allow for including the corresponding header file for the source file at hand. The idea is to ensure that each header file is self contained. - Don't include "config.h" or "nm-default.h" in any header file (except "nm-sd-adapt.h"). Public headers anyway must not include these headers, and internal headers are never included after "nm-default.h", as of the first previous point. - Include all internal headers with quotes instead of angle brackets. In practice it doesn't matter, because in our public headers we must include other headers with angle brackets. As we use our public headers also to compile our interal source files, effectively the result must be the same. Still do it for consistency. - Except for <config.h> itself. Include it with angle brackets as suggested by https://www.gnu.org/software/autoconf/manual/autoconf.html#Configuration-Headers
464 lines
13 KiB
C
464 lines
13 KiB
C
/* -*- 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-editor-grid
|
|
* @short_description: Grid widget for #NmtEditorPages
|
|
*
|
|
* #NmtEditorGrid is the layout grid used by #NmtEditorPages. It
|
|
* consists of a number of rows, each containing either a single
|
|
* widget that spans the entire width of the row, or else containing a
|
|
* label, a widget, and an optional extra widget.
|
|
*
|
|
* Each row of the grid can take up multiple on-screen rows, if
|
|
* its main widget is multiple rows high. The label and extra widgets
|
|
* will be top-aligned if the row is taller than they are.
|
|
*
|
|
* The #NmtEditorGrids in a form behave as though they are all in a
|
|
* "size group" together; they will all use the same column widths,
|
|
* which will be wide enough for the widest labels/widgets in any of
|
|
* the grids. #NmtEditorGrid is also specially aware of #NmtNewtSection,
|
|
* and grids inside sections will automatically take the size of the
|
|
* section border into account as well.
|
|
*/
|
|
|
|
#include "nm-default.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "nmt-editor-grid.h"
|
|
|
|
G_DEFINE_TYPE (NmtEditorGrid, nmt_editor_grid, NMT_TYPE_NEWT_CONTAINER)
|
|
|
|
#define NMT_EDITOR_GRID_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMT_TYPE_EDITOR_GRID, NmtEditorGridPrivate))
|
|
|
|
typedef struct {
|
|
GArray *rows;
|
|
int *row_heights;
|
|
int indent;
|
|
} NmtEditorGridPrivate;
|
|
|
|
typedef struct {
|
|
NmtNewtWidget *label;
|
|
NmtNewtWidget *widget;
|
|
NmtNewtWidget *extra;
|
|
NmtEditorGridRowFlags flags;
|
|
} NmtEditorGridRow;
|
|
|
|
typedef struct {
|
|
int col_widths[3];
|
|
} NmtEditorGridFormState;
|
|
|
|
/**
|
|
* nmt_editor_grid_new:
|
|
*
|
|
* Creates a new #NmtEditorGrid
|
|
*
|
|
* Returns: a new #NmtEditorGrid
|
|
*/
|
|
NmtNewtWidget *
|
|
nmt_editor_grid_new (void)
|
|
{
|
|
return g_object_new (NMT_TYPE_EDITOR_GRID,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
nmt_editor_grid_init (NmtEditorGrid *grid)
|
|
{
|
|
NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (grid);
|
|
|
|
priv->rows = g_array_new (FALSE, TRUE, sizeof (NmtEditorGridRow));
|
|
}
|
|
|
|
static void
|
|
nmt_editor_grid_finalize (GObject *object)
|
|
{
|
|
NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (object);
|
|
|
|
g_array_unref (priv->rows);
|
|
g_clear_pointer (&priv->row_heights, g_free);
|
|
|
|
G_OBJECT_CLASS (nmt_editor_grid_parent_class)->finalize (object);
|
|
}
|
|
|
|
/**
|
|
* nmt_editor_grid_append:
|
|
* @grid: the #NmtEditorGrid
|
|
* @label: (allow-none): the label text for @widget, or %NULL
|
|
* @widget: (allow-none): the (main) widget
|
|
* @extra: (allow-none): optional extra widget
|
|
*
|
|
* Adds a row to @grid.
|
|
*
|
|
* If @label and @widget are both non-%NULL, this will add a three-column row,
|
|
* containing a right-aligned #NmtNewtLabel in the first column, @widget in the
|
|
* second column, and @extra (if non-%NULL) in the third column.
|
|
*
|
|
* If either @label or @widget is %NULL, then the other column will expand into
|
|
* it.
|
|
*
|
|
* See also nmt_editor_grid_set_row_flags().
|
|
*/
|
|
void
|
|
nmt_editor_grid_append (NmtEditorGrid *grid,
|
|
const char *label,
|
|
NmtNewtWidget *widget,
|
|
NmtNewtWidget *extra)
|
|
{
|
|
NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (grid);
|
|
NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_editor_grid_parent_class);
|
|
NmtNewtContainer *container = NMT_NEWT_CONTAINER (grid);
|
|
NmtEditorGridRow row;
|
|
|
|
g_return_if_fail (label != NULL || widget != NULL);
|
|
|
|
memset (&row, 0, sizeof (row));
|
|
|
|
if (label && !widget) {
|
|
widget = nmt_newt_label_new (label);
|
|
label = NULL;
|
|
}
|
|
|
|
if (label) {
|
|
row.label = nmt_newt_label_new (label);
|
|
parent_class->add (container, row.label);
|
|
}
|
|
|
|
row.widget = widget;
|
|
parent_class->add (container, widget);
|
|
if (row.label) {
|
|
g_object_bind_property (row.widget, "valid",
|
|
row.label, "highlight",
|
|
G_BINDING_INVERT_BOOLEAN | G_BINDING_SYNC_CREATE);
|
|
}
|
|
|
|
if (extra) {
|
|
row.extra = extra;
|
|
parent_class->add (container, extra);
|
|
}
|
|
|
|
g_array_append_val (priv->rows, row);
|
|
}
|
|
|
|
static int
|
|
nmt_editor_grid_find_widget (NmtEditorGrid *grid,
|
|
NmtNewtWidget *widget)
|
|
{
|
|
NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (grid);
|
|
NmtEditorGridRow *rows = (NmtEditorGridRow *) priv->rows->data;
|
|
int i;
|
|
|
|
for (i = 0; i < priv->rows->len; i++) {
|
|
if (rows[i].label == widget || rows[i].widget == widget || rows[i].extra == widget)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* NmtEditorGridRowFlags:
|
|
* @NMT_EDITOR_GRID_ROW_LABEL_ALIGN_LEFT: the row's label should be
|
|
* aligned left instead of right.
|
|
* @NMT_EDITOR_GRID_ROW_EXTRA_ALIGN_RIGHT: the row's extra widget
|
|
* should be aligned right instead of left.
|
|
*
|
|
* Flags to alter an #NmtEditorGrid row's layout.
|
|
*/
|
|
|
|
/**
|
|
* nmt_editor_grid_set_row_flags:
|
|
* @grid: an #NmtEditorGrid
|
|
* @widget: the widget whose row you want to adjust
|
|
* @flags: the flags to set
|
|
*
|
|
* Sets flags to adjust the layout of @widget's row in @grid.
|
|
*/
|
|
void
|
|
nmt_editor_grid_set_row_flags (NmtEditorGrid *grid,
|
|
NmtNewtWidget *widget,
|
|
NmtEditorGridRowFlags flags)
|
|
{
|
|
NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (grid);
|
|
NmtEditorGridRow *rows = (NmtEditorGridRow *) priv->rows->data;
|
|
int i;
|
|
|
|
i = nmt_editor_grid_find_widget (grid, widget);
|
|
if (i != -1)
|
|
rows[i].flags = flags;
|
|
}
|
|
|
|
static void
|
|
nmt_editor_grid_remove (NmtNewtContainer *container,
|
|
NmtNewtWidget *widget)
|
|
{
|
|
NmtEditorGrid *grid = NMT_EDITOR_GRID (container);
|
|
NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (grid);
|
|
NmtNewtContainerClass *parent_class = NMT_NEWT_CONTAINER_CLASS (nmt_editor_grid_parent_class);
|
|
NmtEditorGridRow *rows = (NmtEditorGridRow *) priv->rows->data;
|
|
int i;
|
|
|
|
i = nmt_editor_grid_find_widget (grid, widget);
|
|
if (i != -1) {
|
|
if (rows[i].label)
|
|
parent_class->remove (container, rows[i].label);
|
|
parent_class->remove (container, rows[i].widget);
|
|
if (rows[i].extra)
|
|
parent_class->remove (container, rows[i].extra);
|
|
|
|
g_array_remove_index (priv->rows, i);
|
|
return;
|
|
}
|
|
|
|
// FIXME: shouldn't happen
|
|
parent_class->remove (container, widget);
|
|
}
|
|
|
|
static newtComponent *
|
|
nmt_editor_grid_get_components (NmtNewtWidget *widget)
|
|
{
|
|
NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (widget);
|
|
NmtEditorGridRow *rows = (NmtEditorGridRow *) priv->rows->data;
|
|
newtComponent *child_cos;
|
|
GPtrArray *cos;
|
|
int i, c;
|
|
|
|
cos = g_ptr_array_new ();
|
|
|
|
for (i = 0; i < priv->rows->len; i++) {
|
|
if (!nmt_newt_widget_get_visible (rows[i].widget))
|
|
continue;
|
|
|
|
if (rows[i].label) {
|
|
child_cos = nmt_newt_widget_get_components (rows[i].label);
|
|
g_assert (child_cos[0] && !child_cos[1]);
|
|
g_ptr_array_add (cos, child_cos[0]);
|
|
g_free (child_cos);
|
|
}
|
|
|
|
child_cos = nmt_newt_widget_get_components (rows[i].widget);
|
|
for (c = 0; child_cos[c]; c++)
|
|
g_ptr_array_add (cos, child_cos[c]);
|
|
g_free (child_cos);
|
|
|
|
if (rows[i].extra) {
|
|
child_cos = nmt_newt_widget_get_components (rows[i].extra);
|
|
for (c = 0; child_cos[c]; c++)
|
|
g_ptr_array_add (cos, child_cos[c]);
|
|
g_free (child_cos);
|
|
}
|
|
}
|
|
|
|
g_ptr_array_add (cos, NULL);
|
|
return (newtComponent *) g_ptr_array_free (cos, FALSE);
|
|
}
|
|
|
|
static NmtEditorGridFormState *
|
|
get_form_state (NmtNewtWidget *widget)
|
|
{
|
|
NmtNewtForm *form = nmt_newt_widget_get_form (widget);
|
|
NmtEditorGridFormState *state;
|
|
|
|
if (!form)
|
|
return NULL;
|
|
|
|
state = g_object_get_data (G_OBJECT (form), "NmtEditorGridFormState");
|
|
if (state)
|
|
return state;
|
|
|
|
state = g_new0 (NmtEditorGridFormState, 1);
|
|
g_object_set_data_full (G_OBJECT (form), "NmtEditorGridFormState", state, g_free);
|
|
return state;
|
|
}
|
|
|
|
static void
|
|
nmt_editor_grid_realize (NmtNewtWidget *widget)
|
|
{
|
|
NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (widget);
|
|
NmtNewtWidget *parent;
|
|
|
|
NMT_NEWT_WIDGET_CLASS (nmt_editor_grid_parent_class)->realize (widget);
|
|
|
|
/* This is a hack, but it's the simplest way to make it work... */
|
|
priv->indent = 0;
|
|
|
|
parent = nmt_newt_widget_get_parent (widget);
|
|
while (parent) {
|
|
if (NMT_IS_NEWT_SECTION (parent)) {
|
|
priv->indent = 2;
|
|
break;
|
|
}
|
|
parent = nmt_newt_widget_get_parent (parent);
|
|
}
|
|
}
|
|
|
|
static void
|
|
nmt_editor_grid_unrealize (NmtNewtWidget *widget)
|
|
{
|
|
NmtEditorGridFormState *state = get_form_state (widget);
|
|
|
|
if (state)
|
|
memset (state->col_widths, 0, sizeof (state->col_widths));
|
|
|
|
NMT_NEWT_WIDGET_CLASS (nmt_editor_grid_parent_class)->unrealize (widget);
|
|
}
|
|
|
|
static void
|
|
nmt_editor_grid_size_request (NmtNewtWidget *widget,
|
|
int *width,
|
|
int *height)
|
|
{
|
|
NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (widget);
|
|
NmtEditorGridRow *rows = (NmtEditorGridRow *) priv->rows->data;
|
|
NmtEditorGridFormState *state = get_form_state (widget);
|
|
gboolean add_padding = FALSE;
|
|
int i;
|
|
|
|
g_free (priv->row_heights);
|
|
priv->row_heights = g_new0 (int, priv->rows->len);
|
|
|
|
*height = 0;
|
|
for (i = 0; i < priv->rows->len; i++) {
|
|
int lwidth, lheight, wwidth, wheight, ewidth, eheight;
|
|
|
|
if (!nmt_newt_widget_get_visible (rows[i].widget))
|
|
continue;
|
|
|
|
if (rows[i].label) {
|
|
nmt_newt_widget_size_request (rows[i].label, &lwidth, &lheight);
|
|
lwidth += priv->indent;
|
|
state->col_widths[0] = MAX (state->col_widths[0], lwidth);
|
|
|
|
nmt_newt_widget_size_request (rows[i].widget, &wwidth, &wheight);
|
|
state->col_widths[1] = MAX (state->col_widths[1], wwidth);
|
|
priv->row_heights[i] = wheight;
|
|
|
|
add_padding = TRUE;
|
|
} else {
|
|
nmt_newt_widget_size_request (rows[i].widget, &wwidth, &wheight);
|
|
priv->row_heights[i] = wheight;
|
|
}
|
|
|
|
if (rows[i].extra) {
|
|
nmt_newt_widget_size_request (rows[i].extra, &ewidth, &eheight);
|
|
state->col_widths[2] = MAX (state->col_widths[2], ewidth);
|
|
priv->row_heights[i] = MAX (priv->row_heights[i], eheight);
|
|
}
|
|
|
|
*height += priv->row_heights[i];
|
|
}
|
|
|
|
*width = state->col_widths[0] + state->col_widths[1] + state->col_widths[2];
|
|
if (add_padding)
|
|
*width += 2;
|
|
}
|
|
|
|
|
|
static void
|
|
nmt_editor_grid_size_allocate (NmtNewtWidget *widget,
|
|
int x,
|
|
int y,
|
|
int width,
|
|
int height)
|
|
{
|
|
NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (widget);
|
|
NmtEditorGridRow *rows = (NmtEditorGridRow *) priv->rows->data;
|
|
NmtEditorGridFormState *state = get_form_state (widget);
|
|
int col0_width, col1_width, col2_width;
|
|
int i, row;
|
|
|
|
col0_width = state->col_widths[0] - priv->indent;
|
|
col1_width = state->col_widths[1];
|
|
col2_width = state->col_widths[2];
|
|
|
|
for (i = row = 0; i < priv->rows->len; i++) {
|
|
if (!nmt_newt_widget_get_visible (rows[i].widget))
|
|
continue;
|
|
|
|
if (rows[i].label) {
|
|
int lwidth, lheight, lx;
|
|
|
|
if (rows[i].flags & NMT_EDITOR_GRID_ROW_LABEL_ALIGN_LEFT)
|
|
lx = x;
|
|
else {
|
|
nmt_newt_widget_size_request (rows[i].label, &lwidth, &lheight);
|
|
lx = x + col0_width - lwidth;
|
|
}
|
|
|
|
nmt_newt_widget_size_allocate (rows[i].label,
|
|
lx,
|
|
y + row,
|
|
col0_width,
|
|
priv->row_heights[i]);
|
|
|
|
nmt_newt_widget_size_allocate (rows[i].widget,
|
|
x + col0_width + 1,
|
|
y + row,
|
|
col1_width,
|
|
priv->row_heights[i]);
|
|
} else {
|
|
nmt_newt_widget_size_allocate (rows[i].widget,
|
|
x,
|
|
y + row,
|
|
col0_width + col1_width + 1,
|
|
priv->row_heights[i]);
|
|
}
|
|
|
|
if (rows[i].extra) {
|
|
int wwidth, wheight, ex;
|
|
|
|
if (rows[i].flags & NMT_EDITOR_GRID_ROW_EXTRA_ALIGN_RIGHT)
|
|
ex = x + col0_width + col1_width + 2;
|
|
else {
|
|
nmt_newt_widget_size_request (rows[i].widget, &wwidth, &wheight);
|
|
ex = x + col0_width + wwidth + 2;
|
|
}
|
|
|
|
nmt_newt_widget_size_allocate (rows[i].extra,
|
|
ex,
|
|
y + row,
|
|
col2_width,
|
|
priv->row_heights[i]);
|
|
}
|
|
|
|
row += priv->row_heights[i];
|
|
}
|
|
}
|
|
|
|
static void
|
|
nmt_editor_grid_class_init (NmtEditorGridClass *grid_class)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (grid_class);
|
|
NmtNewtWidgetClass *widget_class = NMT_NEWT_WIDGET_CLASS (grid_class);
|
|
NmtNewtContainerClass *container_class = NMT_NEWT_CONTAINER_CLASS (grid_class);
|
|
|
|
g_type_class_add_private (grid_class, sizeof (NmtEditorGridPrivate));
|
|
|
|
/* virtual methods */
|
|
object_class->finalize = nmt_editor_grid_finalize;
|
|
|
|
widget_class->realize = nmt_editor_grid_realize;
|
|
widget_class->unrealize = nmt_editor_grid_unrealize;
|
|
widget_class->get_components = nmt_editor_grid_get_components;
|
|
widget_class->size_request = nmt_editor_grid_size_request;
|
|
widget_class->size_allocate = nmt_editor_grid_size_allocate;
|
|
|
|
container_class->remove = nmt_editor_grid_remove;
|
|
}
|