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  * A class for distribution of tabs through the gui_component_t component.
10  * @author Hj. Malthaner
11  */
12 
13 #include "gui_tab_panel.h"
14 #include "../gui_frame.h"
15 #include "../../simevent.h"
16 #include "../../display/simgraph.h"
17 #include "../../simcolor.h"
18 #include "../simwin.h"
19 
20 #include "../../descriptor/skin_desc.h"
21 
22 #define IMG_WIDTH 20
23 
24 scr_coord_val gui_tab_panel_t::header_vsize = 18;
25 
26 
gui_tab_panel_t()27 gui_tab_panel_t::gui_tab_panel_t() :
28 	required_size( 8, D_TAB_HEADER_HEIGHT )
29 {
30 	active_tab = 0;
31 	offset_tab = 0;
32 	left.init( button_t::arrowleft, NULL, scr_coord(0,0) );
33 	left.add_listener( this );
34 	right.init( button_t::arrowright, NULL, scr_coord(0,0) );
35 	right.add_listener( this );
36 }
37 
38 
39 
add_tab(gui_component_t * c,const char * name,const skin_desc_t * desc,const char * tooltip)40 void gui_tab_panel_t::add_tab(gui_component_t *c, const char *name, const skin_desc_t *desc, const char *tooltip )
41 {
42 	tabs.append( tab(c, desc?NULL:name, desc?desc->get_image(0):NULL, tooltip) );
43 	set_size( get_size() );
44 }
45 
46 
47 
48 
set_size(scr_size size)49 void gui_tab_panel_t::set_size(scr_size size)
50 {
51 	gui_component_t::set_size(size);
52 
53 	required_size = scr_size( 8, required_size.h );
54 	FOR(slist_tpl<tab>, & i, tabs) {
55 		i.x_offset = required_size.w - 4;
56 		i.width             = 8 + (i.title ? proportional_string_width(i.title) : IMG_WIDTH);
57 		required_size.w += i.width;
58 		if (i.title) {
59 			required_size.h = max(required_size.h, LINESPACE + D_V_SPACE);
60 		}
61 		i.component->set_pos(scr_coord(0, required_size.h));
62 		i.component->set_size(get_size() - scr_size(0, required_size.h));
63 	}
64 
65 	if(  required_size.w > size.w  ||  offset_tab > 0  ) {
66 		left.set_pos( scr_coord( 0, 0 ) );
67 		left.set_size( scr_size( D_ARROW_LEFT_WIDTH, required_size.h ) );
68 		right.set_pos( scr_coord( size.w-D_ARROW_RIGHT_WIDTH, 0 ) );
69 		right.set_size( scr_size( D_ARROW_RIGHT_WIDTH, required_size.h ) );
70 	}
71 }
72 
73 
get_min_size() const74 scr_size gui_tab_panel_t::get_min_size() const
75 {
76 	scr_size t_size(0, required_size.h);
77 	scr_size c_size(0, 0);
78 	FOR(slist_tpl<tab>, const& iter, tabs) {
79 		if (iter.title) {
80 			t_size.h = max(t_size.h, LINESPACE + D_V_SPACE);
81 		}
82 		c_size.clip_lefttop( iter.component->get_min_size() );
83 	}
84 	return t_size + c_size;
85 }
86 
87 
action_triggered(gui_action_creator_t * comp,value_t)88 bool gui_tab_panel_t::action_triggered(gui_action_creator_t *comp, value_t)
89 {
90 	if(  comp == &right  ) {
91 		offset_tab = min( offset_tab+1, tabs.get_count()-1 );
92 	}
93 	else if(  comp == &left  ) {
94 		offset_tab = max( offset_tab-1, 0 );
95 	}
96 	return true;
97 }
98 
99 
infowin_event(const event_t * ev)100 bool gui_tab_panel_t::infowin_event(const event_t *ev)
101 {
102 	if(  (required_size.w>size.w  ||  offset_tab > 0)  &&  ev->ev_class!=EVENT_KEYBOARD  &&  ev->ev_code==MOUSE_LEFTBUTTON  ) {
103 		// buttons pressed
104 		if(  left.getroffen(ev->cx, ev->cy)  ) {
105 			event_t ev2 = *ev;
106 			translate_event(&ev2, -left.get_pos().x, -left.get_pos().y);
107 			return left.infowin_event(&ev2);
108 		}
109 		else if(  right.getroffen(ev->cx, ev->cy)  ) {
110 			event_t ev2 = *ev;
111 			translate_event(&ev2, -right.get_pos().x, -right.get_pos().y);
112 			return right.infowin_event(&ev2);
113 		}
114 	}
115 
116 	if(  IS_LEFTRELEASE(ev)  &&  (ev->my > 0  &&  ev->my < required_size.h-1)  )  {
117 		// tab selector was hit
118 		int text_x = required_size.w>size.w ? 14 : 4;
119 		int k=0;
120 		FORX(slist_tpl<tab>, const& i, tabs, ++k) {
121 			if(  k >= offset_tab  ) {
122 				if (text_x < ev->mx && text_x + i.width > ev->mx) {
123 					// either tooltip or change
124 					active_tab = k;
125 					call_listeners((long)active_tab);
126 					return true;
127 				}
128 				text_x += i.width;
129 			}
130 		}
131 		return false;
132 	}
133 
134 	// Knightly : navigate among the tabs using Ctrl-PgUp and Ctrl-PgDn
135 	if(  ev->ev_class==EVENT_KEYBOARD  &&  IS_CONTROL_PRESSED(ev)  ) {
136 		if(  ev->ev_code==SIM_KEY_PGUP  ) {
137 			// Ctrl-PgUp -> go to the previous tab
138 			const int next_tab_idx = active_tab - 1;
139 			active_tab = next_tab_idx<0 ? max(0, (int)tabs.get_count()-1) : next_tab_idx;
140 			return true;
141 		}
142 		else if(  ev->ev_code==SIM_KEY_PGDN  ) {
143 			// Ctrl-PgDn -> go to the next tab
144 			const int next_tab_idx = active_tab + 1;
145 			active_tab = next_tab_idx>=(int)tabs.get_count() ? 0 : next_tab_idx;
146 			return true;
147 		}
148 	}
149 
150 	if(  ev->ev_class == EVENT_KEYBOARD  ||  DOES_WINDOW_CHILDREN_NEED(ev)  ||  get_aktives_tab()->getroffen(ev->mx, ev->my)  ||  get_aktives_tab()->getroffen(ev->cx, ev->cy)) {
151 		// active tab was hit
152 		event_t ev2 = *ev;
153 		translate_event(&ev2, -get_aktives_tab()->get_pos().x, -get_aktives_tab()->get_pos().y );
154 		return get_aktives_tab()->infowin_event(&ev2);
155 	}
156 	return false;
157 }
158 
159 
160 
draw(scr_coord parent_pos)161 void gui_tab_panel_t::draw(scr_coord parent_pos)
162 {
163 	// Position in screen/window
164 	int xpos = parent_pos.x + pos.x;
165 	const int ypos = parent_pos.y + pos.y;
166 
167 	if(  required_size.w>size.w  ||  offset_tab > 0) {
168 		left.draw( parent_pos+pos );
169 		right.draw( parent_pos+pos );
170 		//display_fillbox_wh_clip_rgb(xpos, ypos+required_size.h-1, 10, 1, SYSCOL_TEXT_HIGHLIGHT, true);
171 		display_fillbox_wh_clip_rgb(xpos, ypos+required_size.h-1, D_ARROW_LEFT_WIDTH, 1, SYSCOL_HIGHLIGHT, true);
172 		xpos += D_ARROW_LEFT_WIDTH;
173 	}
174 
175 	int text_x = xpos + 8;
176 	int text_y = ypos + (required_size.h - LINESPACE)/2;
177 
178 	//display_fillbox_wh_clip_rgb(xpos, ypos+required_size.h-1, 4, 1, color_idx_to_rgb(COL_WHITE), true);
179 	display_fillbox_wh_clip_rgb(xpos, ypos+required_size.h-1, 4, 1, SYSCOL_HIGHLIGHT, true);
180 
181 	// do not draw under right button
182 	int xx = required_size.w>get_size().w ? get_size().w-(D_ARROW_LEFT_WIDTH+2+D_ARROW_RIGHT_WIDTH) : get_size().w;
183 
184 	int i=0;
185 	FORX(slist_tpl<tab>, const& iter, tabs, ++i) {
186 		// just draw component, if here ...
187 		if (i == active_tab) {
188 			iter.component->draw(parent_pos + pos);
189 		}
190 		if(i>=offset_tab) {
191 			// set clipping
192 			PUSH_CLIP_FIT(xpos, ypos, xx, required_size.h);
193 			// only start drawing here ...
194 			char const* const text = iter.title;
195 			const int width = text ? proportional_string_width( text ) : IMG_WIDTH;
196 
197 			if (i != active_tab) {
198 				// Non active tabs
199 				display_fillbox_wh_clip_rgb(text_x-3, ypos+2, width+6, 1, SYSCOL_HIGHLIGHT, true);
200 				display_fillbox_wh_clip_rgb(text_x-4, ypos+required_size.h-1, width+8, 1, SYSCOL_HIGHLIGHT, true);
201 
202 				display_vline_wh_clip_rgb(text_x-4, ypos+3, required_size.h-4, SYSCOL_HIGHLIGHT, true);
203 				display_vline_wh_clip_rgb(text_x+width+3, ypos+3, required_size.h-4, SYSCOL_SHADOW, true);
204 
205 				if(text) {
206 					display_proportional_clip_rgb(text_x, text_y, text, ALIGN_LEFT, SYSCOL_TEXT, true);
207 				}
208 				else {
209 					scr_coord_val const y = ypos   - iter.img->get_pic()->y + 10            - iter.img->get_pic()->h / 2;
210 					scr_coord_val const x = text_x - iter.img->get_pic()->x + IMG_WIDTH / 2 - iter.img->get_pic()->w / 2;
211 					display_img_blend(iter.img->get_id(), x, y, TRANSPARENT50_FLAG, false, true);
212 				}
213 			}
214 			else {
215 				// Active tab
216 				display_fillbox_wh_clip_rgb(text_x-3, ypos, width+6, 1, SYSCOL_HIGHLIGHT, true);
217 
218 				display_vline_wh_clip_rgb(text_x-4, ypos+1, required_size.h-2, SYSCOL_HIGHLIGHT, true);
219 				display_vline_wh_clip_rgb(text_x+width+3, ypos+1, required_size.h-2, SYSCOL_SHADOW, true);
220 
221 				if(text) {
222 					display_proportional_clip_rgb(text_x, text_y, text, ALIGN_LEFT, SYSCOL_TEXT_HIGHLIGHT, true);
223 				}
224 				else {
225 					scr_coord_val const y = ypos   - iter.img->get_pic()->y + 10            - iter.img->get_pic()->h / 2;
226 					scr_coord_val const x = text_x - iter.img->get_pic()->x + IMG_WIDTH / 2 - iter.img->get_pic()->w / 2;
227 					display_color_img(iter.img->get_id(), x, y, 0, false, true);
228 				}
229 			}
230 			text_x += width + 8;
231 			// reset clipping
232 			POP_CLIP();
233 		}
234 	}
235 	display_fillbox_wh_clip_rgb(text_x-4, ypos+required_size.h-1, xpos+size.w-(text_x-4), 1, SYSCOL_HIGHLIGHT, true);
236 
237 	// now for tooltips ...
238 	int my = get_mouse_y()-parent_pos.y-pos.y-6;
239 	if(my>=0  &&  my < required_size.h-1) {
240 		// Reiter getroffen?
241 		int mx = get_mouse_x()-parent_pos.x-pos.x-11;
242 		int text_x = 4;
243 		int i=0;
244 		FORX(slist_tpl<tab>, const& iter, tabs, ++i) {
245 			if(  i>=offset_tab  ) {
246 				char const* const text = iter.title;
247 				const int width = text ? proportional_string_width( text ) : IMG_WIDTH;
248 
249 				if(text_x < mx && text_x+width+8 > mx  && (required_size.w<=get_size().w || mx < right.get_pos().x-12)) {
250 					// tooltip or change
251 					win_set_tooltip(get_mouse_x() + 16, ypos + required_size.h + 12, iter.tooltip, &iter, this);
252 					break;
253 				}
254 
255 				text_x += width + 8;
256 			}
257 		}
258 	}
259 }
260 
261 
clear()262 void gui_tab_panel_t::clear()
263 {
264 	tabs.clear();
265 	active_tab = 0;
266 }
267 
268 
take_tabs(gui_tab_panel_t * other)269 void gui_tab_panel_t::take_tabs(gui_tab_panel_t* other)
270 {
271 	tabs.append_list(other->tabs);
272 }
273 
274 
rdwr(loadsave_t * file)275 void gui_tab_panel_t::rdwr( loadsave_t *file )
276 {
277 	sint32 a = get_active_tab_index();
278 	file->rdwr_long(a);
279 	if (file->is_loading()) {
280 		set_active_tab_index(a);
281 	}
282 }
283