SDK Multiplataforma en C logo

SDK Multiplataforma en C

Panel

❮ Anterior
Siguiente ❯

Funciones

Panel*panel_create (void)
Panel*panel_scroll (...)
voidpanel_data (...)
type*panel_get_data (...)
voidpanel_size (...)
uint32_tpanel_layout (...)
Layout*panel_get_layout (...)
voidpanel_visible_layout (...)
voidpanel_update (...)
real32_tpanel_scroll_width (...)
real32_tpanel_scroll_height (...)

Un Panel es un control dentro de una ventana que agrupa otros controles. Define su propio sistema de referencia, es decir, si desplazamos un panel todos sus descendientes se moverán al unísono ya que sus ubicaciones serán relativas al origen del mismo. Admitirá otros (sub)-paneles como descendientes, lo que permite conformar una Jerarquía de ventana (Figura 1). En pro de la portabilidad, esta librería Gui no permite indicar directamente coordenadas ni tamaños concretos para los elementos dentro de un panel, sino que la asociación se lleva a cabo mediante un objeto Layout que se encarga de calcular en tiempo de ejecución las ubicaciones finales de los controles en función de la plataforma y gestor de ventanas. En ¡Hola Subpanel! tienes un ejemplo elemental del uso de paneles.

  • Utiliza panel_create para crear un nuevo panel.
  • Utiliza panel_scroll para crear un nuevo panel con barras de scroll.
  • Utiliza panel_layout para añadir controles al panel.
  • Utiliza panel_size para establecer el tamaño por defecto del panel.
  • Esquema que muestra la jerarquía producida por paneles, subpaneles y controles.
    Figura 1: Jerarquía de ventana.

Cada panel admite varios layouts y permite alternar entre ellos en tiempo de ejecución (Figura 2). Esto permite crear interfaces dinámicas responsivas con muy poco esfuerzo, ya que el propio panel se encarga de vincular y dimensionar los controles en función del layout activo en cada caso. En ¡Hola Multi-layout! tienes un ejemplo.

  • Utiliza panel_visible_layout para alternar entre layouts.
  • Dos configuraciones diferentes de ventana utilizando los mismos controles.
    Figura 2: Panel con dos organizaciones diferentes para los mismos controles.

Debido a que los layout son estructuras lógicas fuera de la jerarquía de ventana, pueden compartir controles al estar vinculados con el mismo panel (Figura 3). Lo que no está permitido es utilizar los mismos objetos en diferentes paneles, por el propio concepto de jerarquía.

Esquema que muestra como compartir correctamente los elementos entre layouts.
Figura 3: Es posible reutilizar los mismos componentes entre layouts del mismo panel.

1. Entendiendo el dimensionado de paneles

Vamos a mostrar, por medio de un ejemplo, la lógica que se esconde detrás de la composición y dimensionado de paneles. Empezamos con (Listado 1) donde creamos un panel relativamente extenso en altura.

Listado 1: Composición de un panel con varias filas de edición.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
static Window *i_window(void)
{
    uint32_t i, n = 20;
    Window *window_create(ekWNSRES);
    Panel *panel = panel_create();
    Layout *layout = layout_create(2, n);

    for (i = 0; i < n; ++i)
    {
        char_t text[64];
        Label *label = label_create();
        Edit *edit = edit_create();
        bstd_sprintf(text, sizeof(text), "Value %02d", i);
        label_text(label, text);
        bstd_sprintf(text, sizeof(text), "Edit here value %02d", i);
        edit_text(edit, text);
        layout_label(layout, label, 0, i);
        layout_edit(layout, edit, 1, i);
    }

    for (i = 0; i < n - 1; ++i)
        layout_vmargin(layout, i, 3);

    layout_hmargin(layout, 0, 5);
    layout_margin4(layout, 10, 10, 10, 10);
    panel_layout(panel, layout);
    window_panel(window, panel);
    return window;
}
  • Las líneas 3-6 crean la ventana, el panel y el layout.
  • El bucle 8-19 añade varias etiquetas y cajas de edición al layout.
  • El bucle 21-22 establece una pequeña separación entre filas.
  • Las líneas 24-25 establecen una separación entre columnas y un margen en el borde.
  • Las líneas 26-27 vinculan el layout con el panel y este con la ventana.

El resultado de este código es el Dimensionado natural del panel (Figura 4), que establece por defecto una anchura de 100 píxeles para los controles de edición. Las etiquetas se ajustan al texto que contienen. También se han aplicado las separaciones y márgenes.

Panel con una lista de controles de edición.
Figura 4: Dimensionado natural del panel definido en (Listado 1).

En este caso es posible redimensionar la ventana, ya que hemos utilizado el flag ekWNSRES al crearla (Figura 5).

Ventana con controles de edición de tamaño extendido.
Figura 5: Comportamiento del panel cuando crece la ventana.

Este comportamiento puede que no sea el más apropiado para el caso que nos ocupa. Por defecto, el layout realiza la Expansión de celdas de manera proporcional. Pero lo que realmente buscamos es "estirar" los controles de edición y que las filas mantengan su altura por defecto (Listado 2).

Listado 2: Cambio en la expansión horizontal y vertical.
 
Layout *layout = layout_create(2, n + 1);
...
layout_hexpand(layout, 1);
layout_vexpand(layout, n);

Las líneas anteriores provocan que la expansión horizontal recaiga exclusivamente sobre la columna 1 (la de los EditBox). Por otro lado, se ha creado una fila extra vacía, volcando en ella toda la expansión vertical (Figura 6).

Ventana con controles de edición de tamaño extendido, mejorando la disposición.
Figura 6: Comportamiento deseado, ante la expansión de la ventana.

Si bien el panel se comporta ahora correctamente ante el crecimiento de la ventana, tenemos dificultades cuando queremos "encogerla" por debajo de cierto límite (Figura 7). Esto es debido a que el dimensionado natural impone un tamaño mínimo, ya que llega un momento que es imposible reducir los controles asociados al layout.

Ventana con controles de edición y tamaño reducido.
Figura 7: Tamaño mínimo del panel.

Esto puede suponer un problema, ya que es posible que tengamos paneles suficientemente grandes que excedan incluso el tamaño del monitor y no puedan mostrarse en su totalidad. Para solucionarlo podemos establecer un tamaño por defecto para todo el panel (Listado 3), que será el que muestre al iniciar la ventana (Figura 8).

Listado 3: Tamaño por defecto del panel.
 
...
panel_size(panel, s2df(400, 300));
...
Ventana con controles de edición y tamaño predeterminado.
Figura 8: Dimensionado natural, forzado a 400x300.

Este comando desvincula, en cierta manera, el tamaño del panel del tamaño de su contenido. De esta forma, el Layout tiene libertad para reducir el tamaño de la vista, independientemente de si puede o no mostrar la totalidad del contenido (Figura 9).

Ventana con controles de edición y tamaño muy reducido.
Figura 9: Reducción de los límites del panel.

Y ya por último, si queremos, podemos crear el panel con barras de scroll (Listado 4) y desplazarnos por el contenido no visible (Figura 10).

Listado 4: Panel con barras de scroll.
 
...
Panel *panel = panel_scroll(TRUE, TRUE);
...
Ventana con controles de edición y barras de scroll.
Figura 10: Panel con barras de scroll.

Y, por supuesto, todo lo dicho funcionará de la misma forma en cualquier plataforma (Figura 11).

Ventana con controles de edición y barras de scroll, versión macOS. Ventana con controles de edición y barras de scroll, versión Linux.
Figura 11: Nuestro panel funcionando en macOS y Linux.

panel_create ()

Crea un panel.

Panel*
panel_create(void);

Retorna

El nuevo panel.


panel_scroll ()

Crea un panel con barras de scroll.

Panel*
panel_scroll(const bool_t hscroll,
             const bool_t vscroll);
hscroll

TRUE si queremos barra de scroll horizontal.

vscroll

TRUE si queremos barra de scroll vertical.

Retorna

El nuevo panel.

Observaciones

Ver Entendiendo el dimensionado de paneles.


panel_data ()

Asocia datos de usuario con el panel.

void
panel_data(Panel *panel,
           type **data,
           FPtr_destroy func_destroy_data,
           type);
panel

El panel.

data

Datos de usuario.

func_destroy_data

Destructor de los datos de usuario. Será llamado al destruir el panel.

type

Tipo de datos de usuario.


panel_get_data ()

Obtiene los datos de usuario asociados con el panel.

type*
panel_get_data(const Panel *panel,
               type);
panel

El panel.

type

Tipo de datos de usuario.

Retorna

Los datos de usuario.


panel_size ()

Establece el tamaño por defecto del área visible de un panel.

void
panel_size(Panel *panel,
           const S2Df size);
panel

El panel.

size

El tamaño por defecto.

Observaciones

Ver Entendiendo el dimensionado de paneles.


panel_layout ()

Añade un layout a un panel.

uint32_t
panel_layout(Panel *panel,
             Layout *layout);
panel

El panel.

layout

El layout.

Retorna

El índice del layout recién añadido.


panel_get_layout ()

Obtiene un layout de un panel.

Layout*
panel_get_layout(Panel *panel,
                 const uint32_t index);
panel

El panel.

index

El índice del layout.

Retorna

El layout.


panel_visible_layout ()

Establece el layout activo dentro del panel.

void
panel_visible_layout(Panel *panel,
                     const uint32_t index);
panel

El panel.

index

El índice del layout.

Observaciones

Para el cambio se haga efectivo, hay que llamar a panel_update.


panel_update ()

Refresca el contenido de la ventana que contiene el panel.

void
panel_update(Panel *panel);
panel

El panel.

Observaciones

Es equivalente a llamar a window_update.


panel_scroll_width ()

Obtiene el ancho de la barra de scroll del panel asociado.

real32_t
panel_scroll_width(const Panel *panel);
panel

El panel.

Retorna

El ancho de la barra.

Observaciones

Solo válida si el panel ha sido creado con panel_scroll. Útil si queremos tener en cuenta el tamaño de las barras de scroll al establecer los márgenes del Layout.


panel_scroll_height ()

Obtiene el alto de la barra de scroll.

real32_t
panel_scroll_height(const Panel *panel);
panel

El panel.

Retorna

El alto de la barra.

Observaciones

Ver panel_scroll_width.

❮ Anterior
Siguiente ❯