|
|
1.1 root 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 [email protected].
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:
65: short NewGraph = 0;
66: short AllMax;
67: unsigned char *History10[HISTORIES];
68: unsigned char *History120[HISTORIES];
69: int HistoryInitialized = 0;
70: short Graph10Max, Graph120Max;
71: Tcl_HashTable GraphCmds;
72: int 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:
81: Tk_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:
99: XDisplay *FindXDisplay();
100:
101:
102: static void
103: DisplaySimGraph(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:
127: void
128: DestroySimGraph(ClientData clientData)
129: {
130: SimGraph *graph = (SimGraph *) clientData;
131:
132: DestroyGraph(graph);
133: }
134:
135:
136: EventuallyRedrawGraph(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:
153: void
154: SimGraphEventProc(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:
192: int 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:
210: int 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:
228: int 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:
250: int 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:
275: int 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:
301: int 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:
327: int
328: DoGraphCmd(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:
353: int
354: GraphViewCmd(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:
408: int
409: ConfigureSimGraph(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:
426: char *HistName[] = {
427: "Residential", "Commercial", "Industrial",
428: "Cash Flow", "Crime", "Pollution"
429: };
430:
431: unsigned char HistColor[] = {
432: COLOR_LIGHTGREEN, COLOR_DARKBLUE, COLOR_YELLOW,
433: COLOR_DARKGREEN, COLOR_RED, COLOR_OLIVE
434: };
435:
436:
437: graph_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:
458: void
459: drawMonth(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:
473: void
474: doAllGraphs(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:
522: void
523: ChangeCensus(void)
524: {
525: CensusChanged = 1;
526: }
527:
528:
529: void
530: graphDoer(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:
549: void
550: initGraphs(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 */
571: InitGraphMax(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:
607: InitNewGraph(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:
644: DestroyGraph(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:
669: DoResizeGraph(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:
691: DoNewGraph(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:
701: DoUpdateGraph(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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.