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