View this PageEdit this PageUploads to this PageVersions of this PageHomeRecent ChangesSearchHelp Guide

sdlui: tutorial02: Layers y transiciones

(Volver a la lista de tutoriales)

Sources:sdlui_tutorial02.tar.gz

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*
 * sdlui_tutorial02.c
 *
 * Layers y transiciones
 */


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include "sdlui.h"

#define DEFAULTWIDTH 800
#define DEFAULTHEIGHT 600

#define MENUWIDTH 160

/* local vars */
volatile int flag_sigint;

/* local func prototypes */
static int install_signal(int num,void (*f)(int));
static void sigint(int num);

static int menu_showhide(sdlui_t *sdlui, int show);
static int main_show(sdlui_t *sdlui, char *mainlayername);

int
main(int argc, char *argv[])
{
        sdlui_t *sdlui;
        SDL_Event event;
        int flag_exit;
        int neww,newh;
        char *actionstr, *actionparams;
        char *p;
        flag_sigint=flag_exit=0;
        install_signal(SIGINT,sigint);
        if((sdlui=sdlui_init("sdlui tutorial 02: Layers y transiciones",DEFAULTWIDTH,DEFAULTHEIGHT))==NULL)
                return(1);
        sdlui_layer_set(sdlui,"common");
        p=sdlui_add(sdlui,_F,_L,"frame:.systembar","-background #035399");
        sdlui_pack(sdlui,_F,_L,p,"-fill x -expand false -height 29 -ipadx 16 -ipady 6,7");
        p=sdlui_add(sdlui,_F,_L,"label:.systembar.menuicon","-text = -fontsize 14 -background #303030 -foreground #e0e0e0 -click systemmenu");
        sdlui_pack(sdlui,_F,_L,p,"-fill none -expand false -side left -width 16 -height 16 -anchor center");
        p=sdlui_add(sdlui,_F,_L,"frame:.notsystembar","-background #ffffff");
        sdlui_pack(sdlui,_F,_L,p,"-fill both -expand true");
        sdlui_autolayertransition_setslide(sdlui,"menu",'w',MENUWIDTH,easetype_easeoutquart,0.5,0.5);
        sdlui_autolayertransition_setfade(sdlui,"lista",easetype_none,0.5,0.5);
        sdlui_autolayertransition_setfade(sdlui,"grid",easetype_none,0.5,0.5);
        main_show(sdlui,"grid");
        while(flag_sigint==0 & flag_exit==0) {
                if(sdlui_isdirty(sdlui)) {
                        sdlui_ghostrender(sdlui);
                        sdlui_waitfps(sdlui);
                        sdlui_render(sdlui);
                } else {
                        sdlui_waitfps(sdlui);
                }
                sdlui_refreshevents(sdlui);
                while(sdlui_getevent(sdlui,&event)==0) {
                        if(sdlui_event_isquit(sdlui,&event))
                                flag_exit=1;
                        if(sdlui_event_isdirty(sdlui,&event))
                                sdlui_setdirty(sdlui);
                        if(sdlui_event_isresize(sdlui,&event,&neww,&newh))
                                sdlui_resize(sdlui,neww,newh);
                }
                while((actionstr=sdlui_getactionstr(sdlui,&actionparams))!=NULL) {
                        if(strcmp(actionstr,"systemmenu")==0) {
                                menu_showhide(sdlui,!sdlui_layer_exists(sdlui,"menu"));
                        } else if(strcmp(actionstr,"frommenulista")==0) {
                                main_show(sdlui,"lista");
                        } else if(strcmp(actionstr,"frommenugrid")==0) {
                                main_show(sdlui,"grid");
                        }
                }
        }
        sdlui_free(sdlui),sdlui=NULL;
        return(0);
}

/* local func bodies */
static int
install_signal(int num,void (*f)(int))
{
        struct sigaction sact;
        sact.sa_handler=f;
        sigemptyset(&sact.sa_mask);
        sact.sa_flags=0;
        return(sigaction(num,&sact,0));
}

static void
sigint(int num)
{
        flag_sigint=1;
}


static int
menu_showhide(sdlui_t *sdlui, int show)
{
        char *p;
        sdlui_destroybylayer(sdlui,_F,_L,"menu");
        if(!show)
                return(0);
        sdlui_layer_set(sdlui,"menu");
        sdlui_layer_setgeomfrom(sdlui,"menu",".notsystembar");
        p=sdlui_add(sdlui,_F,_L,"frame:.menu"," ");
        sdlui_pack(sdlui,_F,_L,p,"-side left -fill both -expand false");
        p=sdlui_add(sdlui,_F,_L,"frame:.menu.left","-background #f0f0f0");
        sdlui_pack(sdlui,_F,_L,p,"-side left -fill both -ipadx 16 -width %i",MENUWIDTH);
        p=sdlui_add(sdlui,_F,_L,"label:.menu.left.l1","-text Lista -fontsize 16 -foreground #404040 -background #f0f0f0 -click frommenulista");
        sdlui_pack(sdlui,_F,_L,p,"-side top -fill x -ipady 16");
        p=sdlui_add(sdlui,_F,_L,"label:.menu.left.l2","-text Grid -fontsize 16 -foreground #404040 -background #f0f0f0 -click frommenugrid");
        sdlui_pack(sdlui,_F,_L,p,"-side top -fill x -ipady 16");
        return(0);
}

static int
main_show(sdlui_t *sdlui, char *mainlayername)
{
        char *p;
        menu_showhide(sdlui,0);
        if(sdlui_layer_exists(sdlui,mainlayername))
                return(0);
        sdlui_destroybylayer(sdlui,_F,_L,"lista");
        sdlui_destroybylayer(sdlui,_F,_L,"grid");
        if(strcmp(mainlayername,"lista")==0) {
                sdlui_layer_set(sdlui,"lista");
                sdlui_layer_setgeomfrom(sdlui,"lista",".notsystembar");
                p=sdlui_add(sdlui,_F,_L,"frame:.lista"," ");
                sdlui_pack(sdlui,_F,_L,p,"-side left -fill both -expand true -ipadx 20 -ipady 20");
                p=sdlui_add(sdlui,_F,_L,"label:.lista.l1","-text \"· Uno\" -fontsize 16 -foreground #404040 -background #fafafa");
                sdlui_pack(sdlui,_F,_L,p,"-side top -fill x -ipady 16 -anchor center");
                p=sdlui_add(sdlui,_F,_L,"label:.lista.l2","-text \"· Dos\" -fontsize 16 -foreground #404040 -background #fafafa");
                sdlui_pack(sdlui,_F,_L,p,"-side top -fill x -ipady 16 -anchor center");
                p=sdlui_add(sdlui,_F,_L,"label:.lista.l3","-text \"· Tres\"  -fontsize 16 -foreground #404040 -background #fafafa");
                sdlui_pack(sdlui,_F,_L,p,"-side top -fill x -ipady 16 -anchor center");
                p=sdlui_add(sdlui,_F,_L,"label:.lista.l4","-text \"· Cuatro\"  -fontsize 16 -foreground #404040 -background #fafafa");
                sdlui_pack(sdlui,_F,_L,p,"-side top -fill x -ipady 16 -anchor center");
        } else if(strcmp(mainlayername,"grid")==0) {
                sdlui_layer_set(sdlui,"grid");
                sdlui_layer_setgeomfrom(sdlui,"grid",".notsystembar");
                p=sdlui_add(sdlui,_F,_L,"frame:.grid"," ");
                sdlui_pack(sdlui,_F,_L,p,"-side top -fill both -expand true -ipadx 20 -ipady 20 -anchor center");
                p=sdlui_add(sdlui,_F,_L,"frame:.grid.table"," ");
                sdlui_pack(sdlui,_F,_L,p,"-side top -expand false");
                p=sdlui_add(sdlui,_F,_L,"frame:.grid.table.row1"," ");
                sdlui_pack(sdlui,_F,_L,p,"-side top -expand false");
                p=sdlui_add(sdlui,_F,_L,"label:.grid.table.row1.l1","-text \"Uno\" -fontsize 16 -foreground #404040 -background #fafafa -anchor center");
                sdlui_pack(sdlui,_F,_L,p,"-side left -width 80 -ipady 50 -padx 20 -pady 20 -anchor center");
                p=sdlui_add(sdlui,_F,_L,"label:.grid.table.row1.l2","-text \"Dos\" -fontsize 16 -foreground #404040 -background #fafafa -anchor center");
                sdlui_pack(sdlui,_F,_L,p,"-side left -width 80 -ipady 50 -padx 20 -pady 20 -anchor center");
                p=sdlui_add(sdlui,_F,_L,"frame:.grid.table.row2"," ");
                sdlui_pack(sdlui,_F,_L,p,"-side top -expand false");
                p=sdlui_add(sdlui,_F,_L,"label:.grid.table.row2.l3","-text \"Tres\"  -fontsize 16 -foreground #404040 -background #fafafa -anchor center");
                sdlui_pack(sdlui,_F,_L,p,"-side left -width 80 -ipady 50 -padx 20 -pady 20 -anchor center");
                p=sdlui_add(sdlui,_F,_L,"label:.grid.table.row2.l4","-text \"Cuatro\"  -fontsize 16 -foreground #404040 -background #fafafa -anchor center");
                sdlui_pack(sdlui,_F,_L,p,"-side left -width 80 -ipady 50 -padx 20 -pady 20 -anchor center");
        }
        return(0);
}



A continuación se explican las partes nuevas con respecto a los tutoriales anteriores

Notas sobre las layers


Las "layers" o capas permiten las siguientes funciones:
  • Cambiar de forma dinámica el contenido de una parte de la pantalla, permitiendo implementar interfaces basados en pestañas (en eso es similar a los fragments de Android).
  • Poner elementos en una capa encima de todo el UI, por ejemplo para hacer modal dialogs.
  • Sacar menús o notificaciones que "entran" desde un borde de la pantalla
  • Tener transiciones, o bien haciendo que una parte del interfaz aparezca desde un borde de la pantalla, o bien con efectos de "desvanecimiento".

Creación de layers

12
13
14
15
...
29
30
31
32
...
37
...
40
41
42
43
44
45
46
47
48
#include "sdlui.h"

#define DEFAULTWIDTH 800
#define DEFAULTHEIGHT 600
...
int
main(int argc, char *argv[])
{
        sdlui_t *sdlui;
...
        char *p;
...
        if((sdlui=sdlui_init("sdlui tutorial 02: Layers y transiciones",DEFAULTWIDTH,DEFAULTHEIGHT))==NULL)
                return(1);
        sdlui_layer_set(sdlui,"common");
        p=sdlui_add(sdlui,_F,_L,"frame:.systembar","-background #035399");
        sdlui_pack(sdlui,_F,_L,p,"-fill x -expand false -height 29 -ipadx 16 -ipady 6,7");
        p=sdlui_add(sdlui,_F,_L,"label:.systembar.menuicon","-text = -fontsize 14 -background #303030 -foreground #e0e0e0 -click systemmenu");
        sdlui_pack(sdlui,_F,_L,p,"-fill none -expand false -side left -width 16 -height 16 -anchor center");
        p=sdlui_add(sdlui,_F,_L,"frame:.notsystembar","-background #ffffff");
        sdlui_pack(sdlui,_F,_L,p,"-fill both -expand true");


Cuando se añaden widgets al interfaz con sdlui_add(), se añaden al layer actual. Por defecto es el layer NULL.

Para hacer que se pongan en un layer diferente, se usa sdlui_layer_set(sdlui_t *sdlui, char *layername), siendo layername una cadena que identifica el layer. A partir de ese momento, todos los widgets se que se creen con sdlui_add() se añaden al layer indicado.

Definición de transiciones


49
50
51
        sdlui_autolayertransition_setslide(sdlui,"menu",'w',MENUWIDTH,easetype_easeoutquart,0.5,0.5);
        sdlui_autolayertransition_setfade(sdlui,"lista",easetype_none,0.5,0.5);
        sdlui_autolayertransition_setfade(sdlui,"grid",easetype_none,0.5,0.5);


Una vez generados los widgets, ponemos las transiciones a realizar para los diferentes layers usando sdlui_autolayertransition_setslide() y sdlui_autolayertransition_setfade(). No hace falta que dichas layers existan todavía, la librería recuerda esta configuración para cuando se creen dichas layers.

Para hacer que un layer entre/salga de la pantalla, se usa sdlui_autolayertransition_setslide(sdlui_t *sdlui, char *layername, char fromborder /* 'n', 's' ,'w' 'e' */, int widthorheight, easetype_t easetype, float fadeinduration, float fadeoutduration), y sus parámetros son:
  • sdlui, el manejador de la librería sdlui
  • layername, el nombre del layer al que queremos configurarle la transición
  • fromborder, una de las siguientes letras: 'n', 's' ,'w' 'e', que representan la inicial de los puntos cardinales (north, east, south, west) e indica el borde de la pantalla desde el que ha de hacer la transición.
  • widthorheight, es el tamaño en píxeles de ese elemento (width para transisiciones 'w' o 'e' y height para transisiciones de tipo 'n' o 's'). Las transiciones de "setslide" sólo están soportadas para elementos que tengan un tamaño fijo (este tamaño ha de ser igual al "-width" o "-height" en el sdlui_pack() que se haga al primer elemento de ese layer).
  • easetype, es para hacer más suave el inicio/fin de la transición, generalmente se usa easetype_easeoutquart o easetype_none (ver sdlui.h para el listado completo, son los mismos que estan disponibles en CSS para HTML5).
  • fadeinduration, el número de segundos que dura la transición de entrada.
  • fadeoutduration, el número de segundos que dura la transición de salida.

Para hacer que un layer aparezca/desaparezca con efecto de desvanecimiento, se usa sdlui_autolayertransition_setfade(sdlui_t *sdlui, char *layername, easetype_t easetype, float fadeinduration, float fadeoutduration), siendo el significado de sus parámetros el mismo que el del nombre equivalente en sdlui_autolayertransition_setslide().

Layer de menú


102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
static int
menu_showhide(sdlui_t *sdlui, int show)
{
        char *p;
        sdlui_destroybylayer(sdlui,_F,_L,"menu");
        if(!show)
                return(0);
        sdlui_layer_set(sdlui,"menu");
        sdlui_layer_setgeomfrom(sdlui,"menu",".notsystembar");
        p=sdlui_add(sdlui,_F,_L,"frame:.menu"," ");
        sdlui_pack(sdlui,_F,_L,p,"-side left -fill both -expand false");
        p=sdlui_add(sdlui,_F,_L,"frame:.menu.left","-background #f0f0f0");
        sdlui_pack(sdlui,_F,_L,p,"-side left -fill both -ipadx 16 -width %i",MENUWIDTH);
        p=sdlui_add(sdlui,_F,_L,"label:.menu.left.l1","-text Lista -fontsize 16 -foreground #404040 -background #f0f0f0 -click frommenulista");
        sdlui_pack(sdlui,_F,_L,p,"-side top -fill x -ipady 16");
        p=sdlui_add(sdlui,_F,_L,"label:.menu.left.l2","-text Grid -fontsize 16 -foreground #404040 -background #f0f0f0 -click frommenugrid");
        sdlui_pack(sdlui,_F,_L,p,"-side top -fill x -ipady 16");
        return(0);
}


Es recomendable que las layers mantengan su propia información, y por eso se suelen definir funciones para inicializar/mostrar/liberar las layers. En el caso de un menú, sólo nos interesa mostrarlo, por lo que con una sola función de showhide es suficiente.

Lo primero que hacemos es destruir todos los widgets del layer con sdlui_destroybylayer(sdlui_t *sdlui, char *filedebug, int linedebug, char *layername), siendo layername el nombre del layer a destruir. Si el layer existía y tenía una transición configurada, esta llamada provocará que se haga la animación de "salida"/"fadeout". En caso de que el layer no exista, esta llamada es inocua, no hace nada.

Si sólo se quería ocultar el layer, con el destroy ya hemos terminado.

Si se quiere mostrar el layer, entonces tenemos que
  • usar sdlui_layer_set() para informar de que los widgets que vamos a crear con sdlui_add() los queremos en la layer de menú.
  • usar sdlui_layer_setgeomfrom(sdlui_t *sdlui, char *layername, char widgetname) para describir dónde se pone el layer. Si widgetname es NULL, el layer va a ocupar toda la pantalla, si por el contrario el widgetname es el nombre de un widget, el layer va a tomar el tamaño y la posición de dicho widget, como una segunda capa encima de ese widget.
  • usar sdlui_add() y sdlui_pack() para añadir los widgets del menú.
  • es importante tener en cuenta que como esta layer va a ser de transición "setslide", hemos puesto al hacer el sdlui_pack() de ".menu.left" que "-width" tiene la anchura que definimos antes para la transición (línea 114).

Al añadir los elementos del menú, usamos "-click" sobre los elementos que queremos que generen una actionstr. NOTA En este caso es directamente sobre los textos, pero en menús que tengan iconos con texto sería sobre el elemento padre que incluye a ambos.

Layer de contenido


122
123
124
125
126
127
128
129
130
131
132
133
134
135
...
144
145
146
147
148
...
163
164
165
static int
main_show(sdlui_t *sdlui, char *mainlayername)
{
        char *p;
        menu_showhide(sdlui,0);
        if(sdlui_layer_exists(sdlui,mainlayername))
                return(0);
        sdlui_destroybylayer(sdlui,_F,_L,"lista");
        sdlui_destroybylayer(sdlui,_F,_L,"grid");
        if(strcmp(mainlayername,"lista")==0) {
                sdlui_layer_set(sdlui,"lista");
                sdlui_layer_setgeomfrom(sdlui,"lista",".notsystembar");
                p=sdlui_add(sdlui,_F,_L,"frame:.lista"," ");
                sdlui_pack(sdlui,_F,_L,p,"-side left -fill both -expand true -ipadx 20 -ipady 20");
...
        } else if(strcmp(mainlayername,"grid")==0) {
                sdlui_layer_set(sdlui,"grid");
                sdlui_layer_setgeomfrom(sdlui,"grid",".notsystembar");
                p=sdlui_add(sdlui,_F,_L,"frame:.grid"," ");
                sdlui_pack(sdlui,_F,_L,p,"-side top -fill both -expand true -ipadx 20 -ipady 20 -anchor center");
...
        }
        return(0);
}


Al igual que con el menú, para el layer de contenido se definen su propias funciones de init/show/free, pero como en este caso no hay datos que mantenemer, sólo definimos una función show para mostrar un contenido u otro.

La función que definimos es main_show(sdlui_t *sdlui, char
*mainlayername), siendo mainlayername el nombre de la "pestaña" que quermos que se vea, en nuestro caso puede ser "grid" o "list". Esta función creará un layer con ese nombre que tenga el contenido correspondiente.

Después de ocultar el menú, lo primero que comprobamos es si ya se está mostrando ese layer (si ya se está mostrando, en ese caso no tenemos que hacer nada). Para hacer esa comprobación nos basta ver si el layer ha sido definido (si hay un layer con ese nombre que tenga algún widget). Para eso usamos la función sdlui_layer_exists(sdlui_t *sdlui, char *layername), siendo layername el nombre del layer del que queremos comprobar su existencia, y la función devuelve 1 si existe y 0 si no existe.

A continuación destruimos los layers de contenido posibles (sólo existirá uno de ellos, pero llamar a la función con un layer que no existe es inocuo, no hace nada), usando sdui_destroybylayer(sdlui_t *sdlui, char *layername), siendo layername el layer a destruir.

Por último, generamos el nuevo layer con el nombre que nos pasaron, y con el contenido que le corresponde,
  • usando sdlui_layer_set() para indicar que todos los widgets generados desde este momento han de estar en el layer con el nombre que nos interesa,
  • usando sdlui_layer_setgeomfrom() para definir la posición y tamaño del nuevo layer , diciendo que los tome del widget ".notsystembar" (widget que definimos al principio del programa, en la líneas 47-48)
  • haciendo las llamadas correspondientes a sdlui_add() y sdlui_pack() para crear cada elemento de esta "pestaña".