Changed up and down to previous and next. And added up and down icons.
[supertux.git] / src / text.cpp
1 //  $Id$
2 // 
3 //  SuperTux
4 //  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 // 
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 //  02111-1307, USA.
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include "globals.h"
24 #include "defines.h"
25 #include "screen.h"
26 #include "text.h"
27
28 Text::Text(const std::string& file, int kind_, int w_, int h_)
29 {
30   kind = kind_;
31   w = w_;
32   h = h_;
33
34   int mx, my;
35   SDL_Surface *conv;
36   int pixels;
37   int i;
38   
39   if(kind == TEXT_TEXT)
40     {
41       mx = 26;
42       my = 3;
43     }
44   else if(kind == TEXT_NUM)
45     {
46       mx = 10;
47       my = 1;
48     }
49   else
50     {
51       mx = 0;
52       my = 0;
53     }
54
55   chars = new Surface(file, USE_ALPHA);
56
57   // Load shadow font.
58   conv = SDL_DisplayFormatAlpha(chars->impl->get_sdl_surface());
59   pixels = conv->w * conv->h;
60   SDL_LockSurface(conv);
61   for(i = 0; i < pixels; ++i)
62     {
63       Uint32 *p = (Uint32 *)conv->pixels + i;
64       *p = *p & conv->format->Amask;
65     }
66   SDL_UnlockSurface(conv);
67   SDL_SetAlpha(conv, SDL_SRCALPHA, 128);
68   shadow_chars = new Surface(conv, USE_ALPHA);
69
70   SDL_FreeSurface(conv);
71 }
72
73 Text::~Text()
74 {
75   delete chars;
76   delete shadow_chars;
77 }
78
79 void
80 Text::draw(const  char* text, int x, int y, int shadowsize, int update)
81 {
82   if(text != NULL)
83     {
84       if(shadowsize != 0)
85         draw_chars(shadow_chars, text,x+shadowsize,y+shadowsize, update);
86
87       draw_chars(chars, text,x,y, update);
88     }
89 }
90
91 void
92 Text::draw_chars(Surface* pchars,const  char* text, int x, int y, int update)
93 {
94   int i,j,len;
95
96   len = strlen(text);
97   int w = this->w;
98   int h = this->h;
99
100   if(kind == TEXT_TEXT)
101     {
102       for( i = 0, j = 0; i < len; ++i,++j)
103         {
104           if( text[i] >= ' ' && text[i] <= '/')
105             pchars->draw_part((int)(text[i] - ' ')*w,  0 , x+(j*w), y, w, h, 255,  update);
106           else if( text[i] >= '0' && text[i] <= '?')
107             pchars->draw_part((int)(text[i] - '0')*w, h*1, x+(j*w), y, w, h, 255,  update);
108           else if ( text[i] >= '@' && text[i] <= 'O')
109             pchars->draw_part((int)(text[i] - '@')*w, h*2, x+(j*w), y, w, h, 255,  update);
110           else if ( text[i] >= 'P' && text[i] <= '_')
111             pchars->draw_part((int)(text[i] - 'P')*w, h*3, x+(j*w), y, w, h, 255,  update);
112           else if ( text[i] >= '`' && text[i] <= 'o')
113             pchars->draw_part((int)(text[i] - '`')*w, h*4, x+(j*w), y, w, h, 255,  update);
114           else if ( text[i] >= 'p' && text[i] <= '~')
115             pchars->draw_part((int)(text[i] - 'p')*w, h*5, x+(j*w), y, w, h, 255,  update);
116           else if ( text[i] == '\n')
117             {
118               y += h + 2;
119               j = 0;
120             }
121         }
122     }
123   else if(kind == TEXT_NUM)
124     {
125       for( i = 0, j = 0; i < len; ++i, ++j)
126         {
127           if ( text[i] >= '0' && text[i] <= '9')
128             pchars->draw_part((int)(text[i] - '0')*w, 0, x+(j*w), y, w, h, 255, update);
129           else if ( text[i] == '\n')
130             {
131               y += h + 2;
132               j = 0;
133             }
134         }
135     }
136 }
137
138 void
139 Text::draw_align(const char* text, int x, int y,
140                       TextHAlign halign, TextVAlign valign, int shadowsize, int update)
141 {
142   if(text != NULL)
143     {
144       switch (halign)
145         {
146         case A_RIGHT:
147           x += -(strlen(text)*w);
148           break;
149         case A_HMIDDLE:
150           x += -((strlen(text)*w)/2);
151           break;
152         case A_LEFT:
153           // default
154           break;
155         }
156
157       switch (valign)
158         {
159         case A_BOTTOM:
160           y -= h;
161           break;
162           
163         case A_VMIDDLE:
164           y -= h/2;
165
166         case A_TOP:
167           // default
168           break;
169         }
170
171       draw(text, x, y, shadowsize, update);
172     }
173 }
174
175 void
176 Text::drawf(const  char* text, int x, int y,
177                  TextHAlign halign, TextVAlign valign, int shadowsize, int update)
178 {
179   if(text != NULL)
180     {
181       if(halign == A_RIGHT)  /* FIXME: this doesn't work correctly for strings with newlines.*/
182         x += screen->w - (strlen(text)*w);
183       else if(halign == A_HMIDDLE)
184         x += screen->w/2 - ((strlen(text)*w)/2);
185
186       if(valign == A_BOTTOM)
187         y += screen->h - h;
188       else if(valign == A_VMIDDLE)
189         y += screen->h/2 - h/2;
190
191       draw(text,x,y,shadowsize, update);
192     }
193 }
194
195 /* --- ERASE TEXT: --- */
196
197 void
198 Text::erasetext(const  char * text, int x, int y, Surface * ptexture, int update, int shadowsize)
199 {
200   SDL_Rect dest;
201
202   dest.x = x;
203   dest.y = y;
204   dest.w = strlen(text) * w + shadowsize;
205   dest.h = h;
206
207   if (dest.w > screen->w)
208     dest.w = screen->w;
209
210   ptexture->draw_part(dest.x,dest.y,dest.x,dest.y,dest.w,dest.h, 255, update);
211
212   if (update == UPDATE)
213     update_rect(screen, dest.x, dest.y, dest.w, dest.h);
214 }
215
216
217 /* --- ERASE CENTERED TEXT: --- */
218
219 void
220 Text::erasecenteredtext(const  char * text, int y, Surface * ptexture, int update, int shadowsize)
221 {
222   erasetext(text, screen->w / 2 - (strlen(text) * 8), y, ptexture, update, shadowsize);
223 }
224
225
226 /* --- SCROLL TEXT FUNCTION --- */
227
228 #define MAX_VEL     10
229 #define SPEED_INC   0.01
230 #define SCROLL      60
231 #define ITEMS_SPACE 4
232
233 void display_text_file(const std::string& file, const std::string& surface, float scroll_speed)
234 {
235   Surface* sur = new Surface(datadir + surface, IGNORE_ALPHA);
236   display_text_file(file, sur, scroll_speed);
237   delete sur;
238 }
239
240 void display_text_file(const std::string& file, Surface* surface, float scroll_speed)
241 {
242   int done;
243   float scroll;
244   float speed;
245   int y;
246   int length;
247   FILE* fi;
248   char temp[1024];
249   string_list_type names;
250   char filename[1024];
251   string_list_init(&names);
252   sprintf(filename,"%s/%s", datadir.c_str(), file.c_str());
253   if((fi = fopen(filename,"r")) != NULL)
254     {
255       while(fgets(temp, sizeof(temp), fi) != NULL)
256         {
257           temp[strlen(temp)-1]='\0';
258           string_list_add_item(&names,temp);
259         }
260       fclose(fi);
261     }
262   else
263     {
264       string_list_add_item(&names,"File was not found!");
265       string_list_add_item(&names,filename);
266       string_list_add_item(&names,"Shame on the guy, who");
267       string_list_add_item(&names,"forgot to include it");
268       string_list_add_item(&names,"in your SuperTux distribution.");
269     }
270
271
272   scroll = 0;
273   speed = scroll_speed / 50;
274   done = 0;
275
276   length = names.num_items;
277
278   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
279
280   Uint32 lastticks = SDL_GetTicks();
281   while(done == 0)
282     {
283       /* in case of input, exit */
284       SDL_Event event;
285       while(SDL_PollEvent(&event))
286         switch(event.type)
287           {
288           case SDL_KEYDOWN:
289             switch(event.key.keysym.sym)
290               {
291               case SDLK_UP:
292                 speed -= SPEED_INC;
293                 break;
294               case SDLK_DOWN:
295                 speed += SPEED_INC;
296                 break;
297               case SDLK_SPACE:
298               case SDLK_RETURN:
299                 if(speed >= 0)
300                   scroll += SCROLL;
301                 break;
302               case SDLK_ESCAPE:
303                 done = 1;
304                 break;
305               default:
306                 break;
307               }
308             break;
309           case SDL_QUIT:
310             done = 1;
311             break;
312           default:
313             break;
314           }
315
316       if(speed > MAX_VEL)
317         speed = MAX_VEL;
318       else if(speed < -MAX_VEL)
319         speed = -MAX_VEL;
320
321       /* draw the credits */
322       surface->draw_bg();
323
324       y = 0;
325       for(int i = 0; i < length; i++)
326         {
327         switch(names.item[i][0])
328           {
329           case ' ':
330             white_small_text->drawf(names.item[i]+1, 0, screen->h+y-int(scroll),
331                 A_HMIDDLE, A_TOP, 1);
332             y += white_small_text->h+ITEMS_SPACE;
333             break;
334           case '        ':
335             white_text->drawf(names.item[i]+1, 0, screen->h+y-int(scroll),
336                 A_HMIDDLE, A_TOP, 1);
337             y += white_text->h+ITEMS_SPACE;
338             break;
339           case '-':
340             white_big_text->drawf(names.item[i]+1, 0, screen->h+y-int(scroll),
341                 A_HMIDDLE, A_TOP, 3);
342             y += white_big_text->h+ITEMS_SPACE;
343             break;
344           default:
345             blue_text->drawf(names.item[i], 0, screen->h+y-int(scroll),
346                 A_HMIDDLE, A_TOP, 1);
347             y += blue_text->h+ITEMS_SPACE;
348             break;
349           }
350         }
351
352       flipscreen();
353
354       if(screen->h+y-scroll < 0 && 20+screen->h+y-scroll < 0)
355         done = 1;
356
357       Uint32 ticks = SDL_GetTicks();
358       scroll += speed * (ticks - lastticks);
359       lastticks = ticks;
360       if(scroll < 0)
361         scroll = 0;
362
363       SDL_Delay(10);
364     }
365   string_list_free(&names);
366
367   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
368   Menu::set_current(main_menu);
369 }
370