1 /*
2  * Copyright (c) 1997 - 2001 Hansj�rg Malthaner
3  *
4  * This file is part of the Simutrans project under the artistic licence.
5  * (see licence.txt)
6  */
7 
8 /*
9  * [Mathew Hounsell] Min Size Button On Map Window 20030313
10  */
11 
12 #include <string>
13 #include <stdio.h>
14 #include <cmath>
15 
16 #include "minimap.h"
17 #include "map_frame.h"
18 
19 #include "simwin.h"
20 #include "../simsys.h"
21 
22 #include "../simworld.h"
23 #include "../display/simgraph.h"
24 #include "../display/viewport.h"
25 #include "../simcolor.h"
26 #include "../bauer/fabrikbauer.h"
27 #include "../bauer/goods_manager.h"
28 #include "../dataobj/environment.h"
29 #include "../dataobj/translator.h"
30 #include "../dataobj/koord.h"
31 #include "../dataobj/loadsave.h"
32 #include "../descriptor/factory_desc.h"
33 #include "../simfab.h"
34 #include "../player/finance.h"
35 
36 static koord old_ij=koord::invalid;
37 
38 karte_ptr_t map_frame_t::welt;
39 
40 scr_size map_frame_t::window_size;
41 bool  map_frame_t::legend_visible=false;
42 bool  map_frame_t::scale_visible=false;
43 bool  map_frame_t::directory_visible=false;
44 bool  map_frame_t::is_cursor_hidden=false;
45 bool  map_frame_t::filter_factory_list=true;
46 
47 // Hajo: we track our position onscreen
48 scr_coord map_frame_t::screenpos;
49 
50 /**
51  * Scroll-container of map. Hack: size calculations of minimap_t are intertwined with map_frame_t.
52  */
53 class gui_scrollpane_map_t : public gui_scrollpane_t
54 {
55 public:
gui_scrollpane_map_t(gui_component_t * comp)56 	gui_scrollpane_map_t(gui_component_t *comp) : gui_scrollpane_t(comp) {}
57 
get_max_size() const58 	scr_size get_max_size() const OVERRIDE { return scr_size::inf;}
59 };
60 
61 /**
62  * Entries in factory legend: show color indicator + name
63  */
64 class legend_entry_t : public gui_component_t
65 {
66 	gui_label_t label;
67 	PIXVAL color;
68 public:
legend_entry_t(const char * text,PIXVAL c)69 	legend_entry_t(const char* text, PIXVAL c) : label(text), color(c) {}
70 
get_min_size() const71 	scr_size get_min_size() const OVERRIDE
72 	{
73 		return  label.get_min_size() + scr_size(D_INDICATOR_BOX_WIDTH + D_H_SPACE, 0);
74 	}
75 
get_max_size() const76 	scr_size get_max_size() const OVERRIDE
77 	{
78 		return scr_size( scr_size::inf.w, label.get_max_size().h );
79 	}
80 
draw(scr_coord offset)81 	void draw(scr_coord offset) OVERRIDE
82 	{
83 		scr_coord pos = get_pos() + offset;
84 		display_fillbox_wh_clip_rgb(pos.x, pos.y + D_GET_CENTER_ALIGN_OFFSET(D_INDICATOR_BOX_HEIGHT,LINESPACE), D_INDICATOR_BOX_WIDTH, D_INDICATOR_BOX_HEIGHT, color, false);
85 		label.draw(pos + scr_size(D_INDICATOR_BOX_WIDTH + D_H_SPACE, 0));
86 	}
87 };
88 
89 /**
90  * Show scale of severity-MAX_SEVERITY_COLORS
91  */
92 class gui_scale_t : public gui_component_t
93 {
94 public:
draw(scr_coord offset)95 	void draw(scr_coord offset) OVERRIDE
96 	{
97 		scr_coord pos = get_pos() + offset;
98 		double bar_width = (double)get_size().w/(double)MAX_SEVERITY_COLORS;
99 		// color bar
100 		for(  int i=0;  i<MAX_SEVERITY_COLORS;  i++  ) {
101 			display_fillbox_wh_clip_rgb(pos.x + (i*bar_width), pos.y+2,  bar_width+1, 7, minimap_t::calc_severity_color(i, MAX_SEVERITY_COLORS-1), false);
102 		}
103 	}
get_min_size() const104 	scr_size get_min_size() const OVERRIDE
105 	{
106 		return scr_size(0, 9);
107 	}
get_max_size() const108 	scr_size get_max_size() const OVERRIDE
109 	{
110 		return scr_size( scr_size::inf.w, 9);
111 	}
112 };
113 
114 typedef struct {
115 	PIXVAL color;
116 	PIXVAL select_color;
117 	const char *button_text;
118 	const char *tooltip_text;
119 	minimap_t::MAP_DISPLAY_MODE mode;
120 } map_button_t;
121 
122 
123 map_button_t button_init[MAP_MAX_BUTTONS] = {
124 	{ COL_LIGHT_GREEN,  COL_DARK_GREEN,  "Towns", "Overlay town names", minimap_t::MAP_TOWN },
125 	{ COL_LIGHT_GREEN,  COL_DARK_GREEN,  "CityLimit", "Overlay city limits", minimap_t::MAP_CITYLIMIT },
126 	{ COL_WHITE,        COL_GREY5,       "Buildings", "Show level of city buildings", minimap_t::MAP_LEVEL },
127 	{ COL_LIGHT_GREEN,  COL_DARK_GREEN,  "PaxDest", "Overlay passenger destinations when a town window is open", minimap_t::MAP_PAX_DEST },
128 	{ COL_LIGHT_GREEN,  COL_DARK_GREEN,  "Tourists", "Highlite tourist attraction", minimap_t::MAP_TOURIST },
129 	{ COL_LIGHT_GREEN,  COL_DARK_GREEN,  "Factories", "Highlite factories", minimap_t::MAP_FACTORIES },
130 	{ COL_LIGHT_YELLOW, COL_DARK_YELLOW, "Passagiere", "Show passenger coverage/passenger network", minimap_t::MAP_PASSENGER },
131 	{ COL_LIGHT_YELLOW, COL_DARK_YELLOW, "Post", "Show mail service coverage/mail network", minimap_t::MAP_MAIL },
132 	{ COL_LIGHT_YELLOW, COL_DARK_YELLOW, "Fracht", "Show transported freight/freight network", minimap_t::MAP_FREIGHT },
133 	{ COL_LIGHT_PURPLE, COL_DARK_PURPLE, "Status", "Show capacity and if halt is overcrowded", minimap_t::MAP_STATUS },
134 	{ COL_LIGHT_PURPLE, COL_DARK_PURPLE, "hl_btn_sort_waiting", "Show how many people/much is waiting at halts", minimap_t::MAP_WAITING },
135 	{ COL_LIGHT_PURPLE, COL_DARK_PURPLE, "Queueing", "Show the change of waiting at halts", minimap_t::MAP_WAITCHANGE },
136 	{ COL_LIGHT_PURPLE, COL_DARK_PURPLE, "Service", "Show how many convoi reach a station", minimap_t::MAP_SERVICE },
137 	{ COL_LIGHT_PURPLE, COL_DARK_PURPLE, "Transfers", "Sum of departure/arrivals at halts", minimap_t::MAP_TRANSFER },
138 	{ COL_LIGHT_PURPLE, COL_DARK_PURPLE, "Origin", "Show initial passenger departure", minimap_t::MAP_ORIGIN },
139 	{ COL_WHITE,        COL_GREY5,       "Traffic", "Show usage of network", minimap_t::MAP_TRAFFIC },
140 	{ COL_WHITE,        COL_GREY5,       "Speedlimit", "Show speedlimit of ways", minimap_t::MAX_SPEEDLIMIT },
141 	{ COL_WHITE,        COL_GREY5,       "Tracks", "Highlight railroad tracks", minimap_t::MAP_TRACKS },
142 	{ COL_LIGHT_GREEN,  COL_DARK_GREEN,  "Depots", "Highlite depots", minimap_t::MAP_DEPOT },
143 	{ COL_WHITE,        COL_GREY5,       "Powerlines", "Highlite electrical transmission lines", minimap_t::MAP_POWERLINES },
144 	{ COL_WHITE,        COL_GREY5,       "Forest", "Highlite forests", minimap_t::MAP_FOREST },
145 	{ COL_WHITE,        COL_GREY5,       "Ownership", "Show the owenership of infrastructure", minimap_t::MAP_OWNER }
146 };
147 
148 #define scrolly (*p_scrolly)
149 
map_frame_t()150 map_frame_t::map_frame_t() :
151 	gui_frame_t( translator::translate("Reliefkarte") )
152 {
153 	// init statics
154 	old_ij = koord::invalid;
155 	is_dragging = false;
156 	zoomed = false;
157 
158 	// init map
159 	minimap_t *karte = minimap_t::get_instance();
160 	karte->init();
161 	karte->set_display_mode( ( minimap_t::MAP_DISPLAY_MODE)env_t::default_mapmode );
162 	// show all players by default
163 	karte->player_showed_on_map = -1;
164 
165 	p_scrolly = new gui_scrollpane_map_t( minimap_t::get_instance());
166 	// initialize scrollbar positions -- LATER
167 	const scr_size size = karte->get_size();
168 	const scr_size s_size=scrolly.get_size();
169 	const koord ij = welt->get_viewport()->get_world_position();
170 	const scr_size win_size = size-s_size; // this is the visible area
171 
172 	scrolly.set_scroll_position(  max(0,min(ij.x-win_size.w/2,size.w)), max(0, min(ij.y-win_size.h/2,size.h)) );
173 	scrolly.set_focusable( true );
174 	scrolly.set_scrollbar_mode(scrollbar_t::show_always);
175 
176 
177 	set_table_layout(1,0);
178 
179 	// first row of controls
180 	add_table(3,1);
181 	{
182 		// first row of controls
183 		// selections button
184 		b_show_legend.init(button_t::roundbox_state, "Show legend");
185 		b_show_legend.set_tooltip("Shows buttons on special topics.");
186 		b_show_legend.add_listener(this);
187 		add_component(&b_show_legend);
188 
189 		// industry list button
190 		b_show_directory.init(button_t::roundbox_state, "Show industry");
191 		b_show_directory.set_tooltip("Shows a listing with all industries on the map.");
192 		b_show_directory.add_listener(this);
193 		add_component(&b_show_directory);
194 
195 		// scale button
196 		b_show_scale.init(button_t::roundbox_state, "Show map scale");
197 		b_show_scale.set_tooltip("Shows the color code for several selections.");
198 		b_show_scale.add_listener(this);
199 		add_component(&b_show_scale);
200 	}
201 	end_table();
202 
203 
204 	// second row of controls
205 	zoom_row = add_table(6,0);
206 	{
207 		// zoom levels label
208 		new_component<gui_label_t>("map zoom");
209 
210 		// zoom levels arrow left
211 		zoom_buttons[0].init(button_t::repeatarrowleft, NULL);
212 		zoom_buttons[0].add_listener( this );
213 		add_component( zoom_buttons+0 );
214 
215 		// zoom level value label
216 		zoom_value_label.buf().append("1:1");
217 		zoom_value_label.update();
218 		add_component( &zoom_value_label );
219 
220 		// zoom levels arrow right
221 		zoom_buttons[1].init(button_t::repeatarrowright, NULL);
222 		zoom_buttons[1].add_listener( this );
223 		add_component( zoom_buttons+1 );
224 
225 		// rotate map 45� (isometric view)
226 		b_rotate45.init( button_t::square_state, "isometric map");
227 		b_rotate45.set_tooltip("Similar view as the main window");
228 		b_rotate45.add_listener(this);
229 		b_rotate45.pressed = karte->is_isometric();
230 		add_component(&b_rotate45);
231 
232 		new_component<gui_fill_t>();
233 	}
234 	end_table();
235 
236 	// filter container
237 	filter_container.set_visible(false);
238 	add_component(&filter_container);
239 	filter_container.set_table_layout(1,0);
240 
241 	filter_container.add_table(5,0);
242 	// insert selections: show networks, in filter container
243 	b_overlay_networks.init(button_t::square_state, "Networks");
244 	b_overlay_networks.set_tooltip("Overlay schedules/network");
245 	b_overlay_networks.add_listener(this);
246 	b_overlay_networks.pressed = (env_t::default_mapmode & minimap_t::MAP_LINES)!=0;
247 	filter_container.add_component( &b_overlay_networks );
248 
249 	// player combo for network overlay
250 	viewed_player_c.new_component<gui_scrolled_list_t::const_text_scrollitem_t>(translator::translate("All"), SYSCOL_TEXT);
251 	viewable_players[ 0 ] = -1;
252 	for(  int np = 0, count = 1;  np < MAX_PLAYER_COUNT;  np++  ) {
253 		if(  welt->get_player( np )  &&  welt->get_player( np )->get_finance()->has_convoi()) {
254 			viewed_player_c.new_component<gui_scrolled_list_t::const_text_scrollitem_t>(welt->get_player( np )->get_name(), color_idx_to_rgb(welt->get_player( np )->get_player_color1()+4));
255 			viewable_players[ count++ ] = np;
256 		}
257 	}
258 	viewed_player_c.set_selection(0);
259 	viewed_player_c.set_focusable( true );
260 	viewed_player_c.add_listener( this );
261 	filter_container.add_component(&viewed_player_c);
262 
263 	// freight combo for network overlay
264 	freight_type_c.set_pos( scr_coord(2*D_BUTTON_WIDTH+3*D_H_SPACE, 0) );
265 	freight_type_c.set_size( scr_size(D_BUTTON_WIDTH,D_BUTTON_HEIGHT) );
266 	freight_type_c.set_max_size( scr_size( 116, 5 * D_BUTTON_HEIGHT) );
267 	{
268 		viewable_freight_types.append(NULL);
269 		freight_type_c.new_component<gui_scrolled_list_t::const_text_scrollitem_t>( translator::translate("All"), SYSCOL_TEXT) ;
270 		viewable_freight_types.append(goods_manager_t::passengers);
271 		freight_type_c.new_component<gui_scrolled_list_t::const_text_scrollitem_t>( translator::translate("Passagiere"), SYSCOL_TEXT) ;
272 		viewable_freight_types.append(goods_manager_t::mail);
273 		freight_type_c.new_component<gui_scrolled_list_t::const_text_scrollitem_t>( translator::translate("Post"), SYSCOL_TEXT) ;
274 		viewable_freight_types.append(goods_manager_t::none); // for all freight ...
275 		freight_type_c.new_component<gui_scrolled_list_t::const_text_scrollitem_t>( translator::translate("Fracht"), SYSCOL_TEXT) ;
276 		for(  int i = 0;  i < goods_manager_t::get_max_catg_index();  i++  ) {
277 			const goods_desc_t *freight_type = goods_manager_t::get_info_catg(i);
278 			const int index = freight_type->get_catg_index();
279 			if(  index == goods_manager_t::INDEX_NONE  ||  freight_type->get_catg()==0  ) {
280 				continue;
281 			}
282 			freight_type_c.new_component<gui_scrolled_list_t::const_text_scrollitem_t>(translator::translate(freight_type->get_catg_name()), SYSCOL_TEXT);
283 			viewable_freight_types.append(freight_type);
284 		}
285 		for(  int i=0;  i < goods_manager_t::get_count();  i++  ) {
286 			const goods_desc_t *ware = goods_manager_t::get_info(i);
287 			if(  ware->get_catg() == 0  &&  ware->get_index() > 2  ) {
288 				// Special freight: Each good is special
289 				viewable_freight_types.append(ware);
290 				freight_type_c.new_component<gui_scrolled_list_t::const_text_scrollitem_t>( translator::translate(ware->get_name()), SYSCOL_TEXT) ;
291 			}
292 		}
293 	}
294 	freight_type_c.set_selection(0);
295 	minimap_t::get_instance()->freight_type_group_index_showed_on_map = NULL;
296 	freight_type_c.set_focusable( true );
297 	freight_type_c.add_listener( this );
298 	filter_container.add_component(&freight_type_c);
299 
300 	// mode of transport combo for network overlay
301 	for (int i = 0; i < simline_t::MAX_LINE_TYPE; i++) {
302 		transport_type_c.new_component<gui_scrolled_list_t::const_text_scrollitem_t>(simline_t::get_linetype_name((simline_t::linetype)i), SYSCOL_TEXT);
303 	}
304 	transport_type_c.set_selection(0);
305 	minimap_t::get_instance()->transport_type_showed_on_map = simline_t::line;
306 	transport_type_c.set_focusable( true );
307 	transport_type_c.add_listener( this );
308 	filter_container.add_component(&transport_type_c);
309 
310 	b_overlay_networks_load_factor.init(button_t::square_state, "Free Capacity");
311 	b_overlay_networks_load_factor.set_tooltip("Color according to transport capacity left");
312 	b_overlay_networks_load_factor.add_listener(this);
313 	b_overlay_networks_load_factor.pressed = 0;
314 	minimap_t::get_instance()->show_network_load_factor = 0;
315 	filter_container.add_component( &b_overlay_networks_load_factor );
316 	filter_container.end_table();
317 
318 	filter_container.add_table(5,0)->set_force_equal_columns(true);
319 	// insert filter buttons in legend container
320 	for (int index=0; index<MAP_MAX_BUTTONS; index++) {
321 		filter_buttons[index].init( button_t::box_state | button_t::flexible, button_init[index].button_text);
322 		filter_buttons[index].text_color = SYSCOL_TEXT;
323 		filter_buttons[index].set_tooltip( button_init[index].tooltip_text );
324 		filter_buttons[index].add_listener(this);
325 		filter_container.add_component(filter_buttons + index);
326 	}
327 	filter_container.end_table();
328 	update_buttons();
329 
330 	// directory container
331 	directory_container.set_table_layout(4,0);
332 	directory_container.set_visible(false);
333 	add_component(&directory_container);
334 
335 	// factory list: show used button
336 	b_filter_factory_list.init(button_t::square_state, "Show only used");
337 	b_filter_factory_list.set_tooltip("In the industry legend show only currently existing factories");
338 	b_filter_factory_list.add_listener(this);
339 	directory_container.add_component( &b_filter_factory_list, 4 );
340 	update_factory_legend();
341 
342 	// scale container
343 	scale_container.set_table_layout(3,0);
344 	scale_container.set_visible(false);
345 	add_component(&scale_container);
346 	scale_container.new_component<gui_label_t>("min");
347 	scale_container.new_component<gui_scale_t>();
348 	scale_container.new_component<gui_label_t>("max");
349 
350 	// map scrolly
351 	scrolly.set_show_scroll_x(true);
352 	scrolly.set_scroll_discrete_y(false);
353 	take_component(p_scrolly);
354 
355 	// restore window size and options
356 	show_hide_legend( legend_visible );
357 	show_hide_scale( scale_visible );
358 	show_hide_directory( directory_visible );
359 
360 	reset_min_windowsize();
361 	set_windowsize( window_size );
362 	set_resizemode(diagonal_resize);
363 }
364 
365 
update_buttons()366 void map_frame_t::update_buttons()
367 {
368 	for(  int i=0;  i<MAP_MAX_BUTTONS;  i++  ) {
369 		filter_buttons[i].pressed = (button_init[i].mode&env_t::default_mapmode)!=0;
370 		filter_buttons[i].background_color = color_idx_to_rgb(filter_buttons[i].pressed ? button_init[i].select_color : button_init[i].color);
371 	}
372 }
373 
374 
update_factory_legend()375 void map_frame_t::update_factory_legend()
376 {
377 	directory_container.remove_all();
378 	directory_container.add_component( &b_filter_factory_list, 4 );
379 
380 	if(  directory_visible  ) {
381 		vector_tpl<const factory_desc_t*> factory_types;
382 		// generate list of factory types
383 		if(  filter_factory_list  ) {
384 			FOR(slist_tpl<fabrik_t*>, const f, welt->get_fab_list()) {
385 				if(  f->get_desc()->get_distribution_weight() > 0  ) {
386 					factory_types.append_unique(f->get_desc());
387 				}
388 			}
389 		}
390 		else {
391 			FOR(stringhashtable_tpl<factory_desc_t const*>, i, factory_builder_t::get_factory_table()) {
392 				factory_desc_t const* const d = i.value;
393 				if (d->get_distribution_weight() > 0) {
394 					factory_types.append_unique(d);
395 				}
396 			}
397 		}
398 		// add corresponding legend entries
399 		FOR(vector_tpl<const factory_desc_t*>, f, factory_types) {
400 			directory_container.new_component<legend_entry_t>(f->get_name(), f->get_color());
401 		}
402 	}
403 }
404 
405 
show_hide_legend(const bool show)406 void map_frame_t::show_hide_legend(const bool show)
407 {
408 	filter_container.set_visible(show);
409 	b_show_legend.pressed = show;
410 	legend_visible = show;
411 	reset_min_windowsize();
412 }
413 
414 
show_hide_scale(const bool show)415 void map_frame_t::show_hide_scale(const bool show)
416 {
417 	scale_container.set_visible(show);
418 	b_show_scale.pressed = show;
419 	scale_visible = show;
420 	reset_min_windowsize();
421 }
422 
423 
show_hide_directory(const bool show)424 void map_frame_t::show_hide_directory(const bool show)
425 {
426 	directory_container.set_visible(show);
427 	b_show_directory.pressed = show;
428 	b_filter_factory_list.pressed = filter_factory_list;
429 	directory_visible = show;
430 	update_factory_legend();
431 	reset_min_windowsize();
432 }
433 
434 
action_triggered(gui_action_creator_t * comp,value_t)435 bool map_frame_t::action_triggered( gui_action_creator_t *comp, value_t)
436 {
437 	if(  comp == &b_show_legend  ) {
438 		show_hide_legend( !b_show_legend.pressed );
439 	}
440 	else if(  comp == &b_show_scale  ) {
441 		show_hide_scale( !b_show_scale.pressed );
442 	}
443 	else if(  comp == &b_show_directory  ) {
444 		show_hide_directory( !b_show_directory.pressed );
445 	}
446 	else if (  comp == &b_filter_factory_list  ) {
447 		filter_factory_list = !filter_factory_list;
448 		show_hide_directory( b_show_directory.pressed );
449 	}
450 	else if(  comp == zoom_buttons+1  ) {
451 		// zoom out
452 		zoom(true);
453 	}
454 	else if(  comp == zoom_buttons+0  ) {
455 		// zoom in
456 		zoom(false);
457 	}
458 	else if(  comp == &b_rotate45  ) {
459 		// rotated/straight map
460 		minimap_t::get_instance()->toggle_isometric();
461 		minimap_t::get_instance()->calc_map_size();
462 		b_rotate45.pressed = minimap_t::get_instance()->is_isometric();
463 		scrolly.set_size( scrolly.get_size() );
464 	}
465 	else if(  comp == &b_overlay_networks  ) {
466 		b_overlay_networks.pressed ^= 1;
467 		if(  b_overlay_networks.pressed  ) {
468 			env_t::default_mapmode |= minimap_t::MAP_LINES;
469 		}
470 		else {
471 			env_t::default_mapmode &= ~minimap_t::MAP_LINES;
472 		}
473 		minimap_t::get_instance()->set_display_mode(  ( minimap_t::MAP_DISPLAY_MODE)env_t::default_mapmode  );
474 	}
475 	else if (  comp == &viewed_player_c  ) {
476 		minimap_t::get_instance()->player_showed_on_map = viewable_players[viewed_player_c.get_selection()];
477 		minimap_t::get_instance()->invalidate_map_lines_cache();
478 	}
479 	else if (  comp == &transport_type_c  ) {
480 		minimap_t::get_instance()->transport_type_showed_on_map = transport_type_c.get_selection();
481 		minimap_t::get_instance()->invalidate_map_lines_cache();
482 	}
483 	else if (  comp == &freight_type_c  ) {
484 		minimap_t::get_instance()->freight_type_group_index_showed_on_map = viewable_freight_types[freight_type_c.get_selection()];
485 		minimap_t::get_instance()->invalidate_map_lines_cache();
486 	}
487 	else if (  comp == &b_overlay_networks_load_factor  ) {
488 		minimap_t::get_instance()->show_network_load_factor = !minimap_t::get_instance()->show_network_load_factor;
489 		b_overlay_networks_load_factor.pressed = !b_overlay_networks_load_factor.pressed;
490 		minimap_t::get_instance()->invalidate_map_lines_cache();
491 	}
492 	else {
493 		for(  int i=0;  i<MAP_MAX_BUTTONS;  i++  ) {
494 			if(  comp == filter_buttons+i  ) {
495 				if(  filter_buttons[i].pressed  ) {
496 					env_t::default_mapmode &= ~button_init[i].mode;
497 				}
498 				else {
499 					if(  (button_init[i].mode & minimap_t::MAP_MODE_FLAGS) == 0  ) {
500 						// clear all persistent states
501 						env_t::default_mapmode &= minimap_t::MAP_MODE_FLAGS;
502 					}
503 					else if(  button_init[i].mode & minimap_t::MAP_MODE_HALT_FLAGS  ) {
504 						// clear all other halt states
505 						env_t::default_mapmode &= ~minimap_t::MAP_MODE_HALT_FLAGS;
506 					}
507 					env_t::default_mapmode |= button_init[i].mode;
508 				}
509 				filter_buttons[i].pressed ^= 1;
510 				break;
511 			}
512 		}
513 		minimap_t::get_instance()->set_display_mode(  ( minimap_t::MAP_DISPLAY_MODE)env_t::default_mapmode  );
514 		update_buttons();
515 	}
516 	return true;
517 }
518 
519 
zoom(bool magnify)520 void map_frame_t::zoom(bool magnify)
521 {
522 	if ( minimap_t::get_instance()->change_zoom_factor(magnify)) {
523 		zoomed = true;
524 
525 		// update zoom factors and zoom label
526 		sint16 zoom_in, zoom_out;
527 		minimap_t::get_instance()->get_zoom_factors(zoom_out, zoom_in);
528 		zoom_value_label.buf().printf("%i:%i", zoom_in, zoom_out );
529 		zoom_value_label.update();
530 		zoom_row->set_size( zoom_row->get_size());
531 	}
532 }
533 
534 
535 /**
536  * Events werden hiermit an die GUI-components
537  * gemeldet
538  * @author Hj. Malthaner
539  */
infowin_event(const event_t * ev)540 bool map_frame_t::infowin_event(const event_t *ev)
541 {
542 	event_t ev2 = *ev;
543 	translate_event(&ev2, -scrolly.get_pos().x, -scrolly.get_pos().y-D_TITLEBAR_HEIGHT);
544 
545 	if(ev->ev_class == INFOWIN) {
546 		if(ev->ev_code == WIN_OPEN) {
547 			minimap_t::get_instance()->set_xy_offset_size( scr_coord(0,0), scr_size(0,0) );
548 		}
549 		else if(ev->ev_code == WIN_CLOSE) {
550 			minimap_t::get_instance()->is_visible = false;
551 		}
552 	}
553 
554 	if(  minimap_t::get_instance()->getroffen(ev2.mx,ev2.my)  ) {
555 		set_focus( minimap_t::get_instance() );
556 	}
557 
558 	if(  (IS_WHEELUP(ev) || IS_WHEELDOWN(ev))  &&  minimap_t::get_instance()->getroffen(ev2.mx,ev2.my)  ) {
559 		// otherwise these would go to the vertical scroll bar
560 		zoom(IS_WHEELUP(ev));
561 		return true;
562 	}
563 
564 	// Hajo: hack: minimap can resize upon right click
565 	// we track this here, and adjust size.
566 	if(  IS_RIGHTCLICK(ev)  ) {
567 		is_dragging = false;
568 		display_show_pointer(false);
569 		is_cursor_hidden = true;
570 		return true;
571 	}
572 	else if(  IS_RIGHTRELEASE(ev)  ) {
573 		is_dragging = false;
574 		display_show_pointer(true);
575 		is_cursor_hidden = false;
576 		return true;
577 	}
578 	else if(  IS_RIGHTDRAG(ev)  &&  ( minimap_t::get_instance()->getroffen(ev2.mx,ev2.my)  ||  minimap_t::get_instance()->getroffen(ev2.cx,ev2.cy))  ) {
579 		int x = scrolly.get_scroll_x();
580 		int y = scrolly.get_scroll_y();
581 		const int scroll_direction = ( env_t::scroll_multi>0 ? 1 : -1 );
582 
583 		x += (ev->mx - ev->cx)*scroll_direction*2;
584 		y += (ev->my - ev->cy)*scroll_direction*2;
585 
586 		is_dragging = true;
587 
588 		scrolly.set_scroll_position(  max(0, x),  max(0, y) );
589 
590 		// Move the mouse pointer back to starting location
591 		// To prevent a infinite mouse event loop, we just do it when needed.
592 		if ((ev->mx - ev->cx)!=0  ||  (ev->my-ev->cy)!=0) {
593 			move_pointer(screenpos.x + ev->cx, screenpos.y+ev->cy);
594 		}
595 
596 		return true;
597 	}
598 	else if(  IS_LEFTDBLCLK(ev)  &&  minimap_t::get_instance()->getroffen(ev2.mx,ev2.my)  ) {
599 		// re-center cursor by scrolling
600 		koord ij = welt->get_viewport()->get_world_position();
601 		scr_coord center = minimap_t::get_instance()->map_to_screen_coord(ij);
602 		const scr_size s_size = scrolly.get_size();
603 
604 		scrolly.set_scroll_position(max(0,center.x-(s_size.w/2)), max(0,center.y-(s_size.h/2)));
605 		zoomed = false;
606 
607 		// remember world position, we do not want to have surprises when scrolling later on
608 		old_ij = ij;
609 		return true;
610 	}
611 	else if(  IS_RIGHTDBLCLK(ev)  ) {
612 		// zoom to fit window
613 		do { // first, zoom all the way in
614 			zoomed = false;
615 			zoom(true);
616 		} while(  zoomed  );
617 
618 		// then zoom back out to fit
619 		const scr_size s_size = scrolly.get_size() - D_SCROLLBAR_SIZE;
620 		scr_size size = minimap_t::get_instance()->get_size();
621 		zoomed = true;
622 		while(  zoomed  &&  max(size.w/s_size.w, size.h/s_size.h)  ) {
623 			zoom(false);
624 			size = minimap_t::get_instance()->get_size();
625 		}
626 		return true;
627 	}
628 	else if(  is_cursor_hidden  ) {
629 		display_show_pointer(true);
630 		is_cursor_hidden = false;
631 	}
632 
633 	return gui_frame_t::infowin_event(ev);
634 }
635 
636 
637 /**
638  * size window in response and save it in static size
639  * @author (Mathew Hounsell)
640  * @date   11-Mar-2003
641  */
set_windowsize(scr_size size)642 void map_frame_t::set_windowsize(scr_size size)
643 {
644 	gui_frame_t::set_windowsize( size );
645 	window_size = get_windowsize();
646 }
647 
648 
649 /**
650  * Draw new component. The values to be passed refer to the window
651  * i.e. It's the screen coordinates of the window where the
652  * component is displayed.
653  * @author Hj. Malthaner
654  */
draw(scr_coord pos,scr_size size)655 void map_frame_t::draw(scr_coord pos, scr_size size)
656 {
657 	// update our stored screen position
658 	screenpos = pos;
659 	minimap_t::get_instance()->set_xy_offset_size( scr_coord(scrolly.get_scroll_x(), scrolly.get_scroll_y()), scrolly.get_client().get_size() );
660 
661 	// first: check if cursor within map screen size
662 	koord ij = welt->get_viewport()->get_world_position();
663 	if(welt->is_within_limits(ij)) {
664 		scr_coord center = minimap_t::get_instance()->map_to_screen_coord(ij);
665 		// only re-center if zoomed or world position has changed and its outside visible area
666 		const scr_size size = scrolly.get_size();
667 		if(zoomed  ||  ( old_ij != ij  &&
668 				( scrolly.get_scroll_x()>center.x  ||  scrolly.get_scroll_x()+size.w<=center.x  ||
669 				  scrolly.get_scroll_y()>center.y  ||  scrolly.get_scroll_y()+size.h<=center.y ) ) ) {
670 				// re-center cursor by scrolling
671 				scrolly.set_scroll_position( max(0,center.x-(size.w/2)), max(0,center.y-(size.h/2)) );
672 				zoomed = false;
673 		}
674 		// remember world position, we do not want to have surprises when scrolling later on
675 		old_ij = ij;
676 	}
677 
678 	// draw all child controls
679 	gui_frame_t::draw(pos, size);
680 
681 	// may add compass
682 	if(  skinverwaltung_t::compass_map  &&  env_t::compass_map_position!=0  ) {
683 		const uint16 isometric_img_offset = minimap_t::get_instance()->is_isometric() ? 4 : 0;
684 		display_img_aligned( skinverwaltung_t::compass_map->get_image_id( isometric_img_offset+welt->get_settings().get_rotation() ),
685 							 scrolly.get_client()+pos+scr_coord(4,4+D_TITLEBAR_HEIGHT)-scr_size(8,8), env_t::compass_map_position, false );
686 	}
687 }
688 
689 
rdwr(loadsave_t * file)690 void map_frame_t::rdwr( loadsave_t *file )
691 {
692 	file->rdwr_bool( legend_visible );
693 	file->rdwr_bool( scale_visible );
694 	file->rdwr_bool( directory_visible );
695 	file->rdwr_long( env_t::default_mapmode );
696 
697 	file->rdwr_bool( b_overlay_networks_load_factor.pressed );
698 
699 	minimap_t::get_instance()->rdwr(file);
700 
701 	window_size.rdwr(file);
702 	scrolly.rdwr(file);
703 
704 	viewed_player_c.rdwr(file);
705 	transport_type_c.rdwr(file);
706 	freight_type_c.rdwr(file);
707 
708 	if(  file->is_loading()  ) {
709 		set_windowsize( window_size );
710 		// notify minimap of new settings
711 		minimap_t::get_instance()->calc_map_size();
712 		scrolly.set_size( scrolly.get_size() );
713 
714 		minimap_t::get_instance()->set_display_mode(( minimap_t::MAP_DISPLAY_MODE)env_t::default_mapmode);
715 		update_buttons();
716 
717 		show_hide_directory(directory_visible);
718 		show_hide_legend(legend_visible);
719 		show_hide_scale(scale_visible);
720 
721 		b_overlay_networks.pressed = (env_t::default_mapmode & minimap_t::MAP_LINES)!=0;
722 
723 		minimap_t::get_instance()->player_showed_on_map = viewable_players[viewed_player_c.get_selection()];
724 		minimap_t::get_instance()->transport_type_showed_on_map = transport_type_c.get_selection();
725 		minimap_t::get_instance()->freight_type_group_index_showed_on_map = viewable_freight_types[freight_type_c.get_selection()];
726 		minimap_t::get_instance()->show_network_load_factor = b_overlay_networks_load_factor.pressed;
727 		minimap_t::get_instance()->invalidate_map_lines_cache();
728 	}
729 }
730