SDK Multiplataforma en C logo

SDK Multiplataforma en C

Window

❮ Anterior
Siguiente ❯

Funciones

Window*window_create (...)
voidwindow_destroy (...)
voidwindow_panel (...)
voidwindow_OnClose (...)
voidwindow_OnMoved (...)
voidwindow_OnResize (...)
voidwindow_title (...)
voidwindow_show (...)
voidwindow_hide (...)
voidwindow_overlay (...)
uint32_twindow_modal (...)
voidwindow_stop_modal (...)
voidwindow_hotkey (...)
voidwindow_clear_hotkeys (...)
voidwindow_cycle_tabstop (...)
gui_focus_twindow_next_tabstop (...)
gui_focus_twindow_previous_tabstop (...)
gui_focus_twindow_focus (...)
GuiControl*window_get_focus (...)
voidwindow_focus_info (...)
voidwindow_update (...)
voidwindow_origin (...)
voidwindow_size (...)
V2Dfwindow_get_origin (...)
S2Dfwindow_get_size (...)
S2Dfwindow_get_client_size (...)
R2Dfwindow_control_frame (...)
V2Dfwindow_client_to_screen (...)
voidwindow_defbutton (...)
voidwindow_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 (Figura 2) es donde residen los controles que conforman la interfaz propiamente dicha y 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.
  • Captura del sistema operativo Windows 3.
    Figura 1: El concepto de ventana aparece desde los primeros sistemas de escritorio.
    Área cliente de una ventana.
    Figura 2: El área de cliente es la parte interior de la ventana.
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 3).

Muestra como se reparte entre los controles el exceso al tamaño al redimensionar la ventana.
Figura 3: Redimensionado de la ventana en la demo Die.

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 las 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.

Al destruir una ventana se realiza, implícitamente, la destrucción de 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 4). 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.
  • Varias ventanas modales.
    Figura 4: Varias ventanas modales.

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.
  • Listado 2: Uso de ventanas modales.
     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. Ventanas superpuestas

En ocasiones puede ser útil mostrar pequeñas ventanas sobre la principal que incluyan controles adicionales de forma temporal. Es un caso similar a las ventanas modales, con la diferencia de que la ventana "padre" no será desactivada y seguirá recibiendo eventos desde el sistema operativo, mientras la secundaria sigue visible. Normalmente no incluyen borde ni barra de título. En ¡Hola Overlay Window! tienes el código fuente de (Figura 5).

Pequeña ventana superpuesta a la principal.
Figura 5: Ventana superpuesta con controles adicionales.

Es habitual que tengamos que posicionar las ventanas secundarias tomando como referencia algún control interior de la ventana principal, pero el origen de la ventana se debe proporcionar en coordenadas de pantalla. En (Listado 3) se muestra como realizar correctamente la transformación de coordenadas de (Figura 5).

Listado 3: Alineación de la ventana secundaria respecto a un Editbox.
 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
30
31
static void i_OnIdleLaunch(FlyOut *flyout, Event *e)
{
    /* Edit control bounds in window coordinates */
    R2Df frame = window_control_frame(flyout->parent, flyout->edit);
    /* Top-Left edit control in screen coordinates */
    V2Df pos = window_client_to_screen(flyout->parent, frame.pos);
    /* Flyout window size */
    S2Df size = window_get_size(flyout->flywin);

    switch (flyout->align) {
    case 0:
        pos.y += frame.size.height;
        break;
    case 1:
        pos.y -= size.height;
        break;
    case 2:
        pos.x -= size.width - frame.size.width;
        pos.y += frame.size.height;
        break;
    case 3:
        pos.x -= size.width - frame.size.width;
        pos.y -= size.height;
        break;
    }

    /* Position in screen coordinates */
    window_origin(flyout->flywin, pos);
    window_overlay(flyout->flywin, flyout->parent);
    unref(e);
}

Si hacemos clic sobre la ventana padre, la secundaria será desactivada y ocultada de forma automática. Deberemos llamar de nuevo a window_overlay para visualizarla. Si queremos evitar el cierre por desactivación, deberemos contemplar el valor ekGUI_CLOSE_DEACT en window_OnClose. Por supuesto, también podremos incluir los flags ekGUI_CLOSE_ESC y ekGUI_CLOSE_INTRO para cerrar la ventana mediante el teclado.


5. 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 de teclas. 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 (Figura 6).

  • Utiliza window_get_focus para obtener el control que dispone del foco del teclado.
  • Dos controles de lista, donde uno de ellos, el de la izquierda, tiene el foco del teclado.
    Figura 6: El control de la izquierda tiene el foco del teclado.

5.1. Cambio del foco

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 varios Edit que pasan al siguiente control cuando se introducen exactamente tres números.
  • Utilizando window_previous_tabstop que equivale a pulsar [SHIFT]+[TAB].
Estas funciones devolverán un gui_focus_t para indicar si el cambio de foco ha tenido éxito o no.

5.2. Protocolo del foco

El cambio del foco entre controles no es directo, mas bien sigue un protocolo (Figura 7). 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 evento OnChange, como vimos en Validar textos.
  • Las vistas personalizadas permiten tomar una decisión en tiempo de ejecución mediante los eventos OnResignFocus y OnAcceptFocus, como también vimos en Uso del teclado. Por defecto, aceptarán ambos casos.
  • Utiliza window_focus_info dentro de edit_OnChange o view_OnResignFocus para obtener información adicional sobre la operación de cambio de foco.

Por ejemplo, si pulsamos [TAB] sobre un Edit, se lanzará el evento OnChange, que puede devolver FALSE como respuesta. En este caso, el foco del teclado permanecerá en dicho Edit y no saltará al siguiente control.

Gráfico que muestra el intercambio de mensajes para cambiar el foco del teclado a un nuevo control.
Figura 7: Protocolo para el cambio del foco.

5.3. Tablist sin ciclos

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].


6. 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.
  • Captura que muestra una ventana donde aparece un botón por defecto.
    Figura 8: Botón por defecto.

7. 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.

Las hotkeys tendrán prioridad sobre el foco del teclado (Figura 9). 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.

Atajo de teclado.
Figura 9: Procesamiento de un atajo de 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.
❮ Anterior
Siguiente ❯

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 NULL tras la destrucción.

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 '\0'.


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_overlay ()

Lanza una ventana superpuesta.

void
window_overlay(Window *window,
               Window *parent);
window

La ventana.

parent

La ventana principal.

Observaciones

Ver Ventanas superpuestas.


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. Ver Ventanas modales


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.

Observaciones

Ver Ventanas modales.


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,
              Listener *listener);
window

La ventana.

key

La tecla.

modifiers

Modificadores. 0 o combinación de mkey_t.

listener

Manejador del evento asociado a la pulsación de la tecla. Si NULL, elimina el evento asociado a la tecla (si existe alguno).

Observaciones

Ver Atajos de teclado.


window_clear_hotkeys ()

Elimina todos los atajos de teclado asociados con la ventana.

void
window_clear_hotkeys(Window *window);
window

La ventana.

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

TRUE para activar los ciclos en tabstops (por defecto).

Observaciones

Ver Tablist sin ciclos.


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 de la operación de cambio del foco.

Observaciones

Ver Cambio del foco.


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 de la operación de cambio del foco.

Observaciones

Ver Cambio del foco.


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 de la operación de cambio del foco.

Observaciones

Ver Cambio del foco.


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_focus_info ()

Obtiene información adicional sobre una operación de cambio del foco del teclado.

void
window_focus_info(Window *window,
                  FocusInfo *info);
window

La ventana.

info

Estructura donde se retornarán los datos de la operación.

Observaciones

En ocasiones, la decisión de liberar el foco del teclado para un control requiere información de contexto. Por ejemplo que acción originó el cambio (pulsar [TAB], clic sobre otro control) o cual será el control que recibirá el foco. Ver Protocolo del foco.


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 (x,y) de la esquina superior-izquierda de la ventana.


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_control_frame ()

Obtiene la posición y tamaño de un control en coordenadas de ventana.

R2Df
window_control_frame(const Window *window,
                     const GuiControl *control);
window

La ventana.

control

El control.

Retorna

Rectángulo en coordenadas de ventana.

Observaciones

control debe pertenecer a la ventana, estar activo y visible. El punto (0,0) corresponde con el vértice superior izquierdo del área cliente de la ventana. Ver Ventanas superpuestas.


window_client_to_screen ()

Transforma un punto expresado en coordenadas de ventana a coordenadas de pantalla.

V2Df
window_client_to_screen(const Window *window,
                        const V2Df point);
window

La ventana.

point

El punto en coordenadas de ventana.

Retorna

El punto en coordenadas de pantalla.

Observaciones

point es un punto interior, donde (0,0) corresponde con el vértice superior izquierdo del área cliente de la ventana. Ver Ventanas superpuestas.


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

Esta función deshabilita el posible anterior botón por defecto. Para que se establezca el nuevo botón, este debe existir en el layout activo, lo que exige que esta función se llame después de window_panel. 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.

❮ Anterior
Siguiente ❯