/[collab-maint]/deb-maint/openttd/trunk/graph_gui.c
ViewVC logotype

Contents of /deb-maint/openttd/trunk/graph_gui.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2489 - (show annotations) (download)
Fri May 27 23:39:24 2005 UTC (7 years, 11 months ago) by matthijs
Original Path: deb-maint/openttd/branches/upstream/current/graph_gui.c
File MIME type: text/plain
File size: 34907 byte(s)
* Import openttd 0.4.0.1 source.
1 #include "stdafx.h"
2 #include "ttd.h"
3 #include "table/strings.h"
4 #include "window.h"
5 #include "gui.h"
6 #include "gfx.h"
7 #include "player.h"
8 #include "economy.h"
9 #include "signs.h"
10 #include "strings.h"
11 #include "debug.h"
12
13 static uint _legend_excludebits;
14 static uint _legend_cargobits;
15
16 /************************/
17 /* GENERIC GRAPH DRAWER */
18 /************************/
19
20 enum {GRAPH_NUM = 16};
21
22 typedef struct GraphDrawer {
23 uint sel; // bitmask of the players *excluded* (e.g. 11111111 means that no players are shown)
24 byte num_dataset;
25 byte num_on_x_axis;
26 byte month;
27 byte year;
28 bool include_neg;
29 byte num_vert_lines;
30 uint16 unk61A;
31 uint16 unk61C;
32 int left, top;
33 uint height;
34 StringID format_str_y_axis;
35 byte color_3, color_2, bg_line_color;
36 byte colors[GRAPH_NUM];
37 uint64 cost[GRAPH_NUM][24]; // last 2 years
38 } GraphDrawer;
39
40 #define INVALID_VALUE 0x80000000
41
42 static void DrawGraph(GraphDrawer *gw)
43 {
44
45 int i,j,k;
46 uint x,y,old_x,old_y;
47 int color;
48 int right, bottom;
49 int num_x, num_dataset;
50 uint64 *row_ptr, *col_ptr;
51 int64 mx;
52 int adj_height;
53 uint64 y_scaling, tmp;
54 int64 value;
55 int64 cur_val;
56 uint sel;
57
58 /* the colors and cost array of GraphDrawer must accomodate
59 * both values for cargo and players. So if any are higher, quit */
60 assert(GRAPH_NUM >= NUM_CARGO && GRAPH_NUM >= MAX_PLAYERS);
61
62 color = _color_list[gw->bg_line_color].window_color_1b;
63
64 /* draw the vertical lines */
65 i = gw->num_vert_lines; assert(i > 0);
66 x = gw->left + 66;
67 bottom = gw->top + gw->height - 1;
68 do {
69 GfxFillRect(x, gw->top, x, bottom, color);
70 x += 22;
71 } while (--i);
72
73 /* draw the horizontal lines */
74 i = 9;
75 x = gw->left + 44;
76 y = gw->height + gw->top;
77 right = gw->left + 44 + gw->num_vert_lines*22-1;
78
79 do {
80 GfxFillRect(x, y, right, y, color);
81 y -= gw->height >> 3;
82 } while (--i);
83
84 /* draw vertical edge line */
85 GfxFillRect(x, gw->top, x, bottom, gw->color_2);
86
87 adj_height = gw->height;
88 if (gw->include_neg) adj_height >>= 1;
89
90 /* draw horiz edge line */
91 y = adj_height + gw->top;
92 GfxFillRect(x, y, right, y, gw->color_2);
93
94 /* find the max element */
95 if (gw->num_on_x_axis == 0)
96 return;
97
98 num_dataset = gw->num_dataset;
99 assert(num_dataset > 0);
100
101 row_ptr = gw->cost[0];
102 mx = 0;
103 /* bit selection for the showing of various players, base max element
104 * on to-be shown player-information. This way the graph can scale */
105 sel = gw->sel;
106 do {
107 if (!(sel&1)) {
108 num_x = gw->num_on_x_axis;
109 assert(num_x > 0);
110 col_ptr = row_ptr;
111 do {
112 if (*col_ptr != INVALID_VALUE) {
113 mx = max64(mx, myabs64(*col_ptr));
114 }
115 } while (col_ptr++, --num_x);
116 }
117 } while (sel>>=1, row_ptr+=24, --num_dataset);
118
119 /* setup scaling */
120 y_scaling = INVALID_VALUE;
121 value = adj_height * 2;
122
123 if (mx > value) {
124 mx = (mx + 7) & ~7;
125 y_scaling = (((uint64) (value>>1) << 32) / mx);
126 value = mx;
127 }
128
129 /* draw text strings on the y axis */
130 tmp = value;
131 if (gw->include_neg) tmp >>= 1;
132 x = gw->left + 45;
133 y = gw->top - 3;
134 i = 9;
135 do {
136 SetDParam(0, gw->format_str_y_axis);
137 SetDParam64(1, (int64)tmp);
138 tmp -= (value >> 3);
139 DrawStringRightAligned(x, y, STR_0170, gw->color_3);
140 y += gw->height >> 3;
141 } while (--i);
142
143 /* draw strings on the x axis */
144 if (gw->month != 0xFF) {
145 x = gw->left + 44;
146 y = gw->top + gw->height + 1;
147 j = gw->month;
148 k = gw->year + MAX_YEAR_BEGIN_REAL;
149 i = gw->num_on_x_axis;assert(i>0);
150 do {
151 SetDParam(2, k);
152 SetDParam(0, j + STR_0162_JAN);
153 SetDParam(1, j + STR_0162_JAN + 2);
154 DrawString(x, y, j == 0 ? STR_016F : STR_016E, gw->color_3);
155
156 j += 3;
157 if (j >= 12) {
158 j = 0;
159 k++;
160 }
161 x += 22;
162 } while (--i);
163 } else {
164 x = gw->left + 52;
165 y = gw->top + gw->height + 1;
166 j = gw->unk61A;
167 i = gw->num_on_x_axis;assert(i>0);
168 do {
169 SetDParam(0, j);
170 DrawString(x, y, STR_01CB, gw->color_3);
171 j += gw->unk61C;
172 x += 22;
173 } while (--i);
174 }
175
176 /* draw lines and dots */
177 i = 0;
178 row_ptr = gw->cost[0];
179 sel = gw->sel; // show only selected lines. GraphDrawer qw->sel set in Graph-Legend (_legend_excludebits)
180 do {
181 if (!(sel & 1)) {
182 x = gw->left + 55;
183 j = gw->num_on_x_axis;assert(j>0);
184 col_ptr = row_ptr;
185 color = gw->colors[i];
186 old_y = old_x = INVALID_VALUE;
187 do {
188 cur_val = *col_ptr++;
189 if (cur_val != INVALID_VALUE) {
190 y = adj_height - BIGMULSS64(cur_val, y_scaling >> 1, 31) + gw->top;
191
192 GfxFillRect(x-1, y-1, x+1, y+1, color);
193 if (old_x != INVALID_VALUE)
194 GfxDrawLine(old_x, old_y, x, y, color);
195
196 old_x = x;
197 old_y = y;
198 } else {
199 old_x = INVALID_VALUE;
200 }
201 } while (x+=22,--j);
202 }
203 } while (sel>>=1,row_ptr+=24, ++i < gw->num_dataset);
204 }
205
206 /****************/
207 /* GRAPH LEGEND */
208 /****************/
209
210 void DrawPlayerIcon(int p, int x, int y)
211 {
212 DrawSprite(SPRITE_PALETTE(PLAYER_SPRITE_COLOR(p) + 0x2EB), x, y);
213 }
214
215 static void GraphLegendWndProc(Window *w, WindowEvent *e)
216 {
217 Player *p;
218
219 switch(e->event) {
220 case WE_PAINT:
221 FOR_ALL_PLAYERS(p) {
222 if (!p->is_active)
223 SETBIT(_legend_excludebits, p->index);
224 }
225 w->click_state = ((~_legend_excludebits) << 3);
226 DrawWindowWidgets(w);
227
228 FOR_ALL_PLAYERS(p) {
229 if (!p->is_active)
230 continue;
231
232 DrawPlayerIcon(p->index, 4, 18+p->index*12);
233
234 SetDParam(0, p->name_1);
235 SetDParam(1, p->name_2);
236 SetDParam(2, GetPlayerNameString(p->index, 3));
237 DrawString(21,17+p->index*12,STR_7021,HASBIT(_legend_excludebits, p->index) ? 0x10 : 0xC);
238 }
239 break;
240
241 case WE_CLICK:
242 if (IS_INT_INSIDE(e->click.widget, 3, 11)) {
243 _legend_excludebits ^= (1 << (e->click.widget-3));
244 SetWindowDirty(w);
245 InvalidateWindow(WC_INCOME_GRAPH, 0);
246 InvalidateWindow(WC_OPERATING_PROFIT, 0);
247 InvalidateWindow(WC_DELIVERED_CARGO, 0);
248 InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
249 InvalidateWindow(WC_COMPANY_VALUE, 0);
250 }
251 break;
252 }
253 }
254
255 static const Widget _graph_legend_widgets[] = {
256 { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
257 { WWT_CAPTION, RESIZE_NONE, 14, 11, 249, 0, 13, STR_704E_KEY_TO_COMPANY_GRAPHS, STR_018C_WINDOW_TITLE_DRAG_THIS},
258 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 249, 14, 113, 0x0,STR_NULL},
259 { WWT_IMGBTN, RESIZE_NONE, 14, 2, 247, 16, 27, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
260 { WWT_IMGBTN, RESIZE_NONE, 14, 2, 247, 28, 39, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
261 { WWT_IMGBTN, RESIZE_NONE, 14, 2, 247, 40, 51, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
262 { WWT_IMGBTN, RESIZE_NONE, 14, 2, 247, 52, 63, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
263 { WWT_IMGBTN, RESIZE_NONE, 14, 2, 247, 64, 75, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
264 { WWT_IMGBTN, RESIZE_NONE, 14, 2, 247, 76, 87, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
265 { WWT_IMGBTN, RESIZE_NONE, 14, 2, 247, 88, 99, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
266 { WWT_IMGBTN, RESIZE_NONE, 14, 2, 247, 100, 111, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
267 { WIDGETS_END},
268 };
269
270 static const WindowDesc _graph_legend_desc = {
271 -1, -1, 250, 114,
272 WC_GRAPH_LEGEND,0,
273 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
274 _graph_legend_widgets,
275 GraphLegendWndProc
276 };
277
278 static void ShowGraphLegend(void)
279 {
280 AllocateWindowDescFront(&_graph_legend_desc, 0);
281 }
282
283 /********************/
284 /* OPERATING PROFIT */
285 /********************/
286
287 static void SetupGraphDrawerForPlayers(GraphDrawer *gd)
288 {
289 Player *p;
290 uint excludebits = _legend_excludebits;
291 int nums;
292 int mo,yr;
293
294 // Exclude the players which aren't valid
295 FOR_ALL_PLAYERS(p) {
296 if (!p->is_active) SETBIT(excludebits,p->index);
297 }
298 gd->sel = excludebits;
299 gd->num_vert_lines = 24;
300
301 nums = 0;
302 FOR_ALL_PLAYERS(p) {
303 if (p->is_active) nums = max(nums,p->num_valid_stat_ent);
304 }
305 gd->num_on_x_axis = min(nums,24);
306
307 mo = (_cur_month/3-nums)*3;
308 yr = _cur_year;
309 while (mo < 0) {
310 yr--;
311 mo += 12;
312 }
313
314 gd->year = yr;
315 gd->month = mo;
316 }
317
318 static void OperatingProfitWndProc(Window *w, WindowEvent *e)
319 {
320 switch(e->event) {
321 case WE_PAINT: {
322 GraphDrawer gd;
323 Player *p;
324 int i,j;
325 int numd;
326
327 DrawWindowWidgets(w);
328
329 gd.left = 2;
330 gd.top = 18;
331 gd.height = 136;
332 gd.include_neg = true;
333 gd.format_str_y_axis = STR_CURRCOMPACT32;
334 gd.color_3 = 0x10;
335 gd.color_2 = 0xD7;
336 gd.bg_line_color = 0xE;
337
338 SetupGraphDrawerForPlayers(&gd);
339
340 numd = 0;
341 FOR_ALL_PLAYERS(p) {
342 if (p->is_active) {
343 gd.colors[numd] = _color_list[p->player_color].window_color_bgb;
344 for(j=gd.num_on_x_axis,i=0; --j >= 0;) {
345 gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)(p->old_economy[j].income + p->old_economy[j].expenses);
346 i++;
347 }
348 }
349 numd++;
350 }
351
352 gd.num_dataset = numd;
353
354 DrawGraph(&gd);
355 } break;
356 case WE_CLICK:
357 if (e->click.widget == 2) /* Clicked on Legend */
358 ShowGraphLegend();
359 break;
360 }
361 }
362
363 static const Widget _operating_profit_widgets[] = {
364 { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
365 { WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7025_OPERATING_PROFIT_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
366 { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
367 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 575, 14, 173, 0x0, STR_NULL},
368 { WIDGETS_END},
369 };
370
371 static const WindowDesc _operating_profit_desc = {
372 -1, -1, 576, 174,
373 WC_OPERATING_PROFIT,0,
374 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
375 _operating_profit_widgets,
376 OperatingProfitWndProc
377 };
378
379
380 void ShowOperatingProfitGraph(void)
381 {
382 if (AllocateWindowDescFront(&_operating_profit_desc, 0)) {
383 InvalidateWindow(WC_GRAPH_LEGEND, 0);
384 }
385 }
386
387
388 /****************/
389 /* INCOME GRAPH */
390 /****************/
391
392 static void IncomeGraphWndProc(Window *w, WindowEvent *e)
393 {
394 switch(e->event) {
395 case WE_PAINT: {
396 GraphDrawer gd;
397 Player *p;
398 int i,j;
399 int numd;
400
401 DrawWindowWidgets(w);
402
403 gd.left = 2;
404 gd.top = 18;
405 gd.height = 104;
406 gd.include_neg = false;
407 gd.format_str_y_axis = STR_CURRCOMPACT32;
408 gd.color_3 = 0x10;
409 gd.color_2 = 0xD7;
410 gd.bg_line_color = 0xE;
411 SetupGraphDrawerForPlayers(&gd);
412
413 numd = 0;
414 FOR_ALL_PLAYERS(p) {
415 if (p->is_active) {
416 gd.colors[numd] = _color_list[p->player_color].window_color_bgb;
417 for(j=gd.num_on_x_axis,i=0; --j >= 0;) {
418 gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].income;
419 i++;
420 }
421 }
422 numd++;
423 }
424
425 gd.num_dataset = numd;
426
427 DrawGraph(&gd);
428 break;
429 }
430
431 case WE_CLICK:
432 if (e->click.widget == 2)
433 ShowGraphLegend();
434 break;
435 }
436 }
437
438 static const Widget _income_graph_widgets[] = {
439 { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
440 { WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7022_INCOME_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
441 { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
442 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 575, 14, 141, 0x0, STR_NULL},
443 { WIDGETS_END},
444 };
445
446 static const WindowDesc _income_graph_desc = {
447 -1, -1, 576, 142,
448 WC_INCOME_GRAPH,0,
449 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
450 _income_graph_widgets,
451 IncomeGraphWndProc
452 };
453
454 void ShowIncomeGraph(void)
455 {
456 if (AllocateWindowDescFront(&_income_graph_desc, 0)) {
457 InvalidateWindow(WC_GRAPH_LEGEND, 0);
458 }
459 }
460
461 /*******************/
462 /* DELIVERED CARGO */
463 /*******************/
464
465 static void DeliveredCargoGraphWndProc(Window *w, WindowEvent *e)
466 {
467 switch(e->event) {
468 case WE_PAINT: {
469 GraphDrawer gd;
470 Player *p;
471 int i,j;
472 int numd;
473
474 DrawWindowWidgets(w);
475
476 gd.left = 2;
477 gd.top = 18;
478 gd.height = 104;
479 gd.include_neg = false;
480 gd.format_str_y_axis = STR_7024;
481 gd.color_3 = 0x10;
482 gd.color_2 = 0xD7;
483 gd.bg_line_color = 0xE;
484 SetupGraphDrawerForPlayers(&gd);
485
486 numd = 0;
487 FOR_ALL_PLAYERS(p) {
488 if (p->is_active) {
489 gd.colors[numd] = _color_list[p->player_color].window_color_bgb;
490 for(j=gd.num_on_x_axis,i=0; --j >= 0;) {
491 gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].delivered_cargo;
492 i++;
493 }
494 }
495 numd++;
496 }
497
498 gd.num_dataset = numd;
499
500 DrawGraph(&gd);
501 break;
502 }
503
504 case WE_CLICK:
505 if (e->click.widget == 2)
506 ShowGraphLegend();
507 break;
508 }
509 }
510
511 static const Widget _delivered_cargo_graph_widgets[] = {
512 { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
513 { WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7050_UNITS_OF_CARGO_DELIVERED, STR_018C_WINDOW_TITLE_DRAG_THIS},
514 { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
515 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 575, 14, 141, 0x0, STR_NULL},
516 { WIDGETS_END},
517 };
518
519 static const WindowDesc _delivered_cargo_graph_desc = {
520 -1, -1, 576, 142,
521 WC_DELIVERED_CARGO,0,
522 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
523 _delivered_cargo_graph_widgets,
524 DeliveredCargoGraphWndProc
525 };
526
527 void ShowDeliveredCargoGraph(void)
528 {
529 if (AllocateWindowDescFront(&_delivered_cargo_graph_desc, 0)) {
530 InvalidateWindow(WC_GRAPH_LEGEND, 0);
531 }
532 }
533
534 /***********************/
535 /* PERFORMANCE HISTORY */
536 /***********************/
537
538 static void PerformanceHistoryWndProc(Window *w, WindowEvent *e)
539 {
540 switch(e->event) {
541 case WE_PAINT: {
542 GraphDrawer gd;
543 Player *p;
544 int i,j;
545 int numd;
546
547 DrawWindowWidgets(w);
548
549 gd.left = 2;
550 gd.top = 18;
551 gd.height = 200;
552 gd.include_neg = false;
553 gd.format_str_y_axis = STR_7024;
554 gd.color_3 = 0x10;
555 gd.color_2 = 0xD7;
556 gd.bg_line_color = 0xE;
557 SetupGraphDrawerForPlayers(&gd);
558
559 numd = 0;
560 FOR_ALL_PLAYERS(p) {
561 if (p->is_active) {
562 gd.colors[numd] = _color_list[p->player_color].window_color_bgb;
563 for(j=gd.num_on_x_axis,i=0; --j >= 0;) {
564 gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].performance_history;
565 i++;
566 }
567 }
568 numd++;
569 }
570
571 gd.num_dataset = numd;
572
573 DrawGraph(&gd);
574 break;
575 }
576
577 case WE_CLICK:
578 if (e->click.widget == 2)
579 ShowGraphLegend();
580 if (e->click.widget == 3)
581 ShowPerformanceRatingDetail();
582 break;
583 }
584 }
585
586 static const Widget _performance_history_widgets[] = {
587 { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
588 { WWT_CAPTION, RESIZE_NONE, 14, 11, 475, 0, 13, STR_7051_COMPANY_PERFORMANCE_RATINGS, STR_018C_WINDOW_TITLE_DRAG_THIS},
589 { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
590 { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 476, 525, 0, 13, STR_PERFORMANCE_DETAIL_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
591 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 575, 14, 237, 0x0, STR_NULL},
592 { WIDGETS_END},
593 };
594
595 static const WindowDesc _performance_history_desc = {
596 -1, -1, 576, 238,
597 WC_PERFORMANCE_HISTORY,0,
598 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
599 _performance_history_widgets,
600 PerformanceHistoryWndProc
601 };
602
603 void ShowPerformanceHistoryGraph(void)
604 {
605 if (AllocateWindowDescFront(&_performance_history_desc, 0)) {
606 InvalidateWindow(WC_GRAPH_LEGEND, 0);
607 }
608 }
609
610 /*****************/
611 /* COMPANY VALUE */
612 /*****************/
613
614 static void CompanyValueGraphWndProc(Window *w, WindowEvent *e)
615 {
616 switch(e->event) {
617 case WE_PAINT: {
618 GraphDrawer gd;
619 Player *p;
620 int i,j;
621 int numd;
622
623 DrawWindowWidgets(w);
624
625 gd.left = 2;
626 gd.top = 18;
627 gd.height = 200;
628 gd.include_neg = false;
629 gd.format_str_y_axis = STR_CURRCOMPACT64;
630 gd.color_3 = 0x10;
631 gd.color_2 = 0xD7;
632 gd.bg_line_color = 0xE;
633 SetupGraphDrawerForPlayers(&gd);
634
635 numd = 0;
636 FOR_ALL_PLAYERS(p) {
637 if (p->is_active) {
638 gd.colors[numd] = _color_list[p->player_color].window_color_bgb;
639 for(j=gd.num_on_x_axis,i=0; --j >= 0;) {
640 gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].company_value;
641 i++;
642 }
643 }
644 numd++;
645 }
646
647 gd.num_dataset = numd;
648
649 DrawGraph(&gd);
650 break;
651 }
652
653 case WE_CLICK:
654 if (e->click.widget == 2)
655 ShowGraphLegend();
656 break;
657 }
658 }
659
660 static const Widget _company_value_graph_widgets[] = {
661 { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
662 { WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7052_COMPANY_VALUES, STR_018C_WINDOW_TITLE_DRAG_THIS},
663 { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
664 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 575, 14, 237, 0x0, STR_NULL},
665 { WIDGETS_END},
666 };
667
668 static const WindowDesc _company_value_graph_desc = {
669 -1, -1, 576, 238,
670 WC_COMPANY_VALUE,0,
671 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
672 _company_value_graph_widgets,
673 CompanyValueGraphWndProc
674 };
675
676 void ShowCompanyValueGraph(void)
677 {
678 if (AllocateWindowDescFront(&_company_value_graph_desc, 0)) {
679 InvalidateWindow(WC_GRAPH_LEGEND, 0);
680 }
681 }
682
683 /*****************/
684 /* PAYMENT RATES */
685 /*****************/
686
687 static const byte _cargo_legend_colors[12] = {152, 32, 15, 174, 208, 194, 191, 84, 184, 10, 202, 215};
688
689 static void CargoPaymentRatesWndProc(Window *w, WindowEvent *e)
690 {
691 switch(e->event) {
692 case WE_PAINT: {
693 int i, j, x, y;
694 GraphDrawer gd;
695
696 gd.sel = _legend_cargobits;
697 w->click_state = (~_legend_cargobits) << 3;
698 DrawWindowWidgets(w);
699
700 x = 495;
701 y = 25;
702
703 for(i=0; i!=NUM_CARGO; i++) {
704 GfxFillRect(x, y, x+8, y+5, 0);
705 GfxFillRect(x+1, y+1, x+7, y+4, _cargo_legend_colors[i]);
706 SetDParam(0, _cargoc.names_s[i]);
707 DrawString(x+14, y, STR_7065, 0);
708 y += 8;
709 }
710
711 gd.left = 2;
712 gd.top = 24;
713 gd.height = 104;
714 gd.include_neg = false;
715 gd.format_str_y_axis = STR_CURRCOMPACT32;
716 gd.color_3 = 16;
717 gd.color_2 = 215;
718 gd.bg_line_color = 14;
719 gd.num_dataset = NUM_CARGO;
720 gd.num_on_x_axis = 20;
721 gd.num_vert_lines = 20;
722 gd.month = 0xFF;
723 gd.unk61A = 10;
724 gd.unk61C = 10;
725
726 for(i=0; i!=NUM_CARGO; i++) {
727 gd.colors[i] = _cargo_legend_colors[i];
728 for(j=0; j!=20; j++) {
729 gd.cost[i][j] = (uint64)GetTransportedGoodsIncome(10, 20, j*6+6,i);
730 }
731 }
732
733 DrawGraph(&gd);
734
735 DrawString(2 + 46, 24 + gd.height + 7, STR_7062_DAYS_IN_TRANSIT, 0);
736 DrawString(2 + 84, 24 - 9, STR_7063_PAYMENT_FOR_DELIVERING, 0);
737 } break;
738
739 case WE_CLICK: {
740 switch(e->click.widget) {
741 case 3: case 4: case 5: case 6:
742 case 7: case 8: case 9: case 10:
743 case 11: case 12: case 13: case 14:
744 _legend_cargobits ^= 1 << (e->click.widget - 3);
745 SetWindowDirty(w);
746 break;
747 }
748 } break;
749 }
750 }
751
752 static const Widget _cargo_payment_rates_widgets[] = {
753 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
754 { WWT_CAPTION, RESIZE_NONE, 14, 11, 567, 0, 13, STR_7061_CARGO_PAYMENT_RATES, STR_018C_WINDOW_TITLE_DRAG_THIS},
755 { WWT_PANEL, RESIZE_NONE, 14, 0, 567, 14, 141, 0x0, STR_NULL},
756 { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 24, 31, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
757 { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 32, 39, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
758 { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 40, 47, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
759 { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 48, 55, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
760 { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 56, 63, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
761 { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 64, 71, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
762 { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 72, 79, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
763 { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 80, 87, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
764 { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 88, 95, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
765 { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 96, 103, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
766 { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 104, 111, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
767 { WWT_PANEL, RESIZE_NONE, 12, 493, 562, 112, 119, 0x0, STR_7064_TOGGLE_GRAPH_FOR_CARGO},
768 { WIDGETS_END},
769 };
770
771 static const WindowDesc _cargo_payment_rates_desc = {
772 -1, -1, 568, 142,
773 WC_PAYMENT_RATES,0,
774 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
775 _cargo_payment_rates_widgets,
776 CargoPaymentRatesWndProc
777 };
778
779
780 void ShowCargoPaymentRates(void)
781 {
782 AllocateWindowDescFront(&_cargo_payment_rates_desc, 0);
783 }
784
785 /************************/
786 /* COMPANY LEAGUE TABLE */
787 /************************/
788
789 static const StringID _performance_titles[] = {
790 STR_7066_ENGINEER,
791 STR_7066_ENGINEER,
792 STR_7067_TRAFFIC_MANAGER,
793 STR_7067_TRAFFIC_MANAGER,
794 STR_7068_TRANSPORT_COORDINATOR,
795 STR_7068_TRANSPORT_COORDINATOR,
796 STR_7069_ROUTE_SUPERVISOR,
797 STR_7069_ROUTE_SUPERVISOR,
798 STR_706A_DIRECTOR,
799 STR_706A_DIRECTOR,
800 STR_706B_CHIEF_EXECUTIVE,
801 STR_706B_CHIEF_EXECUTIVE,
802 STR_706C_CHAIRMAN,
803 STR_706C_CHAIRMAN,
804 STR_706D_PRESIDENT,
805 STR_706E_TYCOON,
806 };
807
808 static inline StringID GetPerformanceTitleFromValue(uint value)
809 {
810 return _performance_titles[minu(value, 1000) >> 6];
811 }
812
813 static int CDECL _perf_hist_comp(const void *elem1, const void *elem2 ) {
814 const Player *p1 = *(const Player* const *)elem1;
815 const Player *p2 = *(const Player* const *)elem2;
816 int32 v = p2->old_economy[1].performance_history - p1->old_economy[1].performance_history;
817 return (v!=0) | (v >> (sizeof(int32)*8-1));
818 }
819
820 static void CompanyLeagueWndProc(Window *w, WindowEvent *e)
821 {
822 switch(e->event) {
823 case WE_PAINT: {
824 Player *p;
825 Player *plist[MAX_PLAYERS];
826 size_t pl_num, i;
827
828 DrawWindowWidgets(w);
829
830 pl_num=0;
831 FOR_ALL_PLAYERS(p) {
832 if (p->is_active)
833 plist[pl_num++] = p;
834 }
835 assert(pl_num > 0);
836
837 qsort(plist, pl_num, sizeof(Player*), _perf_hist_comp);
838
839 i = 0;
840 do {
841 SetDParam(0, i + 1 + STR_01AB);
842 p = plist[i];
843 SetDParam(1, p->name_1);
844 SetDParam(2, p->name_2);
845
846 SetDParam(3, GetPlayerNameString(p->index, 4));
847 /* WARNING ugly hack!
848 GetPlayerNameString sets up (Player #) if the player is human in an extra DPARAM16
849 It seems that if player is non-human, nothing is set up, so param is 0. GetString doesn't like
850 that because there is another param after it.
851 So we'll just shift the rating one back if player is AI and all is fine
852 */
853 SetDParam((IS_HUMAN_PLAYER(p->index) ? 5 : 4), GetPerformanceTitleFromValue(p->old_economy[1].performance_history));
854
855 DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, 0);
856 DrawPlayerIcon(p->index, 27, 16 + i * 10);
857 } while (++i != pl_num);
858
859 break;
860 }
861 }
862 }
863
864
865 static const Widget _company_league_widgets[] = {
866 { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
867 { WWT_CAPTION, RESIZE_NONE, 14, 11, 399, 0, 13, STR_7053_COMPANY_LEAGUE_TABLE, STR_018C_WINDOW_TITLE_DRAG_THIS},
868 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 399, 14, 96, 0x0, STR_NULL},
869 { WIDGETS_END},
870 };
871
872 static const WindowDesc _company_league_desc = {
873 -1, -1, 400, 97,
874 WC_COMPANY_LEAGUE,0,
875 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
876 _company_league_widgets,
877 CompanyLeagueWndProc
878 };
879
880 void ShowCompanyLeagueTable(void)
881 {
882 AllocateWindowDescFront(&_company_league_desc,0);
883 }
884
885 /*****************************/
886 /* PERFORMANCE RATING DETAIL */
887 /*****************************/
888
889 static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e)
890 {
891 switch(e->event) {
892 case WE_PAINT: {
893 int val, needed, score, i;
894 byte owner, x;
895 uint16 y=14;
896 int total_score = 0;
897 int color_done, color_notdone;
898
899 // Draw standard stuff
900 DrawWindowWidgets(w);
901
902 // The player of which we check the detail performance rating
903 owner = FindFirstBit(w->click_state) - 13;
904
905 // Paint the player icons
906 for (i=0;i<MAX_PLAYERS;i++) {
907 if (!DEREF_PLAYER(i)->is_active) {
908 // Check if we have the player as an active player
909 if (!(w->disabled_state & (1 << (i+13)))) {
910 // Bah, player gone :(
911 w->disabled_state += 1 << (i+13);
912 // Is this player selected? If so, select first player (always save? :s)
913 if (w->click_state == 1U << (i + 13))
914 w->click_state = 1 << 13;
915 // We need a repaint
916 SetWindowDirty(w);
917 }
918 continue;
919 }
920
921 // Check if we have the player marked as inactive
922 if ((w->disabled_state & (1 << (i+13)))) {
923 // New player! Yippie :p
924 w->disabled_state -= 1 << (i+13);
925 // We need a repaint
926 SetWindowDirty(w);
927 }
928
929 if (i == owner) x = 1; else x = 0;
930 DrawPlayerIcon(i, i * 37 + 13 + x, 16 + x);
931 }
932
933 // The colors used to show how the progress is going
934 color_done = _color_list[6].window_color_1b;
935 color_notdone = _color_list[4].window_color_1b;
936
937 // Draw all the score parts
938 for (i=0;i<NUM_SCORE;i++) {
939 y += 20;
940 val = _score_part[owner][i];
941 needed = score_info[i].needed;
942 score = score_info[i].score;
943 // SCORE_TOTAL has his own rulez ;)
944 if (i == SCORE_TOTAL) {
945 needed = total_score;
946 score = SCORE_MAX;
947 } else
948 total_score += score;
949
950 DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, 0);
951
952 // Draw the score
953 SetDParam(0, score);
954 DrawStringRightAligned(107, y, SET_PERFORMANCE_DETAIL_INT, 0);
955
956 // Calculate the %-bar
957 if (val > needed) x = 50;
958 else if (val == 0) x = 0;
959 else x = ((val * 50) / needed);
960
961 // SCORE_LOAN is inversed
962 if (val < 0 && i == SCORE_LOAN)
963 x = 0;
964
965 // Draw the bar
966 if (x != 0)
967 GfxFillRect(112, y-2, x + 112, y+10, color_done);
968 if (x != 50)
969 GfxFillRect(x + 112, y-2, 50 + 112, y+10, color_notdone);
970
971 // Calculate the %
972 if (val > needed) x = 100;
973 else x = ((val * 100) / needed);
974
975 // SCORE_LOAN is inversed
976 if (val < 0 && i == SCORE_LOAN)
977 x = 0;
978
979 // Draw it
980 SetDParam(0, x);
981 DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, 0);
982
983 // SCORE_LOAN is inversed
984 if (i == SCORE_LOAN)
985 val = needed - val;
986
987 // Draw the amount we have against what is needed
988 // For some of them it is in currency format
989 SetDParam(0, val);
990 SetDParam(1, needed);
991 switch (i) {
992 case SCORE_MIN_PROFIT:
993 case SCORE_MIN_INCOME:
994 case SCORE_MAX_INCOME:
995 case SCORE_MONEY:
996 case SCORE_LOAN:
997 DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, 0);
998 break;
999 default:
1000 DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_INT, 0);
1001 }
1002 }
1003
1004 break;
1005 }
1006
1007 case WE_CLICK:
1008 // Check which button is clicked
1009 if (IS_INT_INSIDE(e->click.widget, 13, 21)) {
1010 // Is it no on disable?
1011 if ((w->disabled_state & (1 << e->click.widget)) == 0) {
1012 w->click_state = 1 << e->click.widget;
1013 SetWindowDirty(w);
1014 }
1015 }
1016 break;
1017
1018 case WE_CREATE:
1019 {
1020 int i;
1021 Player *p2;
1022 w->hidden_state = 0;
1023 w->disabled_state = 0;
1024
1025 // Hide the player who are not active
1026 for (i=0;i<MAX_PLAYERS;i++) {
1027 if (!DEREF_PLAYER(i)->is_active) {
1028 w->disabled_state += 1 << (i+13);
1029 }
1030 }
1031 // Update all player stats with the current data
1032 // (this is because _score_info is not saved to a savegame)
1033 FOR_ALL_PLAYERS(p2)
1034 if (p2->is_active)
1035 UpdateCompanyRatingAndValue(p2, false);
1036
1037 w->custom[0] = DAY_TICKS;
1038 w->custom[1] = 5;
1039
1040 w->click_state = 1 << 13;
1041
1042 SetWindowDirty(w);
1043 }
1044 break;
1045 case WE_TICK:
1046 {
1047 // Update the player score every 5 days
1048 if (--w->custom[0] == 0) {
1049 w->custom[0] = DAY_TICKS;
1050 if (--w->custom[1] == 0) {
1051 Player *p2;
1052 w->custom[1] = 5;
1053 FOR_ALL_PLAYERS(p2)
1054 // Skip if player is not active
1055 if (p2->is_active)
1056 UpdateCompanyRatingAndValue(p2, false);
1057 SetWindowDirty(w);
1058 }
1059 }
1060 }
1061 break;
1062 }
1063 }
1064
1065 static const Widget _performance_rating_detail_widgets[] = {
1066 { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
1067 { WWT_CAPTION, RESIZE_NONE, 14, 11, 298, 0, 13, STR_PERFORMANCE_DETAIL, STR_018C_WINDOW_TITLE_DRAG_THIS},
1068 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 298, 14, 27, 0x0, STR_NULL},
1069
1070 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 298, 28, 47, 0x0,STR_PERFORMANCE_DETAIL_VEHICLES_TIP},
1071 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 298, 48, 67, 0x0,STR_PERFORMANCE_DETAIL_STATIONS_TIP},
1072 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 298, 68, 87, 0x0,STR_PERFORMANCE_DETAIL_MIN_PROFIT_TIP},
1073 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 298, 88, 107, 0x0,STR_PERFORMANCE_DETAIL_MIN_INCOME_TIP},
1074 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 298, 108, 127, 0x0,STR_PERFORMANCE_DETAIL_MAX_INCOME_TIP},
1075 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 298, 128, 147, 0x0,STR_PERFORMANCE_DETAIL_DELIVERED_TIP},
1076 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 298, 148, 167, 0x0,STR_PERFORMANCE_DETAIL_CARGO_TIP},
1077 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 298, 168, 187, 0x0,STR_PERFORMANCE_DETAIL_MONEY_TIP},
1078 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 298, 188, 207, 0x0,STR_PERFORMANCE_DETAIL_LOAN_TIP},
1079 { WWT_IMGBTN, RESIZE_NONE, 14, 0, 298, 208, 227, 0x0,STR_PERFORMANCE_DETAIL_TOTAL_TIP},
1080
1081 { WWT_IMGBTN, RESIZE_NONE, 14, 2, 38, 14, 26, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1082 { WWT_IMGBTN, RESIZE_NONE, 14, 39, 75, 14, 26, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1083 { WWT_IMGBTN, RESIZE_NONE, 14, 76, 112, 14, 26, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1084 { WWT_IMGBTN, RESIZE_NONE, 14, 113, 149, 14, 26, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1085 { WWT_IMGBTN, RESIZE_NONE, 14, 150, 186, 14, 26, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1086 { WWT_IMGBTN, RESIZE_NONE, 14, 187, 223, 14, 26, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1087 { WWT_IMGBTN, RESIZE_NONE, 14, 224, 260, 14, 26, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1088 { WWT_IMGBTN, RESIZE_NONE, 14, 261, 297, 14, 26, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1089 { WIDGETS_END},
1090 };
1091
1092 static const WindowDesc _performance_rating_detail_desc = {
1093 -1, -1, 299, 228,
1094 WC_PERFORMANCE_DETAIL,0,
1095 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
1096 _performance_rating_detail_widgets,
1097 PerformanceRatingDetailWndProc
1098 };
1099
1100 void ShowPerformanceRatingDetail(void)
1101 {
1102 AllocateWindowDescFront(&_performance_rating_detail_desc, 0);
1103 }
1104
1105
1106 static uint16 _num_sign_sort;
1107
1108 static char _bufcache[64];
1109 static uint16 _last_sign_idx;
1110
1111 static int CDECL SignNameSorter(const void *a, const void *b)
1112 {
1113 char buf1[64];
1114 SignStruct *ss;
1115 const uint16 cmp1 = *(const uint16 *)a;
1116 const uint16 cmp2 = *(const uint16 *)b;
1117
1118 ss = GetSign(cmp1);
1119 GetString(buf1, ss->str);
1120
1121 if (cmp2 != _last_sign_idx) {
1122 _last_sign_idx = cmp2;
1123 ss = GetSign(cmp2);
1124 GetString(_bufcache, ss->str);
1125 }
1126
1127 return strcmp(buf1, _bufcache); // sort by name
1128 }
1129
1130 static void GlobalSortSignList(void)
1131 {
1132 const SignStruct *ss;
1133 uint32 n = 0;
1134
1135 _num_sign_sort = 0;
1136
1137 /* Create array for sorting */
1138 _sign_sort = realloc(_sign_sort, GetSignPoolSize() * sizeof(_sign_sort[0]));
1139 if (_sign_sort == NULL)
1140 error("Could not allocate memory for the sign-sorting-list");
1141
1142 FOR_ALL_SIGNS(ss) {
1143 if(ss->str != STR_NULL) {
1144 _sign_sort[n++] = ss->index;
1145 _num_sign_sort++;
1146 }
1147 }
1148
1149 qsort(_sign_sort, n, sizeof(_sign_sort[0]), SignNameSorter);
1150
1151 _sign_sort_dirty = false;
1152
1153 DEBUG(misc, 1) ("Resorting global sign list...");
1154 }
1155
1156 static void SignListWndProc(Window *w, WindowEvent *e)
1157 {
1158 switch (e->event) {
1159 case WE_PAINT: {
1160 uint32 i;
1161 int y = 16; // offset from top of widget
1162
1163 if (_sign_sort_dirty)
1164 GlobalSortSignList();
1165
1166 SetVScrollCount(w, _num_sign_sort);
1167
1168 SetDParam(0, w->vscroll.count);
1169 DrawWindowWidgets(w);
1170
1171 /* No signs? */
1172 if (w->vscroll.count == 0) {
1173 DrawString(2, y, STR_304A_NONE, 0);
1174 return;
1175 }
1176
1177 {
1178 SignStruct *ss;
1179
1180 /* Start drawing the signs */
1181 i = 0;
1182 for (i = w->vscroll.pos; i < (uint)w->vscroll.cap + w->vscroll.pos && i < w->vscroll.count; i++) {
1183 ss = GetSign(_sign_sort[i]);
1184
1185 if (ss->owner != OWNER_NONE)
1186 DrawPlayerIcon(ss->owner, 4, y + 1);
1187
1188 DrawString(22, y, ss->str, 8);
1189 y += 10;
1190 }
1191 }
1192 } break;
1193
1194 case WE_CLICK: {
1195 switch (e->click.widget) {
1196 case 3: {
1197 uint32 id_v = (e->click.pt.y - 15) / 10;
1198 SignStruct *ss;
1199
1200 if (id_v >= w->vscroll.cap)
1201 return;
1202
1203 id_v += w->vscroll.pos;
1204
1205 if (id_v >= w->vscroll.count)
1206 return;
1207
1208 ss = GetSign(_sign_sort[id_v]);
1209 ScrollMainWindowToTile(TILE_FROM_XY(ss->x, ss->y));
1210 } break;
1211 }
1212 } break;
1213
1214 case WE_RESIZE:
1215 w->vscroll.cap += e->sizing.diff.y / 10;
1216 break;
1217 }
1218 }
1219
1220 static const Widget _sign_list_widget[] = {
1221 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
1222 { WWT_CAPTION, RESIZE_RIGHT, 14, 11, 345, 0, 13, STR_SIGN_LIST_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
1223 { WWT_STICKYBOX, RESIZE_LR, 14, 346, 357, 0, 13, 0x0, STR_STICKY_BUTTON},
1224 { WWT_PANEL, RESIZE_RB, 14, 0, 345, 14, 137, 0x0, STR_NULL},
1225 { WWT_SCROLLBAR, RESIZE_LRB, 14, 346, 357, 14, 125, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
1226 { WWT_RESIZEBOX, RESIZE_LRTB, 14, 346, 357, 126, 137, 0x0, STR_RESIZE_BUTTON},
1227 { WIDGETS_END},
1228 };
1229
1230 static const WindowDesc _sign_list_desc = {
1231 -1, -1, 358, 138,
1232 WC_SIGN_LIST,0,
1233 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
1234 _sign_list_widget,
1235 SignListWndProc
1236 };
1237
1238
1239 void ShowSignList(void)
1240 {
1241 Window *w;
1242
1243 w = AllocateWindowDescFront(&_sign_list_desc, 0);
1244 if (w != NULL) {
1245 w->vscroll.cap = 12;
1246 w->resize.step_height = 10;
1247 w->resize.height = w->height - 10 * 7; // minimum if 5 in the list
1248 }
1249 }

  ViewVC Help
Powered by ViewVC 1.1.5