Window
Funciones
Window* | window_create (...) |
void | window_destroy (...) |
void | window_panel (...) |
void | window_OnClose (...) |
void | window_OnMoved (...) |
void | window_OnResize (...) |
void | window_title (...) |
void | window_show (...) |
void | window_hide (...) |
uint32_t | window_modal (...) |
void | window_stop_modal (...) |
void | window_hotkey (...) |
void | window_cycle_tabstop (...) |
gui_focus_t | window_next_tabstop (...) |
gui_focus_t | window_previous_tabstop (...) |
gui_focus_t | window_focus (...) |
GuiControl | window_get_focus (...) |
void | window_update (...) |
void | window_origin (...) |
void | window_size (...) |
V2Df | window_get_origin (...) |
S2Df | window_get_size (...) |
S2Df | window_get_client_size (...) |
void | window_defbutton (...) |
void | window_cursor (...) |
Los objetos Window son los contenedores de más alto nivel dentro de la interfaz de usuario (Figura 1). Están compuestos por la barra de título, donde se ubican los botones de cerrar, maximizar y minimizar, la zona interior y el marco. Si la ventana admite redimensionado, dicho marco podrá ser arrastrado con el ratón para cambiar su tamaño. La zona interior o área cliente de la ventana, se configura mediante un panel principal. En ¡Hola Mundo! tienes un ejemplo sencillo de composición y muestra de una ventana.
- Utiliza window_create para crear una ventana.
- Utiliza window_panel para asignar el panel principal.
- Utiliza window_show para mostrar una ventana.
- Utiliza el flag ekWINDOW_TITLE para incluir barra de título.
- Utiliza window_title para asignar un título.
NAppGUI no distingue entre ventana, cuadro de diálogo, caja de mensaje, etc. El rol de cada ventana irá en función de los controles que contenga, su ubicación y su comportamiento.
1. Tamaño de la ventana
En principio, el tamaño de la ventana se calcula automáticamente en función del Dimensionado natural de su panel principal, pero puede ser alterado en cualquier momento.
- Utiliza window_size para cambiar el tamaño del panel principal.
- Utiliza el flag ekWINDOW_MAX para incluir el botón de maximizar en la barra de título.
- Utiliza el flag ekWINDOW_MIN para incluir el botón de minimizar en la barra de título.
- Utiliza el flag ekWINDOW_RESIZE para crear una ventana con bordes redimensionables.
El cambio en las dimensiones del área cliente lleva implícita una re-ubicación y re-dimensionado de los controles interiores. Esto se gestiona automáticamente por medio de los objetos layout, en función de como se haya configurado su Expansión de celdas y que se propagará de manera recursiva por todos los sublayouts. En Die tienes un ejemplo del redimensionado de una ventana (Figura 2).
2. Cierre de la ventana
Normalmente una ventana se cierra pulsando el botón [X]
ubicado a la derecha de la barra de título. Pero, en ocasiones, puede ser útil cerrarla también mediante la teclas [ENTER]
o [ESC]
. Cerrar una ventana implica ocultarla, pero no destruirla. Es decir, podemos volver a mostrar una ventana ya cerrada utilizando window_show. En el caso de que el cierre esté condicionado a un estado de la aplicación, como guardar un archivo por ejemplo, deberemos asignar un manejador mediante window_OnClose y decidir ahí si se cierra o no.
- Utiliza window_hide para ocultar una ventana.
- Utiliza window_destroy para destruir definitivamente una ventana.
- Utiliza el flag ekWINDOW_CLOSE para incluir el botón de cierre en la barra de título.
- Utiliza el flag ekWINDOW_RETURN para habilitar el cierre mediante
[ENTER]
. - Utiliza el flag ekWINDOW_ESC para habilitar el cierre mediante
[ESC]
. - Utiliza el flag window_OnClose para evitar el cierre de una ventana (Listado 1).
1 2 3 4 5 6 7 8 9 10 11 |
static void i_OnClose(App *app, Event *e) { const EvWinClose *params = event_params(e, EvWinClose); if (can_close(app, params->origin) == FALSE) { bool_t *result = event_result(e, bool_t); *result = FALSE; } } ... window_OnClose(window, listener(app, i_OnClose, App)); |
Destruir una ventana destruye implícitamente todos sus elementos y controles internos.
3. Ventanas modales
Son aquellas que, al ser lanzadas, bloquean a la ventana anterior (o padre) hasta que no se produzca el cierre de la misma (Figura 3). El ser o no "modal" no es una característica de la ventana en sí, si no del modo de lanzarla. En ¡Hola Modal Window! tienes un ejemplo de uso.
- Utiliza window_modal para mostrar una ventana en modo modal.
- Utiliza window_stop_modal para ocultarla y detener el ciclo modal.
Tras la llamada a window_modal, el programa queda detenido en este punto, a la espera del cierre de la ventana, que podrá realizarse mediante [X]
, [ENTER]
, [ESC]
o llamando a window_stop_modal (Listado 2). El valor retornado por esta función será:
- ekGUI_CLOSE_ESC (1). Si la ventana modal se cerró pulsando
[ESC]
. - ekGUI_CLOSE_INTRO (2). Si la ventana modal se cerró pulsando
[ENTER]
. - ekGUI_CLOSE_BUTTON (3). Si la ventana modal se cerró pulsando
[X]
. - El valor indicado en window_stop_modal.
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 |
static void i_OnAcceptClick(Window *window, Event *e) { window_stop_modal(window, 300); } Window *window = i_create_window_with_accept_button(); // The program will stop HERE until window is closed uint32_t ret = window_modal(window); if (ret == 1) { // Closed by ESC } else if (ret == 2) { // Closed by INTRO } else if (ret == 3) { // Closed by [X] } else if (ret == 300) { // Closed by window_stop_modal } window_destroy(&window); |
Por defecto, la ventana modal se ocultará tras recibir la llamada a window_stop_modal, pero no se destruirá como ya hemos indicado anteriormente. En determinadas ocasiones (aunque no muy habituales), es posible que queramos relanzar la ventana tras acabar el ciclo modal sin que se produzca un anti-estético "parpadeo" debido a una nueva (y rápida) visualización tras el cierre de la ventana.
- Utiliza el flag ekWINDOW_MODAL_NOHIDE al crear la ventana para evitar que se oculte tras el ciclo modal.
4. Foco del teclado
Determinadas ventanas, como los cuadros de diálogo, hacen un uso intensivo del teclado. Incluso es posible que el usuario deba gestionar la entrada de datos prescindiendo del ratón. Es por esto que tenemos que tener muy claro como se comportan los diferentes elementos ante las pulsaciones. Se denomina foco del teclado al único control que recibe los eventos de teclas dentro de una ventana determinada. Normalmente este control aparece con el borde resaltado.
- Utiliza window_get_focus para obtener el actual foco del teclado.
El foco del teclado se asigna automáticamente al primer control de la tab-list cuando se activa la ventana y se puede cambiar de diferentes maneras:
- Mediante
[TAB]
o[SHIFT]+[TAB]
nos desplazaremos por los controles incluidos en la tab-list, como ya vimos en Tabstops. - Haciendo clic sobre el control al que queremos conectar el teclado.
- Utilizando window_focus, que lo establecerá en el control deseado mediante código.
- Utilizando window_next_tabstop que equivale a pulsar
[TAB]
. En ¡Hola IP-Input! tienes variosEdit
que pasan al siguiente control cuando se introducen exactamente tres números. - Utilizando window_previous_tabstop que equivale a pulsar
[SHIFT]+[TAB]
.
El cambio del foco entre controles no es directo, mas bien sigue un protocolo (Figura 4). Por lo general no nos tenemos que preocupar por esto, ya que cada control presenta un comportamiento por defecto a la hora de liberar o aceptar el foco. Los puntos a tener presentes son los siguientes:
- Los controles
Edit
pueden retener el foco como respuesta a un eventoOnChange
, como vimos en Filtrar textos. - Las vistas personalizadas permiten tomar una decisión en tiempo de ejecución mediante los eventos
OnResignFocus
yOnAcceptFocus
, como también vimos en Uso del teclado. Por defecto, aceptarán ambos casos.
Volviendo a la navegación mediante la tecla [TAB]
, lo habitual será que los tabstops funcionen de manera cíclica (por defecto). Es decir, si el último control de la tab-list tiene el foco y pulsamos [TAB]
, el foco pasará de nuevo al primer control de la tab-list. Es posible deshabilitar este comportamiento, quedando el foco fijo en el último control aunque pulsemos repetidamente la tecla [TAB]
. De igual forma, el foco quedará fijo en el primer control aunque pulsemos [SHIFT]+[TAB]
.
- Utiliza window_cycle_tabstop para activar/desactivar el ciclo de tabstops.
5. Botón por defecto
El botón por defecto es aquel que aparece resaltado dentro de la ventana y que recibirá un evento OnClick
cada vez que se pulse la tecla [RETURN]
, independientemente de que control tenga el foco del teclado. En principio, no existe ningún botón por defecto, hay que indicarlo explícitamente en la ventana.
- Utiliza window_defbutton para establecer el botón por defecto.
6. Atajos de teclado
Como ya hemos indicado, el foco del teclado estará fijado en algún control del interior de la ventana ya sea un Edit
, Button
, View
, etc. Pero es posible que queramos definir acciones globales asociadas a alguna tecla concreta.
- Utilizar window_hotkey para asignar una acción a una tecla.
Las hotkeys tendrán prioridad sobre el foco del teclado (Figura 6). Es decir, si tenemos una acción vinculada con la tecla [F9]
, la ventana capturará el evento ekGUI_EVENT_KEYDOWN (F9) y este no llegará al control que tiene actualmente el foco del teclado.
Para concluir, resumimos todos los puntos a tener en cuenta a la hora de realizar una correcta gestión del teclado.
- Cierre de la ventana con
[RETURN]
o[ESC
. - Gestionar correctamente la tab-list y el foco del teclado.
- Definir un botón por defecto, que se active al pulsar
[RETURN]
. - Definir los atajos de teclado oportunos.
window_create ()
Crea una nueva ventana.
Window* window_create(const uint32_t flags);
flags | Combinación de valores window_flag_t. |
Retorna
La ventana recién creada.
window_destroy ()
Destruye la ventana y todo su contenido.
void window_destroy(Window **window);
window | La ventana. Será puesto a |
Observaciones
Se destruirán recursivamente paneles, layouts y componentes.
window_panel ()
Asocia el panel principal a una ventana.
void window_panel(Window *window, Panel *panel);
window | La ventana. |
panel | Panel principal, que integra todo el contenido de la ventana (vistas, controles, etc). |
Observaciones
El tamaño de la ventana se ajustará en función del Dimensionado natural del panel principal.
window_OnClose ()
Establece un manejador para el evento de cierre de la ventana.
void window_OnClose(Window *window, Listener *listener);
window | La ventana. |
listener | Función callback que se llamará antes de cerrar una ventana. |
Observaciones
Ver Cierre de la ventana.
window_OnMoved ()
Establece un manejador para el desplazamiento de la ventana por el escritorio.
void window_OnMoved(Window *window, Listener *listener);
window | La ventana. |
listener | Función callback que se llamará a medida que se arrastre la barra de título y se mueva la ventana por el escritorio. |
Observaciones
Ver Eventos GUI.
window_OnResize ()
Establece un manejador para el redimensionado de la ventana.
void window_OnResize(Window *window, Listener *listener);
window | La ventana. |
listener | Función callback que se llamará a medida que se arrastren los bordes externos de la ventana para cambiar su tamaño. |
Observaciones
El redimensionado y rehubicación de elementos se realiza de forma automática en función del Layout principal, por lo que no suele ser necesario que la aplicación responda a este evento. Ver Eventos GUI.
window_title ()
Establece el texto que mostrará la ventana en la barra de título.
void window_title(Window *window, const char_t *text);
window | La ventana. |
text | Cadena C UTF8 terminada en carácter nulo |
window_show ()
Muestra la ventana. Por defecto las ventanas se crean ocultas. Hay que mostrarlas explícitamente.
void window_show(Window *window);
window | La ventana. |
window_hide ()
Oculta la ventana.
void window_hide(Window *window);
window | La ventana. |
window_modal ()
Lanza una ventana en modo modal.
uint32_t window_modal(Window *window, Window *parent);
window | La ventana. |
parent | La ventana bloqueada. |
Retorna
Valor retornado por window_stop_modal.
Observaciones
parent
dejará de recibir eventos hasta que no se llame a window_stop_modal.
window_stop_modal ()
Termina el ciclo modal de una ventana.
void window_stop_modal(Window *window, const uint32_t return_value);
window | La ventana lanzada previamente con window_modal. |
return_value | Valor que deberá devolver window_modal. |
window_hotkey ()
Establece una acción asociada a la pulsación de una tecla.
void window_hotkey(Window *window, const vkey_t key, const uint32_t modifiers);
window | La ventana. |
key | La tecla. |
modifiers | Modificadores. |
Observaciones
Ver Atajos de teclado.
window_cycle_tabstop ()
Activa o desactiva el comportamiento cíclico de los tabstops.
void window_cycle_tabstop(Window *window, const bool_t cycle);
window | La ventana. |
cycle |
|
Observaciones
Ver Tabstops.
window_next_tabstop ()
Mueve el foco del teclado al siguiente control en la tab-list. Produce el mismo efecto que pulsar [TAB]
.
gui_focus_t window_next_tabstop(Window *window);
window | La ventana. |
Retorna
Resultado.
window_previous_tabstop ()
Mueve el foco del teclado al anterior control en la tab-list. Produce el mismo efecto que pulsar [SHIFT]+[TAB]
.
gui_focus_t window_previous_tabstop(Window *window);
window | La ventana. |
Retorna
Resultado.
window_focus ()
Establece el foco del teclado en un control concreto.
gui_focus_t window_focus(Window *window, GuiControl *control);
window | La ventana. |
control | El control que recibirá el foco. |
Retorna
Resultado.
window_get_focus ()
Obtiene el control que posee el foco del teclado.
GuiControl window_get_focus(Window *window);
window | La ventana. |
Retorna
El control.
window_update ()
Recalcula la posición y tamaño de los controles tras modificar cualquier Layout.
void window_update(Window *window);
window | La ventana. |
window_origin ()
Mueve la ventana a unas coordenadas concretas del escritorio.
void window_origin(Window *window, const V2Df origin);
window | La ventana. |
origin | Posición |
window_size ()
Establece el tamaño del área cliente de la ventana.
void window_size(Window *window, const S2Df size);
window | La ventana. |
size | Tamaño del panel principal. |
Observaciones
El tamaño final dependerá de la configuración del marco de la ventana y del tema de escritorio. Esta medida solo hace referencia al área interior.
window_get_origin ()
Obtiene la posición de la ventana.
V2Df window_get_origin(const Window *window);
window | La ventana. |
Retorna
Posición (x,y)
de la esquina superior-izquierda de la ventana.
window_get_size ()
Obtiene las dimensiones totales de la ventana.
S2Df window_get_size(const Window *window);
window | La ventana. |
Retorna
Tamaño de la ventana.
Observaciones
Se tiene en cuenta el marco y barra de título.
window_get_client_size ()
Obtiene las dimensiones del área cliente de la ventana.
S2Df window_get_client_size(const Window *window);
window | La ventana. |
Retorna
Tamaño del panel principal.
window_defbutton ()
Establece el botón por defecto de la ventana. Será activado cuando se pulse [Intro]
.
void window_defbutton(Window *window, Button *button);
window | La ventana. |
button | El botón. |
Observaciones
Ver Botón por defecto.
window_cursor ()
Cambia el cursor del ratón.
void window_cursor(Window *window, const gui_cursor_t cursor, const Image *image, const real32_t hot_x, const real32_t hot_y);
window | La ventana. |
cursor | Identificador del nuevo cursor. |
image | Imagen personalizada. Solo válido en ekGUI_CURSOR_USER. |
hot_x | Coordenada x del punto de clic. Solo válido en ekGUI_CURSOR_USER. |
hot_y | Coordenada y del punto de clic. Solo válido en ekGUI_CURSOR_USER. |
Observaciones
hot_x, hot_y
indican el punto "sensible" dentro de la imagen, que indicará la posición exacta del ratón.