/** * Show credits with list of contributors. * * Names of people are shown scrolling up like in movie-credits.\n * Uses map from wesnoth or campaign as background. */ void show_about(CVideo &video, const std::string &campaign) { boost::scoped_ptr<cursor::setter> cur(new cursor::setter(cursor::WAIT)); surface& screen = video.getSurface(); if (screen == nullptr) return; // If the title is multi-line, we need to split it accordingly or we // get slight scrolling glitches in the credits screen. std::vector<std::string> text = about::get_text(campaign, true); SDL_Rect screen_rect = sdl::create_rect(0, 0, screen->w, screen->h); const surface_restorer restorer(&video, screen_rect); cur.reset(); std::vector<std::string> image_list; if(campaign.size() && !images[campaign].empty()){ image_list = utils::parenthetical_split(images[campaign], ','); } else{ image_list = utils::parenthetical_split(images_default, ','); } surface map_image, map_image_scaled; if(!image_list.empty()) { map_image = image::get_image(image_list[0]); } else { image_list.push_back(""); } if(!map_image){ image_list[0]=game_config::images::game_title_background; map_image=image::get_image(image_list[0]); } gui::button close(video,_("Close")); close.set_location((screen->w/2)-(close.width()/2), screen->h - 30); const int def_size = font::SIZE_XLARGE; const SDL_Color def_color = font::NORMAL_COLOR; //substitute in the correct control characters for '+' and '-' std::string before_header(2, ' '); before_header[0] = font::LARGE_TEXT; for(unsigned i = 0; i < text.size(); ++i) { std::string &s = text[i]; if (s.empty()) continue; char &first = s[0]; if (first == '-') first = font::SMALL_TEXT; else if (first == '+') { first = font::LARGE_TEXT; text.insert(text.begin() + i, before_header); ++i; } } text.insert(text.begin(), 10, before_header); int startline = 0; //TODO: use values proportional to screen ? // distance from top of map image to top of scrolling text const int top_margin = 60; // distance from bottom of scrolling text to bottom of map image const int bottom_margin = 40; // distance from left of scrolling text to the frame border const int text_left_padding = screen->w/32; int offset = 0; bool is_new_line = true; int first_line_height = 0; SDL_Rect frame_area; // we use a dialog to contains the text. Strange idea but at least the style // will be consistent with the titlescreen gui::dialog_frame f(video, "", gui::dialog_frame::titlescreen_style, false); // the text area's dimensions SDL_Rect text_rect = { 0, 0, 0, 0 }; // we'll retain a copy to prevent SDL_blit to change its w and h SDL_Rect text_rect_blit; surface text_surf; CKey key; bool last_escape; int image_count = 0; int scroll_speed = 4; // scroll_speed*50 = speed of scroll in pixel per second // Initially redraw all bool redraw_mapimage = true; bool update_dimensions = true; int max_text_width = 0; do { last_escape = key[SDLK_ESCAPE] != 0; // check to see if background image has changed if(text.size() && (image_count < ((startline * static_cast<int>(image_list.size())) / static_cast<int>(text.size())))){ image_count++; surface temp=image::get_image(image_list[image_count]); map_image=temp?temp:map_image; redraw_mapimage = true; } if (update_dimensions) { // rescale the background map_image_scaled = scale_surface(map_image, screen->w, screen->h); screen_rect = sdl::create_rect(0, 0, screen->w, screen->h); redraw_mapimage = true; // update the frame frame_area = sdl::create_rect( screen->w * 3 / 32 , top_margin , screen->w * 13 / 16 , screen->h - top_margin - bottom_margin); text_rect = f.layout(frame_area).interior; // update the text area text_rect.x += text_left_padding; text_rect.w -= text_left_padding; text_rect_blit = text_rect; text_surf = create_compatible_surface(screen, text_rect.w, text_rect.h); SDL_SetAlpha(text_surf, SDL_RLEACCEL, SDL_ALPHA_OPAQUE); // relocate the close button close.set_location((screen->w/2)-(close.width()/2), screen->h - 30); update_dimensions = false; } if (redraw_mapimage) { // draw map to screen, thus erasing all text sdl_blit(map_image_scaled, nullptr, screen, nullptr); update_rect(screen_rect); // redraw the dialog f.draw_background(); f.draw_border(); // cache the dialog background (alpha blending + blurred map) sdl_blit(screen, &text_rect, text_surf, nullptr); redraw_mapimage = false; } else { // redraw the saved part of the dialog where text scrolled // thus erasing all text SDL_Rect modified = sdl::create_rect(0, 0, max_text_width, text_rect.h); sdl_blit(text_surf, &modified, screen, &text_rect_blit); update_rect(text_rect); } int y = text_rect.y - offset; int line = startline; max_text_width = 0; { // clip to keep text into the frame (thus the new code block) clip_rect_setter set_clip_rect(screen, &text_rect); const int line_spacing = 5; do { // draw the text (with ellipsis if needed) // update the max_text_width for future cleaning int w = font::draw_text(&video, text_rect, def_size, def_color, text[line], text_rect.x, y).w; max_text_width = std::max<int>(max_text_width, w); // since the real drawing on screen is clipped, // we do a dummy one to get the height of the not clipped line. // (each time because special format characters may change it) const int line_height = font::draw_text(nullptr, text_rect, def_size, def_color, text[line], 0,0).h; if(is_new_line) { is_new_line = false; first_line_height = line_height + line_spacing; } line++; if(size_t(line) > text.size()-1) line = 0; y += line_height + line_spacing; } while(y < text_rect.y + text_rect.h); } // performs the actual scrolling offset += scroll_speed; if (offset>=first_line_height) { offset -= first_line_height; is_new_line = true; startline++; if(size_t(startline) == text.size()){ startline = 0; image_count = -1; } } // handle events if (key[SDLK_UP] && scroll_speed < 20) { ++scroll_speed; } if (key[SDLK_DOWN] && scroll_speed > 0) { --scroll_speed; } if (screen->w != screen_rect.w || screen->h != screen_rect.h) { update_dimensions = true; } events::pump(); events::raise_process_event(); events::raise_draw_event(); // flip screen and wait, so the text does not scroll too fast video.flip(); CVideo::delay(20); } while(!close.pressed() && (last_escape || !key[SDLK_ESCAPE])); }
/** * Show credits with list of contributors. * * Names of people are shown scrolling up like in movie-credits.\n * Uses map from wesnoth or campaign as background. */ void show_about(display &disp, std::string campaign) { cursor::set(cursor::WAIT); CVideo &video = disp.video(); // surface screen = video.getSurface(); // if (screen == NULL) return; std::vector<std::string> text = about::get_text(campaign); // SDL_Rect screen_rect = {0, 0, video.getx(), video.gety()}; // const surface_restorer restorer(&video, screen_rect); cursor::set(cursor::NORMAL); std::vector<shared_string> image_list; if(campaign.size() && !images[campaign].empty()){ image_list=utils::split_shared(images[campaign]); }else{ image_list=utils::split_shared(images_default,',',utils::STRIP_SPACES); } surface map_image(scale_surface(image::get_image(image_list[0]), video.getx(), video.gety())); if(! map_image){ image_list[0]=game_config::game_title; map_image=surface(scale_surface(image::get_image(image_list[0]), video.getx(), video.gety())); } gui::button close(video,_("Close")); close.set_location((video.getx()/2)-(close.width()/2), video.gety() - 30); close.set_volatile(true); const int def_size = font::SIZE_XLARGE; const SDL_Color def_color = font::NORMAL_COLOUR; //substitute in the correct control characters for '+' and '-' std::string before_header(2, ' '); before_header[0] = font::LARGE_TEXT; for(unsigned i = 0; i < text.size(); ++i) { std::string &s = text[i]; if (s.empty()) continue; char &first = s[0]; if (first == '-') first = font::SMALL_TEXT; else if (first == '+') { first = font::LARGE_TEXT; text.insert(text.begin() + i, before_header); ++i; } } text.insert(text.begin(), 10, before_header); int startline = 0; //TODO: use values proportionnal to screen ? // distance from top of map image to top of scrolling text const int top_margin = 60; // distance from bottom of scrolling text to bottom of map image const int bottom_margin = 40; // distance from left of scrolling text to the frame border const int text_left_padding = video.getx()/32; int offset = 0; bool is_new_line = true; int first_line_height = 0; SDL_Rect frame_area = { video.getx() * 3/32, top_margin, video.getx() * 13 / 16, video.gety() - top_margin - bottom_margin }; // we use a dialog to contains the text. Strange idea but at least the style // will be consistent with the titlescreen gui::dialog_frame f(video, "", gui::dialog_frame::titlescreen_style, false); // set the layout and get the interior rectangle SDL_Rect text_rect = f.layout(frame_area).interior; text_rect.x += text_left_padding; text_rect.w -= text_left_padding; // make a copy to prevent SDL_blit to change its w and h SDL_Rect text_rect_blit = text_rect; CKey key; bool last_escape; surface text_surf = create_neutral_surface(text_rect.w, text_rect.h); //create_compatible_surface(screen, text_rect.w, text_rect.h); SDL_SetAlpha(text_surf, SDL_RLEACCEL, SDL_ALPHA_OPAQUE); int image_count = 0; int scroll_speed = 4; // scroll_speed*50 = speed of scroll in pixel per second // initialy redraw all bool redraw_mapimage = true; int max_text_width = text_rect.w; do { last_escape = key[SDLK_ESCAPE] != 0; // check to see if background image has changed if(text.size() && (image_count < ((startline * static_cast<int>(image_list.size())) / static_cast<int>(text.size())))){ image_count++; surface temp=surface(scale_surface(image::get_image(image_list[image_count]), video.getx(), video.gety())); map_image=temp?temp:map_image; redraw_mapimage = true; } // if (redraw_mapimage) { // draw map to screen, thus erasing all text //SDL_BlitSurface(map_image, NULL, screen, NULL); blit_surface(0, 0, map_image); // update_rect(screen_rect); // redraw the dialog f.draw_background(); f.draw_border(); // cache the dialog background (alpha blending + blurred map) //SDL_BlitSurface(screen, &text_rect, text_surf, NULL); redraw_mapimage = false; } /* else { // redraw the saved part of the dialog where text scrolled // thus erasing all text SDL_Rect modified = {0,0, max_text_width, text_rect.h}; SDL_BlitSurface(text_surf, &modified, screen, &text_rect_blit); //update_rect(text_rect); } */ const int line_spacing = 5; int y = text_rect.y - offset; int line = startline; int cur_line = 0; max_text_width = 0; { // clip to keep text into the frame (thus the new code block) clip_rect_setter set_clip_rect(/*screen,*/ text_rect); do { // draw the text (with ellipsis if needed) // update the max_text_width for future cleaning int w = font::draw_text(&video, text_rect, def_size, def_color, text[line], text_rect.x, y).w; max_text_width = std::max<int>(max_text_width, w); // since the real drawing on screen is clipped, // we do a dummy one to get the height of the not clipped line. // (each time because special format characters may change it) const int line_height = font::draw_text(NULL, text_rect, def_size, def_color, text[line], 0,0).h; if(is_new_line) { is_new_line = false; first_line_height = line_height + line_spacing; } line++; if(size_t(line) > text.size()-1) line = 0; y += line_height + line_spacing; cur_line++; } while(y < text_rect.y + text_rect.h); } // performs the actual scrolling offset += scroll_speed; if (offset>=first_line_height) { offset -= first_line_height; is_new_line = true; startline++; if(size_t(startline) == text.size()){ startline = 0; image_count = -1; } } // handle events if (key[SDLK_UP] && scroll_speed < 20) { ++scroll_speed; } if (key[SDLK_DOWN] && scroll_speed > 0) { --scroll_speed; } events::pump(); events::raise_process_event(); events::raise_draw_event(); // flip screen and wait, so the text does not scroll too fast disp.flip(); disp.delay(20); } while(!close.pressed() && (last_escape || !key[SDLK_ESCAPE])); }