SDK Multiplataforma en C logo

SDK Multiplataforma en C

View

❮ Anterior
Siguiente ❯

Funciones

View*view_create (void)
View*view_scroll (void)
View*view_custom (...)
voidview_data (...)
type*view_get_data (...)
voidview_size (...)
voidview_OnDraw (...)
voidview_OnOverlay (...)
voidview_OnSize (...)
voidview_OnEnter (...)
voidview_OnExit (...)
voidview_OnMove (...)
voidview_OnDown (...)
voidview_OnUp (...)
voidview_OnClick (...)
voidview_OnDrag (...)
voidview_OnWheel (...)
voidview_OnKeyDown (...)
voidview_OnKeyUp (...)
voidview_OnFocus (...)
voidview_OnResignFocus (...)
voidview_OnAcceptFocus (...)
voidview_OnScroll (...)
voidview_keybuf (...)
voidview_get_size (...)
voidview_content_size (...)
voidview_scroll_x (...)
voidview_scroll_y (...)
voidview_scroll_size (...)
voidview_scroll_visible (...)
voidview_viewport (...)
voidview_point_scale (...)
voidview_update (...)
void*view_native (...)

Los controles View o vistas personalizadas (Figura 1) son áreas en blanco dentro de la ventana que nos permiten implementar nuestros propios componentes. Tendremos total libertad para dibujar y capturar los eventos del teclado o ratón que nos permitan interactuar con la misma.

  • Utiliza view_create para crear una vista.
  • Utiliza view_data para vincular un objeto.
  • Utiliza view_get_data para obtener este objeto.
  • Utiliza view_size para establecer el tamaño por defecto.
  • Captura de una sencilla aplicación que incorpora una vista personalizada.
    Figura 1: Control de vista personalizada.

1. Dibujar en vistas

El contenido del área de dibujo deberá refrescarse en determinadas ocasiones. Bien porque el sistema operativo deba actualizar una parte previamente solapada, o bien porque el dibujo en sí haya cambiado (animaciones, acciones del usuario, etc). Llegado el momento, el gestor de ventanas lanzará un evento OnDraw que la aplicación debe capturar para implementar los comandos de dibujo que permitan recrear el contenido.

  • Utiliza view_OnDraw para establecer la función de dibujo.
  • Utiliza view_update para forzar la actualización del contenido.

El manejador del evento OnDraw recibirá un contexto de dibujo, sobre el cual se podrán aplicar las diferentes Primitivas de dibujo (Listado 1).

Listado 1: Dibujo básico en vistas personalizadas.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
static void i_OnDraw(App *app, Event *e)
{
    const EvDraw *p = event_params(e, EvDraw);
    draw_clear(p->ctx, kCOLOR_RED);
    draw_line_width(p->ctx, 10.f);,
    draw_line_color(p->ctx, kCOLOR_GREEN);
    draw_rect(p->ctx, ekSTROKE, 0, 0, p->width, p->height);
}
...
view_OnDraw(view, listener(app, i_OnDraw, App));

En Die tienes una sencilla aplicación de ejemplo que implementa el dibujado de vistas personalizadas. En ella se representa la figura de un dado, permitiéndonos editar ciertos parámetros del dibujo. Esta interacción irá lanzando una serie de eventos que requerirán el re-dibujado de nuestra figura. El ciclo completo puede resumirse en estos pasos (Figura 2):

  • Se produce algún evento que requiere actualizar el contenido de la vista.
  • La aplicación llama al método view_update para notificar que la vista debe ser actualizada.
  • En el momento oportuno, el sistema mandará un evento OnDraw con un contexto DCtx listo para dibujar. Aquí puedes aplicar todo lo visto en Draw2D y utilizar líneas, figuras o textos para representar el contenido del control.
  • Gráfico con las diferentes fases de la actualización de una vista.
    Figura 2: Ciclo de refresco de una vista personalizada.
El sistema operativo puede lanzar eventos OnDraw en cualquier momento sin que hallamos llamado previamente a view_update.

2. Vistas con scroll

Es posible que la "escena" a representar sea mucho más grande que el propio control, por lo que este mostrará solo un pequeño fragmento de la misma (Figura 3). En estos casos diremos que la vista es un viewport de la escena. Podemos gestionarlo de dos maneras:

Relación de una escena 2D con el viewport donde de visualiza.
Figura 3: Escena y vista (viewport).
  • Utilizar draw_matrixf al inicio de OnDraw para indicar la transformación que integra el desplazamiento, zoom y posible rotación del viewport con respecto a la escena. Todo ello debe ser gestionado por la aplicación y no tenemos que hacer nada especial, salvo llamar a view_update cada vez que sea necesario refrescar.
  • Utilizar barras de scroll que permitan al usuario desplazarse libremente por el contenido. En este caso la gestión de la vista se complica un poco más. Esto es lo que debemos tener en cuenta:
    • Utilizar view_scroll o view_custom para crear la vista.
    • Utilizar view_content_size para indicar las medidas de la escena, con el fin de que se dimensionen correctamente las barras laterales.
    • Utilizar view_scroll_x, view_scroll_y si queremos mover las barras de scroll desde el código.
    • Utilizar view_viewport para obtener la posición y dimensiones del área visible.
    • Utilizar view_OnScroll para detectar cuando el usuario manipula las barras de scroll.

Algo importante a tener en cuenta, es evitar dibujar elementos no visibles, sobre todo en escenas muy grandes o con multitud de objetos. El sistema operativo mandará sucesivos eventos OnDraw() a medida que el usuario manipule las scrollbars, indicando en la estructura EvDraw los parámetros del viewport. En DrawBig tienes una aplicación de ejemplo que muestra como gestionar correctamente este tipo de casos.

Es posible que las dimensiones del viewport recibido en OnDraw sean algo superiores al tamaño del control. Esto es debido a que determinados gestores de ventanas obligan a dibujar en ciertas zonas no visibles cercanas a los bordes, con el fin de evitar parpadeos en desplazamientos muy rápidos.

3. Dibujo de overlays

Un overlay es una capa gráfica que se dibuja encima del contenido principal volcado por el evento OnDraw. Utiliza el sistema de coordenadas del control View donde la coordenada (0,0) corresponde al border superior-izquierdo (Figura 4) (Listado 2). Por tanto, los overlays permanecen fijos, independientemente del desplazamiento de las barras de scroll. Son útiles para dibujar marcadores o información que no queremos que sea desplazada. También pueden utilizarse en vistas sin barras de scroll.

Animación que muestra el dibujo de un overlay.
Figura 4: Dibujo de overlay. Animación en https://nappgui.com/img/gui/overlay.gif.
Listado 2: Código para generar el overlay.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
static void i_OnOverlay(App *app, Event *e)
{
    const EvDraw *p = event_params(e, EvDraw);
    cassert_no_null(app);
    if (app->overlay == TRUE)
    {
        draw_fill_color(p->ctx, kCOLOR_BLACK);
        draw_text_color(p->ctx, kCOLOR_WHITE);
        draw_rect(p->ctx, ekFILL, 5, 5, 80, 20);
        draw_text(p->ctx, "OVERLAY", 5, 5);
    }
}
...
view_OnOverlay(view, listener(app, i_OnOverlay, App));

4. Uso del ratón

Para poder interactuar con el control es necesario definir manejadores para los diferentes eventos del ratón (Listado 3), (Figura 5). El sistema operativo notificará las acciones del usuario con el fin de que la aplicación pueda lanzar las acciones pertinentes. No es necesario utilizarlos todos, tan solo los imprescindibles en cada caso.

Listado 3: Respuesta a eventos de ratón.
1
2
3
4
5
6
7
static void i_OnMove(App *app, Event *e)
{
    const EvMouse *p = event_params(e, Event);
    do_something_onmouse_moved(app, p->x, p->y);
}
...
view_OnMove(view, listener(app, i_OnMove, App));
Ilustración de los eventos de ratón de una vista 2d.
Figura 5: Eventos de posición con respecto a la vista.
  • Utiliza view_OnEnter para saber cuando el cursor entra en la vista.
  • Utiliza view_OnExit para saber cuando el cursor sale de la vista.
  • Utiliza view_OnMove para saber cuando el cursor se está moviendo por la vista.
  • Utiliza view_OnDown para saber cuando se pulsa un botón dentro de la vista.
  • Utiliza view_OnUp para saber cuando se libera un botón dentro de la vista.
  • Utiliza view_OnClick para identificar un click (Up + Down rápido).
  • Utiliza view_OnDrag para desplazamientos del cursor con un botón pulsado.
  • Utiliza view_OnWheel para el uso de la ruedecilla del ratón.
Si la vista utiliza barras de scroll, la posición (x,y) del cursor pasada a EvMouse en cada evento, hace referencia a los coordenadas globales de la escena, teniendo en cuenta el desplazamiento. En vistas sin barras de scroll, son las coordenadas locales del control. Las coordenadas locales del viewport están en (lx,ly).

5. Uso del teclado

Cuando una vista reciba el Foco del teclado, todas las pulsaciones irán dirigidas a ella, por lo que deberemos implementar los manejadores apropiados.

  • Utiliza view_OnKeyDown para detectar cuando se pulsa una tecla.
  • Utiliza view_OnKeyUp para detectar cuando se libera una tecla.
  • Utiliza view_OnFocus para notificar a la aplicación cada vez que la vista reciba (o pierda) el foco del teclado. En (Figura 6), la vista cambia el color de la celda activa cuando tiene el foco.
  • Utiliza view_OnResignFocus para evitar que la vista pierda el foco del teclado.
  • Utiliza view_OnAcceptFocus para evitar que la vista obtenga el foco del teclado.
  • Cambio del foco del teclado entre dos controles.
    Figura 6: Vista sin el foco del teclado (izquierda) y con él (derecha).
Si una vista no necesita utilizar el teclado, asegúrate que no pueda recibir el foco al pulsar [TAB] Tabstops. También implementa view_OnAcceptFocus para evitar que obtenga el foco al hacer click sobre ella.

En los eventos KeyDown y KeyUp se recibirá un vkey_t con el valor de la tecla pulsada. En (Figura 7) y (Figura 8) se muestran la correspondencia de estos códigos. En Aplicaciones síncronas es posible que necesitemos saber si una tecla está pulsada o no durante el ciclo de actualización (síncrono) donde no tenemos acceso a los eventos OnKeyDown y OnKeyUp (asíncronos). Esto es posible hacerlo asignando a la vista un búfer de teclado mediante view_keybuf, que capturá los eventos asociados a cada tecla y nos permitirá consultar su estado en cualquier momento de forma cómoda.

Representación de un teclado con el código de cada tecla.
Figura 7: Códigos del teclado.
Representación de un teclado extendido con el código de cada tecla extendida.
Figura 8: Códigos extendidos del teclado.
❮ Anterior
Siguiente ❯

view_create ()

Crea una nueva vista personalizada.

View*
view_create(void);

Retorna

El control vista.


view_scroll ()

Crea una nueva vista con barras de scroll.

View*
view_scroll(void);

Retorna

El control vista.


view_custom ()

Crea una nueva vista con todas las opciones.

View*
view_custom(const bool_t scroll,
            const bool_t border);
scroll

Uso de barras de scroll.

border

Dibuja un borde.

Retorna

El control vista.

Observaciones

Muchos gestores de ventanas resaltan el borde cuando la vista tenga el foco del teclado.


view_data ()

Asocia datos de usuario con la vista.

void
view_data(View *view,
          type **data,
          FPtr_destroy func_destroy_data,
          type);
view

La vista.

data

Datos de usuario.

func_destroy_data

Destructor de los datos de usuario. Será llamado al destruir la vista.

type

Tipo de datos de usuario.


view_get_data ()

Obtiene los datos de usuario asociados con la vista.

type*
view_get_data(const View *view,
              type);
view

La vista.

type

Tipo de datos de usuario.

Retorna

Los datos de usuario.


view_size ()

Establece el tamaño por defecto de la vista.

void
view_size(View *view,
          const S2Df size);
view

La vista.

size

El tamaño.

Observaciones

Corresponde al Dimensionado natural del control. Por defecto 128x128.


view_OnDraw ()

Establece un manejador para dibujar en la vista.

void
view_OnDraw(View *view,
            Listener *listener);
view

La vista.

listener

Función callback que se llamará cada vez que deba refrescarse el dibujo.

Observaciones

Ver Dibujar en vistas y Eventos GUI.


view_OnOverlay ()

Establece un manejador para dibujar el overlay.

void
view_OnOverlay(View *view,
               Listener *listener);
view

La vista.

listener

Función callback que se llamará cada vez que deba refrescarse el overlay.

Observaciones

Ver Dibujo de overlays y Eventos GUI.


view_OnSize ()

Establece un manejador para el cambio de tamaño.

void
view_OnSize(View *view,
            Listener *listener);
view

La vista.

listener

Función callback que se llamará cada vez que la vista cambie de tamaño.

Observaciones

Ver Eventos GUI.


view_OnEnter ()

Establece un manejador para la entrada del ratón.

void
view_OnEnter(View *view,
             Listener *listener);
view

La vista.

listener

Función callback que se llamará cuando el cursor del ratón entre en el área de la vista.

Observaciones

Ver Uso del ratón y Eventos GUI.


view_OnExit ()

Establece un manejador para la salida del ratón.

void
view_OnExit(View *view,
            Listener *listener);
view

La vista.

listener

Función callback que se llamará cuando el cursor del ratón salga del área de la vista.

Observaciones

Ver Uso del ratón y Eventos GUI.


view_OnMove ()

Establece un manejador para el movimiento del ratón.

void
view_OnMove(View *view,
            Listener *listener);
view

La vista.

listener

Función callback que se llamará a medida que el cursor del ratón se desplace por encima de la vista.

Observaciones

Ver Uso del ratón y Eventos GUI.


view_OnDown ()

Establece un manejador para la pulsación de un botón del ratón.

void
view_OnDown(View *view,
            Listener *listener);
view

La vista.

listener

Función callback que se llamará cuando se pulse un botón.

Observaciones

Ver Uso del ratón y Eventos GUI.


view_OnUp ()

Establece un manejador para la liberación de un botón del ratón.

void
view_OnUp(View *view,
          Listener *listener);
view

La vista.

listener

Función callback que se llamará cuando se libere un botón.

Observaciones

Ver Uso del ratón y Eventos GUI.


view_OnClick ()

Establece un manejador para el clic del ratón.

void
view_OnClick(View *view,
             Listener *listener);
view

La vista.

listener

Función callback que se llamará cada vez que se haga clic sobre la vista.

Observaciones

Ver Uso del ratón y Eventos GUI.


view_OnDrag ()

Establece un manejador para el arrastre del ratón.

void
view_OnDrag(View *view,
            Listener *listener);
view

La vista.

listener

Función callback que se llamará mientras se esté arrastrando el cursor del ratón sobre la vista.

Observaciones

"Arrastrar" es desplazar el ratón con uno de los botones pulsados. Ver Uso del ratón y Eventos GUI.


view_OnWheel ()

Establece un manejador para la ruedecilla del ratón.

void
view_OnWheel(View *view,
             Listener *listener);
view

La vista.

listener

Función callback que se llamará cuando se mueva la ruedecilla del ratón sobre la vista.

Observaciones

Ver Uso del ratón y Eventos GUI.


view_OnKeyDown ()

Establece un manejador para la pulsación de una tecla.

void
view_OnKeyDown(View *view,
               Listener *listener);
view

La vista.

listener

Función callback que se llamará cuando se pulse una tecla y la vista tenga el foco del teclado.

Observaciones

Ver Uso del teclado y Eventos GUI.


view_OnKeyUp ()

Establece un manejador para la liberación de una tecla.

void
view_OnKeyUp(View *view,
             Listener *listener);
view

La vista.

listener

Función callback que se llamará cuando se libere una tecla y la vista tenga el foco del teclado.

Observaciones

Ver Uso del teclado y Eventos GUI.


view_OnFocus ()

Establece un manejador para el foco del teclado.

void
view_OnFocus(View *view,
             Listener *listener);
view

La vista.

listener

Función callback que se llamará cuando se reciba o se pierda el foco del teclado.

Observaciones

Ver Uso del teclado y Eventos GUI.


view_OnResignFocus ()

Establece un manejador para evitar perder el foco del teclado.

void
view_OnResignFocus(View *view,
                   Listener *listener);
view

La vista.

listener

Función callback que se llamará cuando la vista está a punto de perder el foco. Si devolvemos FALSE, el foco no pasará a otro control, permanecerá en la vista.

Observaciones

Ver Uso del teclado y Eventos GUI.


view_OnAcceptFocus ()

Establece un manejador para evitar obtener el foco del teclado.

void
view_OnAcceptFocus(View *view,
                   Listener *listener);
view

La vista.

listener

Función callback que se llamará cuando la vista está a punto de obtener el foco. Si devolvemos FALSE, el foco permanecerá en el control actual y no pasará a la vista.

Observaciones

Ver Uso del teclado y Eventos GUI.


view_OnScroll ()

Establece un manejador para las barras de scroll.

void
view_OnScroll(View *view,
              Listener *listener);
view

La vista.

listener

Función callback que se llamará cuando el usuario manipule las barras de scroll.

Observaciones

No es habitual tener que responder a estos eventos, ya que la vista genera los eventos OnDraw de forma automática cuando se manipulan las barras de scroll. Ver Vistas con scroll y Eventos GUI.


view_keybuf ()

Establece un búfer de teclado para la consulta síncrona o asíncrona del estado de las teclas.

void
view_keybuf(View *view,
            Keybuf *buffer);
view

La vista.

buffer

Bufer de teclado que será mantenido por la vista, capturando los eventos OnKeyDown y OnKeyUp.

Observaciones

Solo mantiene una referencia al búfer, que deberá ser destruido por el objeto que lo creó. Ver Búfer de teclado. La aplicación podrá seguir recibiendo eventos de teclado a través de view_OnKeyDown y view_OnKeyUp.


view_get_size ()

Obtiene el tamaño actual de la vista.

void
view_get_size(const View *view,
              S2Df *size);
view

La vista.

size

El tamaño.


view_content_size ()

Establece el tamaño del área de dibujo cuando existen barras de scroll.

void
view_content_size(View *view,
                  const S2Df size);
view

La vista.

size

El tamaño interno del área de dibujo.

Observaciones

Cuando se crea una vista con scroll, este método indica la totalidad del área de dibujo. El control lo utilizará para dimensionar y posicionar las barras de scroll.


view_scroll_x ()

Desplaza la barra de scroll horizontal.

void
view_scroll_x(View *view,
              const real32_t pos);
view

La vista.

pos

Nueva posición de la barra horizontal.


view_scroll_y ()

Desplaza la barra de scroll vertical.

void
view_scroll_y(View *view,
              const real32_t pos);
view

La vista.

pos

Nueva posición de la barra vertical.


view_scroll_size ()

Obtiene las medidas de las barras de scroll.

void
view_scroll_size(const View *view,
                 real32_t *width,
                 real32_t *height);
view

La vista.

width

La anchura de la barra vertical.

height

La altura de la barra horizontal.

Observaciones

Útil para considerar lo que ocupan las barras de scroll a la hora de dibujar. Si las barras están superpuestas, retornará 0.


view_scroll_visible ()

Muestra u oculta las barras de scroll.

void
view_scroll_visible(View *view,
                    const bool_t horizontal,
                    const bool_t vertical);
view

La vista.

horizontal

Barra horizontal.

vertical

Barra vertical.


view_viewport ()

Obtiene las dimensiones del área visible de la vista.

void
view_viewport(const View *view,
              V2Df *pos,
              S2Df *size);
view

La vista.

pos

La posición del viewport. Puede ser NULL.

size

El tamaño del viewport. Puede ser NULL.

Observaciones

Si la vista no tiene barras de scroll, pos será (0,0).


view_point_scale ()

Obtiene el escalado del punto.

void
view_point_scale(const View *view,
                 real32_t *scale);
view

La vista.

scale

El escalado.

Observaciones

El tamaño de la vista y coordenadas de dibujo se expresan en puntos, que normalmente corresponden con píxeles (1pt = 1px). En Pantallas retina puede ocurrir que (1pt = 2px). Si bien los Contextos 2D gestionan esto automáticamente, es posible que necesitemos saber la cantidad de píxeles para crear otro tipo de framebuffers (OpenGL, DirectX, etc). Pixels = view_get_size * view_point_scale.


view_update ()

Manda una orden al sistema operativo que la vista debe ser refrescada.

void
view_update(View *view);
view

La vista.


view_native ()

Obtiene un puntero al control nativo.

void*
view_native(View *view);
view

La vista.

Retorna

HWND en Windows, GtkWidget en Linux y NSView en macOS.

Observaciones

No utilizar esta función si no sabes muy bien que estás haciendo.

❮ Anterior
Siguiente ❯