- joined run sign
[supertux.git] / src / textscroller.cpp
1 //  $Id$
2 // 
3 //  SuperTux
4 //  Copyright (C) 2005 Matthias Braun <matze@braunis.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 #include <config.h>
21
22 #include "textscroller.hpp"
23
24 #include <stdexcept>
25 #include "resources.hpp"
26 #include "video/font.hpp"
27 #include "video/drawing_context.hpp"
28 #include "lisp/parser.hpp"
29 #include "lisp/lisp.hpp"
30 #include "audio/sound_manager.hpp"
31 #include "main.hpp"
32 #include "control/joystickkeyboardcontroller.hpp"
33
34 static const float DEFAULT_SPEED = .02;
35 static const float SCROLL = 60;
36 static const float ITEMS_SPACE = 4;
37
38 static void split_text(const std::string& text, std::vector<std::string>& lines)
39 {
40   // Split text string lines into a vector
41   lines.clear();
42   std::string::size_type i, l;
43   i = 0;
44   while(true) {
45     l = text.find("\n", i);
46
47     if(l == std::string::npos) {
48       lines.push_back(text.substr(i, text.size()-i));
49       break;
50     }
51
52     lines.push_back(text.substr(i, l-i));
53     i = l+1;
54   }
55 }
56
57 void display_text_file(const std::string& filename)
58 {
59   const Font* heading_font = white_big_text;
60   const Font* normal_font = white_text;
61   const Font* small_font = white_small_text;
62   const Font* reference_font = blue_text;
63   float defaultspeed = DEFAULT_SPEED;
64   float speed = defaultspeed;
65   
66   std::string text;
67   std::string background_file;
68   std::vector<std::string> lines;
69   std::map<std::string, Surface*> images;
70
71   lisp::Parser parser;
72   try {
73     std::auto_ptr<lisp::Lisp> root (parser.parse(filename));
74
75     const lisp::Lisp* text_lisp = root->get_lisp("supertux-text");
76     if(!text_lisp)
77       throw std::runtime_error("File isn't a supertux-text file");
78     
79     if(!text_lisp->get("text", text))
80       throw std::runtime_error("file doesn't contain a text field");
81     if(!text_lisp->get("background", background_file))
82       throw std::runtime_error("file doesn't contain a background file");
83     if(text_lisp->get("speed", defaultspeed))
84       defaultspeed /= 50;
85   } catch(std::exception& e) {
86     std::cerr << "Couldn't load file '" << filename << "': " << e.what() <<
87       "\n";
88     return;
89   }
90
91   // Split text string lines into a vector
92   split_text(text, lines);
93
94   for(size_t i = 0; i < lines.size(); ++i) {
95     const std::string& line = lines[i];
96     if(line.size() == 0)
97       continue;
98     if(line[0] == '!') {
99       std::string imagename = line.substr(1, line.size()-1);
100       std::cout << "Imagename: " << imagename << "\n";
101       images.insert(std::make_pair(imagename, new Surface(imagename)));
102     }
103   }
104
105   // load background image
106   Surface* background = new Surface("images/background/" + background_file);
107
108   bool done = false;
109   float scroll = 0;
110   float left_border = 50;
111
112   DrawingContext context;
113   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
114
115   Uint32 lastticks = SDL_GetTicks();
116   while(!done) {
117     main_controller->update();
118     /* in case of input, exit */
119     SDL_Event event;
120     while(SDL_PollEvent(&event)) {
121       main_controller->process_event(event);
122       if(event.type == SDL_QUIT)
123         throw std::runtime_error("received window close");
124     }
125
126     if(main_controller->hold(Controller::UP)) {
127       speed = -defaultspeed*5;
128     } else if(main_controller->hold(Controller::DOWN)) {
129       speed = defaultspeed*5;
130     } else {
131       speed = defaultspeed;
132     }
133     if(main_controller->pressed(Controller::JUMP)
134        || main_controller->pressed(Controller::ACTION)
135        || main_controller->pressed(Controller::MENU_SELECT))
136       scroll += SCROLL;    
137     if(main_controller->pressed(Controller::PAUSE_MENU))
138       done = true;
139     
140     /* draw the credits */
141     context.draw_surface(background, Vector(0,0), 0);
142
143     float y = 0;
144     for(size_t i = 0; i < lines.size(); i++) {
145       const std::string& line = lines[i];
146       if(line.size() == 0) {
147         y += normal_font->get_height() + ITEMS_SPACE;
148         continue;
149       }
150       
151       const Font* font = 0;
152       const Surface* image = 0;
153       bool center = true;
154       switch(line[0])
155       {
156         case ' ': font = small_font; break;
157         case '\t': font = normal_font; break;
158         case '-': font = heading_font; break;
159         case '*': font = reference_font; break;
160         case '#': font = normal_font; center = false; break;
161         case '!': {
162             std::string imagename = line.substr(1, line.size()-1);
163             image = images[imagename];
164             break;
165         }
166         default:
167           std::cerr << "Warning: text contains an unformated line.\n";
168           font = normal_font;
169           center = false;
170           break;
171       }
172      
173       if(font != 0) {
174         if(center) {
175           context.draw_text(font,
176               line.substr(1, line.size()-1),
177               Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT + y - scroll),
178               CENTER_ALLIGN, LAYER_FOREGROUND1);
179         } else {
180           context.draw_text(font,
181               line.substr(1, line.size()-1),
182               Vector(left_border, SCREEN_HEIGHT + y - scroll),
183               LEFT_ALLIGN, LAYER_FOREGROUND1);
184         }
185         y += font->get_height() + ITEMS_SPACE;
186       }
187       if(image != 0) {
188         context.draw_surface(image,
189             Vector( (SCREEN_WIDTH - image->get_width()) / 2,
190                     SCREEN_HEIGHT + y - scroll), 255);
191         y += image->get_height() + ITEMS_SPACE;
192       }
193     }
194     
195     context.do_drawing();
196     sound_manager->update();
197     
198     if(SCREEN_HEIGHT+y-scroll < 0 && 20+SCREEN_HEIGHT+y-scroll < 0)
199       done = 1;
200     
201     Uint32 ticks = SDL_GetTicks();
202     scroll += speed * (ticks - lastticks);
203     lastticks = ticks;
204     if(scroll < 0)
205       scroll = 0;
206     
207     SDL_Delay(10);
208   }
209
210   for(std::map<std::string, Surface*>::iterator i = images.begin();
211       i != images.end(); ++i)
212     delete i->second;
213
214   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
215   delete background;
216 }
217
218 InfoBox::InfoBox(const std::string& text)
219   : firstline(0)
220 {
221   split_text(text, lines);
222 }
223
224 InfoBox::~InfoBox()
225 {
226 }
227
228 void
229 InfoBox::draw(DrawingContext& context)
230 {
231   const Font* heading_font = white_big_text;
232   const Font* normal_font = white_text;
233   const Font* small_font = white_small_text;
234   const Font* reference_font = blue_text;
235   
236   float x1 = 200;
237   float y1 = 100;
238   float width = 400;
239   float height = 200;
240   
241   context.draw_filled_rect(Vector(x1, y1), Vector(width, height),
242       Color(0.6f, 0.7f, 0.8f, 0.5f), LAYER_GUI-1);
243
244   float y = y1;
245   for(size_t i = firstline; i < lines.size(); ++i) {
246     const std::string& line = lines[i];
247     if(y >= y1 + height)
248       break;
249
250     if(line.size() == 0) {
251       y += normal_font->get_height() + ITEMS_SPACE;    
252       continue;                                        
253     }
254
255     const Font* font = 0;
256     bool center = true;
257     switch(line[0])
258     {
259       case ' ': font = small_font; break;
260       case '\t': font = normal_font; break;
261       case '-': font = heading_font; break;
262       case '*': font = reference_font; break;
263       case '#': font = normal_font; center = false; break;
264       default:
265         std::cerr << "Warning: text contains an unformated line.\n";
266         font = normal_font;
267         center = false;
268         break;
269     }
270     
271     if(center) {
272       context.draw_text(font,
273           line.substr(1, line.size()-1),
274           Vector(SCREEN_WIDTH/2, y),
275           CENTER_ALLIGN, LAYER_GUI);
276     } else {
277       context.draw_text(font,
278           line.substr(1, line.size()-1),
279           Vector(x1, y),
280           LEFT_ALLIGN, LAYER_GUI);
281     }
282       
283     y += font->get_height() + ITEMS_SPACE;
284   }
285 }
286
287 void
288 InfoBox::scrollup()
289 {
290   if(firstline > 0)
291     firstline--;
292 }
293
294 void
295 InfoBox::scrolldown()
296 {
297   if(firstline < lines.size()-1)
298     firstline++;
299 }
300
301 void
302 InfoBox::pageup()
303 {
304 }
305
306 void
307 InfoBox::pagedown()
308 {
309 }
310