1 //	Status Indicators
2 //
3 //		Simple HUD window to show the status of things
4 //
5 //	TODO change list
6 //		Possibly use a coloured light or preferably an icon for
7 //		the indicators rather than simple characters.
8 //
9 //		Author bluap/pjbroad Jan 2014
10 //
11 
12 #include <vector>
13 #include <string>
14 #include <iostream>
15 #include <cstring>
16 #include <sstream>
17 #include <utility>
18 
19 #include "asc.h"
20 #include "chat.h"
21 #include "context_menu.h"
22 #include "counters.h"
23 #include "errors.h"
24 #include "font.h"
25 #include "elconfig.h"
26 #include "elwindows.h"
27 #include "gamewin.h"
28 #include "gl_init.h"
29 #include "hud.h"
30 #ifdef JSON_FILES
31 #include "json_io.h"
32 #endif
33 #include "sound.h"
34 #include "spells.h"
35 #include "text.h"
36 #include "translate.h"
37 
38 using namespace eternal_lands;
39 
40 namespace Indicators
41 {
42 	//	Constants used by the window.
43 	//
44 	class Vars
45 	{
46 		public:
zoom(void)47 			static float zoom(void) { return scale; }
space(void)48 			static int space(void) { return (int)(0.5 + scale * 5); }
border(void)49 			static int border(void) { return (int)(0.5 + scale * 2); }
font_x(void)50 			static float font_x(void)
51 			{
52 				return FontManager::get_instance()
53 					.max_width_spacing(FontManager::Category::UI_FONT);
54 			}
font_y(void)55 			static float font_y(void)
56 			{
57 				return FontManager::get_instance().line_height(FontManager::Category::UI_FONT);
58 			}
y_len(void)59 			static int y_len(void) { return static_cast<int>(border() + zoom() * font_y() + 0.5); }
set_scale(float new_scale)60 			static void set_scale(float new_scale) { scale = new_scale; }
61 		private:
62 			static float scale;
63 	};
64 
65 	float Vars::scale = 1.0;
66 
67 	//	A class to hold the state for an individual, basic indicator.
68 	//	Has a simple on / of state and no action.
69 	//
70 	class Basic_Indicator
71 	{
72 		public:
73 			Basic_Indicator(const char *the_strings, int (*ctrl)(void), int (*unavailable)(void), int no);
74 			virtual void do_draw(int x_pos);
do_action(void) const75 			virtual void do_action(void) const { do_alert1_sound(); }
76 			virtual void get_tooltip(std::string & tooltip) const;
get_context_menu_str(void) const77 			virtual const std::string & get_context_menu_str(void) const { return context_menu_str; }
get_active_var(void)78 			virtual int *get_active_var(void) { return &is_active; }
set_active(bool new_active)79 			virtual void set_active(bool new_active) { is_active = (new_active) ?1 :0; }
not_active(void) const80 			virtual bool not_active(void) const { return (is_active==0); }
set_over(void)81 			virtual void set_over(void) { mouse_over = true; }
get_width(void) const82 			virtual int get_width(void) const { return indicator_text.size() * static_cast<int>(Vars::font_x() * Vars::zoom()); }
~Basic_Indicator(void)83 			virtual ~Basic_Indicator(void) {}
84 		protected:
85 			std::string on_tooltip;
86 			std::string off_tooltip;
87 			std::string unavailable_tooltip;
88 			int (*cntr_func)(void);
89 			int (*unavailable_func)(void);
90 		private:
91 			std::string indicator_text;
92 			std::string context_menu_str;
93 			int is_active;
94 			bool mouse_over;
95 	};
96 
97 
98 	//	A class to hold the state for an individual, basic indicator with a parsed action.
99 	//	Has a simple on/off state and an action string that is passed to the input parser.
100 	//
101 	class Parse_Action_Indicator: public Basic_Indicator
102 	{
103 		public:
Parse_Action_Indicator(const char * the_strings,int (* ctrl)(void),int (* unavailable)(void),int no,const char * the_action)104 			Parse_Action_Indicator(const char *the_strings, int (*ctrl)(void), int (*unavailable)(void), int no, const char *the_action)
105 				: Basic_Indicator(the_strings, ctrl, unavailable, no), action(the_action) {}
106 			virtual void do_action(void) const;
~Parse_Action_Indicator(void)107 			virtual ~Parse_Action_Indicator(void) { }
108 		private:
109 			std::string action;
110 	};
111 
112 
113 	//	A class to hold the state for an individual, basic indicator with value and a click action function.
114 	//	Has a value rather than on/off state displayed in the tool-tip, the value is typically cleared by the action.
115 	//
116 	class Value_Indicator : public Basic_Indicator
117 	{
118 		public:
Value_Indicator(const char * the_strings,int (* ctrl)(void),int (* unavailable)(void),int no,void (* action)(void))119 			Value_Indicator(const char *the_strings, int (*ctrl)(void), int (*unavailable)(void), int no, void (*action)(void))
120 				: Basic_Indicator(the_strings, ctrl, unavailable, no), action_function(action) {}
121 			virtual void do_action(void) const;
122 			virtual void get_tooltip(std::string & tooltip) const;
~Value_Indicator(void)123 			virtual ~Value_Indicator(void) { }
124 		private:
125 			void (*action_function)(void);
126 	};
127 
128 
129 	//	Class for the collection of indicators, and the window state and action methods.
130 	//
131 	class Indicators_Container
132 	{
133 		public:
Indicators_Container(void)134 			Indicators_Container(void)
135 				: indicators_win(-1), cm_menu_id(CM_INIT_VALUE),
136 					cm_relocatable(0), x_len(0), y_len(0), default_location(true),
137 					option_settings(0), position_settings(0), have_settings(false),
138 					background_on(0), border_on(0) {}
139 			void init(void);
140 			void destroy(void);
show(void)141 			void show(void) { if (indicators_win >= 0) show_window (indicators_win); }
hide(void)142 			void hide(void) { if (indicators_win >= 0) hide_window (indicators_win); }
143 			void toggle(int show);
144 			void draw(void);
145 			void show_tooltip(window_info *win, int mx);
146 			void click(int mx, Uint32 flags);
147 			int cm_handler(window_info *win, int widget_id, int mx, int my, int option);
set_settings(unsigned int opts,unsigned int pos)148 			void set_settings(unsigned int opts, unsigned int pos) { option_settings = opts; position_settings = pos; have_settings = true;}
149 			void get_settings(unsigned int *opts, unsigned int *pos) const;
150 #ifdef JSON_FILES
151 			void read_settings(const char *dict_name);
152 			void write_settings(const char *dict_name) const;
153 #endif
ui_scale_handler(window_info * win)154 			void ui_scale_handler(window_info *win) { x_len = 0; y_len = 0; Vars::set_scale(win->current_scale); }
155 			int get_default_width(void);
156 		private:
157 			void set_win_flag(Uint32 flag, int state);
set_background(bool on)158 			void set_background(bool on) { background_on = on; set_win_flag(ELW_USE_BACKGROUND, background_on); }
set_border(bool on)159 			void set_border(bool on) { border_on = on; set_win_flag(ELW_USE_BORDER, border_on); }
160 			std::vector<Basic_Indicator *> indicators;
161 			int indicators_win;
162 			size_t cm_menu_id;
163 			int cm_relocatable;
164 			int x_len;
165 			int y_len;
166 			bool default_location;
167 			unsigned int option_settings;
168 			unsigned int position_settings;
169 			bool have_settings;
170 			int background_on;
171 			int border_on;
172 			std::vector<Basic_Indicator *>::iterator get_over(int mx);
173 			std::pair<int,int> get_default_location(void);
174 			void change_width(int new_x_len);
175 			enum {	CMHI_RELOC=ELW_CM_MENU_LEN+1, CMHI_BACKGROUND, CMHI_BORDER,
176 					CMHI_SPACE1, CMHI_RESET, CMHI_SPACE2, CMHI_INDBASE};
177 	};
178 
179 
180 	//	Construct the indicator deriving the strings from the "||" separated string passed.
181 	//
Basic_Indicator(const char * the_strings,int (* ctrl)(void),int (* unavailable)(void),int no)182 	Basic_Indicator::Basic_Indicator(const char *the_strings, int (*ctrl)(void), int (*unavailable)(void), int no)
183 		: on_tooltip("Unset"), off_tooltip("Unset"), unavailable_tooltip("Unset"), cntr_func(ctrl), unavailable_func(unavailable),
184 			indicator_text("*"), is_active(1), mouse_over(false)
185 	{
186 		if (the_strings)
187 		{
188 			std::string line_text(the_strings);
189 			std::string::size_type from_index = 0;
190 			std::string::size_type to_index = 0;
191 			std::string delim = "||";
192 			std::string::size_type len = 0;
193 			std::vector<std::string> fields;
194 			while ((to_index = line_text.find(delim, from_index)) != std::string::npos)
195 			{
196 				if ((len = to_index-from_index) > 0)
197 					fields.push_back(line_text.substr(from_index, len));
198 				from_index = to_index + delim.size();
199 			}
200 			if ((len = line_text.size()-from_index) > 0)
201 				fields.push_back(line_text.substr(from_index, len));
202 			if (fields.size() >= 4)
203 			{
204 				indicator_text = fields[0];
205 				on_tooltip = fields[1];
206 				off_tooltip = fields[2];
207 				context_menu_str = fields[3];
208 				if (fields.size() == 5)
209 					unavailable_tooltip = fields[4];
210 			}
211 		}
212 	}
213 
214 
215 	//	Simply draw the single character, highlighted if the status is true.
216 	//
do_draw(int x_pos)217 	void Basic_Indicator::do_draw(int x_pos)
218 	{
219 		if (mouse_over)
220 			glColor3f(1.0f,1.0f,1.0f);
221 		else if (unavailable_func && unavailable_func())
222 			glColor3f(gui_dull_color[0]/2, gui_dull_color[1]/2, gui_dull_color[2]/2);
223 		else if (cntr_func && cntr_func())
224 			glColor3fv(gui_bright_color);
225 		else
226 			glColor3fv(gui_dull_color);
227 		draw_string_zoomed(x_pos, Vars::border(), (const unsigned char*)indicator_text.c_str(), 1, Vars::zoom());
228 		mouse_over = false;
229 	}
230 
get_tooltip(std::string & tooltip) const231 	void Basic_Indicator::get_tooltip(std::string & tooltip) const
232 	{
233 		if (unavailable_func && unavailable_func())
234 			tooltip = unavailable_tooltip;
235 		else
236 			tooltip = ((cntr_func && cntr_func()) ?on_tooltip : off_tooltip);
237 	}
238 
239 	//	If an action string is defined, execute using the standard command line parser.
240 	//
do_action(void) const241 	void Parse_Action_Indicator::do_action(void) const
242 	{
243 		if (action.empty())
244 		{
245 			Basic_Indicator::do_action();
246 			return;
247 		}
248 		size_t command_len = action.size() + 1;
249 		do_click_sound();
250 		char temp[command_len];
251 		safe_strncpy(temp, action.c_str(), command_len);
252 		parse_input(temp, strlen(temp));
253 	}
254 
255 
256 	//	Execute the click action, typically this clears the value.
257 	//
do_action(void) const258 	void Value_Indicator::do_action(void) const
259 	{
260 		if (!action_function)
261 		{
262 			Basic_Indicator::do_action();
263 			return;
264 		}
265 		do_click_sound();
266 		action_function();
267 	}
268 
269 
270 	//	Show the tool-tip that explains the status and includes the current value if non-zero.
271 	//
get_tooltip(std::string & tooltip) const272 	void Value_Indicator::get_tooltip(std::string & tooltip) const
273 	{
274 		if (unavailable_func && unavailable_func())
275 		{
276 			tooltip = unavailable_tooltip;
277 			return;
278 		}
279 		std::ostringstream ss("");
280 		int value = (cntr_func) ?cntr_func() :0;
281 		if (value > 0)
282 			ss << on_tooltip << " [" << value << "]";
283 		else
284 			ss << off_tooltip;
285 		tooltip = ss.str();
286 	}
287 
288 
289 	//	The indicators instance.
290 	static Indicators_Container container;
291 
292 
293 	//	Window callback functions.
294 	//
display_indicators_handler(window_info * win)295 	static int display_indicators_handler(window_info *win) { container.draw(); return 1; }
mouseover_indicators_handler(window_info * win,int mx,int my)296 	static int mouseover_indicators_handler(window_info *win, int mx, int my) { if (my>=0) container.show_tooltip(win, mx); return 0; }
ui_scale_indicators_handler(window_info * win)297 	static int ui_scale_indicators_handler(window_info *win) { container.ui_scale_handler(win); return 1; }
click_indicators_handler(window_info * win,int mx,int my,Uint32 flags)298 	static int click_indicators_handler(window_info *win, int mx, int my, Uint32 flags) { if (my>=0) container.click(mx, flags); return 1; }
cm_indicators_handler(window_info * win,int widget_id,int mx,int my,int option)299 	static int cm_indicators_handler(window_info *win, int widget_id, int mx, int my, int option) { return container.cm_handler(win, widget_id, mx, my, option); }
300 
301 
302 	//	Initialise the indicators, create or re-initialise the window.
303 	//
init(void)304 	void Indicators_Container::init(void)
305 	{
306 		if (!FontManager::get_instance().is_initialized())
307 			return;
308 
309 		std::pair<int,int> loc = get_default_location();
310 
311 		if (indicators.empty())
312 		{
313 			indicators.reserve(6);
314 			indicators.push_back(new Parse_Action_Indicator(day_indicator_str, today_is_special_day, 0, indicators.size(), "#day"));
315 			indicators.push_back(new Basic_Indicator(harvest_indicator_str, now_harvesting, 0, indicators.size()));
316 			indicators.push_back(new Basic_Indicator(poison_indicator_str, we_are_poisoned, 0, indicators.size()));
317 			indicators.push_back(new Value_Indicator(messages_indicator_str, get_seen_pm_count, 0, indicators.size(), clear_seen_pm_count));
318 			indicators.push_back(new Parse_Action_Indicator(ranginglock_indicator_str, ranging_lock_is_on, 0, indicators.size(), "#keypress #K_RANGINGLOCK"));
319 			indicators.push_back(new Parse_Action_Indicator(glowperk_indicator_str, glow_perk_is_active, glow_perk_is_unavailable, indicators.size(), "#glow"));
320 		}
321 
322 		x_len = static_cast<int>(Vars::font_x() * indicators.size() * Vars::zoom() +
323 			2 * Vars::border() + 2 * Vars::space() * indicators.size() + 0.5);
324 		y_len = Vars::y_len();
325 
326 		if (indicators_win < 0)
327 		{
328 			if (have_settings)
329 			{
330 				unsigned int flags = option_settings;
331 				default_location = !((flags >> 24) & 1);
332 				if (!default_location)
333 				{
334 					loc.first = static_cast<int>(position_settings & 0xFFFF);
335 					loc.second = static_cast<int>((position_settings >> 16) & 0xFFFF);
336 				}
337 				std::vector<Basic_Indicator *>::iterator i;
338 				for (i=indicators.begin(); i<indicators.end(); ++i)
339 				{
340 					(*i)->set_active(!static_cast<bool>(flags&1));
341 					flags >>= 1;
342 				}
343 			}
344 		}
345 		else if (!default_location)
346 		{
347 			loc.first = windows_list.window[indicators_win].cur_x;
348 			loc.second = windows_list.window[indicators_win].cur_y;
349 		}
350 
351 		if ((loc.first > (window_width - x_len)) || (loc.second > (window_height - y_len)))
352 			loc = get_default_location();
353 
354 		if (indicators_win < 0)
355 		{
356 			indicators_win = create_window("Indicators", -1, 0, loc.first, loc.second, x_len, y_len, ELW_USE_UISCALE|ELW_SHOW|ELW_ALPHA_BORDER|ELW_SWITCHABLE_OPAQUE);
357 			if (indicators_win < 0 || indicators_win >= windows_list.num_windows)
358 			{
359 				LOG_ERROR("%s: Failed to create indicators window\n", __FILE__ );
360 				return;
361 			}
362 			set_window_handler(indicators_win, ELW_HANDLER_DISPLAY, (int (*)())&display_indicators_handler);
363 			set_window_handler(indicators_win, ELW_HANDLER_MOUSEOVER, (int (*)())&mouseover_indicators_handler);
364 			set_window_handler(indicators_win, ELW_HANDLER_CLICK, (int (*)())&click_indicators_handler);
365 			set_window_handler(indicators_win, ELW_HANDLER_UI_SCALE, (int (*)())&ui_scale_indicators_handler);
366 			ui_scale_indicators_handler(&windows_list.window[indicators_win]);
367 
368 			background_on = ((option_settings >> 25) & 1);
369 			border_on = ((option_settings >> 26) & 1);
370 			set_background(background_on);
371 			set_border(border_on);
372 		}
373 		else
374 			init_window(indicators_win, -1, 0, loc.first, loc.second, x_len, y_len);
375 
376 		if (!cm_valid(cm_menu_id))
377 		{
378 			std::vector<Basic_Indicator *>::iterator i;
379 			int j;
380 			std::ostringstream cm_menu("");
381 			cm_menu << cm_indicators_str;
382 			for (i=indicators.begin(); i<indicators.end(); ++i)
383 				cm_menu << (*i)->get_context_menu_str() << std::endl;
384 			cm_menu_id = cm_create(cm_title_menu_str, NULL);
385 			cm_bool_line(cm_menu_id, 1, &windows_list.window[indicators_win].opaque, NULL);
386 			cm_bool_line(cm_menu_id, 2, &windows_on_top, "windows_on_top");
387 			cm_add(cm_menu_id, cm_menu.str().c_str(), cm_indicators_handler);
388 			cm_bool_line(cm_menu_id, CMHI_RELOC, &cm_relocatable, 0);
389 			cm_bool_line(cm_menu_id, CMHI_BACKGROUND, &background_on, 0);
390 			cm_bool_line(cm_menu_id, CMHI_BORDER, &border_on, 0);
391 			for (i=indicators.begin(), j=0; i<indicators.end(); ++i, j++)
392 				cm_bool_line(cm_menu_id, CMHI_INDBASE+j, (*i)->get_active_var(), 0);
393 			cm_add_window(cm_menu_id, indicators_win);
394 		}
395 	}
396 
397 
398 	//	Delete the indicators and destroy the window.
399 	//
destroy(void)400 	void Indicators_Container::destroy(void)
401 	{
402 		std::vector<Basic_Indicator *>::iterator i;
403 		for (i=indicators.begin(); i<indicators.end(); ++i)
404 			delete (*i);
405 		indicators.clear();
406 		destroy_window(indicators_win);
407 		indicators_win = -1;
408 		if (cm_valid(cm_menu_id))
409 			cm_destroy(cm_menu_id);
410 	}
411 
412 
413 	//	Called if the state changed in the configuration window.
414 	//
toggle(int show)415 	void Indicators_Container::toggle(int show)
416 	{
417 		if (show)
418 		{
419 			if (indicators_win < 0)
420 				init();
421 			else
422 				show_window(indicators_win);
423 		}
424 		else
425 			hide_window(indicators_win);
426 	}
427 
428 
429 	//	Draw all the indicators.
430 	//
draw(void)431 	void Indicators_Container::draw(void)
432 	{
433 		int pos_x = Vars::border();
434 		bool have_active = false;
435 		std::vector<Basic_Indicator *>::iterator i = indicators.begin();
436 		for (;i<indicators.end(); ++i)
437 		{
438 			if ((*i)->not_active())
439 				continue;
440 			pos_x += Vars::space();
441 			(*i)->do_draw(pos_x);
442 			pos_x += (*i)->get_width() + Vars::space();
443 			have_active = true;
444 		}
445 		if (!have_active)
446 		{
447 			glColor3fv(gui_dull_color);
448 			draw_string_zoomed(pos_x, Vars::border(), (const unsigned char *)no_indicators_str, 1, Vars::zoom());
449 			pos_x += static_cast<int>(strlen(no_indicators_str) * Vars::zoom() * Vars::font_x() + 0.5);
450 		}
451 		change_width(pos_x + Vars::border());
452 	}
453 
454 
455 	//	If different, resize the window and move if in the default location.
456 	//
change_width(int new_x_len)457 	void Indicators_Container::change_width(int new_x_len)
458 	{
459 		if (new_x_len != x_len)
460 		{
461 			x_len = new_x_len;
462 			y_len = Vars::y_len();
463 			resize_window (indicators_win, x_len, y_len);
464 			if (default_location)
465 			{
466 				std::pair<int,int> loc = get_default_location();
467 				move_window(indicators_win, -1, 0, loc.first, loc.second);
468 			}
469 		}
470 	}
471 
472 
473 	//	Return an iterator to the indicator under the mouse or .end()
474 	//
get_over(int mx)475 	std::vector<Basic_Indicator *>::iterator Indicators_Container::get_over(int mx)
476 	{
477 		std::vector<Basic_Indicator *>::iterator i = indicators.begin();
478 		int pos_x = Vars::border();
479 		for (; i<indicators.end(); ++i)
480 		{
481 			if ((*i)->not_active())
482 				continue;
483 			int width = (*i)->get_width() + 2 * Vars::space();
484 			if ((mx > pos_x) && (mx < (pos_x + width)))
485 			{
486 				(*i)->set_over();
487 				return i;
488 			}
489 			pos_x += width;
490 		}
491 		return indicators.end();
492 	}
493 
494 
495 	//	If the mouse is over an indicator, draw the tool-tip.
496 	//
show_tooltip(window_info * win,int mx)497 	void Indicators_Container::show_tooltip(window_info *win, int mx)
498 	{
499 		std::vector<Basic_Indicator *>::iterator i = get_over(mx);
500 		if (win && (i < indicators.end()))
501 		{
502 			eternal_lands::FontManager &fmgr = eternal_lands::FontManager::get_instance();
503 			std::string tooltip("");
504 			(*i)->get_tooltip(tooltip);
505 			int width = fmgr.line_width(win->font_category, (const unsigned char*)tooltip.c_str(),
506 				tooltip.length(), win->current_scale_small);
507 			int x_offset = -(Vars::border() + width);
508 			if ((win->cur_x + x_offset) < 0)
509 				x_offset = win->len_x;
510 			show_help(tooltip.c_str(), x_offset, Vars::border(), win->current_scale);
511 		}
512 	}
513 
514 
515 	//	If click an indicator, execute the action.
516 	//
click(int mx,Uint32 flags)517 	void Indicators_Container::click(int mx, Uint32 flags)
518 	{
519 		if (flags&ELW_LEFT_MOUSE)
520 		{
521 			std::vector<Basic_Indicator *>::iterator i = get_over(mx);
522 			if (i < indicators.end())
523 				(*i)->do_action();
524 		}
525 	}
526 
527 
528 	//	Change a window property bit flag
529 	//
set_win_flag(Uint32 flag,int state)530 	void Indicators_Container::set_win_flag(Uint32 flag, int state)
531 	{
532 		if ((indicators_win > -1) && (indicators_win < windows_list.num_windows))
533 		{
534 			Uint32 *flags = &windows_list.window[indicators_win].flags;
535 			if (state)
536 				*flags |= flag;
537 			else
538 				*flags &= ~flag;
539 		}
540 	}
541 
542 
543 	//	The context menu callback function.
544 	//
cm_handler(window_info * win,int widget_id,int mx,int my,int option)545 	int Indicators_Container::cm_handler(window_info *win, int widget_id, int mx, int my, int option)
546 	{
547 		size_t index = static_cast<size_t>(option - CMHI_INDBASE);
548 		if (option < ELW_CM_MENU_LEN)
549 			return cm_title_handler(win, widget_id, mx, my, option);
550 		if (index < indicators.size())
551 			return 1;
552 		switch (option)
553 		{
554 			case CMHI_RELOC:
555 				if (win->flags & ELW_TITLE_BAR)
556 				{
557 					win->flags &= ~(ELW_TITLE_BAR|ELW_DRAGGABLE);
558 					cm_relocatable = 0;
559 				}
560 				else
561 				{
562 					win->flags |= ELW_TITLE_BAR|ELW_DRAGGABLE;
563 					cm_relocatable = 1;
564 					default_location = false;
565 					if (win->cur_y == 0)
566 						move_window(win->window_id, -1, 0, win->cur_x, win->title_height);
567 				}
568 				if (win->cur_y == win->title_height)
569 					move_window(win->window_id, -1, 0, win->cur_x, 0);
570 				else if (win->cur_y == 0)
571 					move_window(win->window_id, -1, 0, win->cur_x, win->title_height);
572 				break;
573 			case CMHI_BACKGROUND: set_background(background_on); break;
574 			case CMHI_BORDER: set_border(border_on); break;
575 			case CMHI_RESET:
576 				{
577 					std::pair<int,int> loc = get_default_location();
578 					move_window(indicators_win, -1, 0, loc.first, loc.second);
579 					win->flags &= ~(ELW_TITLE_BAR|ELW_DRAGGABLE);
580 					cm_relocatable = 0;
581 					default_location = true;
582 					set_background(false);
583 					set_border(false);
584 					break;
585 				}
586 			default:
587 				return 0;
588 		}
589 		return 1;
590 	}
591 
592 
593 	//	Get the width of the indicators window if enabled and in the default location, otherwise 0.
594 	//
get_default_width(void)595 	int Indicators_Container::get_default_width(void)
596 	{
597 		if (!get_show_window(indicators_win) || !default_location || indicators_win < 0)
598 			return 0;
599 		return windows_list.window[indicators_win].len_x;
600 	}
601 
602 
603 	//	Get the x,y location, nice and snug against the bottom and right border
604 	//
get_default_location(void)605 	std::pair<int,int> Indicators_Container::get_default_location(void)
606 	{
607 		std::pair<int,int> loc;
608 		loc.first = window_width - HUD_MARGIN_X - x_len;
609 		loc.second = window_height - y_len;
610 		return loc;
611 	}
612 
613 
614 	//	Called when saving client settings
615 	//
get_settings(unsigned int * opts,unsigned int * pos) const616 	void Indicators_Container::get_settings(unsigned int *opts, unsigned int *pos) const
617 	{
618 		unsigned int flags = 0;
619 		unsigned int shift = 0;
620 		unsigned int x = 0;
621 		unsigned int y = 0;
622 
623 		if (indicators_win < 0)
624 		{
625 			*opts = option_settings;
626 			*pos = position_settings;
627 			return;
628 		}
629 
630 		std::vector<Basic_Indicator *>::const_iterator i;
631 		for (i=indicators.begin(); i<indicators.end(); ++i, shift++)
632 			flags |= (((*i)->not_active()) ?1 :0) << shift;
633 
634 		if (!default_location)
635 			flags |= 1 << 24;
636 		flags |= background_on << 25;
637 		flags |= border_on << 26;
638 		*opts = flags;
639 
640 		x = static_cast<unsigned int>(windows_list.window[indicators_win].cur_x);
641 		y = static_cast<unsigned int>(windows_list.window[indicators_win].cur_y);
642 		*pos = x | (y<<16);
643 	}
644 
645 
646 #ifdef JSON_FILES
647 	//	Read the options from the client state file
648 	//
read_settings(const char * dict_name)649 	void Indicators_Container::read_settings(const char *dict_name)
650 	{
651 		int pos_x = json_cstate_get_int(dict_name, "pos_x", 0);
652 		int pos_y = json_cstate_get_int(dict_name, "pos_y", 0);
653 		position_settings = (pos_x & 0xFFFF) | ((pos_y & 0xFFFF) << 16);
654 
655 		option_settings = json_cstate_get_unsigned_int(dict_name, "disabled_flags", 0);
656 		option_settings |= json_cstate_get_bool(dict_name, "relocated", 0) << 24;
657 		option_settings |= json_cstate_get_bool(dict_name, "background_on", 0) << 25;
658 		option_settings |= json_cstate_get_bool(dict_name, "border_on", 0) << 26;
659 		have_settings = true;
660 	}
661 
662 
663 	//	Write the options from the client state file
664 	//
write_settings(const char * dict_name) const665 	void Indicators_Container::write_settings(const char *dict_name) const
666 	{
667 		if (indicators_win < 0)
668 		{
669 			json_cstate_set_int(dict_name, "pos_x", position_settings & 0xFFFF);
670 			json_cstate_set_int(dict_name, "pos_y", (position_settings >> 16 ) & 0xFFFF);
671 			json_cstate_set_unsigned_int(dict_name, "disabled_flags", option_settings & 0x00FFFFFF);
672 			json_cstate_set_bool(dict_name, "relocated", (option_settings >> 24) & 1);
673 			json_cstate_set_bool(dict_name, "background_on", (option_settings >> 25) & 1);
674 			json_cstate_set_bool(dict_name, "border_on", (option_settings >> 26) & 1);
675 			return;
676 		}
677 
678 		unsigned int disabled_flags = 0, shift = 0;
679 		std::vector<Basic_Indicator *>::const_iterator  i;
680 		for (i=indicators.begin(); i<indicators.end(); ++i, shift++)
681 			disabled_flags |= (((*i)->not_active()) ?1 :0) << shift;
682 		json_cstate_set_unsigned_int(dict_name, "disabled_flags", disabled_flags);
683 
684 		json_cstate_set_unsigned_int(dict_name, "pos_x", static_cast<unsigned int>(windows_list.window[indicators_win].cur_x));
685 		json_cstate_set_unsigned_int(dict_name, "pos_y", static_cast<unsigned int>(windows_list.window[indicators_win].cur_y));
686 		json_cstate_set_bool(dict_name, "relocated", (default_location) ?0: 1);
687 		json_cstate_set_bool(dict_name, "background_on", background_on);
688 		json_cstate_set_bool(dict_name, "border_on", border_on);
689 	}
690 #endif
691 
692 } // end namespace
693 
694 
695 //	Variables and functions accessible from rest of client
696 //
697 extern "C"
698 {
699 	int show_hud_indicators = 1;
init_hud_indicators(void)700 	void init_hud_indicators(void) { if (show_hud_indicators) Indicators::container.init(); }
destroy_hud_indicators(void)701 	void destroy_hud_indicators(void) { Indicators::container.destroy(); }
show_hud_indicators_window(void)702 	void show_hud_indicators_window(void) { if (show_hud_indicators) Indicators::container.show(); }
hide_hud_indicators_window(void)703 	void hide_hud_indicators_window(void) { Indicators::container.hide(); }
toggle_hud_indicators_window(int * show)704 	void toggle_hud_indicators_window(int *show) { *show = !*show; Indicators::container.toggle(*show); }
set_settings_hud_indicators(unsigned int opts,unsigned int pos)705 	void set_settings_hud_indicators(unsigned int opts, unsigned int pos) { Indicators::container.set_settings(opts, pos); }
get_settings_hud_indicators(unsigned int * opts,unsigned int * pos)706 	void get_settings_hud_indicators(unsigned int *opts, unsigned int *pos) { Indicators::container.get_settings(opts, pos); }
707 #ifdef JSON_FILES
read_settings_hud_indicators(const char * dict_name)708 	void read_settings_hud_indicators(const char *dict_name) { Indicators::container.read_settings(dict_name); }
write_settings_hud_indicators(const char * dict_name)709 	void write_settings_hud_indicators(const char *dict_name) { Indicators::container.write_settings(dict_name); }
710 #endif
get_hud_indicators_default_width(void)711 	int get_hud_indicators_default_width(void) { if (show_hud_indicators) return Indicators::container.get_default_width(); else return 0; }
712 }
713