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