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.
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.
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/>.
21 * ADDITIONAL TERMS per GNU GPL Section 7
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.
29 * Any propagation or conveyance of this program must include this
30 * copyright notice and these terms.
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.
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.
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
66 Tcl_HashTable DateCmds
;
67 int DateUpdateTime
= 200;
69 void DoUpdateDate(SimDate
*date
);
70 void DoNewDate(SimDate
*date
);
71 void DoResizeDate(SimDate
*date
, int w
, int h
);
72 void DestroyDate(SimDate
*date
);
73 void InitNewDate(SimDate
*date
);
74 int ConfigureSimDate(Tcl_Interp
*interp
, SimDate
*date
,
75 int argc
, char **argv
, int flags
);
78 #define DEF_DATE_FONT "-Adobe-Helvetica-Bold-R-Normal-*-140-*"
79 #define DEF_DATE_BG_COLOR "#b0b0b0"
80 #define DEF_DATE_BG_MONO "#ffffff"
81 #define DEF_DATE_BORDER_WIDTH "2"
82 #define DEF_DATE_PADY "1"
83 #define DEF_DATE_PADX "1"
84 #define DEF_DATE_WIDTH "0"
85 #define DEF_DATE_MONTHTAB "7"
86 #define DEF_DATE_YEARTAB "13"
88 Tk_ConfigSpec DateConfigSpecs
[] = {
89 {TK_CONFIG_FONT
, "-font", (char *) NULL
, (char *) NULL
,
90 DEF_DATE_FONT
, Tk_Offset(SimDate
, fontPtr
), 0},
91 {TK_CONFIG_BORDER
, "-background", "background", "Background",
92 DEF_DATE_BG_COLOR
, Tk_Offset(SimDate
, border
),
93 TK_CONFIG_COLOR_ONLY
},
94 {TK_CONFIG_BORDER
, "-background", "background", "Background",
95 DEF_DATE_BG_MONO
, Tk_Offset(SimDate
, border
),
97 {TK_CONFIG_PIXELS
, "-borderwidth", "borderWidth", "BorderWidth",
98 DEF_DATE_BORDER_WIDTH
, Tk_Offset(SimDate
, borderWidth
), 0},
99 {TK_CONFIG_PIXELS
, "-padx", "padX", "Pad",
100 DEF_DATE_PADX
, Tk_Offset(SimDate
, padX
), 0},
101 {TK_CONFIG_PIXELS
, "-pady", "padY", "Pad",
102 DEF_DATE_PADY
, Tk_Offset(SimDate
, padY
), 0},
103 {TK_CONFIG_INT
, "-width", "width", "Width",
104 DEF_DATE_WIDTH
, Tk_Offset(SimDate
, width
), 0},
105 {TK_CONFIG_INT
, "-monthtab", "monthtab", "MonthTab",
106 DEF_DATE_MONTHTAB
, Tk_Offset(SimDate
, monthTab
), 0},
107 {TK_CONFIG_INT
, "-yeartab", "yeartab", "YearTab",
108 DEF_DATE_YEARTAB
, Tk_Offset(SimDate
, yearTab
), 0},
109 {TK_CONFIG_END
, (char *) NULL
, (char *) NULL
, (char *) NULL
,
114 XDisplay
*FindXDisplay();
118 DisplaySimDate(ClientData clientData
)
120 SimDate
*date
= (SimDate
*) clientData
;
121 Tk_Window tkwin
= date
->tkwin
;
123 date
->flags
&= ~VIEW_REDRAW_PENDING
;
124 //fprintf(stderr, "DisplaySimDate cleared VIEW_REDRAW_PENDING\n");
126 assert(date
->draw_date_token
!= 0);
127 if (date
->draw_date_token
!= 0) {
128 // Tk_DeleteTimerHandler(date->draw_date_token);
129 date
->draw_date_token
= 0;
132 if (date
->visible
&& (tkwin
!= NULL
) && Tk_IsMapped(tkwin
)) {
139 DestroySimDate(ClientData clientData
)
141 SimDate
*date
= (SimDate
*) clientData
;
148 EventuallyRedrawDate(SimDate
*date
)
150 if (!(date
->flags
& VIEW_REDRAW_PENDING
)) {
151 assert(date
->draw_date_token
== 0);
152 if (date
->draw_date_token
== 0) {
153 date
->draw_date_token
=
154 Tk_CreateTimerHandler(
158 date
->flags
|= VIEW_REDRAW_PENDING
;
159 //fprintf(stderr, "EventuallyRedrawDate set VIEW_REDRAW_PENDING\n");
166 SimDateEventProc(ClientData clientData
, XEvent
*eventPtr
)
168 SimDate
*date
= (SimDate
*) clientData
;
170 if ((eventPtr
->type
== Expose
) && (eventPtr
->xexpose
.count
== 0)) {
172 EventuallyRedrawDate(date
);
173 } else if (eventPtr
->type
== MapNotify
) {
175 } else if (eventPtr
->type
== UnmapNotify
) {
177 } else if (eventPtr
->type
== VisibilityNotify
) {
178 if (eventPtr
->xvisibility
.state
== VisibilityFullyObscured
)
182 } else if (eventPtr
->type
== ConfigureNotify
) {
184 eventPtr
->xconfigure
.width
,
185 eventPtr
->xconfigure
.height
);
186 EventuallyRedrawDate(date
);
187 } else if (eventPtr
->type
== DestroyNotify
) {
188 Tcl_DeleteCommand(date
->interp
, Tk_PathName(date
->tkwin
));
190 if (date
->flags
& VIEW_REDRAW_PENDING
) {
191 assert(date
->draw_date_token
!= 0);
192 if (date
->draw_date_token
!= 0) {
193 Tk_DeleteTimerHandler(date
->draw_date_token
);
194 date
->draw_date_token
= 0;
196 date
->flags
&= ~VIEW_REDRAW_PENDING
;
197 //fprintf(stderr, "SimDateEventProc cleared VIEW_REDRAW_PENDING\n");
199 Tk_EventuallyFree((ClientData
) date
, DestroySimDate
);
205 ComputeDateGeometry(SimDate
*date
)
209 unsigned int width
, height
;
212 XTextExtents(date
->fontPtr
, "0", 1,
213 &dummy
, &dummy
, &dummy
, &bbox
);
214 charWidth
= (bbox
.lbearing
+ bbox
.rbearing
);
216 if (date
->width
== 0) {
217 char *maxString
= "Date: MMM 1000000";
218 int maxStringLength
= strlen(maxString
);
220 XTextExtents(date
->fontPtr
, maxString
, maxStringLength
,
221 &dummy
, &dummy
, &dummy
, &bbox
);
222 width
= bbox
.lbearing
+ bbox
.rbearing
;
224 width
= date
->width
* charWidth
;
227 height
= date
->fontPtr
->ascent
+ date
->fontPtr
->descent
;
229 width
+= 2 * date
->padX
;
230 height
+= 2 * date
->padY
;
234 (int) (width
+ (2 * date
->borderWidth
) + 2),
235 (int) (height
+ (2 * date
->borderWidth
) + 2));
236 Tk_SetInternalBorder(
240 date
->yearTabX
= date
->yearTab
* charWidth
;
241 date
->monthTabX
= date
->monthTab
* charWidth
;
245 int DateCmdconfigure(DATE_ARGS
)
250 result
= Tk_ConfigureInfo(interp
, date
->tkwin
, DateConfigSpecs
,
251 (char *) date
, (char *) NULL
, 0);
252 } else if (argc
== 3) {
253 result
= Tk_ConfigureInfo(interp
, date
->tkwin
, DateConfigSpecs
,
254 (char *) date
, argv
[2], 0);
256 result
= ConfigureSimDate(interp
, date
, argc
-2, argv
+2,
257 TK_CONFIG_ARGV_ONLY
);
263 int DateCmdposition(DATE_ARGS
)
265 if ((argc
!= 2) && (argc
!= 4)) {
269 if ((Tcl_GetInt(interp
, argv
[2], &date
->w_x
) != TCL_OK
)
270 || (Tcl_GetInt(interp
, argv
[3], &date
->w_y
) != TCL_OK
)) {
274 sprintf(interp
->result
, "%d %d", date
->w_x
, date
->w_y
);
279 int DateCmdsize(DATE_ARGS
)
281 if ((argc
!= 2) && (argc
!= 4)) {
287 if (Tcl_GetInt(interp
, argv
[2], &w
) != TCL_OK
) {
290 if (Tcl_GetInt(interp
, argv
[3], &h
) != TCL_OK
) {
296 sprintf(interp
->result
, "%d %d", date
->w_width
, date
->w_height
);
301 int DateCmdVisible(DATE_ARGS
)
305 if ((argc
!= 2) && (argc
!= 3)) {
306 Tcl_AppendResult(interp
, "wrong # args", (char *) NULL
);
311 if ((Tcl_GetInt(interp
, argv
[2], &visible
) != TCL_OK
) ||
312 (visible
< 0) || (visible
> 1)) {
313 Tcl_AppendResult(interp
, " bogus args", (char *) NULL
);
317 date
->visible
= visible
;
320 sprintf(interp
->result
, "%d", date
->visible
);
326 int DateCmdReset(DATE_ARGS
)
329 Tcl_AppendResult(interp
, "wrong # args", (char *) NULL
);
335 // ComputeDateGeometry(date); // ???
337 EventuallyRedrawDate(date
);
343 int DateCmdSet(DATE_ARGS
)
346 Tcl_AppendResult(interp
, "wrong # args", (char *) NULL
);
350 if ((Tcl_GetInt(interp
, argv
[2], &date
->month
) != TCL_OK
) ||
352 (date
->month
>= 12)) {
353 Tcl_AppendResult(interp
, " bogus args", (char *) NULL
);
357 if ((Tcl_GetInt(interp
, argv
[3], &date
->year
) != TCL_OK
) ||
359 Tcl_AppendResult(interp
, " bogus args", (char *) NULL
);
363 // ComputeDateGeometry(date); // ???
365 EventuallyRedrawDate(date
);
372 DoDateCmd(CLIENT_ARGS
)
374 SimDate
*date
= (SimDate
*) clientData
;
383 if ((ent
= Tcl_FindHashEntry(&DateCmds
, argv
[1]))) {
384 cmd
= (int (*)())ent
->clientData
;
385 Tk_Preserve((ClientData
) date
);
386 result
= cmd(date
, interp
, argc
, argv
);
387 Tk_Release((ClientData
) date
);
389 Tcl_AppendResult(interp
, "unknown command name: \"",
390 argv
[0], " ", argv
[1], "\".", (char *) NULL
);
398 DateViewCmd(CLIENT_ARGS
)
401 Tk_Window tkwin
= (Tk_Window
) clientData
;
404 Tcl_AppendResult(interp
, "wrong # args: should be \"",
405 argv
[0], " pathName ?options?\"", (char *) NULL
);
409 tkwin
= Tk_CreateWindowFromPath(interp
, tkwin
,
410 argv
[1], (char *) NULL
);
415 date
= (SimDate
*)ckalloc(sizeof (SimDate
));
418 date
->interp
= interp
;
426 Tk_SetClass(date
->tkwin
, "DateView");
427 Tk_CreateEventHandler(date
->tkwin
,
428 VisibilityChangeMask
|
431 SimDateEventProc
, (ClientData
) date
);
432 Tcl_CreateCommand(interp
, Tk_PathName(date
->tkwin
),
433 DoDateCmd
, (ClientData
) date
, (void (*)()) NULL
);
436 Tk_MakeWindowExist(date->tkwin);
439 if (getenv("XSYNCHRONIZE") != NULL
) {
440 XSynchronize(Tk_Display(tkwin
), 1);
446 if (ConfigureSimDate(interp
, date
, argc
-2, argv
+2, 0) != TCL_OK
) {
447 /* XXX: destroy date */
448 Tk_DestroyWindow(date
->tkwin
);
452 interp
->result
= Tk_PathName(date
->tkwin
);
458 ConfigureSimDate(Tcl_Interp
*interp
, SimDate
*date
,
459 int argc
, char **argv
, int flags
)
461 if (Tk_ConfigureWidget(interp
, date
->tkwin
, DateConfigSpecs
,
462 argc
, argv
, (char *) date
, flags
) != TCL_OK
) {
466 Tk_SetBackgroundFromBorder(date
->tkwin
, date
->border
);
468 ComputeDateGeometry(date
);
470 EventuallyRedrawDate(date
);
477 date_command_init(void)
479 Tcl_CreateCommand(tk_mainInterp
, "dateview", DateViewCmd
,
480 (ClientData
)MainWindow
, (void (*)()) NULL
);
482 Tcl_InitHashTable(&DateCmds
, TCL_STRING_KEYS
);
484 #define DATE_CMD(name) HASHED_CMD(Date, name)
496 InitNewDate(SimDate
*date
)
500 /* This stuff was initialized in our caller (DateCmd) */
501 /* date->tkwin = NULL; */
502 /* date->interp = NULL; */
503 /* date->flags = 0; */
507 date
->w_x
= date
->w_y
= 0;
508 date
->w_width
= date
->w_height
= 0;
511 date
->fontPtr
= NULL
;
513 date
->borderWidth
= 0;
521 date
->draw_date_token
= 0;
528 date
->x
= FindXDisplay(date
->tkwin
);
529 IncRefDisplay(date
->x
);
531 date
->pixels
= date
->x
->pixels
;
532 date
->fontPtr
= NULL
;
534 DoResizeDate(date
, 16, 16);
539 DestroyDate(SimDate
*date
)
543 for (gp
= &sim
->date
;
545 gp
= &((*gp
)->next
)) {
553 if (date
->pixmap
!= None
) {
554 XFreePixmap(date
->x
->dpy
, date
->pixmap
);
558 DecRefDisplay(date
->x
);
560 ckfree((char *) date
);
565 DoResizeDate(SimDate
*date
, int w
, int h
)
567 date
->w_width
= w
; date
->w_height
= h
;
569 if (date
->pixmap
!= None
) {
570 XFreePixmap(date
->x
->dpy
, date
->pixmap
);
573 date
->pixmap
= XCreatePixmap(date
->x
->dpy
, date
->x
->root
,
574 w
, h
, date
->x
->depth
);
575 if (date
->pixmap
== None
) {
577 "Sorry, Micropolis can't create a pixmap on X display \"%s\".\n",
579 sim_exit(1); // Just sets tkMustExit and ExitReturn
586 DoNewDate(SimDate
*date
)
588 sim
->dates
++; date
->next
= sim
->date
; sim
->date
= date
;
597 DoUpdateDate(SimDate
*date
)
606 if (!date
->visible
) {
618 XSetFont(date
->x
->dpy
, date
->x
->gc
, date
->fontPtr
->fid
);
621 if (date
->x
->color
) {
622 XSetForeground(dpy
, gc
, pix
[COLOR_LIGHTGRAY
]);
624 XSetForeground(dpy
, gc
, pix
[COLOR_WHITE
]);
627 XSetForeground(dpy
, gc
, Tk_3DBorderColor(date
->border
)->pixel
);
630 XFillRectangle(dpy
, pm
, gc
, 0, 0, w
, h
);
632 tx
= BORDER
; ty
= BORDER
;
634 if ((w
-= (2 * BORDER
)) < 1) w
= 1;
635 if ((h
-= (2 * BORDER
)) < 1) h
= 1;
637 x
= date
->borderWidth
+ date
->padX
+ 1;
638 y
= date
->borderWidth
+ date
->padY
+ date
->fontPtr
->ascent
;
642 date
->lastyear
= date
->year
;
643 date
->lastmonth
= date
->month
;
647 char *dateString
= "Date:";
648 char yearString
[256];
649 int month
= date
->month
;
650 int year
= date
->year
;
651 int lastmonth
= date
->lastmonth
;
652 int lastyear
= date
->lastyear
;
657 if (yearsPassed
< 0) yearsPassed
= 1;
658 if (yearsPassed
> 9) yearsPassed
= 9;
660 (month
- lastmonth
) +
663 if (monthsPassed
> 11) monthsPassed
= 11;
664 if (monthsPassed
== 1) monthsPassed
= 0;
669 XSetForeground(dpy
, gc
, pix
[COLOR_DARKGRAY
]);
671 for (i
= 0; i
< monthsPassed
; i
++) {
673 XDrawString(date
->x
->dpy
, pm
, date
->x
->gc
,
674 x
+ date
->monthTabX
, y
,
676 strlen(dateStr
[date
->month
]));
682 if (year
!= lastyear
) {
684 if ((year
- yy
) > 10) {
688 for (i
= yy
; i
< year
; i
++) {
694 XDrawString(date
->x
->dpy
, pm
, date
->x
->gc
,
695 x
+ date
->yearTabX
, y
,
701 EventuallyRedrawDate(date
);
704 date
->lastmonth
= month
;
705 date
->lastyear
= year
;
707 XSetForeground(dpy
, gc
, pix
[COLOR_BLACK
]);
709 XDrawString(date
->x
->dpy
, pm
, date
->x
->gc
,
714 XDrawString(date
->x
->dpy
, pm
, date
->x
->gc
,
715 x
+ date
->monthTabX
, y
,
716 dateStr
[date
->month
],
717 strlen(dateStr
[date
->month
]));
724 XDrawString(date
->x
->dpy
, pm
, date
->x
->gc
,
725 x
+ date
->yearTabX
, y
,
730 XCopyArea(date
->x
->dpy
, date
->pixmap
,
731 Tk_WindowId(date
->tkwin
), date
->x
->gc
,
732 0, 0, date
->w_width
, date
->w_height
, 0, 0);