/[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 2491 - (hide annotations) (download)
Fri May 27 23:46:09 2005 UTC (7 years, 11 months ago) by matthijs
File MIME type: text/plain
File size: 34907 byte(s)
* Copied upstream source to trunk
1 matthijs 2489 #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