34 #include "widgets/button.hpp"
37 #define ERR_NG LOG_STREAM(err, log_engine)
38 #define WARN_NG LOG_STREAM(warn, log_engine)
39 #define LOG_NG LOG_STREAM(info, log_engine)
43 int const storybox_padding = 10;
45 int const storyshadow_a = 125;
47 double const storyshadow_opacity = 0.5;
49 int const storyshadow_r = 0;
50 int const storyshadow_g = 0;
51 int const storyshadow_b = 0;
53 int const titlebox_padding = 20;
54 int const titleshadow_padding = 5;
56 int const titleshadow_a = 125;
58 double const titleshadow_opacity = 0.5;
60 int const titleshadow_r = 0;
61 int const titleshadow_g = 0;
62 int const titleshadow_b = 0;
64 int const titlebox_font_size = 20;
65 int const storybox_font_size = 14;
67 Uint32
const titlebox_font_color = 0xFFFFFFFF;
68 Uint32
const storybox_font_color = 0xDDDDDDFF;
72 std::string const storybox_top_border_path =
"dialogs/translucent54-border-top.png";
73 std::string const storybox_bottom_border_path =
"dialogs/translucent54-border-bottom.png";
75 void blur_area(
CVideo& video,
int y,
int h)
90 :
events::sdl_handler(false)
94 , next_button_(next_button)
95 , back_button_(back_button)
96 , play_button_(play_button)
98 , ret_(
NEXT), skip_(false), last_key_(false)
99 , x_scale_factor_(1.0)
100 , y_scale_factor_(1.0)
103 , background_images_()
104 , background_positions_()
106 , background_(nullptr)
109 , has_background_(false)
124 bool no_base_yet =
true;
129 if (!bl.file().empty()) {
130 layer = image::get_texture(bl.file());
133 if(layer.null() || layer.width() * layer.height() == 0) {
137 const double xscale = 1.0 *
video_.
getx() / layer.base_width();
138 const double yscale = 1.0 *
video_.
gety() / layer.base_height();
139 const bool scalev = bl.scale_vertically();
140 const bool scaleh = bl.scale_horizontally();
141 const bool keep_ratio = bl.keep_aspect_ratio();
142 const bool tileh = bl.tile_horizontally();
143 const bool tilev = bl.tile_vertically();
145 double x_scale_factor = scaleh ? xscale : 1.0;
146 double y_scale_factor = scalev ? yscale : 1.0;
148 if (scalev && scaleh && keep_ratio) {
149 x_scale_factor = y_scale_factor = std::min<double>(xscale, yscale);
150 }
else if (keep_ratio && scaleh) {
151 x_scale_factor = y_scale_factor = xscale;
152 }
else if (keep_ratio && scalev) {
153 x_scale_factor = y_scale_factor = yscale;
156 layer.set_smooth_scaling(
true);
157 SDL_Rect clip =
sdl::create_rect(0, 0, layer.base_width(), layer.base_height());
159 clip.x = (layer.base_width() -
video_.
getx())/2;
164 clip.y = (layer.base_height() -
video_.
gety())/2;
168 layer.set_clip(clip);
169 layer.set_scale(x_scale_factor, y_scale_factor);
177 background_images_.push_back(layer);
178 background_positions_.push_back(std::pair<int, int>(base_rect.x, base_rect.y));
180 if (bl.is_base_layer() || no_base_yet) {
192 bool no_base_yet =
true;
198 if(bl.file().empty() !=
true) {
202 if(layer.
null() || layer->w * layer->h == 0) {
208 const double xscale = 1.0 *
video_.
getx() / layer->w;
209 const double yscale = 1.0 *
video_.
gety() / layer->h;
210 const bool scalev = bl.scale_vertically();
211 const bool scaleh = bl.scale_horizontally();
212 const bool keep_ratio = bl.keep_aspect_ratio();
214 double x_scale_factor = scaleh ? xscale : 1.0;
215 double y_scale_factor = scalev ? yscale : 1.0;
217 if (scalev && scaleh && keep_ratio) {
218 x_scale_factor = y_scale_factor = std::min<double>(xscale, yscale);
219 }
else if (keep_ratio && scaleh) {
220 x_scale_factor = y_scale_factor = xscale;
221 }
else if (keep_ratio && scalev) {
222 x_scale_factor = y_scale_factor = yscale;
225 layer =
scale_surface(layer, static_cast<int>(layer->w*x_scale_factor), static_cast<int>(layer->h*y_scale_factor),
false);
227 const int tilew = bl.tile_horizontally() ?
video_.
getx() : layer->w;
228 const int tileh = bl.tile_vertically() ?
video_.
gety() : layer->h;
242 SDL_Rect base_rect = drect;
257 ASSERT_LOG(layer.
null() ==
false,
"Oops: a storyscreen part background layer got nullptr");
259 if (bl.is_base_layer() || no_base_yet) {
330 if(!ri.image.null()) {
331 ri.image.draw(
video_, ri.rect.x, ri.rect.y);
338 for (
int i = 0;
i != (delay + delay_step - 1) / delay_step; ++
i)
360 if(!ri.image.null()) {
362 for (
size_t i = 0;
i <= fi_n;
i++)
373 for (
int i = 0;
i != (delay + delay_step - 1) / delay_step; ++
i)
392 if(titletxt.empty()) {
396 int titlebox_x, titlebox_y, titlebox_max_w, titlebox_max_h;
400 titlebox_x = titlebox_padding;
401 titlebox_max_w =
base_rect_.w - 2*titlebox_padding;
402 titlebox_y = titlebox_padding;
403 titlebox_max_h =
base_rect_.h - 2*titlebox_padding;
407 ERR_NG <<
"Text: Invalid markup in '"
408 << titletxt <<
"' rendered as is.\n";
417 sdl::timage txttxt = t.render_as_texture();
420 ERR_NG <<
"storyscreen titlebox rendering resulted in a null surface" << std::endl;
424 const int titlebox_w = txttxt.width();
425 const int titlebox_h = txttxt.height();
429 titlebox_x =
base_rect_.w / 2 - titlebox_w / 2 - titlebox_padding;
432 titlebox_x =
base_rect_.w - titlebox_padding - titlebox_w;
443 titlebox_x - titleshadow_padding,
444 titlebox_y - titleshadow_padding,
445 titlebox_w + 2*titleshadow_padding,
446 titlebox_h + 2*titleshadow_padding
452 video_.draw_texture(txttxt, titlebox_x, titlebox_y);
455 if(titletxt.empty()) {
459 int titlebox_x, titlebox_y, titlebox_max_w, titlebox_max_h;
463 titlebox_x = titlebox_padding;
464 titlebox_max_w =
base_rect_.w - 2*titlebox_padding;
465 titlebox_y = titlebox_padding;
466 titlebox_max_h =
base_rect_.h - 2*titlebox_padding;
470 ERR_NG <<
"Text: Invalid markup in '"
471 << titletxt <<
"' rendered as is.\n";
483 ERR_NG <<
"storyscreen titlebox rendering resulted in a null surface" << std::endl;
487 const int titlebox_w = txtsurf->w;
488 const int titlebox_h = txtsurf->h;
492 titlebox_x =
base_rect_.w / 2 - titlebox_w / 2 - titlebox_padding;
495 titlebox_x =
base_rect_.w - titlebox_padding - titlebox_w;
508 base_rect_.x + titlebox_x - titleshadow_padding,
509 base_rect_.y + titlebox_y - titleshadow_padding,
510 titlebox_w + 2*titleshadow_padding,
511 titlebox_h + 2*titleshadow_padding,
512 titleshadow_r, titleshadow_g, titleshadow_b,
520 static_cast<size_t>(std::max(0,
base_rect_.x + titlebox_x)),
521 static_cast<size_t>(std::max(0,
base_rect_.y + titlebox_y)),
522 static_cast<size_t>(std::max(0, titlebox_w)),
523 static_cast<size_t>(std::max(0, titlebox_h))
543 sdl::timage border_top;
544 sdl::timage border_bottom;
547 border_top = image::get_texture(storybox_top_border_path);
551 border_bottom = image::get_texture(storybox_bottom_border_path);
560 if(border_top.null() !=
true) {
561 const float xscale = float(
screen_area().
w) / border_top.base_width();
562 border_top.set_hscale(xscale);
564 video_.draw_texture(border_top, 0,
565 update_area.y - border_top.base_height());
568 if(border_bottom.null() !=
true) {
569 const float xscale = float(
screen_area().
w) / border_bottom.base_width();
570 border_bottom.set_hscale(xscale);
572 video_.draw_texture(border_bottom, 0,
573 update_area.y - border_top.base_height());
582 surface border_bottom =
nullptr;
598 if(border_top.
null() !=
true) {
600 WARN_NG <<
"storyscreen got a null top border surface after rescaling" << std::endl;
603 update_area.y -= border_top->h;
604 update_area.h += border_top->h;
605 blur_area(
video_, update_area.y, border_top->h);
610 if(border_bottom.
null() !=
true) {
612 WARN_NG <<
"storyscreen got a null bottom border surface after rescaling" << std::endl;
615 blur_area(
video_, update_area.h, border_bottom->h);
617 update_area.h += border_bottom->h;
628 LOG_NG <<
"ENTER part_ui()::render_story_box()\n";
631 if(storytxt.empty()) {
639 const int max_height =
screen_area().h - storybox_padding;
646 ERR_NG <<
"Text: Invalid markup in '"
647 <<
p_.
text() <<
"' rendered as is.\n";
655 sdl::timage txttxt = t.render_as_texture();
658 ERR_NG <<
"storyscreen text area rendering resulted in a null texture" << std::endl;
666 (std::max(0,
screen_area().
h - txttxt.height() - 2*(storybox_padding+1))) :
672 fix_text_h = std::max(txttxt.height() + 2*storybox_padding,
screen_area().h/4);
675 fix_text_h = std::max(txttxt.height() + 2*storybox_padding,
screen_area().h/3);
702 storyshadow_b, storyshadow_a);
712 const int scan_height = 1, scan_width = txttxt.width();
715 bool scan_finished =
false;
717 scan_finished = scan.y >= txttxt.base_height();
720 dstrect.y = fix_text_y + scan.y + storybox_padding;
721 txttxt.set_clip(scan);
722 video_.draw_texture(txttxt, dstrect.x, dstrect.y);
730 if (!
skip_ || scan_finished) {
739 LOG_NG<<
"ENTER part_ui()::render_story_box()\n";
756 if(storytxt.empty()) {
764 bool scan_finished =
false;
788 int max_height =
screen_area().h - storybox_padding;
791 ERR_NG <<
"Text: Invalid markup in '"
792 <<
p_.
text() <<
"' rendered as is.\n";
804 ERR_NG <<
"storyscreen text area rendering resulted in a null surface" << std::endl;
812 (std::max(0,
screen_area().
h - txtsurf->h - 2*(storybox_padding+1))) :
818 fix_text_h = std::max(txtsurf->h + 2*storybox_padding,
screen_area().
h/4);
821 fix_text_h = std::max(txtsurf->h + 2*storybox_padding,
screen_area().
h/3);
844 blur_area(
video_, fix_text_y, fix_text_h);
850 storyshadow_r, storyshadow_g, storyshadow_b,
864 if(!
imgs_.empty() && update_area.h > 0) {
871 const int scan_height = 1, scan_width = txtsurf->w;
880 scan_finished = scan.y >= txtsurf->h;
884 dstrect.y = fix_text_y + scan.y + storybox_padding;
899 if (!
skip_ || scan_finished) {
914 LOG_NG <<
"ENTER part_ui()::wait_for_input()\n";
927 bool next_keydown =
keys_[SDLK_SPACE] ||
keys_[SDLK_RETURN] ||
929 bool back_keydown =
keys_[SDLK_BACKSPACE] ||
keys_[SDLK_LEFT];
930 bool play_keydown =
keys_[SDLK_ESCAPE];
955 last_key_ = next_keydown || back_keydown || play_keydown;
971 if(
p_.
music().empty() !=
true) {
975 if(
p_.
sound().empty() !=
true) {
984 ERR_NG <<
"invalid UTF-8 sequence in story text, skipping part..." << std::endl;
1004 if (event.type == SDL_WINDOWEVENT &&
1005 (event.window.event == SDL_WINDOWEVENT_MAXIMIZED ||
1006 event.window.event == SDL_WINDOWEVENT_RESIZED ||
1007 event.window.event == SDL_WINDOWEVENT_EXPOSED ||
1008 event.window.event == SDL_WINDOWEVENT_RESTORED)) {
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
surface create_neutral_surface(int w, int h)
bool handle_interface()
Returns true if the user did an action.
static lg::log_domain log_engine("engine")
void fill_rect(surface &dst, SDL_Rect *dst_rect, const Uint32 color)
Fill a rectangle on a given surface.
Storyscreen parts and floating images representation.
virtual void handle_window_event(const SDL_Event &event)
The user pressed the go-next button.
ttext & set_font_style(const unsigned font_style)
SDL_Rect rect
Corrected rectangle for rendering surf.
BLOCK_LOCATION story_text_location() const
Retrieves the area of the screen on which the story text is displayed.
Center on the topmost edge of the screen.
ttext & set_font_size(const unsigned font_size)
const std::string & title() const
Retrieves the story screen title.
const std::vector< background_layer > & get_background_layers() const
Retrieve background layers for this story screen.
GLint GLint GLint GLint GLint GLint y
surface scale_surface(const surface &surf, int w, int h)
ttext & set_maximum_width(int width)
void blit_surface(int x, int y, surface surf, SDL_Rect *srcrect=nullptr, SDL_Rect *clip_rect=nullptr)
surface get_surface_portion(const surface &src, SDL_Rect &area)
Get a portion of the screen.
void prepare_background()
Constructor implementation details.
void play_sound(const std::string &files, channel_group group, unsigned int repeats)
void blit_surface(const surface &surf, const SDL_Rect *srcrect, surface &dst, const SDL_Rect *dstrect)
Replacement for sdl_blit.
The user pressed the go-back button.
void draw_solid_tinted_rectangle(int x, int y, int w, int h, int r, int g, int b, double alpha, surface target)
Fills a specified rectangle area of a surface with a given color and opacity.
GLenum GLenum GLuint GLint GLint layer
const std::string & music() const
Retrieves the background music.
ttext & set_maximum_height(int height, bool multiline)
Represents and contains information about image labels used in story screen parts.
Storyscreen parts rendering interface.
const std::string & text() const
Retrieves the story text itself.
GLubyte GLubyte GLubyte GLubyte w
RESULT
Storyscreen result.
gui::button & play_button_
surface blur_surface(const surface &surf, int depth, bool optimize)
Cross-fades a surface.
static const unsigned STYLE_NORMAL
The flags have the same values as the ones in SDL_TTF so it's easy to mix them for now...
Represents and contains information about a single storyscreen part.
bool render_floating_images()
Renders all floating images in sequence.
void raise_process_event()
const std::string & sound() const
Retrieves a one-time-only sound effect.
surface render() const
Returns the rendered text.
Thrown by operations encountering invalid UTF-8 data.
gui::button & next_button_
RESULT show()
Render and display the storyscreen, process and return user input.
GLfloat GLfloat GLfloat GLfloat h
virtual void handle_event(const SDL_Event &)
gui::button & back_button_
int display_delay() const
Delay before displaying, in milliseconds.
void render_story_box_borders(SDL_Rect &)
Handling of system events.
SDL_Rect create_rect(const int x, const int y, const int w, const int h)
Creates an empty SDL_Rect.
bool show_title() const
Whether the story screen title should be displayed or not.
Contains the SDL_Rect helper code.
surface tile_surface(const surface &surf, int w, int h, bool optimize)
Tile a surface.
void play_music_repeatedly(const std::string &id)
surface make_neutral_surface(const surface &surf)
TEXT_ALIGNMENT title_text_alignment() const
Retrieves the alignment of the title text against the screen.
Standard logging facilities (interface).
void assign(const surface &o)
static void delay(unsigned int milliseconds)
bool set_text(const std::string &text, const bool markedup)
Sets the text to render.
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
surface image
Surface, scaled if required.
std::vector< floating_image::render_input > imgs_
part_ui(part &p, CVideo &video, gui::button &next_button, gui::button &back_button, gui::button &play_button)
Constructor.
void update_rect(const SDL_Rect &)
const std::vector< floating_image > & get_floating_images() const
Retrieve any associated floating images for this story screen.
GLsizei const GLcharARB ** string
void prepare_floating_images()
Constructor implementation details.
BLOCK_LOCATION
Currently used to indicate where the text block should be placed.
void prepare_geometry()
Constructor implementation details.
ttext & set_foreground_color(const Uint32 color)