]> cvs.zerfleddert.de Git - micropolis/blame - src/sim/w_graph.c
Add "Pause" to Priority menu
[micropolis] / src / sim / w_graph.c
CommitLineData
6a5fa4e0
MG
1/* w_graph.c
2 *
3 * Micropolis, Unix Version. This game was released for the Unix platform
4 * in or about 1990 and has been modified for inclusion in the One Laptop
5 * Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
6 * you need assistance with this program, you may contact:
7 * http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details. You should have received a
18 * copy of the GNU General Public License along with this program. If
19 * not, see <http://www.gnu.org/licenses/>.
20 *
21 * ADDITIONAL TERMS per GNU GPL Section 7
22 *
23 * No trademark or publicity rights are granted. This license does NOT
24 * give you any right, title or interest in the trademark SimCity or any
25 * other Electronic Arts trademark. You may not distribute any
26 * modification of this program using the trademark SimCity or claim any
27 * affliation or association with Electronic Arts Inc. or its employees.
28 *
29 * Any propagation or conveyance of this program must include this
30 * copyright notice and these terms.
31 *
32 * If you convey this program (or any modifications of it) and assume
33 * contractual liability for the program to recipients of it, you agree
34 * to indemnify Electronic Arts for any liability that those contractual
35 * assumptions impose on Electronic Arts.
36 *
37 * You may not misrepresent the origins of this program; modified
38 * versions of the program must be marked as such and not identified as
39 * the original program.
40 *
41 * This disclaimer supplements the one included in the General Public
42 * License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
43 * PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
44 * OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
45 * SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
46 * DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
47 * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
48 * FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
49 * RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
50 * USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
51 * INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
52 * MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
53 * UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
54 * WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
55 * CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
56 * ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
57 * JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
58 * WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
59 * CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
60 * NOT APPLY TO YOU.
61 */
62#include "sim.h"
63
64
65short NewGraph = 0;
66short AllMax;
67unsigned char *History10[HISTORIES];
68unsigned char *History120[HISTORIES];
69int HistoryInitialized = 0;
70short Graph10Max, Graph120Max;
71Tcl_HashTable GraphCmds;
72int GraphUpdateTime = 100;
73
74
75#define DEF_GRAPH_FONT "-Adobe-Helvetica-Bold-R-Normal-*-140-*"
76#define DEF_GRAPH_BG_COLOR "#b0b0b0"
77#define DEF_GRAPH_BG_MONO "#ffffff"
78#define DEF_GRAPH_BORDER_WIDTH "0"
79#define DEF_GRAPH_RELIEF "flat"
80
81Tk_ConfigSpec GraphConfigSpecs[] = {
82 {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL,
83 DEF_GRAPH_FONT, Tk_Offset(SimGraph, fontPtr), 0},
84 {TK_CONFIG_BORDER, "-background", "background", "Background",
85 DEF_GRAPH_BG_COLOR, Tk_Offset(SimGraph, border),
86 TK_CONFIG_COLOR_ONLY},
87 {TK_CONFIG_BORDER, "-background", "background", "Background",
88 DEF_GRAPH_BG_MONO, Tk_Offset(SimGraph, border),
89 TK_CONFIG_MONO_ONLY},
90 {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
91 DEF_GRAPH_BORDER_WIDTH, Tk_Offset(SimGraph, borderWidth), 0},
92 {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
93 DEF_GRAPH_RELIEF, Tk_Offset(SimGraph, relief), 0},
94 {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
95 (char *) NULL, 0, 0}
96 };
97
98
99XDisplay *FindXDisplay();
100
101
102static void
103DisplaySimGraph(ClientData clientData)
104{
105 SimGraph *graph = (SimGraph *) clientData;
106 Tk_Window tkwin = graph->tkwin;
107 Pixmap pm = None;
108 Drawable d;
109
110 graph->flags &= ~VIEW_REDRAW_PENDING;
111
112//fprintf(stderr, "DisplaySimGraph token %d\n", graph->draw_graph_token);
113
114 assert(graph->draw_graph_token != 0);
115
116 if (graph->draw_graph_token != 0) {
117// Tk_DeleteTimerHandler(graph->draw_graph_token);
118 graph->draw_graph_token = 0;
119 }
120
121 if (graph->visible && (tkwin != NULL) && Tk_IsMapped(tkwin)) {
122 DoUpdateGraph(graph);
123 }
124}
125
126
127void
128DestroySimGraph(ClientData clientData)
129{
130 SimGraph *graph = (SimGraph *) clientData;
131
132 DestroyGraph(graph);
133}
134
135
136EventuallyRedrawGraph(SimGraph *graph)
137{
138 if (!(graph->flags & VIEW_REDRAW_PENDING)) {
139 assert(graph->draw_graph_token == 0);
140 if (graph->draw_graph_token == 0) {
141 graph->draw_graph_token =
142 Tk_CreateTimerHandler(
143 GraphUpdateTime,
144 DisplaySimGraph,
145 (ClientData) graph);
146 graph->flags |= VIEW_REDRAW_PENDING;
147//fprintf(stderr, "EventuallyRedrawGraph token %d\n", graph->draw_graph_token);
148 }
149 }
150}
151
152
153void
154SimGraphEventProc(ClientData clientData, XEvent *eventPtr)
155{
156 SimGraph *graph = (SimGraph *) clientData;
157
158 if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
159 graph->visible = 1;
160 EventuallyRedrawGraph(graph);
161 } else if (eventPtr->type == MapNotify) {
162 graph->visible = 1;
163 } else if (eventPtr->type == UnmapNotify) {
164 graph->visible = 0;
165 } else if (eventPtr->type == VisibilityNotify) {
166 if (eventPtr->xvisibility.state == VisibilityFullyObscured)
167 graph->visible = 0;
168 else
169 graph->visible = 1;
170 } else if (eventPtr->type == ConfigureNotify) {
171 DoResizeGraph(graph,
172 eventPtr->xconfigure.width,
173 eventPtr->xconfigure.height);
174 EventuallyRedrawGraph(graph);
175 } else if (eventPtr->type == DestroyNotify) {
176 Tcl_DeleteCommand(graph->interp, Tk_PathName(graph->tkwin));
177 graph->tkwin = NULL;
178 if (graph->flags & VIEW_REDRAW_PENDING) {
179//fprintf(stderr, "SimGraphEventProc Destroy token %d\n", graph->draw_graph_token);
180 assert(graph->draw_graph_token != 0);
181 if (graph->draw_graph_token != 0) {
182 Tk_DeleteTimerHandler(graph->draw_graph_token);
183 graph->draw_graph_token = 0;
184 }
185 graph->flags &= ~VIEW_REDRAW_PENDING;
186 }
187 Tk_EventuallyFree((ClientData) graph, DestroySimGraph);
188 }
189}
190
191
192int GraphCmdconfigure(GRAPH_ARGS)
193{
194 int result = TCL_OK;
195
196 if (argc == 2) {
197 result = Tk_ConfigureInfo(interp, graph->tkwin, GraphConfigSpecs,
198 (char *) graph, (char *) NULL, 0);
199 } else if (argc == 3) {
200 result = Tk_ConfigureInfo(interp, graph->tkwin, GraphConfigSpecs,
201 (char *) graph, argv[2], 0);
202 } else {
203 result = ConfigureSimGraph(interp, graph, argc-2, argv+2,
204 TK_CONFIG_ARGV_ONLY);
205 }
206 return TCL_OK;
207}
208
209
210int GraphCmdposition(GRAPH_ARGS)
211{
212 int result = TCL_OK;
213
214 if ((argc != 2) && (argc != 4)) {
215 return TCL_ERROR;
216 }
217 if (argc == 4) {
218 if ((Tcl_GetInt(interp, argv[2], &graph->w_x) != TCL_OK)
219 || (Tcl_GetInt(interp, argv[3], &graph->w_y) != TCL_OK)) {
220 return TCL_ERROR;
221 }
222 }
223 sprintf(interp->result, "%d %d", graph->w_x, graph->w_y);
224 return TCL_OK;
225}
226
227
228int GraphCmdsize(GRAPH_ARGS)
229{
230 if ((argc != 2) && (argc != 4)) {
231 return TCL_ERROR;
232 }
233 if (argc == 4) {
234 int w, h;
235
236 if (Tcl_GetInt(interp, argv[2], &w) != TCL_OK) {
237 return TCL_ERROR;
238 }
239 if (Tcl_GetInt(interp, argv[3], &h) != TCL_OK) {
240 return TCL_ERROR;
241 }
242 graph->w_width = w;
243 graph->w_height = h;
244 }
245 sprintf(interp->result, "%d %d", graph->w_width, graph->w_height);
246 return TCL_OK;
247}
248
249
250int GraphCmdVisible(GRAPH_ARGS)
251{
252 int visible;
253
254 if ((argc != 2) && (argc != 3)) {
255 Tcl_AppendResult(interp, "wrong # args", (char *) NULL);
256 return TCL_ERROR;
257 }
258
259 if (argc == 3) {
260 if ((Tcl_GetInt(interp, argv[2], &visible) != TCL_OK) ||
261 (visible < 0) || (visible > 1)) {
262 Tcl_AppendResult(interp, " bogus args", (char *) NULL);
263 return TCL_ERROR;
264 }
265
266 graph->visible = visible;
267 }
268
269 sprintf(interp->result, "%d", graph->visible);
270
271 return TCL_OK;
272}
273
274
275int GraphCmdRange(GRAPH_ARGS)
276{
277 int range;
278
279 if ((argc != 2) && (argc != 3)) {
280 Tcl_AppendResult(interp, "wrong # args", (char *) NULL);
281 return TCL_ERROR;
282 }
283
284 if (argc == 3) {
285 if ((Tcl_GetInt(interp, argv[2], &range) != TCL_OK) ||
286 ((range != 10) && (range != 120))) {
287 Tcl_AppendResult(interp, " bogus args", (char *) NULL);
288 return TCL_ERROR;
289 }
290
291 graph->range = range;
292 NewGraph = 1;
293 }
294
295 sprintf(interp->result, "%d", graph->range);
296
297 return TCL_OK;
298}
299
300
301int GraphCmdMask(GRAPH_ARGS)
302{
303 int mask;
304
305 if ((argc != 2) && (argc != 3)) {
306 Tcl_AppendResult(interp, "wrong # args", (char *) NULL);
307 return TCL_ERROR;
308 }
309
310 if (argc == 3) {
311 if ((Tcl_GetInt(interp, argv[2], &mask) != TCL_OK) ||
312 (mask < 0) || (mask > 63)) {
313 Tcl_AppendResult(interp, " bogus args", (char *) NULL);
314 return TCL_ERROR;
315 }
316
317 graph->mask = mask;
318 NewGraph = 1;
319 }
320
321 sprintf(interp->result, "%d", graph->mask);
322
323 return TCL_OK;
324}
325
326
327int
328DoGraphCmd(CLIENT_ARGS)
329{
330 SimGraph *graph = (SimGraph *) clientData;
331 Tcl_HashEntry *ent;
332 int result = TCL_OK;
333 int (*cmd)();
334
335 if (argc < 2) {
336 return TCL_ERROR;
337 }
338
339 if (ent = Tcl_FindHashEntry(&GraphCmds, argv[1])) {
340 cmd = (int (*)())ent->clientData;
341 Tk_Preserve((ClientData) graph);
342 result = cmd(graph, interp, argc, argv);
343 Tk_Release((ClientData) graph);
344 } else {
345 Tcl_AppendResult(interp, "unknown command name: \"",
346 argv[0], " ", argv[1], "\".", (char *) NULL);
347 result = TCL_ERROR;
348 }
349 return result;
350}
351
352
353int
354GraphViewCmd(CLIENT_ARGS)
355{
356 SimGraph *graph;
357 Tk_Window tkwin = (Tk_Window) clientData;
358
359 if (argc < 2) {
360 Tcl_AppendResult(interp, "wrong # args: should be \"",
361 argv[0], " pathName ?options?\"", (char *) NULL);
362 return TCL_ERROR;
363 }
364
365 tkwin = Tk_CreateWindowFromPath(interp, tkwin,
366 argv[1], (char *) NULL);
367 if (tkwin == NULL) {
368 return TCL_ERROR;
369 }
370
371 graph = (SimGraph *)ckalloc(sizeof (SimGraph));
372
373 graph->tkwin = tkwin;
374 graph->interp = interp;
375 graph->flags = 0;
376
377 Tk_SetClass(graph->tkwin, "GraphView");
378 Tk_CreateEventHandler(graph->tkwin,
379 VisibilityChangeMask |
380 ExposureMask |
381 StructureNotifyMask,
382 SimGraphEventProc, (ClientData) graph);
383 Tcl_CreateCommand(interp, Tk_PathName(graph->tkwin),
384 DoGraphCmd, (ClientData) graph, (void (*)()) NULL);
385
386/*
387 Tk_MakeWindowExist(graph->tkwin);
388*/
389
390 if (getenv("XSYNCHRONIZE") != NULL) {
391 XSynchronize(Tk_Display(tkwin), 1);
392 }
393
394 InitNewGraph(graph);
395 DoNewGraph(graph);
396
397 if (ConfigureSimGraph(interp, graph, argc-2, argv+2, 0) != TCL_OK) {
398 /* XXX: destroy graph */
399 Tk_DestroyWindow(graph->tkwin);
400 return TCL_ERROR;
401 }
402
403 interp->result = Tk_PathName(graph->tkwin);
404 return TCL_OK;
405}
406
407
408int
409ConfigureSimGraph(Tcl_Interp *interp, SimGraph *graph,
410 int argc, char **argv, int flags)
411{
412 if (Tk_ConfigureWidget(interp, graph->tkwin, GraphConfigSpecs,
413 argc, argv, (char *) graph, flags) != TCL_OK) {
414 return TCL_ERROR;
415 }
416
417 Tk_SetBackgroundFromBorder(graph->tkwin, graph->border);
418
419 EventuallyRedrawGraph(graph);
420 return TCL_OK;
421}
422
423
424
425
426char *HistName[] = {
427 "Residential", "Commercial", "Industrial",
428 "Cash Flow", "Crime", "Pollution"
429};
430
431unsigned char HistColor[] = {
432 COLOR_LIGHTGREEN, COLOR_DARKBLUE, COLOR_YELLOW,
433 COLOR_DARKGREEN, COLOR_RED, COLOR_OLIVE
434};
435
436
437graph_command_init()
438{
439 int new;
440
441 Tcl_CreateCommand(tk_mainInterp, "graphview", GraphViewCmd,
442 (ClientData)MainWindow, (void (*)()) NULL);
443
444 Tcl_InitHashTable(&GraphCmds, TCL_STRING_KEYS);
445
446#define GRAPH_CMD(name) HASHED_CMD(Graph, name)
447
448 GRAPH_CMD(configure);
449 GRAPH_CMD(position);
450 GRAPH_CMD(size);
451 GRAPH_CMD(Visible);
452 GRAPH_CMD(Range);
453 GRAPH_CMD(Mask);
454}
455
456
457
458void
459drawMonth(short *hist, unsigned char *s, float scale)
460{
461 register short val;
462 register short x;
463
464 for (x = 0; x < 120; x++) {
465 val = hist[x] * scale;
466 if (val < 0) val = 0;
467 if (val > 255) val = 255;
468 s[119 - x] = val;
469 }
470}
471
472
473void
474doAllGraphs(void)
475{
476 float scaleValue;
477
478 AllMax = 0;
479 if (ResHisMax > AllMax) AllMax = ResHisMax;
480 if (ComHisMax > AllMax) AllMax = ComHisMax;
481 if (IndHisMax > AllMax) AllMax = IndHisMax;
482 if (AllMax <= 128) AllMax = 0;
483
484 if (AllMax) {
485 scaleValue = 128.0 / AllMax;
486 } else {
487 scaleValue = 1.0;
488 }
489
490 // scaleValue = 0.5; // XXX
491
492 drawMonth(ResHis, History10[RES_HIST], scaleValue);
493 drawMonth(ComHis, History10[COM_HIST], scaleValue);
494 drawMonth(IndHis, History10[IND_HIST], scaleValue);
495 drawMonth(MoneyHis, History10[MONEY_HIST], 1.0);
496 drawMonth(CrimeHis, History10[CRIME_HIST], 1.0);
497 drawMonth(PollutionHis, History10[POLLUTION_HIST], 1.0);
498
499 AllMax = 0;
500 if (Res2HisMax > AllMax) AllMax = Res2HisMax;
501 if (Com2HisMax > AllMax) AllMax = Com2HisMax;
502 if (Ind2HisMax > AllMax) AllMax = Ind2HisMax;
503 if (AllMax <= 128) AllMax = 0;
504
505 if (AllMax) {
506 scaleValue = 128.0 / AllMax;
507 } else {
508 scaleValue = 1.0;
509 }
510
511 // scaleValue = 0.5; // XXX
512
513 drawMonth(ResHis + 120, History120[RES_HIST], scaleValue);
514 drawMonth(ComHis + 120, History120[COM_HIST], scaleValue);
515 drawMonth(IndHis + 120, History120[IND_HIST], scaleValue);
516 drawMonth(MoneyHis + 120, History120[MONEY_HIST], 1.0);
517 drawMonth(CrimeHis + 120, History120[CRIME_HIST], 1.0);
518 drawMonth(PollutionHis + 120, History120[POLLUTION_HIST], 1.0);
519}
520
521
522void
523ChangeCensus(void)
524{
525 CensusChanged = 1;
526}
527
528
529void
530graphDoer(void)
531{
532 SimGraph *graph;
533
534 if (CensusChanged) {
535 doAllGraphs();
536 NewGraph = 1;
537 CensusChanged = 0;
538 }
539
540 if (NewGraph) {
541 for (graph = sim->graph; graph != NULL; graph = graph->next) {
542 EventuallyRedrawGraph(graph);
543 }
544 NewGraph = 0;
545 }
546}
547
548
549void
550initGraphs(void)
551{
552 int i;
553 SimGraph *graph;
554
555 for (graph = sim->graph; graph != NULL; graph = graph->next) {
556 graph->range = 10;
557 graph->mask = ALL_HISTORIES;
558 }
559
560 if (!HistoryInitialized) {
561 HistoryInitialized = 1;
562 for (i = 0; i < HISTORIES; i++) {
563 History10[i] = (unsigned char *)ckalloc(120);
564 History120[i] = (unsigned char *)ckalloc(120);
565 }
566 }
567}
568
569
570/* comefrom: InitWillStuff */
571InitGraphMax(void)
572{
573 register x;
574
575 ResHisMax = 0;
576 ComHisMax = 0;
577 IndHisMax = 0;
578 for (x = 118; x >= 0; x--) {
579 if (ResHis[x] > ResHisMax) ResHisMax = ResHis[x];
580 if (ComHis[x] > ComHisMax) ComHisMax = ComHis[x];
581 if (IndHis[x] > IndHisMax) IndHisMax = IndHis[x];
582 if (ResHis[x] < 0) ResHis[x] = 0;
583 if (ComHis[x] < 0) ComHis[x] = 0;
584 if (IndHis[x] < 0) IndHis[x] = 0;
585 }
586 Graph10Max = ResHisMax;
587 if (ComHisMax > Graph10Max) Graph10Max = ComHisMax;
588 if (IndHisMax > Graph10Max) Graph10Max = IndHisMax;
589
590 Res2HisMax = 0;
591 Com2HisMax = 0;
592 Ind2HisMax = 0;
593 for (x = 238; x >= 120; x--) {
594 if (ResHis[x] > Res2HisMax) Res2HisMax = ResHis[x];
595 if (ComHis[x] > Com2HisMax) Com2HisMax = ComHis[x];
596 if (IndHis[x] > Ind2HisMax) Ind2HisMax = IndHis[x];
597 if (ResHis[x] < 0) ResHis[x] = 0;
598 if (ComHis[x] < 0) ComHis[x] = 0;
599 if (IndHis[x] < 0) IndHis[x] = 0;
600 }
601 Graph120Max = Res2HisMax;
602 if (Com2HisMax > Graph120Max) Graph120Max = Com2HisMax;
603 if (Ind2HisMax > Graph120Max) Graph120Max = Ind2HisMax;
604}
605
606
607InitNewGraph(SimGraph *graph)
608{
609 int d = 8;
610 struct XDisplay *xd;
611
612 graph->next = NULL;
613 graph->range = 10;
614 graph->mask = ALL_HISTORIES;
615
616/* This stuff was initialized in our caller (GraphCmd) */
617/* graph->tkwin = NULL; */
618/* graph->interp = NULL; */
619/* graph->flags = 0; */
620
621 graph->x = NULL;
622 graph->visible = 0;
623 graph->w_x = graph->w_y = 0;
624 graph->w_width = graph->w_height = 0;
625 graph->pixmap = None;
626 graph->pixels = NULL;
627 graph->fontPtr = NULL;
628 graph->border = NULL;
629 graph->borderWidth = 0;
630 graph->relief = TK_RELIEF_FLAT;
631 graph->draw_graph_token = 0;
632//fprintf(stderr, "InitNewGraph token %d\n", graph->draw_graph_token);
633
634 graph->x = FindXDisplay(graph->tkwin);
635 IncRefDisplay(graph->x);
636
637 graph->pixels = graph->x->pixels;
638 graph->fontPtr = NULL;
639
640 DoResizeGraph(graph, 16, 16);
641}
642
643
644DestroyGraph(SimGraph *graph)
645{
646 SimGraph **gp;
647
648 for (gp = &sim->graph;
649 (*gp) != NULL;
650 gp = &((*gp)->next)) {
651 if ((*gp) == graph) {
652 (*gp) = graph->next;
653 sim->graphs--;
654 break;
655 }
656 }
657
658 if (graph->pixmap != None) {
659 XFreePixmap(graph->x->dpy, graph->pixmap);
660 graph->pixmap = None;
661 }
662
663 DecRefDisplay(graph->x);
664
665 ckfree((char *) graph);
666}
667
668
669DoResizeGraph(SimGraph *graph, int w, int h)
670{
671 int resize = 0;
672
673 graph->w_width = w; graph->w_height = h;
674
675 if (graph->pixmap != None) {
676 XFreePixmap(graph->x->dpy, graph->pixmap);
677 graph->pixmap = None;
678 }
679 graph->pixmap = XCreatePixmap(graph->x->dpy, graph->x->root,
680 w, h, graph->x->depth);
681 if (graph->pixmap == None) {
682 fprintf(stderr,
683 "Sorry, Micropolis can't create a pixmap on X display \"%s\".\n",
684 graph->x->display);
685 sim_exit(1); // Just sets tkMustExit and ExitReturn
686 return;
687 }
688}
689
690
691DoNewGraph(SimGraph *graph)
692{
693 sim->graphs++; graph->next = sim->graph; sim->graph = graph;
694
695 NewGraph = 1;
696}
697
698
699#define BORDER 5
700
701DoUpdateGraph(SimGraph *graph)
702{
703 Display *dpy;
704 GC gc;
705 Pixmap pm;
706 int *pix;
707 unsigned char **hist;
708 int w, h, mask, i, j, x, y;
709 XPoint points[121];
710 int year = (CityTime / 48) + StartingYear;
711 int month = (CityTime / 4) % 12;
712 int do_top_labels = 0;
713 int do_right_labels = 0;
714 int top_label_height = 30;
715 int right_label_width = 65;
716 int tx, ty;
717 float sx, sy;
718
719 if (!graph->visible) {
720 return;
721 }
722
723 if (graph->range == 10) {
724 hist = History10;
725 } else {
726 hist = History120;
727 }
728
729 dpy = graph->x->dpy;
730 gc = graph->x->gc;
731 pm = graph->pixmap;
732 pix = graph->pixels;
733
734 w = graph->w_width;
735 h = graph->w_height;
736
737 XSetFont(graph->x->dpy, graph->x->gc, graph->fontPtr->fid);
738 XSetLineAttributes(dpy, gc, 3, LineSolid, CapButt, JoinBevel);
739 if (graph->x->color) {
740 XSetForeground(dpy, gc, pix[COLOR_LIGHTGRAY]);
741 } else {
742 XSetForeground(dpy, gc, pix[COLOR_WHITE]);
743 }
744 XFillRectangle(dpy, pm, gc, 0, 0, w, h);
745
746 tx = BORDER; ty = BORDER;
747
748 if ((w -= (2 * BORDER)) < 1) w = 1;
749 if ((h -= (2 * BORDER)) < 1) h = 1;
750
751 if (w > (4 * right_label_width)) {
752 w -= right_label_width;
753 do_right_labels = 1;
754 }
755
756 if (do_right_labels &&
757 (h > (3 * top_label_height))) {
758 ty += top_label_height;
759 h -= top_label_height;
760 do_top_labels = 1;
761 }
762
763 sx = ((float)w) / 120.0; sy = ((float)h) / 256.0;
764
765 mask = graph->mask;
766 for (i = 0; i < HISTORIES; i++, mask >>= 1, hist++) {
767 if (mask & 1) {
768 int fg = COLOR_WHITE;
769 int bg = COLOR_BLACK;
770 Pixmap stipple = None;
771
772 for (j = 0; j < 120; j++) {
773 x = tx + (j * sx);
774 y = ty + ((int)(h - (((float)(*hist)[j]) * sy)));
775 points[j].x = x; points[j].y = y;
776 }
777 x = tx + (j * sx);
778 points[j].x = x; points[j].y = y;
779
780 if (graph->x->color) {
781 XSetForeground(dpy, gc, pix[HistColor[i]]);
782 } else {
783 switch (i) {
784 case 0: /* res */
785 stipple = graph->x->gray50_stipple;
786 break;
787 case 1: /* com */
788 stipple = graph->x->gray25_stipple;
789 break;
790 case 2: /* ind */
791 stipple = graph->x->gray75_stipple;
792 break;
793 case 3: /* cash */
794 fg = COLOR_BLACK;
795 break;
796 case 4: /* crime */
797 stipple = graph->x->horiz_stipple;
798 break;
799 case 5: /* pol */
800 stipple = graph->x->vert_stipple;
801 break;
802 }
803 if (stipple != None) {
804 XSetStipple(graph->x->dpy, gc, stipple);
805 XSetTSOrigin(graph->x->dpy, gc, 0, 0);
806 XSetForeground(graph->x->dpy, gc, pix[fg]);
807 XSetBackground(graph->x->dpy, gc, pix[bg]);
808 XSetFillStyle(graph->x->dpy, gc, FillOpaqueStippled);
809 } else {
810 XSetForeground(graph->x->dpy, gc, pix[fg]);
811 }
812 }
813
814 XDrawLines(dpy, pm, gc, points, 121, CoordModeOrigin);
815
816 if (!graph->x->color && (stipple != None)) {
817 XSetFillStyle(graph->x->dpy, gc, FillSolid);
818 }
819
820 if (do_right_labels) {
821 if (graph->x->color) {
822 XSetForeground(dpy, gc, pix[HistColor[i]]);
823 XDrawString(graph->x->dpy, pm, graph->x->gc,
824 x + 4, y + 5,
825 HistName[i], strlen(HistName[i]));
826 XDrawString(graph->x->dpy, pm, graph->x->gc,
827 x + 5, y + 4,
828 HistName[i], strlen(HistName[i]));
829
830 XSetForeground(dpy, gc, pix[COLOR_BLACK]);
831 XDrawString(graph->x->dpy, pm, graph->x->gc,
832 x + 5, y + 5,
833 HistName[i], strlen(HistName[i]));
834 } else {
835 XSetForeground(dpy, gc, pix[COLOR_BLACK]);
836 XDrawString(graph->x->dpy, pm, graph->x->gc,
837 x + 5, y + 5,
838 HistName[i], strlen(HistName[i]));
839 }
840 }
841 }
842 }
843
844 XSetLineAttributes(dpy, gc, 1, LineSolid, CapButt, JoinMiter);
845
846 XSetForeground(dpy, gc, pix[COLOR_BLACK]);
847 XDrawLine(dpy, pm, gc, tx, ty - 1, tx + w, ty - 1);
848 XDrawLine(dpy, pm, gc, tx, ty + h, tx + w, ty + h);
849
850 if (graph->range == 10) {
851 for (x = 120 - month; x >= 0; x -= 12) {
852 int xx, yy;
853 xx = tx + (x * sx);
854 XDrawLine(dpy, pm, gc, xx, ty - 1, xx, ty + h);
855 if (do_top_labels) {
856 char buf[256];
857
858 sprintf(buf, "%d", year--);
859 xx = tx + (x * sx) + 2;
860 yy = ty - ((year & 1) ? 4 : 20);
861 XDrawString(graph->x->dpy, pm, graph->x->gc,
862 xx, yy, buf, strlen(buf));
863 }
864 }
865 } else {
866 int past;
867
868 sx /= 10;
869 past = 10 * (year % 10);
870 year /= 10;
871
872 for (x = 1200 - past; x >= 0; x -= 120) {
873 int xx, yy;
874 xx = tx + (x * sx);
875 XDrawLine(dpy, pm, gc, xx, ty - 1, xx, ty + h);
876 if (do_top_labels) {
877 char buf[256];
878
879 sprintf(buf, "%d0", year--);
880
881 xx = tx + (x * sx) + 2;
882 yy = ty - ((year & 1) ? 4 : 20);
883 XDrawString(graph->x->dpy, pm, graph->x->gc,
884 xx, yy, buf, strlen(buf));
885 }
886 }
887 }
888
889 XCopyArea(graph->x->dpy, graph->pixmap,
890 Tk_WindowId(graph->tkwin), graph->x->gc,
891 0, 0, graph->w_width, graph->w_height, 0, 0);
892}
893
894
Impressum, Datenschutz