Panel
Funciones
Panel* | panel_create (void) |
Panel* | panel_scroll (...) |
void | panel_data (...) |
type* | panel_get_data (...) |
void | panel_size (...) |
uint32_t | panel_layout (...) |
Layout* | panel_get_layout (...) |
void | panel_visible_layout (...) |
void | panel_update (...) |
real32_t | panel_scroll_width (...) |
real32_t | panel_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.
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.
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.
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.
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(ekWINDOW_STDRES); 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.
En este caso es posible redimensionar la ventana, ya que hemos utilizado el flag ekWINDOW_STDRES al crearla (Figura 5).
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).
|
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).
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.
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).
|
... panel_size(panel, s2df(400, 300)); ... |
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).
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).
|
... Panel *panel = panel_scroll(TRUE, TRUE); ... |
Y, por supuesto, todo lo dicho funcionará de la misma forma en cualquier plataforma (Figura 11).
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 |
|
vscroll |
|
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.