1 
2 /* Battle Tanks Game
3  * Copyright (C) 2006-2009 Battle Tanks team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  */
19 
20 /*
21  * Additional rights can be granted beyond the GNU General Public License
22  * on the terms provided in the Exception. If you modify this file,
23  * you may extend this exception to your version of the file,
24  * but you are not obligated to do so. If you do not wish to provide this
25  * exception without modification, you must delete this exception statement
26  * from your version and license this file solely under the GPL without exception.
27 */
28 
29 #include <ctype.h>
30 #include "tooltip.h"
31 
32 #include "mrt/logger.h"
33 #include "menu/box.h"
34 #include "resource_manager.h"
35 #include "config.h"
36 #include "sdlx/font.h"
37 #include "mrt/utf8_utils.h"
38 #include "i18n.h"
39 
40 #include <math.h>
41 #include <assert.h>
42 #include <deque>
43 
Tooltip(const std::string & area,const std::string & message,const bool use_background,int w)44 Tooltip::Tooltip(const std::string &area, const std::string &message, const bool use_background, int w)  :
45 area(area), message(message) {
46 	init(I18n->get(area, message), use_background, w);
47 }
48 
Tooltip(const std::string & area,const std::string & message,const std::string & text,const bool use_background,int w)49 Tooltip::Tooltip(const std::string &area, const std::string &message, const std::string &text, const bool use_background, int w) :
50 area(area), message(message) {
51 	init(text, use_background, w);
52 }
53 
init(const std::string & _text,const bool use_background,int width)54 void Tooltip::init(const std::string &_text, const bool use_background, int width) {
55 	_use_background = use_background;
56 	std::string text;
57 	bool space = true;
58 	size_t i;
59 	for(i = 0; i < _text.size(); ++i) {
60 		const char c = _text[i];
61 		const bool c_space = c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\f';
62 		if (c == '\\' && i + 1 < _text.size() && _text[i + 1] == 'n') {
63 			//\n hack :)
64 			++i;
65 			if (space) {
66 				text += "\n ";
67 			} else {
68 				text += " \n ";
69 				space = true;
70 			}
71 			continue;
72 		}
73 
74 		//LOG_DEBUG(("%d '%c': %s %s", c, c, space?"true":"false", c_space?"true":"false"));
75 		if (space) {
76 			if (c_space)
77 				continue;
78 			space = false;
79 			text += c;
80 		} else {
81 			if (c_space) {
82 				space = true;
83 				text += ' ';
84 			} else
85 				text += c;
86 		}
87 	}
88 	if (text.empty())
89 		throw_ex(("tooltip with empty text is not allowed"));
90 	//LOG_DEBUG(("trimmed string : '%s'", text.c_str()));
91 
92 	GET_CONFIG_VALUE("engine.tooltip-speed", float, td, 20);
93 	_time = ((float)mrt::utf8_length(text)) / td;
94 
95 	std::vector<std::string> words;
96 	mrt::split(words, text, " ");
97 	for(size_t i = 0; i < words.size(); ++i) {
98 		mrt::replace(words[i], "\\s", " ");
99 	}
100 	std::vector<int> lens;
101 	lens.resize(words.size());
102 
103 	const sdlx::Font * font = ResourceManager->loadFont("small", false);
104 	int line_h = font->get_height();
105 
106 	int total = 0, nl_n = 0;
107 	for(size_t i = 0; i < words.size(); ++i) {
108 		const std::string &word = words[i];
109 		if (word == "\n") {
110 			nl_n += line_h;
111 			continue;
112 		}
113 
114 		lens[i] = font->render(NULL, 0, 0, word + " ");
115 		total += lens[i] * line_h;
116 	}
117 	bool hard;
118 	if (width == 0) {
119 		width = (int)(sqrt(total * 2 / 3.0f + nl_n * nl_n / 4.0f) + 0.5f);
120 		hard = false;
121 	} else {
122 		hard = !_use_background;
123 	}
124 
125 	std::vector<std::string> lines;
126 
127 	int line_w = 0, real_width = 1;
128 	std::string line;
129 	for(size_t i = 0; i < words.size(); ++i) {
130 		const std::string &word = words[i];
131 		const int len = lens[i];
132 		line_w += len;
133 
134 		bool last = i + 1 == words.size();
135 		bool nl = line_w >= width || word == "\n" || last;
136 
137 		if (nl) {
138 			if (hard && !line.empty() && !last) { //hard edge
139 				line_w -= len;
140 				if (line_w > real_width)
141 					real_width = line_w;
142 				lines.push_back(line);
143 				line = word + " ";
144 				line_w = len;
145 			} else {
146 				if (line_w > real_width)
147 					real_width = line_w;
148 				lines.push_back(line + word);
149 				line.clear();
150 				line_w = 0;
151 			}
152 		} else {
153 			line += word + " ";
154 		}
155 	}
156 
157 	//LOG_DEBUG(("line width: %d, lines: %u", width, lines.size()));
158 	int xp = 0, yp = 0;
159 	int height = line_h * lines.size();
160 	if (_use_background) {
161 		const sdlx::Surface *bg = ResourceManager->load_surface("menu/background_box.png");
162 		int mx = bg->get_width() / 3, my =  bg->get_height() / 3;
163 		_background.init("menu/background_box.png", real_width + mx * 2, height + my * 2);
164 		_surface.create_rgb(_background.w, _background.h, 32, SDL_SRCALPHA);
165 		xp = (_background.w - real_width) / 2;
166 		yp = (_background.h - height) / 2;
167 	} else {
168 		_surface.create_rgb(real_width, height, 32, SDL_SRCALPHA);
169 	}
170 	_surface.display_format_alpha();
171 
172 	for(size_t i = 0; i < lines.size(); ++i) {
173 		font->render(_surface, xp, yp + i * line_h, lines[i]);
174 	}
175 }
176 
render(sdlx::Surface & surface,const int x,const int y) const177 void Tooltip::render(sdlx::Surface &surface, const int x, const int y) const {
178 	if (_use_background)
179 		_background.render(surface, x, y);
180 	surface.blit(_surface, x, y);
181 }
182 
get_size(int & w,int & h) const183 void Tooltip::get_size(int &w, int &h) const {
184 	w = _surface.get_width();
185 	h = _surface.get_height();
186 }
187