From ea212b5bc257a1cfc77f5667756bac67560354b2 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Sat, 7 Mar 2015 21:22:03 -0500 Subject: [PATCH] move class floating_label from font.cpp to its own file floating_label is essentially a primitive GUI1 widget, consisting just of a text label and non-interacting. It's also used for the map labels displayed in-game iiuc. --- src/CMakeLists.txt | 1 + src/SConscript | 1 + src/display_chat_manager.cpp | 2 +- src/floating_label.cpp | 509 +++++++++++++++++++++ src/floating_label.hpp | 149 ++++++ src/floating_textbox.cpp | 1 + src/font.cpp | 478 ------------------- src/font.hpp | 125 ----- src/game_display.cpp | 1 + src/game_initialization/multiplayer_ui.hpp | 1 + src/gui/widgets/window.cpp | 1 + src/map_label.cpp | 1 + src/play_controller.hpp | 1 + src/show_dialog.cpp | 1 + src/show_dialog.hpp | 1 + src/tooltips.cpp | 1 + src/video.cpp | 1 + src/wesnoth.cpp | 1 + 18 files changed, 672 insertions(+), 604 deletions(-) create mode 100644 src/floating_label.cpp create mode 100644 src/floating_label.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3be2ddcfcf7e..31de7c98e8c8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1044,6 +1044,7 @@ set(libwesnoth-game_STAT_SRC display.cpp display_context.cpp events.cpp + floating_label.cpp font.cpp format_time_summary.cpp generators/cave_map_generator.cpp diff --git a/src/SConscript b/src/SConscript index 559390f598c8..7451d1c71489 100644 --- a/src/SConscript +++ b/src/SConscript @@ -80,6 +80,7 @@ libwesnoth_sources = Split(""" display.cpp display_context.cpp events.cpp + floating_label.cpp format_time_summary.cpp generic_event.cpp hotkey/hotkey_item.cpp diff --git a/src/display_chat_manager.cpp b/src/display_chat_manager.cpp index 50e72c0c6146..0d72c24249aa 100644 --- a/src/display_chat_manager.cpp +++ b/src/display_chat_manager.cpp @@ -17,7 +17,7 @@ #include "desktop/notifications.hpp" #include "display.hpp" -#include "font.hpp" +#include "floating_label.hpp" #include "game_board.hpp" // <-- only needed for is_observer() #include "game_preferences.hpp" #include "log.hpp" diff --git a/src/floating_label.cpp b/src/floating_label.cpp new file mode 100644 index 000000000000..93d7e1f864d7 --- /dev/null +++ b/src/floating_label.cpp @@ -0,0 +1,509 @@ +/* + Copyright (C) 2003 by David White + Part of the Battle for Wesnoth Project http://www.wesnoth.org/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. + + See the COPYING file for more details. +*/ + +#include "floating_label.hpp" + +#include "display.hpp" +#include "font.hpp" +#include "log.hpp" +#include "text.hpp" + +#include +#include +#include + +static lg::log_domain log_font("font"); +#define DBG_FT LOG_STREAM(debug, log_font) +#define LOG_FT LOG_STREAM(info, log_font) +#define WRN_FT LOG_STREAM(warn, log_font) +#define ERR_FT LOG_STREAM(err, log_font) + +namespace { + +typedef std::map label_map; +label_map labels; +int label_id = 1; + +std::stack > label_contexts; +} + +namespace font { + +floating_label::floating_label(const std::string& text, const surface& surf) +#if 0 + : img_(), +#else + : surf_(surf), buf_(NULL), +#endif + text_(text), + font_size_(SIZE_NORMAL), + color_(NORMAL_COLOR), bgcolor_(), bgalpha_(0), + xpos_(0), ypos_(0), + xmove_(0), ymove_(0), lifetime_(-1), + width_(-1), height_(-1), + clip_rect_(screen_area()), + alpha_change_(0), visible_(true), align_(CENTER_ALIGN), + border_(0), scroll_(ANCHOR_LABEL_SCREEN), use_markup_(true) +{} + +void floating_label::move(double xmove, double ymove) +{ + xpos_ += xmove; + ypos_ += ymove; +} + +int floating_label::xpos(size_t width) const +{ + int xpos = int(xpos_); + if(align_ == font::CENTER_ALIGN) { + xpos -= width/2; + } else if(align_ == font::RIGHT_ALIGN) { + xpos -= width; + } + + return xpos; +} + +#if 0 +sdl::timage floating_label::create_image() +{ + if (img_.null()) { + font::ttext text; + text.set_foreground_color((color_.r << 24) | (color_.g << 16) | (color_.b << 8) | 255); + text.set_font_size(font_size_); + text.set_maximum_width(width_ < 0 ? clip_rect_.w : width_); + text.set_maximum_height(height_ < 0 ? clip_rect_.h : height_, true); + + //ignore last '\n' + if(!text_.empty() && *(text_.rbegin()) == '\n'){ + text.set_text(std::string(text_.begin(), text_.end()-1), use_markup_); + } else { + text.set_text(text_, use_markup_); + } + + surface foreground = text.render(); + + if(foreground == NULL) { + ERR_FT << "could not create floating label's text" << std::endl; + return sdl::timage(); + } + + // combine foreground text with its background + if(bgalpha_ != 0) { + // background is a dark tooltip box + surface background = create_neutral_surface(foreground->w + border_*2, foreground->h + border_*2); + + if (background == NULL) { + ERR_FT << "could not create tooltip box" << std::endl; + img_ = sdl::timage(foreground); + return img_; + } + + Uint32 color = SDL_MapRGBA(foreground->format, bgcolor_.r,bgcolor_.g, bgcolor_.b, bgalpha_); + sdl::fill_rect(background,NULL, color); + + // we make the text less transparent, because the blitting on the + // dark background will darken the anti-aliased part. + // This 1.13 value seems to restore the brightness of version 1.4 + // (where the text was blitted directly on screen) + foreground = adjust_surface_alpha(foreground, ftofxp(1.13), false); + + SDL_Rect r = sdl::create_rect( border_, border_, 0, 0); + SDL_SetAlpha(foreground,SDL_SRCALPHA,SDL_ALPHA_OPAQUE); + blit_surface(foreground, NULL, background, &r); + + img_ = sdl::timage(background); + } + else { + // background is blurred shadow of the text + surface background = create_neutral_surface + (foreground->w + 4, foreground->h + 4); + sdl::fill_rect(background, NULL, 0); + SDL_Rect r = { 2, 2, 0, 0 }; + blit_surface(foreground, NULL, background, &r); + background = shadow_image(background, false); + + if (background == NULL) { + ERR_FT << "could not create floating label's shadow" << std::endl; + img_ = sdl::timage(foreground); + return img_; + } + SDL_SetAlpha(foreground,SDL_SRCALPHA,SDL_ALPHA_OPAQUE); + blit_surface(foreground, NULL, background, &r); + img_ = sdl::timage(background); + } + } + + return img_; +} + +#else +surface floating_label::create_surface() +{ + if (surf_.null()) { + font::ttext text; + text.set_foreground_color((color_.r << 24) | (color_.g << 16) | (color_.b << 8) | 255); + text.set_font_size(font_size_); + text.set_maximum_width(width_ < 0 ? clip_rect_.w : width_); + text.set_maximum_height(height_ < 0 ? clip_rect_.h : height_, true); + + //ignore last '\n' + if(!text_.empty() && *(text_.rbegin()) == '\n'){ + text.set_text(std::string(text_.begin(), text_.end()-1), use_markup_); + } else { + text.set_text(text_, use_markup_); + } + + surface foreground = text.render(); + + if(foreground == NULL) { + ERR_FT << "could not create floating label's text" << std::endl; + return NULL; + } + + // combine foreground text with its background + if(bgalpha_ != 0) { + // background is a dark tooltip box + surface background = create_neutral_surface(foreground->w + border_*2, foreground->h + border_*2); + + if (background == NULL) { + ERR_FT << "could not create tooltip box" << std::endl; + surf_ = create_optimized_surface(foreground); + return surf_; + } + + Uint32 color = SDL_MapRGBA(foreground->format, bgcolor_.r,bgcolor_.g, bgcolor_.b, bgalpha_); + sdl::fill_rect(background,NULL, color); + + // we make the text less transparent, because the blitting on the + // dark background will darken the anti-aliased part. + // This 1.13 value seems to restore the brightness of version 1.4 + // (where the text was blitted directly on screen) + foreground = adjust_surface_alpha(foreground, ftofxp(1.13), false); + + SDL_Rect r = sdl::create_rect( border_, border_, 0, 0); + SDL_SetAlpha(foreground,SDL_SRCALPHA,SDL_ALPHA_OPAQUE); + blit_surface(foreground, NULL, background, &r); + + surf_ = create_optimized_surface(background); + // RLE compression seems less efficient for big semi-transparent area + // so, remove it for this case, but keep the optimized display format + SDL_SetAlpha(surf_,SDL_SRCALPHA,SDL_ALPHA_OPAQUE); + } + else { + // background is blurred shadow of the text + surface background = create_neutral_surface + (foreground->w + 4, foreground->h + 4); + sdl::fill_rect(background, NULL, 0); + SDL_Rect r = { 2, 2, 0, 0 }; + blit_surface(foreground, NULL, background, &r); + background = shadow_image(background, false); + + if (background == NULL) { + ERR_FT << "could not create floating label's shadow" << std::endl; + surf_ = create_optimized_surface(foreground); + return surf_; + } + SDL_SetAlpha(foreground,SDL_SRCALPHA,SDL_ALPHA_OPAQUE); + blit_surface(foreground, NULL, background, &r); + surf_ = create_optimized_surface(background); + } + } + + return surf_; +} +#endif + +#ifdef SDL_GPU +void floating_label::draw(CVideo &video) +{ + if (!visible_) { + return; + } +#if 0 + create_image(); + if (img_.null()) { + return; + } + + video.draw_texture(img_, xpos(img_.width()), int(ypos_)); +#else + create_surface(); + if (surf_.null()) { + return; + } + + video.blit_to_overlay(surf_, xpos(surf_->w), int(ypos_)); +#endif +} + +#else +void floating_label::draw(surface screen) +{ + if(!visible_) { + buf_.assign(NULL); + return; + } + + create_surface(); + if(surf_ == NULL) { + return; + } + + if(buf_ == NULL) { + buf_.assign(create_compatible_surface(screen, surf_->w, surf_->h)); + if(buf_ == NULL) { + return; + } + } + + if(screen == NULL) { + return; + } + + SDL_Rect rect = sdl::create_rect(xpos(surf_->w), ypos_, surf_->w, surf_->h); + const clip_rect_setter clip_setter(screen, &clip_rect_); + sdl_blit(screen,&rect,buf_,NULL); + sdl_blit(surf_,NULL,screen,&rect); + + update_rect(rect); +} +#endif + +#ifdef SDL_GPU +void floating_label::undraw(CVideo &video) +{ + SDL_Rect r = sdl::create_rect(xpos(surf_->w), ypos_, surf_->w, surf_->h); + video.clear_overlay_area(r); +} +#else +void floating_label::undraw(surface screen) +{ + if(screen == NULL || buf_ == NULL) { + return; + } + SDL_Rect rect = sdl::create_rect(xpos(surf_->w), ypos_, surf_->w, surf_->h); + const clip_rect_setter clip_setter(screen, &clip_rect_); + sdl_blit(buf_,NULL,screen,&rect); + + update_rect(rect); + + move(xmove_,ymove_); + if(lifetime_ > 0) { + --lifetime_; + if(alpha_change_ != 0 && (xmove_ != 0.0 || ymove_ != 0.0) && surf_ != NULL) { + // fade out moving floating labels + // note that we don't optimize these surfaces since they will always change + surf_.assign(adjust_surface_alpha_add(surf_,alpha_change_,false)); + } + } +} +#endif + +int add_floating_label(const floating_label& flabel) +{ + if(label_contexts.empty()) { + return 0; + } + + ++label_id; + labels.insert(std::pair(label_id, flabel)); + label_contexts.top().insert(label_id); + return label_id; +} + +void move_floating_label(int handle, double xmove, double ymove) +{ + const label_map::iterator i = labels.find(handle); + if(i != labels.end()) { + i->second.move(xmove,ymove); + } +} + +void scroll_floating_labels(double xmove, double ymove) +{ + for(label_map::iterator i = labels.begin(); i != labels.end(); ++i) { + if(i->second.scroll() == ANCHOR_LABEL_MAP) { + i->second.move(xmove,ymove); + } + } +} + +void remove_floating_label(int handle) +{ + const label_map::iterator i = labels.find(handle); + if(i != labels.end()) { + if(label_contexts.empty() == false) { + label_contexts.top().erase(i->first); + } + + labels.erase(i); + } +} + +void show_floating_label(int handle, bool value) +{ + const label_map::iterator i = labels.find(handle); + if(i != labels.end()) { + i->second.show(value); + } +} + +SDL_Rect get_floating_label_rect(int handle) +{ + const label_map::iterator i = labels.find(handle); +#if 0 + if(i != labels.end()) { + const sdl::timage img = i->second.create_image(); + if(!img.null()) { + return sdl::create_rect(0, 0, img.width(), img.height()); + } + } +#else + if(i != labels.end()) { + const surface surf = i->second.create_surface(); + if(surf != NULL) { + return sdl::create_rect(0, 0, surf->w, surf->h); + } + } +#endif + return sdl::empty_rect; +} + +floating_label_context::floating_label_context() +{ +#ifdef SDL_GPU + +#else +#if SDL_VERSION_ATLEAST(2, 0, 0) + surface const screen = NULL; +#else + surface const screen = SDL_GetVideoSurface(); +#endif + if(screen != NULL) { + draw_floating_labels(screen); + } +#endif + + label_contexts.push(std::set()); +} + +floating_label_context::~floating_label_context() +{ + const std::set& labels = label_contexts.top(); + for(std::set::const_iterator i = labels.begin(); i != labels.end(); ) { + remove_floating_label(*i++); + } + + label_contexts.pop(); + +#ifdef SDL_GPU + //TODO +#else +#if SDL_VERSION_ATLEAST(2, 0, 0) + surface const screen = NULL; +#else + surface const screen = SDL_GetVideoSurface(); +#endif + if(screen != NULL) { + undraw_floating_labels(screen); + } +#endif +} + +#ifdef SDL_GPU +void draw_floating_labels(CVideo &video) +{ + if(label_contexts.empty()) { + return; + } + + const std::set& context = label_contexts.top(); + + //draw the labels in the order they were added, so later added labels (likely to be tooltips) + //are displayed over earlier added labels. + for(label_map::iterator i = labels.begin(); i != labels.end(); ++i) { + if(context.count(i->first) > 0) { + i->second.draw(video); + } + } +} + +void undraw_floating_labels(CVideo &video) +{ + if(label_contexts.empty()) { + return; + } + + std::set& context = label_contexts.top(); + + //remove expired labels + for(label_map::iterator j = labels.begin(); j != labels.end(); ) { + if(context.count(j->first) > 0 && j->second.expired()) { + j->second.undraw(video); + context.erase(j->first); + labels.erase(j++); + } else { + ++j; + } + } +} + +#else +void draw_floating_labels(surface screen) +{ + if(label_contexts.empty()) { + return; + } + + const std::set& context = label_contexts.top(); + + //draw the labels in the order they were added, so later added labels (likely to be tooltips) + //are displayed over earlier added labels. + for(label_map::iterator i = labels.begin(); i != labels.end(); ++i) { + if(context.count(i->first) > 0) { + i->second.draw(screen); + } + } +} + +void undraw_floating_labels(surface screen) +{ + if(label_contexts.empty()) { + return; + } + + std::set& context = label_contexts.top(); + + //undraw labels in reverse order, so that a LIFO process occurs, and the screen is restored + //into the exact state it started in. + for(label_map::reverse_iterator i = labels.rbegin(); i != labels.rend(); ++i) { + if(context.count(i->first) > 0) { + i->second.undraw(screen); + } + } + + //remove expired labels + for(label_map::iterator j = labels.begin(); j != labels.end(); ) { + if(context.count(j->first) > 0 && j->second.expired()) { + context.erase(j->first); + labels.erase(j++); + } else { + ++j; + } + } +} +#endif +} + diff --git a/src/floating_label.hpp b/src/floating_label.hpp new file mode 100644 index 000000000000..81029a2f6c0e --- /dev/null +++ b/src/floating_label.hpp @@ -0,0 +1,149 @@ +/* + Copyright (C) 2003 by David White + Part of the Battle for Wesnoth Project http://www.wesnoth.org/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. + + See the COPYING file for more details. +*/ + +#pragma once + +#include "font.hpp" + +#include "sdl/utils.hpp" +#include + +namespace font { + +/// structure which will hide all current floating labels, and cause floating labels +/// instantiated after it is created to be displayed +struct floating_label_context +{ + floating_label_context(); + ~floating_label_context(); +}; + +enum ALIGN { LEFT_ALIGN, CENTER_ALIGN, RIGHT_ALIGN }; + +enum LABEL_SCROLL_MODE { ANCHOR_LABEL_SCREEN, ANCHOR_LABEL_MAP }; + +class floating_label +{ +public: + floating_label(const std::string& text, const surface& surface = NULL); + + void set_font_size(int font_size) {font_size_ = font_size;} + + // set the location on the screen to display the text. + void set_position(double xpos, double ypos){ + xpos_ = xpos; + ypos_ = ypos; + } + // set the amount to move the text each frame + void set_move(double xmove, double ymove){ + xmove_ = xmove; + ymove_ = ymove; + } + // set the number of frames to display the text for, or -1 to display until removed + void set_lifetime(int lifetime) { + lifetime_ = lifetime; + alpha_change_ = -255 / lifetime_; + } + void set_color(const SDL_Color& color) {color_ = color;} + void set_bg_color(const SDL_Color& bg_color) { + bgcolor_ = bg_color; +#if SDL_VERSION_ATLEAST(2,0,0) + bgalpha_ = bg_color.a; +#else + bgalpha_ = bg_color.unused; +#endif + } + void set_border_size(int border) {border_ = border;} + // set width for word wrapping (use -1 to disable it) + void set_width(int w) {width_ = w;} + void set_height(int h) { height_ = h; } + void set_clip_rect(const SDL_Rect& r) {clip_rect_ = r;} + void set_alignment(ALIGN align) {align_ = align;} + void set_scroll_mode(LABEL_SCROLL_MODE scroll) {scroll_ = scroll;} + void use_markup(bool b) {use_markup_ = b;} + + void move(double xmove, double ymove); +#ifdef SDL_GPU + void draw(CVideo &video); + void undraw(CVideo &video); +#else + void draw(surface screen); + void undraw(surface screen); +#endif + +#if 0 + sdl::timage create_image(); +#else + surface create_surface(); +#endif + + bool expired() const { return lifetime_ == 0; } + + void show(const bool value) { visible_ = value; } + + LABEL_SCROLL_MODE scroll() const { return scroll_; } + +private: + + int xpos(size_t width) const; +#if 0 + sdl::timage img_; +#else + surface surf_, buf_; +#endif + std::string text_; + int font_size_; + SDL_Color color_, bgcolor_; + int bgalpha_; + double xpos_, ypos_, xmove_, ymove_; + int lifetime_; + int width_, height_; + SDL_Rect clip_rect_; + int alpha_change_; + bool visible_; + font::ALIGN align_; + int border_; + LABEL_SCROLL_MODE scroll_; + bool use_markup_; +}; + + +/// add a label floating on the screen above everything else. +/// @returns a handle to the label which can be used with other label functions + +int add_floating_label(const floating_label& flabel); + + +/// moves the floating label given by 'handle' by (xmove,ymove) +void move_floating_label(int handle, double xmove, double ymove); + +/// moves all floating labels that have 'scroll_mode' set to ANCHOR_LABEL_MAP +void scroll_floating_labels(double xmove, double ymove); + +/// removes the floating label given by 'handle' from the screen +void remove_floating_label(int handle); + +/// hides or shows a floating label +void show_floating_label(int handle, bool show); + +SDL_Rect get_floating_label_rect(int handle); +#ifdef SDL_GPU +void draw_floating_labels(CVideo &video); +void undraw_floating_labels(CVideo &video); +#else +void draw_floating_labels(surface screen); +void undraw_floating_labels(surface screen); +#endif + +} // end namespace font diff --git a/src/floating_textbox.cpp b/src/floating_textbox.cpp index 3db7b0ee91a4..d975fe03379e 100644 --- a/src/floating_textbox.cpp +++ b/src/floating_textbox.cpp @@ -17,6 +17,7 @@ #include "floating_textbox.hpp" #include "display_chat_manager.hpp" +#include "floating_label.hpp" #include "game_display.hpp" #include "game_preferences.hpp" #include "log.hpp" diff --git a/src/font.cpp b/src/font.cpp index 9949fc2db58a..8e4b907e7bd8 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -1028,484 +1028,6 @@ std::string make_text_ellipsis(const std::string &text, int font_size, } -namespace { - -typedef std::map label_map; -label_map labels; -int label_id = 1; - -std::stack > label_contexts; -} - - -namespace font { - -floating_label::floating_label(const std::string& text, const surface& surf) -#if 0 - : img_(), -#else - : surf_(surf), buf_(NULL), -#endif - text_(text), - font_size_(SIZE_NORMAL), - color_(NORMAL_COLOR), bgcolor_(), bgalpha_(0), - xpos_(0), ypos_(0), - xmove_(0), ymove_(0), lifetime_(-1), - width_(-1), height_(-1), - clip_rect_(screen_area()), - alpha_change_(0), visible_(true), align_(CENTER_ALIGN), - border_(0), scroll_(ANCHOR_LABEL_SCREEN), use_markup_(true) -{} - -void floating_label::move(double xmove, double ymove) -{ - xpos_ += xmove; - ypos_ += ymove; -} - -int floating_label::xpos(size_t width) const -{ - int xpos = int(xpos_); - if(align_ == font::CENTER_ALIGN) { - xpos -= width/2; - } else if(align_ == font::RIGHT_ALIGN) { - xpos -= width; - } - - return xpos; -} - -#if 0 -sdl::timage floating_label::create_image() -{ - if (img_.null()) { - font::ttext text; - text.set_foreground_color((color_.r << 24) | (color_.g << 16) | (color_.b << 8) | 255); - text.set_font_size(font_size_); - text.set_maximum_width(width_ < 0 ? clip_rect_.w : width_); - text.set_maximum_height(height_ < 0 ? clip_rect_.h : height_, true); - - //ignore last '\n' - if(!text_.empty() && *(text_.rbegin()) == '\n'){ - text.set_text(std::string(text_.begin(), text_.end()-1), use_markup_); - } else { - text.set_text(text_, use_markup_); - } - - surface foreground = text.render(); - - if(foreground == NULL) { - ERR_FT << "could not create floating label's text" << std::endl; - return sdl::timage(); - } - - // combine foreground text with its background - if(bgalpha_ != 0) { - // background is a dark tooltip box - surface background = create_neutral_surface(foreground->w + border_*2, foreground->h + border_*2); - - if (background == NULL) { - ERR_FT << "could not create tooltip box" << std::endl; - img_ = sdl::timage(foreground); - return img_; - } - - Uint32 color = SDL_MapRGBA(foreground->format, bgcolor_.r,bgcolor_.g, bgcolor_.b, bgalpha_); - sdl::fill_rect(background,NULL, color); - - // we make the text less transparent, because the blitting on the - // dark background will darken the anti-aliased part. - // This 1.13 value seems to restore the brightness of version 1.4 - // (where the text was blitted directly on screen) - foreground = adjust_surface_alpha(foreground, ftofxp(1.13), false); - - SDL_Rect r = sdl::create_rect( border_, border_, 0, 0); - SDL_SetAlpha(foreground,SDL_SRCALPHA,SDL_ALPHA_OPAQUE); - blit_surface(foreground, NULL, background, &r); - - img_ = sdl::timage(background); - } - else { - // background is blurred shadow of the text - surface background = create_neutral_surface - (foreground->w + 4, foreground->h + 4); - sdl::fill_rect(background, NULL, 0); - SDL_Rect r = { 2, 2, 0, 0 }; - blit_surface(foreground, NULL, background, &r); - background = shadow_image(background, false); - - if (background == NULL) { - ERR_FT << "could not create floating label's shadow" << std::endl; - img_ = sdl::timage(foreground); - return img_; - } - SDL_SetAlpha(foreground,SDL_SRCALPHA,SDL_ALPHA_OPAQUE); - blit_surface(foreground, NULL, background, &r); - img_ = sdl::timage(background); - } - } - - return img_; -} - -#else -surface floating_label::create_surface() -{ - if (surf_.null()) { - font::ttext text; - text.set_foreground_color((color_.r << 24) | (color_.g << 16) | (color_.b << 8) | 255); - text.set_font_size(font_size_); - text.set_maximum_width(width_ < 0 ? clip_rect_.w : width_); - text.set_maximum_height(height_ < 0 ? clip_rect_.h : height_, true); - - //ignore last '\n' - if(!text_.empty() && *(text_.rbegin()) == '\n'){ - text.set_text(std::string(text_.begin(), text_.end()-1), use_markup_); - } else { - text.set_text(text_, use_markup_); - } - - surface foreground = text.render(); - - if(foreground == NULL) { - ERR_FT << "could not create floating label's text" << std::endl; - return NULL; - } - - // combine foreground text with its background - if(bgalpha_ != 0) { - // background is a dark tooltip box - surface background = create_neutral_surface(foreground->w + border_*2, foreground->h + border_*2); - - if (background == NULL) { - ERR_FT << "could not create tooltip box" << std::endl; - surf_ = create_optimized_surface(foreground); - return surf_; - } - - Uint32 color = SDL_MapRGBA(foreground->format, bgcolor_.r,bgcolor_.g, bgcolor_.b, bgalpha_); - sdl::fill_rect(background,NULL, color); - - // we make the text less transparent, because the blitting on the - // dark background will darken the anti-aliased part. - // This 1.13 value seems to restore the brightness of version 1.4 - // (where the text was blitted directly on screen) - foreground = adjust_surface_alpha(foreground, ftofxp(1.13), false); - - SDL_Rect r = sdl::create_rect( border_, border_, 0, 0); - SDL_SetAlpha(foreground,SDL_SRCALPHA,SDL_ALPHA_OPAQUE); - blit_surface(foreground, NULL, background, &r); - - surf_ = create_optimized_surface(background); - // RLE compression seems less efficient for big semi-transparent area - // so, remove it for this case, but keep the optimized display format - SDL_SetAlpha(surf_,SDL_SRCALPHA,SDL_ALPHA_OPAQUE); - } - else { - // background is blurred shadow of the text - surface background = create_neutral_surface - (foreground->w + 4, foreground->h + 4); - sdl::fill_rect(background, NULL, 0); - SDL_Rect r = { 2, 2, 0, 0 }; - blit_surface(foreground, NULL, background, &r); - background = shadow_image(background, false); - - if (background == NULL) { - ERR_FT << "could not create floating label's shadow" << std::endl; - surf_ = create_optimized_surface(foreground); - return surf_; - } - SDL_SetAlpha(foreground,SDL_SRCALPHA,SDL_ALPHA_OPAQUE); - blit_surface(foreground, NULL, background, &r); - surf_ = create_optimized_surface(background); - } - } - - return surf_; -} -#endif - -#ifdef SDL_GPU -void floating_label::draw(CVideo &video) -{ - if (!visible_) { - return; - } -#if 0 - create_image(); - if (img_.null()) { - return; - } - - video.draw_texture(img_, xpos(img_.width()), int(ypos_)); -#else - create_surface(); - if (surf_.null()) { - return; - } - - video.blit_to_overlay(surf_, xpos(surf_->w), int(ypos_)); -#endif -} - -#else -void floating_label::draw(surface screen) -{ - if(!visible_) { - buf_.assign(NULL); - return; - } - - create_surface(); - if(surf_ == NULL) { - return; - } - - if(buf_ == NULL) { - buf_.assign(create_compatible_surface(screen, surf_->w, surf_->h)); - if(buf_ == NULL) { - return; - } - } - - if(screen == NULL) { - return; - } - - SDL_Rect rect = sdl::create_rect(xpos(surf_->w), ypos_, surf_->w, surf_->h); - const clip_rect_setter clip_setter(screen, &clip_rect_); - sdl_blit(screen,&rect,buf_,NULL); - sdl_blit(surf_,NULL,screen,&rect); - - update_rect(rect); -} -#endif - -#ifdef SDL_GPU -void floating_label::undraw(CVideo &video) -{ - SDL_Rect r = sdl::create_rect(xpos(surf_->w), ypos_, surf_->w, surf_->h); - video.clear_overlay_area(r); -} -#else -void floating_label::undraw(surface screen) -{ - if(screen == NULL || buf_ == NULL) { - return; - } - SDL_Rect rect = sdl::create_rect(xpos(surf_->w), ypos_, surf_->w, surf_->h); - const clip_rect_setter clip_setter(screen, &clip_rect_); - sdl_blit(buf_,NULL,screen,&rect); - - update_rect(rect); - - move(xmove_,ymove_); - if(lifetime_ > 0) { - --lifetime_; - if(alpha_change_ != 0 && (xmove_ != 0.0 || ymove_ != 0.0) && surf_ != NULL) { - // fade out moving floating labels - // note that we don't optimize these surfaces since they will always change - surf_.assign(adjust_surface_alpha_add(surf_,alpha_change_,false)); - } - } -} -#endif - -int add_floating_label(const floating_label& flabel) -{ - if(label_contexts.empty()) { - return 0; - } - - ++label_id; - labels.insert(std::pair(label_id, flabel)); - label_contexts.top().insert(label_id); - return label_id; -} - -void move_floating_label(int handle, double xmove, double ymove) -{ - const label_map::iterator i = labels.find(handle); - if(i != labels.end()) { - i->second.move(xmove,ymove); - } -} - -void scroll_floating_labels(double xmove, double ymove) -{ - for(label_map::iterator i = labels.begin(); i != labels.end(); ++i) { - if(i->second.scroll() == ANCHOR_LABEL_MAP) { - i->second.move(xmove,ymove); - } - } -} - -void remove_floating_label(int handle) -{ - const label_map::iterator i = labels.find(handle); - if(i != labels.end()) { - if(label_contexts.empty() == false) { - label_contexts.top().erase(i->first); - } - - labels.erase(i); - } -} - -void show_floating_label(int handle, bool value) -{ - const label_map::iterator i = labels.find(handle); - if(i != labels.end()) { - i->second.show(value); - } -} - -SDL_Rect get_floating_label_rect(int handle) -{ - const label_map::iterator i = labels.find(handle); -#if 0 - if(i != labels.end()) { - const sdl::timage img = i->second.create_image(); - if(!img.null()) { - return sdl::create_rect(0, 0, img.width(), img.height()); - } - } -#else - if(i != labels.end()) { - const surface surf = i->second.create_surface(); - if(surf != NULL) { - return sdl::create_rect(0, 0, surf->w, surf->h); - } - } -#endif - return sdl::empty_rect; -} - -floating_label_context::floating_label_context() -{ -#ifdef SDL_GPU - -#else -#if SDL_VERSION_ATLEAST(2, 0, 0) - surface const screen = NULL; -#else - surface const screen = SDL_GetVideoSurface(); -#endif - if(screen != NULL) { - draw_floating_labels(screen); - } -#endif - - label_contexts.push(std::set()); -} - -floating_label_context::~floating_label_context() -{ - const std::set& labels = label_contexts.top(); - for(std::set::const_iterator i = labels.begin(); i != labels.end(); ) { - remove_floating_label(*i++); - } - - label_contexts.pop(); - -#ifdef SDL_GPU - //TODO -#else -#if SDL_VERSION_ATLEAST(2, 0, 0) - surface const screen = NULL; -#else - surface const screen = SDL_GetVideoSurface(); -#endif - if(screen != NULL) { - undraw_floating_labels(screen); - } -#endif -} - -#ifdef SDL_GPU -void draw_floating_labels(CVideo &video) -{ - if(label_contexts.empty()) { - return; - } - - const std::set& context = label_contexts.top(); - - //draw the labels in the order they were added, so later added labels (likely to be tooltips) - //are displayed over earlier added labels. - for(label_map::iterator i = labels.begin(); i != labels.end(); ++i) { - if(context.count(i->first) > 0) { - i->second.draw(video); - } - } -} - -void undraw_floating_labels(CVideo &video) -{ - if(label_contexts.empty()) { - return; - } - - std::set& context = label_contexts.top(); - - //remove expired labels - for(label_map::iterator j = labels.begin(); j != labels.end(); ) { - if(context.count(j->first) > 0 && j->second.expired()) { - j->second.undraw(video); - context.erase(j->first); - labels.erase(j++); - } else { - ++j; - } - } -} - -#else -void draw_floating_labels(surface screen) -{ - if(label_contexts.empty()) { - return; - } - - const std::set& context = label_contexts.top(); - - //draw the labels in the order they were added, so later added labels (likely to be tooltips) - //are displayed over earlier added labels. - for(label_map::iterator i = labels.begin(); i != labels.end(); ++i) { - if(context.count(i->first) > 0) { - i->second.draw(screen); - } - } -} - -void undraw_floating_labels(surface screen) -{ - if(label_contexts.empty()) { - return; - } - - std::set& context = label_contexts.top(); - - //undraw labels in reverse order, so that a LIFO process occurs, and the screen is restored - //into the exact state it started in. - for(label_map::reverse_iterator i = labels.rbegin(); i != labels.rend(); ++i) { - if(context.count(i->first) > 0) { - i->second.undraw(screen); - } - } - - //remove expired labels - for(label_map::iterator j = labels.begin(); j != labels.end(); ) { - if(context.count(j->first) > 0 && j->second.expired()) { - context.erase(j->first); - labels.erase(j++); - } else { - ++j; - } - } -} -#endif -} static bool add_font_to_fontlist(const config &fonts_config, std::vector& fontlist, const std::string& name) diff --git a/src/font.hpp b/src/font.hpp index fe12bbf2a092..ee15f2b4e998 100644 --- a/src/font.hpp +++ b/src/font.hpp @@ -103,131 +103,6 @@ std::string make_text_ellipsis(const std::string& text, int font_size, int max_w int style = TTF_STYLE_NORMAL); -/// structure which will hide all current floating labels, and cause floating labels -/// instantiated after it is created to be displayed -struct floating_label_context -{ - floating_label_context(); - ~floating_label_context(); -}; - -enum ALIGN { LEFT_ALIGN, CENTER_ALIGN, RIGHT_ALIGN }; - -enum LABEL_SCROLL_MODE { ANCHOR_LABEL_SCREEN, ANCHOR_LABEL_MAP }; - -class floating_label -{ -public: - floating_label(const std::string& text, const surface& surface = NULL); - - void set_font_size(int font_size) {font_size_ = font_size;} - - // set the location on the screen to display the text. - void set_position(double xpos, double ypos){ - xpos_ = xpos; - ypos_ = ypos; - } - // set the amount to move the text each frame - void set_move(double xmove, double ymove){ - xmove_ = xmove; - ymove_ = ymove; - } - // set the number of frames to display the text for, or -1 to display until removed - void set_lifetime(int lifetime) { - lifetime_ = lifetime; - alpha_change_ = -255 / lifetime_; - } - void set_color(const SDL_Color& color) {color_ = color;} - void set_bg_color(const SDL_Color& bg_color) { - bgcolor_ = bg_color; -#if SDL_VERSION_ATLEAST(2,0,0) - bgalpha_ = bg_color.a; -#else - bgalpha_ = bg_color.unused; -#endif - } - void set_border_size(int border) {border_ = border;} - // set width for word wrapping (use -1 to disable it) - void set_width(int w) {width_ = w;} - void set_height(int h) { height_ = h; } - void set_clip_rect(const SDL_Rect& r) {clip_rect_ = r;} - void set_alignment(ALIGN align) {align_ = align;} - void set_scroll_mode(LABEL_SCROLL_MODE scroll) {scroll_ = scroll;} - void use_markup(bool b) {use_markup_ = b;} - - void move(double xmove, double ymove); -#ifdef SDL_GPU - void draw(CVideo &video); - void undraw(CVideo &video); -#else - void draw(surface screen); - void undraw(surface screen); -#endif - -#if 0 - sdl::timage create_image(); -#else - surface create_surface(); -#endif - - bool expired() const { return lifetime_ == 0; } - - void show(const bool value) { visible_ = value; } - - LABEL_SCROLL_MODE scroll() const { return scroll_; } - -private: - - int xpos(size_t width) const; -#if 0 - sdl::timage img_; -#else - surface surf_, buf_; -#endif - std::string text_; - int font_size_; - SDL_Color color_, bgcolor_; - int bgalpha_; - double xpos_, ypos_, xmove_, ymove_; - int lifetime_; - int width_, height_; - SDL_Rect clip_rect_; - int alpha_change_; - bool visible_; - font::ALIGN align_; - int border_; - LABEL_SCROLL_MODE scroll_; - bool use_markup_; -}; - - -/// add a label floating on the screen above everything else. -/// @returns a handle to the label which can be used with other label functions - -int add_floating_label(const floating_label& flabel); - - -/// moves the floating label given by 'handle' by (xmove,ymove) -void move_floating_label(int handle, double xmove, double ymove); - -/// moves all floating labels that have 'scroll_mode' set to ANCHOR_LABEL_MAP -void scroll_floating_labels(double xmove, double ymove); - -/// removes the floating label given by 'handle' from the screen -void remove_floating_label(int handle); - -/// hides or shows a floating label -void show_floating_label(int handle, bool show); - -SDL_Rect get_floating_label_rect(int handle); -#ifdef SDL_GPU -void draw_floating_labels(CVideo &video); -void undraw_floating_labels(CVideo &video); -#else -void draw_floating_labels(surface screen); -void undraw_floating_labels(surface screen); -#endif - bool load_font_config(); /** Returns the currently defined fonts. */ diff --git a/src/game_display.cpp b/src/game_display.cpp index 44e5084ee65a..7b742a48081f 100644 --- a/src/game_display.cpp +++ b/src/game_display.cpp @@ -27,6 +27,7 @@ #include "display_chat_manager.hpp" #include "fake_unit_manager.hpp" #include "fake_unit_ptr.hpp" +#include "floating_label.hpp" #include "game_board.hpp" #include "game_preferences.hpp" #include "halo.hpp" diff --git a/src/game_initialization/multiplayer_ui.hpp b/src/game_initialization/multiplayer_ui.hpp index 6c554c20f24f..749c02497810 100644 --- a/src/game_initialization/multiplayer_ui.hpp +++ b/src/game_initialization/multiplayer_ui.hpp @@ -15,6 +15,7 @@ #define MULTIPLAYER_UI_HPP_INCLUDED #include "chat_events.hpp" +#include "floating_label.hpp" #include "hotkey/command_executor.hpp" #include "network.hpp" #include "preferences_display.hpp" diff --git a/src/gui/widgets/window.cpp b/src/gui/widgets/window.cpp index f061162bea04..69199a762882 100644 --- a/src/gui/widgets/window.cpp +++ b/src/gui/widgets/window.cpp @@ -25,6 +25,7 @@ #include "cursor.hpp" #include "display.hpp" #include "events.hpp" +#include "floating_label.hpp" #include "formula_callable.hpp" #include "font.hpp" #include "gettext.hpp" diff --git a/src/map_label.cpp b/src/map_label.cpp index 09b671013d2b..2a66e77c367e 100644 --- a/src/map_label.cpp +++ b/src/map_label.cpp @@ -15,6 +15,7 @@ #include "global.hpp" #include "display.hpp" +#include "floating_label.hpp" #include "game_board.hpp" #include "game_data.hpp" #include "map_label.hpp" diff --git a/src/play_controller.hpp b/src/play_controller.hpp index 23239908894f..224c9ca23522 100644 --- a/src/play_controller.hpp +++ b/src/play_controller.hpp @@ -17,6 +17,7 @@ #define PLAY_CONTROLLER_H_INCLUDED #include "controller_base.hpp" +#include "floating_label.hpp" #include "game_end_exceptions.hpp" #include "game_state.hpp" #include "help/help.hpp" diff --git a/src/show_dialog.cpp b/src/show_dialog.cpp index 302490dc7f91..0503e54d4582 100644 --- a/src/show_dialog.cpp +++ b/src/show_dialog.cpp @@ -20,6 +20,7 @@ #include "construct_dialog.hpp" #include "display.hpp" +#include "floating_label.hpp" #include "gettext.hpp" #include "gui/auxiliary/event/handler.hpp" #include "help/help.hpp" diff --git a/src/show_dialog.hpp b/src/show_dialog.hpp index e68bfc5939da..5ac167116139 100644 --- a/src/show_dialog.hpp +++ b/src/show_dialog.hpp @@ -20,6 +20,7 @@ class CVideo; class display; #include "cursor.hpp" +#include "floating_label.hpp" #include "font.hpp" #include "tooltips.hpp" diff --git a/src/tooltips.cpp b/src/tooltips.cpp index 22500638c2b7..8b28bf82353a 100644 --- a/src/tooltips.cpp +++ b/src/tooltips.cpp @@ -15,6 +15,7 @@ #include "tooltips.hpp" +#include "floating_label.hpp" #include "font.hpp" #include "game_display.hpp" #include "help/help.hpp" diff --git a/src/video.cpp b/src/video.cpp index 26372cfb5989..0c3f29afbf67 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -20,6 +20,7 @@ #include "global.hpp" #include "font.hpp" +#include "floating_label.hpp" #include "image.hpp" #include "log.hpp" #include "preferences.hpp" diff --git a/src/wesnoth.cpp b/src/wesnoth.cpp index 47a3f6218163..0ef55899b41e 100644 --- a/src/wesnoth.cpp +++ b/src/wesnoth.cpp @@ -22,6 +22,7 @@ #include "cursor.hpp" // for set, CURSOR_TYPE::NORMAL, etc #include "editor/editor_main.hpp" #include "filesystem.hpp" // for filesystem::file_exists, filesystem::io_exception, etc +#include "floating_label.hpp" #include "font.hpp" // for load_font_config, etc #include "formula.hpp" // for formula_error #include "game_config.hpp" // for path, debug, debug_lua, etc