about.cpp

Go to the documentation of this file.
00001 /* $Id: about.cpp 52616 2012-01-16 04:58:33Z shadowmaster $ */
00002 /*
00003    Copyright (C) 2003 - 2012 by David White <dave@whitevine.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 /**
00017  * @file
00018  * Show screen with scrolling credits.
00019  */
00020 
00021 #include "about.hpp"
00022 
00023 #include "construct_dialog.hpp"
00024 #include "display.hpp"
00025 #include "foreach.hpp"
00026 #include "gettext.hpp"
00027 #include "marked-up_text.hpp"
00028 
00029 /**
00030  * @namespace about
00031  * Display credits %about all contributors.
00032  *
00033  * This module is used from the startup screen. \n
00034  * When show_about() is called, a list of contributors
00035  * to the game will be presented to the user.
00036  */
00037 namespace about
00038 {
00039     static config about_list = config();
00040     static std::map<std::string , std::string> images;
00041     static std::string images_default;
00042 
00043 /**
00044  * Given a vector of strings, and a config representing an [about] section,
00045  * add all the credits lines from the about section to the list of strings.
00046  */
00047 static void add_lines(std::vector<std::string> &res, config const &c) {
00048     std::string title = c["title"];
00049     if (!title.empty()) {
00050         title = "+" + title;
00051         res.push_back(title);
00052     }
00053 
00054     std::vector<std::string> lines = utils::split(c["text"], '\n');
00055     foreach (std::string &line, lines)
00056     {
00057         if (line.size() > 1 && line[0] == '+')
00058             line = "+  " + line.substr(1);
00059         else
00060             line = "-  " + line;
00061 
00062         if (!line.empty())
00063         {
00064             if (line[0] == '_')
00065                 line = gettext(line.substr(1).c_str());
00066             res.push_back(line);
00067         }
00068     }
00069 
00070     foreach (const config &entry, c.child_range("entry")) {
00071         res.push_back("-  "+ entry["name"].str());
00072     }
00073 }
00074 
00075 
00076 std::vector<std::string> get_text(const std::string &campaign)
00077 {
00078     std::vector< std::string > res;
00079 
00080     config::child_itors about_entries = about_list.child_range("about");
00081 
00082     if (!campaign.empty()) {
00083         foreach (const config &about, about_entries) {
00084             // just finished a particular campaign
00085             if (campaign == about["id"]) {
00086                 add_lines(res, about);
00087             }
00088         }
00089     }
00090 
00091     foreach (const config &about, about_entries) {
00092         add_lines(res, about);
00093     }
00094 
00095     return res;
00096 }
00097 
00098 void set_about(const config &cfg)
00099 {
00100     about_list.clear();
00101     images.clear();
00102     images_default = "";
00103 
00104     foreach (const config &about, cfg.child_range("about"))
00105     {
00106         about_list.add_child("about", about);
00107         const std::string &im = about["images"];
00108         if (!images.empty())
00109         {
00110             if (images_default.empty())
00111                 images_default = im;
00112             else
00113                 images_default += ',' + im;
00114         }
00115     }
00116 
00117     foreach (const config &campaign, cfg.child_range("campaign"))
00118     {
00119         config::const_child_itors abouts = campaign.child_range("about");
00120         if (abouts.first == abouts.second) continue;
00121 
00122         config temp;
00123         std::ostringstream text;
00124         const std::string &id = campaign["id"];
00125         temp["title"] = campaign["name"];
00126         temp["id"] = id;
00127         std::string campaign_images;
00128 
00129         foreach (const config &about, abouts)
00130         {
00131             const std::string &subtitle = about["title"];
00132             if (!subtitle.empty())
00133             {
00134                 text << '+';
00135                 if (subtitle[0] == '_')
00136                     text << gettext(subtitle.substr(1, subtitle.size() - 1).c_str());
00137                 else
00138                     text << subtitle;
00139                 text << '\n';
00140             }
00141 
00142             foreach (const std::string &line, utils::split(about["text"], '\n'))
00143             {
00144                 text << "    " << line << '\n';
00145             }
00146 
00147             foreach (const config &entry, about.child_range("entry"))
00148             {
00149                 text << "    " << entry["name"] << '\n';
00150             }
00151 
00152             const std::string &im = about["images"];
00153             if (!im.empty())
00154             {
00155                 if (campaign_images.empty())
00156                     campaign_images = im;
00157                 else
00158                     campaign_images += ',' + im;
00159             }
00160         }
00161 
00162         images[id] = campaign_images;
00163         temp["text"] = text.str();
00164         about_list.add_child("about",temp);
00165     }
00166 }
00167 
00168 /**
00169  * Show credits with list of contributors.
00170  *
00171  * Names of people are shown scrolling up like in movie-credits.\n
00172  * Uses map from wesnoth or campaign as background.
00173  */
00174 void show_about(display &disp, const std::string &campaign)
00175 {
00176     cursor::set(cursor::WAIT);
00177     CVideo &video = disp.video();
00178     surface screen = video.getSurface();
00179     if (screen == NULL) return;
00180 
00181     std::vector<std::string> text = about::get_text(campaign);
00182     SDL_Rect screen_rect = create_rect(0, 0, screen->w, screen->h);
00183 
00184     const surface_restorer restorer(&video, screen_rect);
00185 
00186     cursor::set(cursor::NORMAL);
00187 
00188     std::vector<std::string> image_list;
00189     if(campaign.size() && !images[campaign].empty()){
00190         image_list = utils::parenthetical_split(images[campaign], ',');
00191     } else{
00192         image_list = utils::parenthetical_split(images_default, ',');
00193     }
00194 
00195     surface map_image;
00196 
00197     if(!image_list.empty()) {
00198         map_image = scale_surface(image::get_image(image_list[0]), screen->w, screen->h);
00199     } else {
00200         image_list.push_back("");
00201     }
00202 
00203     if(!map_image){
00204         image_list[0]=game_config::images::game_title;
00205         map_image=surface(scale_surface(image::get_image(image_list[0]), screen->w, screen->h));
00206     }
00207 
00208     gui::button close(video,_("Close"));
00209     close.set_location((screen->w/2)-(close.width()/2), screen->h - 30);
00210     close.set_volatile(true);
00211 
00212     const int def_size = font::SIZE_XLARGE;
00213     const SDL_Color def_color = font::NORMAL_COLOR;
00214 
00215     //substitute in the correct control characters for '+' and '-'
00216     std::string before_header(2, ' ');
00217     before_header[0] = font::LARGE_TEXT;
00218     for(unsigned i = 0; i < text.size(); ++i) {
00219         std::string &s = text[i];
00220         if (s.empty()) continue;
00221         char &first = s[0];
00222         if (first == '-')
00223             first = font::SMALL_TEXT;
00224         else if (first == '+') {
00225             first = font::LARGE_TEXT;
00226             text.insert(text.begin() + i, before_header);
00227             ++i;
00228         }
00229     }
00230     text.insert(text.begin(), 10, before_header);
00231 
00232     int startline = 0;
00233 
00234     //TODO: use values proportionnal to screen ?
00235     // distance from top of map image to top of scrolling text
00236     const int top_margin = 60;
00237     // distance from bottom of scrolling text to bottom of map image
00238     const int bottom_margin = 40;
00239     // distance from left of scrolling text to the frame border
00240     const int text_left_padding = screen->w/32;
00241 
00242     int offset = 0;
00243     bool is_new_line = true;
00244 
00245     int first_line_height = 0;
00246 
00247     SDL_Rect frame_area = create_rect(
00248               screen->w * 3 / 32
00249             , top_margin
00250             , screen->w * 13 / 16
00251             , screen->h - top_margin - bottom_margin);
00252 
00253     // we use a dialog to contains the text. Strange idea but at least the style
00254     // will be consistent with the titlescreen
00255     gui::dialog_frame f(video, "", gui::dialog_frame::titlescreen_style, false);
00256 
00257     // set the layout and get the interior rectangle
00258     SDL_Rect text_rect = f.layout(frame_area).interior;
00259     text_rect.x += text_left_padding;
00260     text_rect.w -= text_left_padding;
00261     // make a copy to prevent SDL_blit to change its w and h
00262     SDL_Rect text_rect_blit = text_rect;
00263 
00264     CKey key;
00265     bool last_escape;
00266 
00267     surface text_surf = create_compatible_surface(screen, text_rect.w, text_rect.h);
00268     SDL_SetAlpha(text_surf, SDL_RLEACCEL, SDL_ALPHA_OPAQUE);
00269 
00270     int image_count = 0;
00271     int scroll_speed = 4;   // scroll_speed*50 = speed of scroll in pixel per second
00272 
00273     // initialy redraw all
00274     bool redraw_mapimage = true;
00275     int max_text_width = text_rect.w;
00276 
00277     do {
00278         last_escape = key[SDLK_ESCAPE] != 0;
00279 
00280         // check to see if background image has changed
00281         if(text.size() && (image_count <
00282                 ((startline * static_cast<int>(image_list.size())) /
00283                 static_cast<int>(text.size())))){
00284 
00285             image_count++;
00286             surface temp=surface(scale_surface(image::get_image(image_list[image_count]), screen->w, screen->h));
00287             map_image=temp?temp:map_image;
00288             redraw_mapimage = true;
00289         }
00290 
00291         if (redraw_mapimage) {
00292             // draw map to screen, thus erasing all text
00293             sdl_blit(map_image, NULL, screen, NULL);
00294             update_rect(screen_rect);
00295 
00296             // redraw the dialog
00297             f.draw_background();
00298             f.draw_border();
00299             // cache the dialog background (alpha blending + blurred map)
00300             sdl_blit(screen, &text_rect, text_surf, NULL);
00301             redraw_mapimage = false;
00302         } else {
00303             // redraw the saved part of the dialog where text scrolled
00304             // thus erasing all text
00305             SDL_Rect modified = create_rect(0, 0, max_text_width, text_rect.h);
00306             sdl_blit(text_surf, &modified, screen, &text_rect_blit);
00307             update_rect(text_rect);
00308         }
00309 
00310         const int line_spacing = 5;
00311 
00312         int y = text_rect.y - offset;
00313         int line = startline;
00314         max_text_width = 0;
00315 
00316         {
00317         // clip to keep text into the frame (thus the new code block)
00318         clip_rect_setter set_clip_rect(screen, &text_rect);
00319             do {
00320                 // draw the text (with ellipsis if needed)
00321                 // update the max_text_width for future cleaning
00322                 int w = font::draw_text(&video, text_rect, def_size, def_color,
00323                                         text[line], text_rect.x, y).w;
00324                 max_text_width = std::max<int>(max_text_width, w);
00325                 // since the real drawing on screen is clipped,
00326                 // we do a dummy one to get the height of the not clipped line.
00327                 // (each time because special format characters may change it)
00328                 const int line_height = font::draw_text(NULL, text_rect, def_size, def_color,
00329                                         text[line], 0,0).h;
00330 
00331                 if(is_new_line) {
00332                     is_new_line = false;
00333                     first_line_height = line_height + line_spacing;
00334                 }
00335                 line++;
00336                 if(size_t(line) > text.size()-1)
00337                     line = 0;
00338                 y += line_height + line_spacing;
00339             } while(y < text_rect.y + text_rect.h);
00340         }
00341 
00342         // performs the actual scrolling
00343         offset += scroll_speed;
00344         if (offset>=first_line_height) {
00345             offset -= first_line_height;
00346             is_new_line = true;
00347             startline++;
00348             if(size_t(startline) == text.size()){
00349                 startline = 0;
00350                 image_count = -1;
00351             }
00352         }
00353 
00354         // handle events
00355         if (key[SDLK_UP] && scroll_speed < 20) {
00356             ++scroll_speed;
00357         }
00358         if (key[SDLK_DOWN] && scroll_speed > 0) {
00359             --scroll_speed;
00360         }
00361 
00362         events::pump();
00363         events::raise_process_event();
00364         events::raise_draw_event();
00365 
00366         // flip screen and wait, so the text does not scroll too fast
00367         disp.flip();
00368         disp.delay(20);
00369 
00370     } while(!close.pressed() && (last_escape || !key[SDLK_ESCAPE]));
00371 }
00372 
00373 } // end namespace about
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Tue May 22 2012 01:03:33 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs