View
Funciones
View* | view_create (void) |
View* | view_scroll (void) |
View* | view_custom (...) |
void | view_data (...) |
type* | view_get_data (...) |
void | view_size (...) |
void | view_OnDraw (...) |
void | view_OnOverlay (...) |
void | view_OnSize (...) |
void | view_OnEnter (...) |
void | view_OnExit (...) |
void | view_OnMove (...) |
void | view_OnDown (...) |
void | view_OnUp (...) |
void | view_OnClick (...) |
void | view_OnDrag (...) |
void | view_OnWheel (...) |
void | view_OnKeyDown (...) |
void | view_OnKeyUp (...) |
void | view_OnFocus (...) |
void | view_OnResignFocus (...) |
void | view_OnAcceptFocus (...) |
void | view_OnScroll (...) |
void | view_allow_tab (...) |
void | view_keybuf (...) |
void | view_get_size (...) |
void | view_content_size (...) |
void | view_scroll_x (...) |
void | view_scroll_y (...) |
void | view_scroll_size (...) |
void | view_scroll_visible (...) |
void | view_viewport (...) |
void | view_point_scale (...) |
void | view_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.
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).
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.
El sistema operativo puede lanzar eventosOnDraw
en cualquier momento sin que hallamos llamado previamente aview_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:
- 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 aview_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
- Utiliza view_OnOverlay para dibujar 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.
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.
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)); |
- 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.
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.
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 |
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 |
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_allow_tab ()
Permite capturar la pulsación de la tecla [TAB]
.
void view_allow_tab(View *view, const bool_t allow);
view | La vista. |
allow | Permitir o no la captura de |
Observaciones
Si TRUE
la pulsación de [TAB]
con el foco del teclado en la vista será capturado como evento KeyDown
y no como navegación entre los controles de la ventana. La llamada a esta función no tendrá efecto si no existe un manejador OnKeyDown
asociado. En general, no se debería utilizar esta función.
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 |
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 |
size | El tamaño del viewport. Puede ser |
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.