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;
70 #define DEF_DATE_FONT "-Adobe-Helvetica-Bold-R-Normal-*-140-*"
71 #define DEF_DATE_BG_COLOR "#b0b0b0"
72 #define DEF_DATE_BG_MONO "#ffffff"
73 #define DEF_DATE_BORDER_WIDTH "2"
74 #define DEF_DATE_PADY "1"
75 #define DEF_DATE_PADX "1"
76 #define DEF_DATE_WIDTH "0"
77 #define DEF_DATE_MONTHTAB "7"
78 #define DEF_DATE_YEARTAB "13"
80 Tk_ConfigSpec DateConfigSpecs
[] = {
81 {TK_CONFIG_FONT
, "-font", (char *) NULL
, (char *) NULL
,
82 DEF_DATE_FONT
, Tk_Offset(SimDate
, fontPtr
), 0},
83 {TK_CONFIG_BORDER
, "-background", "background", "Background",
84 DEF_DATE_BG_COLOR
, Tk_Offset(SimDate
, border
),
85 TK_CONFIG_COLOR_ONLY
},
86 {TK_CONFIG_BORDER
, "-background", "background", "Background",
87 DEF_DATE_BG_MONO
, Tk_Offset(SimDate
, border
),
89 {TK_CONFIG_PIXELS
, "-borderwidth", "borderWidth", "BorderWidth",
90 DEF_DATE_BORDER_WIDTH
, Tk_Offset(SimDate
, borderWidth
), 0},
91 {TK_CONFIG_PIXELS
, "-padx", "padX", "Pad",
92 DEF_DATE_PADX
, Tk_Offset(SimDate
, padX
), 0},
93 {TK_CONFIG_PIXELS
, "-pady", "padY", "Pad",
94 DEF_DATE_PADY
, Tk_Offset(SimDate
, padY
), 0},
95 {TK_CONFIG_INT
, "-width", "width", "Width",
96 DEF_DATE_WIDTH
, Tk_Offset(SimDate
, width
), 0},
97 {TK_CONFIG_INT
, "-monthtab", "monthtab", "MonthTab",
98 DEF_DATE_MONTHTAB
, Tk_Offset(SimDate
, monthTab
), 0},
99 {TK_CONFIG_INT
, "-yeartab", "yeartab", "YearTab",
100 DEF_DATE_YEARTAB
, Tk_Offset(SimDate
, yearTab
), 0},
101 {TK_CONFIG_END
, (char *) NULL
, (char *) NULL
, (char *) NULL
,
106 XDisplay
*FindXDisplay();
110 DisplaySimDate(ClientData clientData
)
112 SimDate
*date
= (SimDate
*) clientData
;
113 Tk_Window tkwin
= date
->tkwin
;
117 date
->flags
&= ~VIEW_REDRAW_PENDING
;
118 //fprintf(stderr, "DisplaySimDate cleared VIEW_REDRAW_PENDING\n");
120 assert(date
->draw_date_token
!= 0);
121 if (date
->draw_date_token
!= 0) {
122 // Tk_DeleteTimerHandler(date->draw_date_token);
123 date
->draw_date_token
= 0;
126 if (date
->visible
&& (tkwin
!= NULL
) && Tk_IsMapped(tkwin
)) {
133 DestroySimDate(ClientData clientData
)
135 SimDate
*date
= (SimDate
*) clientData
;
141 EventuallyRedrawDate(SimDate
*date
)
143 if (!(date
->flags
& VIEW_REDRAW_PENDING
)) {
144 assert(date
->draw_date_token
== 0);
145 if (date
->draw_date_token
== 0) {
146 date
->draw_date_token
=
147 Tk_CreateTimerHandler(
151 date
->flags
|= VIEW_REDRAW_PENDING
;
152 //fprintf(stderr, "EventuallyRedrawDate set VIEW_REDRAW_PENDING\n");
159 SimDateEventProc(ClientData clientData
, XEvent
*eventPtr
)
161 SimDate
*date
= (SimDate
*) clientData
;
163 if ((eventPtr
->type
== Expose
) && (eventPtr
->xexpose
.count
== 0)) {
165 EventuallyRedrawDate(date
);
166 } else if (eventPtr
->type
== MapNotify
) {
168 } else if (eventPtr
->type
== UnmapNotify
) {
170 } else if (eventPtr
->type
== VisibilityNotify
) {
171 if (eventPtr
->xvisibility
.state
== VisibilityFullyObscured
)
175 } else if (eventPtr
->type
== ConfigureNotify
) {
177 eventPtr
->xconfigure
.width
,
178 eventPtr
->xconfigure
.height
);
179 EventuallyRedrawDate(date
);
180 } else if (eventPtr
->type
== DestroyNotify
) {
181 Tcl_DeleteCommand(date
->interp
, Tk_PathName(date
->tkwin
));
183 if (date
->flags
& VIEW_REDRAW_PENDING
) {
184 assert(date
->draw_date_token
!= 0);
185 if (date
->draw_date_token
!= 0) {
186 Tk_DeleteTimerHandler(date
->draw_date_token
);
187 date
->draw_date_token
= 0;
189 date
->flags
&= ~VIEW_REDRAW_PENDING
;
190 //fprintf(stderr, "SimDateEventProc cleared VIEW_REDRAW_PENDING\n");
192 Tk_EventuallyFree((ClientData
) date
, DestroySimDate
);
198 ComputeDateGeometry(SimDate
*date
)
202 unsigned int width
, height
;
205 XTextExtents(date
->fontPtr
, "0", 1,
206 &dummy
, &dummy
, &dummy
, &bbox
);
207 charWidth
= (bbox
.lbearing
+ bbox
.rbearing
);
209 if (date
->width
== 0) {
210 char *maxString
= "Date: MMM 1000000";
211 int maxStringLength
= strlen(maxString
);
213 XTextExtents(date
->fontPtr
, maxString
, maxStringLength
,
214 &dummy
, &dummy
, &dummy
, &bbox
);
215 width
= bbox
.lbearing
+ bbox
.rbearing
;
217 width
= date
->width
* charWidth
;
220 height
= date
->fontPtr
->ascent
+ date
->fontPtr
->descent
;
222 width
+= 2 * date
->padX
;
223 height
+= 2 * date
->padY
;
227 (int) (width
+ (2 * date
->borderWidth
) + 2),
228 (int) (height
+ (2 * date
->borderWidth
) + 2));
229 Tk_SetInternalBorder(
233 date
->yearTabX
= date
->yearTab
* charWidth
;
234 date
->monthTabX
= date
->monthTab
* charWidth
;
238 int DateCmdconfigure(DATE_ARGS
)
243 result
= Tk_ConfigureInfo(interp
, date
->tkwin
, DateConfigSpecs
,
244 (char *) date
, (char *) NULL
, 0);
245 } else if (argc
== 3) {
246 result
= Tk_ConfigureInfo(interp
, date
->tkwin
, DateConfigSpecs
,
247 (char *) date
, argv
[2], 0);
249 result
= ConfigureSimDate(interp
, date
, argc
-2, argv
+2,
250 TK_CONFIG_ARGV_ONLY
);
256 int DateCmdposition(DATE_ARGS
)
260 if ((argc
!= 2) && (argc
!= 4)) {
264 if ((Tcl_GetInt(interp
, argv
[2], &date
->w_x
) != TCL_OK
)
265 || (Tcl_GetInt(interp
, argv
[3], &date
->w_y
) != TCL_OK
)) {
269 sprintf(interp
->result
, "%d %d", date
->w_x
, date
->w_y
);
274 int DateCmdsize(DATE_ARGS
)
276 if ((argc
!= 2) && (argc
!= 4)) {
282 if (Tcl_GetInt(interp
, argv
[2], &w
) != TCL_OK
) {
285 if (Tcl_GetInt(interp
, argv
[3], &h
) != TCL_OK
) {
291 sprintf(interp
->result
, "%d %d", date
->w_width
, date
->w_height
);
296 int DateCmdVisible(DATE_ARGS
)
300 if ((argc
!= 2) && (argc
!= 3)) {
301 Tcl_AppendResult(interp
, "wrong # args", (char *) NULL
);
306 if ((Tcl_GetInt(interp
, argv
[2], &visible
) != TCL_OK
) ||
307 (visible
< 0) || (visible
> 1)) {
308 Tcl_AppendResult(interp
, " bogus args", (char *) NULL
);
312 date
->visible
= visible
;
315 sprintf(interp
->result
, "%d", date
->visible
);
321 int DateCmdReset(DATE_ARGS
)
326 Tcl_AppendResult(interp
, "wrong # args", (char *) NULL
);
332 // ComputeDateGeometry(date); // ???
334 EventuallyRedrawDate(date
);
340 int DateCmdSet(DATE_ARGS
)
345 Tcl_AppendResult(interp
, "wrong # args", (char *) NULL
);
349 if ((Tcl_GetInt(interp
, argv
[2], &date
->month
) != TCL_OK
) ||
351 (date
->month
>= 12)) {
352 Tcl_AppendResult(interp
, " bogus args", (char *) NULL
);
356 if ((Tcl_GetInt(interp
, argv
[3], &date
->year
) != TCL_OK
) ||
358 Tcl_AppendResult(interp
, " bogus args", (char *) NULL
);
362 // ComputeDateGeometry(date); // ???
364 EventuallyRedrawDate(date
);
371 DoDateCmd(CLIENT_ARGS
)
373 SimDate
*date
= (SimDate
*) clientData
;
382 if (ent
= Tcl_FindHashEntry(&DateCmds
, argv
[1])) {
383 cmd
= (int (*)())ent
->clientData
;
384 Tk_Preserve((ClientData
) date
);
385 result
= cmd(date
, interp
, argc
, argv
);
386 Tk_Release((ClientData
) date
);
388 Tcl_AppendResult(interp
, "unknown command name: \"",
389 argv
[0], " ", argv
[1], "\".", (char *) NULL
);
397 DateViewCmd(CLIENT_ARGS
)
400 Tk_Window tkwin
= (Tk_Window
) clientData
;
403 Tcl_AppendResult(interp
, "wrong # args: should be \"",
404 argv
[0], " pathName ?options?\"", (char *) NULL
);
408 tkwin
= Tk_CreateWindowFromPath(interp
, tkwin
,
409 argv
[1], (char *) NULL
);
414 date
= (SimDate
*)ckalloc(sizeof (SimDate
));
417 date
->interp
= interp
;
425 Tk_SetClass(date
->tkwin
, "DateView");
426 Tk_CreateEventHandler(date
->tkwin
,
427 VisibilityChangeMask
|
430 SimDateEventProc
, (ClientData
) date
);
431 Tcl_CreateCommand(interp
, Tk_PathName(date
->tkwin
),
432 DoDateCmd
, (ClientData
) date
, (void (*)()) NULL
);
435 Tk_MakeWindowExist(date->tkwin);
438 if (getenv("XSYNCHRONIZE") != NULL
) {
439 XSynchronize(Tk_Display(tkwin
), 1);
445 if (ConfigureSimDate(interp
, date
, argc
-2, argv
+2, 0) != TCL_OK
) {
446 /* XXX: destroy date */
447 Tk_DestroyWindow(date
->tkwin
);
451 interp
->result
= Tk_PathName(date
->tkwin
);
457 ConfigureSimDate(Tcl_Interp
*interp
, SimDate
*date
,
458 int argc
, char **argv
, int flags
)
460 if (Tk_ConfigureWidget(interp
, date
->tkwin
, DateConfigSpecs
,
461 argc
, argv
, (char *) date
, flags
) != TCL_OK
) {
465 Tk_SetBackgroundFromBorder(date
->tkwin
, date
->border
);
467 ComputeDateGeometry(date
);
469 EventuallyRedrawDate(date
);
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)
495 InitNewDate(SimDate
*date
)
502 /* This stuff was initialized in our caller (DateCmd) */
503 /* date->tkwin = NULL; */
504 /* date->interp = NULL; */
505 /* date->flags = 0; */
509 date
->w_x
= date
->w_y
= 0;
510 date
->w_width
= date
->w_height
= 0;
513 date
->fontPtr
= NULL
;
515 date
->borderWidth
= 0;
523 date
->draw_date_token
= 0;
530 date
->x
= FindXDisplay(date
->tkwin
);
531 IncRefDisplay(date
->x
);
533 date
->pixels
= date
->x
->pixels
;
534 date
->fontPtr
= NULL
;
536 DoResizeDate(date
, 16, 16);
540 DestroyDate(SimDate
*date
)
544 for (gp
= &sim
->date
;
546 gp
= &((*gp
)->next
)) {
554 if (date
->pixmap
!= None
) {
555 XFreePixmap(date
->x
->dpy
, date
->pixmap
);
559 DecRefDisplay(date
->x
);
561 ckfree((char *) date
);
565 DoResizeDate(SimDate
*date
, int w
, int h
)
569 date
->w_width
= w
; date
->w_height
= h
;
571 if (date
->pixmap
!= None
) {
572 XFreePixmap(date
->x
->dpy
, date
->pixmap
);
575 date
->pixmap
= XCreatePixmap(date
->x
->dpy
, date
->x
->root
,
576 w
, h
, date
->x
->depth
);
577 if (date
->pixmap
== None
) {
579 "Sorry, Micropolis can't create a pixmap on X display \"%s\".\n",
581 sim_exit(1); // Just sets tkMustExit and ExitReturn
587 DoNewDate(SimDate
*date
)
589 sim
->dates
++; date
->next
= sim
->date
; sim
->date
= date
;
597 DoUpdateDate(SimDate
*date
)
603 int w
, h
, i
, j
, x
, y
;
607 if (!date
->visible
) {
619 XSetFont(date
->x
->dpy
, date
->x
->gc
, date
->fontPtr
->fid
);
622 if (date
->x
->color
) {
623 XSetForeground(dpy
, gc
, pix
[COLOR_LIGHTGRAY
]);
625 XSetForeground(dpy
, gc
, pix
[COLOR_WHITE
]);
628 XSetForeground(dpy
, gc
, Tk_3DBorderColor(date
->border
)->pixel
);
631 XFillRectangle(dpy
, pm
, gc
, 0, 0, w
, h
);
633 tx
= BORDER
; ty
= BORDER
;
635 if ((w
-= (2 * BORDER
)) < 1) w
= 1;
636 if ((h
-= (2 * BORDER
)) < 1) h
= 1;
638 x
= date
->borderWidth
+ date
->padX
+ 1;
639 y
= date
->borderWidth
+ date
->padY
+ date
->fontPtr
->ascent
;
643 date
->lastyear
= date
->year
;
644 date
->lastmonth
= date
->month
;
648 char *dateString
= "Date:";
649 char yearString
[256];
650 int month
= date
->month
;
651 int year
= date
->year
;
652 int lastmonth
= date
->lastmonth
;
653 int lastyear
= date
->lastyear
;
658 if (yearsPassed
< 0) yearsPassed
= 1;
659 if (yearsPassed
> 9) yearsPassed
= 9;
661 (month
- lastmonth
) +
664 if (monthsPassed
> 11) monthsPassed
= 11;
665 if (monthsPassed
== 1) monthsPassed
= 0;
670 XSetForeground(dpy
, gc
, pix
[COLOR_DARKGRAY
]);
672 for (i
= 0; i
< monthsPassed
; i
++) {
674 XDrawString(date
->x
->dpy
, pm
, date
->x
->gc
,
675 x
+ date
->monthTabX
, y
,
677 strlen(dateStr
[date
->month
]));
683 if (year
!= lastyear
) {
685 if ((year
- yy
) > 10) {
689 for (i
= yy
; i
< year
; i
++) {
695 XDrawString(date
->x
->dpy
, pm
, date
->x
->gc
,
696 x
+ date
->yearTabX
, y
,
702 EventuallyRedrawDate(date
);
705 date
->lastmonth
= month
;
706 date
->lastyear
= year
;
708 XSetForeground(dpy
, gc
, pix
[COLOR_BLACK
]);
710 XDrawString(date
->x
->dpy
, pm
, date
->x
->gc
,
715 XDrawString(date
->x
->dpy
, pm
, date
->x
->gc
,
716 x
+ date
->monthTabX
, y
,
717 dateStr
[date
->month
],
718 strlen(dateStr
[date
->month
]));
725 XDrawString(date
->x
->dpy
, pm
, date
->x
->gc
,
726 x
+ date
->yearTabX
, y
,
731 XCopyArea(date
->x
->dpy
, date
->pixmap
,
732 Tk_WindowId(date
->tkwin
), date
->x
->gc
,
733 0, 0, date
->w_width
, date
->w_height
, 0, 0);