1 /*
2    Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3    Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY.
11 
12    See the COPYING file for more details.
13 */
14 
15 /**
16  *  @file
17  *  Definitions related to theme-support.
18  */
19 
20 #pragma once
21 
22 #include "color.hpp"
23 #include "config.hpp"
24 #include "generic_event.hpp"
25 
26 #include <memory>
27 #include <SDL2/SDL_rect.h>
28 
29 struct _rect { size_t x1,y1,x2,y2; };
30 
31 struct theme_info
32 {
33 	std::string id;
34 	t_string name;
35 	t_string description;
36 };
37 
38 class theme
39 {
40 
41 	class object
42 	{
43 	public:
44 		object();
45 		object(const config& cfg);
~object()46 		virtual ~object() { }
47 
48 		virtual SDL_Rect& location(const SDL_Rect& screen) const;
get_location() const49 		const SDL_Rect& get_location() const { return loc_; }
get_id() const50 		const std::string& get_id() const { return id_; }
51 
52 		// This supports relocating of theme elements ingame.
53 		// It is needed for [change] tags in theme WML.
54 		void modify_location(const _rect& rect);
55 		void modify_location(std::string rect_str, SDL_Rect rect_ref);
56 
57 		// All on-screen objects have 'anchoring' in the x and y dimensions.
58 		// 'fixed' means that they have fixed co-ordinates and don't move.
59 		// 'top anchored' means they are anchored to the top (or left) side
60 		// of the screen - the top (or left) edge stays a constant distance
61 		// from the top of the screen.
62 		// 'bottom anchored' is the inverse of top anchored.
63 		// 'proportional' means the location and dimensions change
64 		// proportionally to the screen size.
65 		enum ANCHORING { FIXED, TOP_ANCHORED, PROPORTIONAL, BOTTOM_ANCHORED };
66 
67 	private:
68 		bool location_modified_;
69 		std::string id_;
70 		SDL_Rect loc_;
71 		mutable SDL_Rect relative_loc_;
72 		mutable SDL_Rect last_screen_;
73 
74 		ANCHORING xanchor_, yanchor_;
75 
76 		static ANCHORING read_anchor(const std::string& str);
77 	};
78 
79 	struct border_t
80 	{
81 
82 		border_t();
83 		border_t(const config& cfg);
84 
85 		double size;
86 
87 		std::string background_image;
88 		std::string tile_image;
89 
90 		bool show_border;
91 	};
92 
93 public:
94 
95 	class label : public object
96 	{
97 	public:
98 		label();
99 		explicit label(const config& cfg);
100 
101 		using object::location;
102 
text() const103 		const std::string& text() const { return text_; }
set_text(const std::string & text)104 		void set_text(const std::string& text) { text_ = text; }
icon() const105 		const std::string& icon() const { return icon_; }
106 
empty() const107 		bool empty() const { return text_.empty() && icon_.empty(); }
108 
font_size() const109 		size_t font_size() const { return font_; }
font_rgb() const110 		color_t font_rgb() const { return font_rgb_; }
font_rgb_set() const111 		bool font_rgb_set() const { return font_rgb_set_; }
112 	private:
113 		std::string text_, icon_;
114 		size_t font_;
115 		bool font_rgb_set_;
116 		color_t font_rgb_;
117 	};
118 
119 	class status_item : public object
120 	{
121 	public:
122 
123 		explicit status_item(const config& cfg);
124 
125 		using object::location;
126 
prefix() const127 		const std::string& prefix() const { return prefix_; }
postfix() const128 		const std::string& postfix() const { return postfix_; }
129 
130 		// If the item has a label associated with it, Show where the label is
get_label() const131 		const label* get_label() const { return label_.empty() ? nullptr : &label_; }
132 
font_size() const133 		size_t font_size() const { return font_; }
font_rgb() const134 		color_t font_rgb() const { return font_rgb_; }
font_rgb_set() const135 		bool font_rgb_set() const { return font_rgb_set_; }
136 
137 	private:
138 		std::string prefix_, postfix_;
139 		label label_;
140 		size_t font_;
141 		bool font_rgb_set_;
142 		color_t font_rgb_;
143 	};
144 
145 	class panel : public object
146 	{
147 	public:
148 		explicit panel(const config& cfg);
149 
150 		using object::location;
151 
image() const152 		const std::string& image() const { return image_; }
153 
154 	private:
155 		std::string image_;
156 	};
157 
158 	class action : public object
159 	{
160 	public:
161 		action();
162 		explicit action(const config& cfg);
163 
164 		using object::location;
165 
is_context() const166 		bool is_context() const  { return context_; }
167 
title() const168 		const std::string& title() const { return title_; }
169 
170 		const std::string tooltip(size_t index) const;
171 
type() const172 		const std::string& type() const { return type_; }
173 
image() const174 		const std::string& image() const { return image_; }
175 
overlay() const176 		const std::string& overlay() const { return overlay_; }
177 
items() const178 		const std::vector<std::string>& items() const { return items_; }
179 
set_title(const std::string & new_title)180 		void set_title(const std::string& new_title) { title_ = new_title; }
181 	private:
182 		bool context_, auto_tooltip_, tooltip_name_prepend_;
183 		std::string title_, tooltip_, image_, overlay_,  type_;
184 		std::vector<std::string> items_;
185 	};
186 
187 	class slider : public object
188 	{
189 	public:
190 		slider();
191 		explicit slider(const config& cfg);
192 
193 		using object::location;
194 
title() const195 		const std::string& title() const { return title_; }
196 
tooltip() const197 		const std::string& tooltip() const { return tooltip_; }
198 
image() const199 		const std::string& image() const { return image_; }
200 
overlay() const201 		const std::string& overlay() const { return overlay_; }
202 
black_line() const203 		bool black_line() const { return black_line_; }
204 
set_title(const std::string & new_title)205 		void set_title(const std::string& new_title) { title_ = new_title; }
206 	private:
207 		std::string title_, tooltip_, image_, overlay_;
208 		bool black_line_;
209 	};
210 
211 	class menu : public object
212 	{
213 	public:
214 		menu();
215 		explicit menu(const config& cfg);
216 
217 		using object::location;
218 
is_button() const219 		bool is_button() const { return button_; }
220 
is_context() const221 		bool is_context() const  { return context_; }
222 
title() const223 		const std::string& title() const { return title_; }
224 
tooltip() const225 		const std::string& tooltip() const { return tooltip_; }
226 
image() const227 		const std::string& image() const { return image_; }
228 
overlay() const229 		const std::string& overlay() const { return overlay_; }
230 
items() const231 		const std::vector<config>& items() const { return items_; }
232 
set_title(const std::string & new_title)233 		void set_title(const std::string& new_title) { title_ = new_title; }
234 	private:
235 		bool button_;
236 		bool context_;
237 		std::string title_, tooltip_, image_, overlay_;
238 		std::vector<config> items_;
239 	};
240 
241 	explicit theme(const config& cfg, const SDL_Rect& screen);
242 	theme(const theme&) = delete;
243 	theme& operator=(const theme&) = delete;
244 	theme& operator=(theme&&);
245 
246 	bool set_resolution(const SDL_Rect& screen);
247 	void modify(const config &cfg);
248 
panels() const249 	const std::vector<panel>& panels() const { return panels_; }
labels() const250 	const std::vector<label>& labels() const { return labels_; }
menus() const251 	const std::vector<menu>& menus() const { return menus_; }
sliders() const252 	const std::vector<slider>& sliders() const { return sliders_; }
actions() const253 	const std::vector<action>& actions() const { return actions_; }
254 
context_menu() const255 	const menu* context_menu() const
256 		{ return context_.is_context() ? &context_ : nullptr; }
257 
258 	//refresh_title2 changes the title of a menu entry, identified by id.
259 	//If no menu entry is found, an empty menu object is returned.
260 	object* refresh_title(const std::string& id, const std::string& new_title);
261 	object* refresh_title2(const std::string& id, const std::string& title_tag);
262 	void modify_label(const std::string& id, const std::string& text);
263 
264 	const status_item* get_status_item(const std::string& item) const;
265 	const menu *get_menu_item(const std::string &key) const;
266 	const action* get_action_item(const std::string &key) const;
267 
main_map_location(const SDL_Rect & screen) const268 	const SDL_Rect& main_map_location(const SDL_Rect& screen) const
269 		{ return main_map_.location(screen); }
mini_map_location(const SDL_Rect & screen) const270 	const SDL_Rect& mini_map_location(const SDL_Rect& screen) const
271 		{ return mini_map_.location(screen); }
unit_image_location(const SDL_Rect & screen) const272 	const SDL_Rect& unit_image_location(const SDL_Rect& screen) const
273 		{ return unit_image_.location(screen); }
palette_location(const SDL_Rect & screen) const274 	const SDL_Rect& palette_location(const SDL_Rect& screen) const
275 		{ return palette_.location(screen); }
276 
277     static void set_known_themes(const config* cfg);
278     static std::vector<theme_info> get_known_themes();
279 
border() const280 	const border_t& border() const { return border_; }
281 
theme_reset_event()282 	events::generic_event& theme_reset_event() { return theme_reset_event_; }
283 
284 private:
285 	theme::object& find_element(const std::string& id);
286 	void add_object(const config& cfg);
287 	void remove_object(const std::string& id);
288 	void set_object_location(theme::object& element, std::string rect_str, std::string ref_id);
289 
290 	//notify observers that the theme has been rebuilt completely
291 	//atm this is used for replay_controller to add replay controls to the standard theme
292 	events::generic_event theme_reset_event_;
293 
294 	static std::map<std::string, config> known_themes;
295 	std::string cur_theme;
296 	config cfg_;
297 	std::vector<panel> panels_;
298 	std::vector<label> labels_;
299 	std::vector<menu> menus_;
300 	std::vector<action> actions_;
301 	std::vector<slider> sliders_;
302 
303 	menu context_;
304 	action action_context_;
305 
306 	std::map<std::string, std::unique_ptr<status_item>> status_;
307 
308 	object main_map_, mini_map_, unit_image_, palette_;
309 
310 	border_t border_;
311 
312 	SDL_Rect screen_dimensions_;
313 };
314