]> git.zerfleddert.de Git - micropolis/blame - src/sim/w_graph.c
show less event history on small screens
[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
6f214ac0
MG
74void DoUpdateGraph(SimGraph *graph);
75void DoNewGraph(SimGraph *graph);
76void DoResizeGraph(SimGraph *graph, int w, int h);
77void InitNewGraph(SimGraph *graph);
78
6a5fa4e0
MG
79
80#define DEF_GRAPH_FONT "-Adobe-Helvetica-Bold-R-Normal-*-140-*"
81#define DEF_GRAPH_BG_COLOR "#b0b0b0"
82#define DEF_GRAPH_BG_MONO "#ffffff"
83#define DEF_GRAPH_BORDER_WIDTH "0"
84#define DEF_GRAPH_RELIEF "flat"
85
86Tk_ConfigSpec GraphConfigSpecs[] = {
87 {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL,
88 DEF_GRAPH_FONT, Tk_Offset(SimGraph, fontPtr), 0},
89 {TK_CONFIG_BORDER, "-background", "background", "Background",
90 DEF_GRAPH_BG_COLOR, Tk_Offset(SimGraph, border),
91 TK_CONFIG_COLOR_ONLY},
92 {TK_CONFIG_BORDER, "-background", "background", "Background",
93 DEF_GRAPH_BG_MONO, Tk_Offset(SimGraph, border),
94 TK_CONFIG_MONO_ONLY},
95 {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
96 DEF_GRAPH_BORDER_WIDTH, Tk_Offset(SimGraph, borderWidth), 0},
97 {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
98 DEF_GRAPH_RELIEF, Tk_Offset(SimGraph, relief), 0},
99 {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
100 (char *) NULL, 0, 0}
101 };
102
103
104XDisplay *FindXDisplay();
105
106
107static void
108DisplaySimGraph(ClientData clientData)
109{
110 SimGraph *graph = (SimGraph *) clientData;
111 Tk_Window tkwin = graph->tkwin;
6a5fa4e0
MG
112
113 graph->flags &= ~VIEW_REDRAW_PENDING;
114
115//fprintf(stderr, "DisplaySimGraph token %d\n", graph->draw_graph_token);
116
117 assert(graph->draw_graph_token != 0);
118
119 if (graph->draw_graph_token != 0) {
120// Tk_DeleteTimerHandler(graph->draw_graph_token);
121 graph->draw_graph_token = 0;
122 }
123
124 if (graph->visible && (tkwin != NULL) && Tk_IsMapped(tkwin)) {
125 DoUpdateGraph(graph);
126 }
127}
128
129
130void
131DestroySimGraph(ClientData clientData)
132{
133 SimGraph *graph = (SimGraph *) clientData;
134
135 DestroyGraph(graph);
136}
137
138
6f214ac0 139void
6a5fa4e0
MG
140EventuallyRedrawGraph(SimGraph *graph)
141{
142 if (!(graph->flags & VIEW_REDRAW_PENDING)) {
143 assert(graph->draw_graph_token == 0);
144 if (graph->draw_graph_token == 0) {
145 graph->draw_graph_token =
146 Tk_CreateTimerHandler(
147 GraphUpdateTime,
148 DisplaySimGraph,
149 (ClientData) graph);
150 graph->flags |= VIEW_REDRAW_PENDING;
151//fprintf(stderr, "EventuallyRedrawGraph token %d\n", graph->draw_graph_token);
152 }
153 }
154}
155
156
157void
158SimGraphEventProc(ClientData clientData, XEvent *eventPtr)
159{
160 SimGraph *graph = (SimGraph *) clientData;
161
162 if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
163 graph->visible = 1;
164 EventuallyRedrawGraph(graph);
165 } else if (eventPtr->type == MapNotify) {
166 graph->visible = 1;
167 } else if (eventPtr->type == UnmapNotify) {
168 graph->visible = 0;
169 } else if (eventPtr->type == VisibilityNotify) {
170 if (eventPtr->xvisibility.state == VisibilityFullyObscured)
171 graph->visible = 0;
172 else
173 graph->visible = 1;
174 } else if (eventPtr->type == ConfigureNotify) {
175 DoResizeGraph(graph,
176 eventPtr->xconfigure.width,
177 eventPtr->xconfigure.height);
178 EventuallyRedrawGraph(graph);
179 } else if (eventPtr->type == DestroyNotify) {
180 Tcl_DeleteCommand(graph->interp, Tk_PathName(graph->tkwin));
181 graph->tkwin = NULL;
182 if (graph->flags & VIEW_REDRAW_PENDING) {
183//fprintf(stderr, "SimGraphEventProc Destroy token %d\n", graph->draw_graph_token);
184 assert(graph->draw_graph_token != 0);
185 if (graph->draw_graph_token != 0) {
186 Tk_DeleteTimerHandler(graph->draw_graph_token);
187 graph->draw_graph_token = 0;
188 }
189 graph->flags &= ~VIEW_REDRAW_PENDING;
190 }
191 Tk_EventuallyFree((ClientData) graph, DestroySimGraph);
192 }
193}
194
195
196int GraphCmdconfigure(GRAPH_ARGS)
197{
198 int result = TCL_OK;
199
200 if (argc == 2) {
201 result = Tk_ConfigureInfo(interp, graph->tkwin, GraphConfigSpecs,
202 (char *) graph, (char *) NULL, 0);
203 } else if (argc == 3) {
204 result = Tk_ConfigureInfo(interp, graph->tkwin, GraphConfigSpecs,
205 (char *) graph, argv[2], 0);
206 } else {
207 result = ConfigureSimGraph(interp, graph, argc-2, argv+2,
208 TK_CONFIG_ARGV_ONLY);
209 }
210 return TCL_OK;
211}
212
213
214int GraphCmdposition(GRAPH_ARGS)
215{
6a5fa4e0
MG
216 if ((argc != 2) && (argc != 4)) {
217 return TCL_ERROR;
218 }
219 if (argc == 4) {
220 if ((Tcl_GetInt(interp, argv[2], &graph->w_x) != TCL_OK)
221 || (Tcl_GetInt(interp, argv[3], &graph->w_y) != TCL_OK)) {
222 return TCL_ERROR;
223 }
224 }
225 sprintf(interp->result, "%d %d", graph->w_x, graph->w_y);
226 return TCL_OK;
227}
228
229
230int GraphCmdsize(GRAPH_ARGS)
231{
232 if ((argc != 2) && (argc != 4)) {
233 return TCL_ERROR;
234 }
235 if (argc == 4) {
236 int w, h;
237
238 if (Tcl_GetInt(interp, argv[2], &w) != TCL_OK) {
239 return TCL_ERROR;
240 }
241 if (Tcl_GetInt(interp, argv[3], &h) != TCL_OK) {
242 return TCL_ERROR;
243 }
244 graph->w_width = w;
245 graph->w_height = h;
246 }
247 sprintf(interp->result, "%d %d", graph->w_width, graph->w_height);
248 return TCL_OK;
249}
250
251
252int GraphCmdVisible(GRAPH_ARGS)
253{
254 int visible;
255
256 if ((argc != 2) && (argc != 3)) {
257 Tcl_AppendResult(interp, "wrong # args", (char *) NULL);
258 return TCL_ERROR;
259 }
260
261 if (argc == 3) {
262 if ((Tcl_GetInt(interp, argv[2], &visible) != TCL_OK) ||
263 (visible < 0) || (visible > 1)) {
264 Tcl_AppendResult(interp, " bogus args", (char *) NULL);
265 return TCL_ERROR;
266 }
267
268 graph->visible = visible;
269 }
270
271 sprintf(interp->result, "%d", graph->visible);
272
273 return TCL_OK;
274}
275
276
277int GraphCmdRange(GRAPH_ARGS)
278{
279 int range;
280
281 if ((argc != 2) && (argc != 3)) {
282 Tcl_AppendResult(interp, "wrong # args", (char *) NULL);
283 return TCL_ERROR;
284 }
285
286 if (argc == 3) {
287 if ((Tcl_GetInt(interp, argv[2], &range) != TCL_OK) ||
288 ((range != 10) && (range != 120))) {
289 Tcl_AppendResult(interp, " bogus args", (char *) NULL);
290 return TCL_ERROR;
291 }
292
293 graph->range = range;
294 NewGraph = 1;
295 }
296
297 sprintf(interp->result, "%d", graph->range);
298
299 return TCL_OK;
300}
301
302
303int GraphCmdMask(GRAPH_ARGS)
304{
305 int mask;
306
307 if ((argc != 2) && (argc != 3)) {
308 Tcl_AppendResult(interp, "wrong # args", (char *) NULL);
309 return TCL_ERROR;
310 }
311
312 if (argc == 3) {
313 if ((Tcl_GetInt(interp, argv[2], &mask) != TCL_OK) ||
314 (mask < 0) || (mask > 63)) {
315 Tcl_AppendResult(interp, " bogus args", (char *) NULL);
316 return TCL_ERROR;
317 }
318
319 graph->mask = mask;
320 NewGraph = 1;
321 }
322
323 sprintf(interp->result, "%d", graph->mask);
324
325 return TCL_OK;
326}
327
328
329int
330DoGraphCmd(CLIENT_ARGS)
331{
332 SimGraph *graph = (SimGraph *) clientData;
333 Tcl_HashEntry *ent;
334 int result = TCL_OK;
335 int (*cmd)();
336
337 if (argc < 2) {
338 return TCL_ERROR;
339 }
340
6f214ac0 341 if ((ent = Tcl_FindHashEntry(&GraphCmds, argv[1]))) {
6a5fa4e0
MG
342 cmd = (int (*)())ent->clientData;
343 Tk_Preserve((ClientData) graph);
344 result = cmd(graph, interp, argc, argv);
345 Tk_Release((ClientData) graph);
346 } else {
347 Tcl_AppendResult(interp, "unknown command name: \"",
348 argv[0], " ", argv[1], "\".", (char *) NULL);
349 result = TCL_ERROR;
350 }
351 return result;
352}
353
354
355int
356GraphViewCmd(CLIENT_ARGS)
357{
358 SimGraph *graph;
359 Tk_Window tkwin = (Tk_Window) clientData;
360
361 if (argc < 2) {
362 Tcl_AppendResult(interp, "wrong # args: should be \"",
363 argv[0], " pathName ?options?\"", (char *) NULL);
364 return TCL_ERROR;
365 }
366
367 tkwin = Tk_CreateWindowFromPath(interp, tkwin,
368 argv[1], (char *) NULL);
369 if (tkwin == NULL) {
370 return TCL_ERROR;
371 }
372
373 graph = (SimGraph *)ckalloc(sizeof (SimGraph));
374
375 graph->tkwin = tkwin;
376 graph->interp = interp;
377 graph->flags = 0;
378
379 Tk_SetClass(graph->tkwin, "GraphView");
380 Tk_CreateEventHandler(graph->tkwin,
381 VisibilityChangeMask |
382 ExposureMask |
383 StructureNotifyMask,
384 SimGraphEventProc, (ClientData) graph);
385 Tcl_CreateCommand(interp, Tk_PathName(graph->tkwin),
386 DoGraphCmd, (ClientData) graph, (void (*)()) NULL);
387
388/*
389 Tk_MakeWindowExist(graph->tkwin);
390*/
391
392 if (getenv("XSYNCHRONIZE") != NULL) {
393 XSynchronize(Tk_Display(tkwin), 1);
394 }
395
396 InitNewGraph(graph);
397 DoNewGraph(graph);
398
399 if (ConfigureSimGraph(interp, graph, argc-2, argv+2, 0) != TCL_OK) {
400 /* XXX: destroy graph */
401 Tk_DestroyWindow(graph->tkwin);
402 return TCL_ERROR;
403 }
404
405 interp->result = Tk_PathName(graph->tkwin);
406 return TCL_OK;
407}
408
409
410int
411ConfigureSimGraph(Tcl_Interp *interp, SimGraph *graph,
412 int argc, char **argv, int flags)
413{
414 if (Tk_ConfigureWidget(interp, graph->tkwin, GraphConfigSpecs,
415 argc, argv, (char *) graph, flags) != TCL_OK) {
416 return TCL_ERROR;
417 }
418
419 Tk_SetBackgroundFromBorder(graph->tkwin, graph->border);
420
421 EventuallyRedrawGraph(graph);
422 return TCL_OK;
423}
424
425
426
427
428char *HistName[] = {
429 "Residential", "Commercial", "Industrial",
430 "Cash Flow", "Crime", "Pollution"
431};
432
433unsigned char HistColor[] = {
434 COLOR_LIGHTGREEN, COLOR_DARKBLUE, COLOR_YELLOW,
435 COLOR_DARKGREEN, COLOR_RED, COLOR_OLIVE
436};
437
438
6f214ac0
MG
439void
440graph_command_init(void)
6a5fa4e0 441{
6a5fa4e0
MG
442 Tcl_CreateCommand(tk_mainInterp, "graphview", GraphViewCmd,
443 (ClientData)MainWindow, (void (*)()) NULL);
444
445 Tcl_InitHashTable(&GraphCmds, TCL_STRING_KEYS);
446
447#define GRAPH_CMD(name) HASHED_CMD(Graph, name)
448
449 GRAPH_CMD(configure);
450 GRAPH_CMD(position);
451 GRAPH_CMD(size);
452 GRAPH_CMD(Visible);
453 GRAPH_CMD(Range);
454 GRAPH_CMD(Mask);
455}
456
457
458
459void
460drawMonth(short *hist, unsigned char *s, float scale)
461{
462 register short val;
463 register short x;
464
465 for (x = 0; x < 120; x++) {
466 val = hist[x] * scale;
467 if (val < 0) val = 0;
468 if (val > 255) val = 255;
469 s[119 - x] = val;
470 }
471}
472
473
474void
475doAllGraphs(void)
476{
477 float scaleValue;
478
479 AllMax = 0;
480 if (ResHisMax > AllMax) AllMax = ResHisMax;
481 if (ComHisMax > AllMax) AllMax = ComHisMax;
482 if (IndHisMax > AllMax) AllMax = IndHisMax;
483 if (AllMax <= 128) AllMax = 0;
484
485 if (AllMax) {
486 scaleValue = 128.0 / AllMax;
487 } else {
488 scaleValue = 1.0;
489 }
490
491 // scaleValue = 0.5; // XXX
492
493 drawMonth(ResHis, History10[RES_HIST], scaleValue);
494 drawMonth(ComHis, History10[COM_HIST], scaleValue);
495 drawMonth(IndHis, History10[IND_HIST], scaleValue);
496 drawMonth(MoneyHis, History10[MONEY_HIST], 1.0);
497 drawMonth(CrimeHis, History10[CRIME_HIST], 1.0);
498 drawMonth(PollutionHis, History10[POLLUTION_HIST], 1.0);
499
500 AllMax = 0;
501 if (Res2HisMax > AllMax) AllMax = Res2HisMax;
502 if (Com2HisMax > AllMax) AllMax = Com2HisMax;
503 if (Ind2HisMax > AllMax) AllMax = Ind2HisMax;
504 if (AllMax <= 128) AllMax = 0;
505
506 if (AllMax) {
507 scaleValue = 128.0 / AllMax;
508 } else {
509 scaleValue = 1.0;
510 }
511
512 // scaleValue = 0.5; // XXX
513
514 drawMonth(ResHis + 120, History120[RES_HIST], scaleValue);
515 drawMonth(ComHis + 120, History120[COM_HIST], scaleValue);
516 drawMonth(IndHis + 120, History120[IND_HIST], scaleValue);
517 drawMonth(MoneyHis + 120, History120[MONEY_HIST], 1.0);
518 drawMonth(CrimeHis + 120, History120[CRIME_HIST], 1.0);
519 drawMonth(PollutionHis + 120, History120[POLLUTION_HIST], 1.0);
520}
521
522
523void
524ChangeCensus(void)
525{
526 CensusChanged = 1;
527}
528
529
530void
531graphDoer(void)
532{
533 SimGraph *graph;
534
535 if (CensusChanged) {
536 doAllGraphs();
537 NewGraph = 1;
538 CensusChanged = 0;
539 }
540
541 if (NewGraph) {
542 for (graph = sim->graph; graph != NULL; graph = graph->next) {
543 EventuallyRedrawGraph(graph);
544 }
545 NewGraph = 0;
546 }
547}
548
549
550void
551initGraphs(void)
552{
553 int i;
554 SimGraph *graph;
555
556 for (graph = sim->graph; graph != NULL; graph = graph->next) {
557 graph->range = 10;
558 graph->mask = ALL_HISTORIES;
559 }
560
561 if (!HistoryInitialized) {
562 HistoryInitialized = 1;
563 for (i = 0; i < HISTORIES; i++) {
564 History10[i] = (unsigned char *)ckalloc(120);
565 History120[i] = (unsigned char *)ckalloc(120);
566 }
567 }
568}
569
570
571/* comefrom: InitWillStuff */
6f214ac0 572void
6a5fa4e0
MG
573InitGraphMax(void)
574{
6f214ac0 575 register int x;
6a5fa4e0
MG
576
577 ResHisMax = 0;
578 ComHisMax = 0;
579 IndHisMax = 0;
580 for (x = 118; x >= 0; x--) {
581 if (ResHis[x] > ResHisMax) ResHisMax = ResHis[x];
582 if (ComHis[x] > ComHisMax) ComHisMax = ComHis[x];
583 if (IndHis[x] > IndHisMax) IndHisMax = IndHis[x];
584 if (ResHis[x] < 0) ResHis[x] = 0;
585 if (ComHis[x] < 0) ComHis[x] = 0;
586 if (IndHis[x] < 0) IndHis[x] = 0;
587 }
588 Graph10Max = ResHisMax;
589 if (ComHisMax > Graph10Max) Graph10Max = ComHisMax;
590 if (IndHisMax > Graph10Max) Graph10Max = IndHisMax;
591
592 Res2HisMax = 0;
593 Com2HisMax = 0;
594 Ind2HisMax = 0;
595 for (x = 238; x >= 120; x--) {
596 if (ResHis[x] > Res2HisMax) Res2HisMax = ResHis[x];
597 if (ComHis[x] > Com2HisMax) Com2HisMax = ComHis[x];
598 if (IndHis[x] > Ind2HisMax) Ind2HisMax = IndHis[x];
599 if (ResHis[x] < 0) ResHis[x] = 0;
600 if (ComHis[x] < 0) ComHis[x] = 0;
601 if (IndHis[x] < 0) IndHis[x] = 0;
602 }
603 Graph120Max = Res2HisMax;
604 if (Com2HisMax > Graph120Max) Graph120Max = Com2HisMax;
605 if (Ind2HisMax > Graph120Max) Graph120Max = Ind2HisMax;
606}
607
608
6f214ac0 609void
6a5fa4e0
MG
610InitNewGraph(SimGraph *graph)
611{
6a5fa4e0
MG
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
6f214ac0 644void
6a5fa4e0
MG
645DestroyGraph(SimGraph *graph)
646{
647 SimGraph **gp;
648
649 for (gp = &sim->graph;
650 (*gp) != NULL;
651 gp = &((*gp)->next)) {
652 if ((*gp) == graph) {
653 (*gp) = graph->next;
654 sim->graphs--;
655 break;
656 }
657 }
658
659 if (graph->pixmap != None) {
660 XFreePixmap(graph->x->dpy, graph->pixmap);
661 graph->pixmap = None;
662 }
663
664 DecRefDisplay(graph->x);
665
666 ckfree((char *) graph);
667}
668
669
6f214ac0 670void
6a5fa4e0
MG
671DoResizeGraph(SimGraph *graph, int w, int h)
672{
6a5fa4e0
MG
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
6f214ac0 691void
6a5fa4e0
MG
692DoNewGraph(SimGraph *graph)
693{
694 sim->graphs++; graph->next = sim->graph; sim->graph = graph;
695
696 NewGraph = 1;
697}
698
699
700#define BORDER 5
701
6f214ac0 702void
6a5fa4e0
MG
703DoUpdateGraph(SimGraph *graph)
704{
705 Display *dpy;
706 GC gc;
707 Pixmap pm;
708 int *pix;
709 unsigned char **hist;
710 int w, h, mask, i, j, x, y;
711 XPoint points[121];
712 int year = (CityTime / 48) + StartingYear;
713 int month = (CityTime / 4) % 12;
714 int do_top_labels = 0;
715 int do_right_labels = 0;
716 int top_label_height = 30;
717 int right_label_width = 65;
718 int tx, ty;
719 float sx, sy;
720
721 if (!graph->visible) {
722 return;
723 }
724
725 if (graph->range == 10) {
726 hist = History10;
727 } else {
728 hist = History120;
729 }
730
731 dpy = graph->x->dpy;
732 gc = graph->x->gc;
733 pm = graph->pixmap;
734 pix = graph->pixels;
735
736 w = graph->w_width;
737 h = graph->w_height;
738
739 XSetFont(graph->x->dpy, graph->x->gc, graph->fontPtr->fid);
740 XSetLineAttributes(dpy, gc, 3, LineSolid, CapButt, JoinBevel);
741 if (graph->x->color) {
742 XSetForeground(dpy, gc, pix[COLOR_LIGHTGRAY]);
743 } else {
744 XSetForeground(dpy, gc, pix[COLOR_WHITE]);
745 }
746 XFillRectangle(dpy, pm, gc, 0, 0, w, h);
747
748 tx = BORDER; ty = BORDER;
749
750 if ((w -= (2 * BORDER)) < 1) w = 1;
751 if ((h -= (2 * BORDER)) < 1) h = 1;
752
753 if (w > (4 * right_label_width)) {
754 w -= right_label_width;
755 do_right_labels = 1;
756 }
757
758 if (do_right_labels &&
759 (h > (3 * top_label_height))) {
760 ty += top_label_height;
761 h -= top_label_height;
762 do_top_labels = 1;
763 }
764
765 sx = ((float)w) / 120.0; sy = ((float)h) / 256.0;
766
767 mask = graph->mask;
768 for (i = 0; i < HISTORIES; i++, mask >>= 1, hist++) {
769 if (mask & 1) {
770 int fg = COLOR_WHITE;
771 int bg = COLOR_BLACK;
772 Pixmap stipple = None;
773
774 for (j = 0; j < 120; j++) {
775 x = tx + (j * sx);
776 y = ty + ((int)(h - (((float)(*hist)[j]) * sy)));
777 points[j].x = x; points[j].y = y;
778 }
779 x = tx + (j * sx);
780 points[j].x = x; points[j].y = y;
781
782 if (graph->x->color) {
783 XSetForeground(dpy, gc, pix[HistColor[i]]);
784 } else {
785 switch (i) {
786 case 0: /* res */
787 stipple = graph->x->gray50_stipple;
788 break;
789 case 1: /* com */
790 stipple = graph->x->gray25_stipple;
791 break;
792 case 2: /* ind */
793 stipple = graph->x->gray75_stipple;
794 break;
795 case 3: /* cash */
796 fg = COLOR_BLACK;
797 break;
798 case 4: /* crime */
799 stipple = graph->x->horiz_stipple;
800 break;
801 case 5: /* pol */
802 stipple = graph->x->vert_stipple;
803 break;
804 }
805 if (stipple != None) {
806 XSetStipple(graph->x->dpy, gc, stipple);
807 XSetTSOrigin(graph->x->dpy, gc, 0, 0);
808 XSetForeground(graph->x->dpy, gc, pix[fg]);
809 XSetBackground(graph->x->dpy, gc, pix[bg]);
810 XSetFillStyle(graph->x->dpy, gc, FillOpaqueStippled);
811 } else {
812 XSetForeground(graph->x->dpy, gc, pix[fg]);
813 }
814 }
815
816 XDrawLines(dpy, pm, gc, points, 121, CoordModeOrigin);
817
818 if (!graph->x->color && (stipple != None)) {
819 XSetFillStyle(graph->x->dpy, gc, FillSolid);
820 }
821
822 if (do_right_labels) {
823 if (graph->x->color) {
824 XSetForeground(dpy, gc, pix[HistColor[i]]);
825 XDrawString(graph->x->dpy, pm, graph->x->gc,
826 x + 4, y + 5,
827 HistName[i], strlen(HistName[i]));
828 XDrawString(graph->x->dpy, pm, graph->x->gc,
829 x + 5, y + 4,
830 HistName[i], strlen(HistName[i]));
831
832 XSetForeground(dpy, gc, pix[COLOR_BLACK]);
833 XDrawString(graph->x->dpy, pm, graph->x->gc,
834 x + 5, y + 5,
835 HistName[i], strlen(HistName[i]));
836 } else {
837 XSetForeground(dpy, gc, pix[COLOR_BLACK]);
838 XDrawString(graph->x->dpy, pm, graph->x->gc,
839 x + 5, y + 5,
840 HistName[i], strlen(HistName[i]));
841 }
842 }
843 }
844 }
845
846 XSetLineAttributes(dpy, gc, 1, LineSolid, CapButt, JoinMiter);
847
848 XSetForeground(dpy, gc, pix[COLOR_BLACK]);
849 XDrawLine(dpy, pm, gc, tx, ty - 1, tx + w, ty - 1);
850 XDrawLine(dpy, pm, gc, tx, ty + h, tx + w, ty + h);
851
852 if (graph->range == 10) {
853 for (x = 120 - month; x >= 0; x -= 12) {
854 int xx, yy;
855 xx = tx + (x * sx);
856 XDrawLine(dpy, pm, gc, xx, ty - 1, xx, ty + h);
857 if (do_top_labels) {
858 char buf[256];
859
860 sprintf(buf, "%d", year--);
861 xx = tx + (x * sx) + 2;
862 yy = ty - ((year & 1) ? 4 : 20);
863 XDrawString(graph->x->dpy, pm, graph->x->gc,
864 xx, yy, buf, strlen(buf));
865 }
866 }
867 } else {
868 int past;
869
870 sx /= 10;
871 past = 10 * (year % 10);
872 year /= 10;
873
874 for (x = 1200 - past; x >= 0; x -= 120) {
875 int xx, yy;
876 xx = tx + (x * sx);
877 XDrawLine(dpy, pm, gc, xx, ty - 1, xx, ty + h);
878 if (do_top_labels) {
879 char buf[256];
880
881 sprintf(buf, "%d0", year--);
882
883 xx = tx + (x * sx) + 2;
884 yy = ty - ((year & 1) ? 4 : 20);
885 XDrawString(graph->x->dpy, pm, graph->x->gc,
886 xx, yy, buf, strlen(buf));
887 }
888 }
889 }
890
891 XCopyArea(graph->x->dpy, graph->pixmap,
892 Tk_WindowId(graph->tkwin), graph->x->gc,
893 0, 0, graph->w_width, graph->w_height, 0, 0);
894}
895
896
Impressum, Datenschutz