]>
Commit | Line | Data |
---|---|---|
6a5fa4e0 MG |
1 | /* w_date.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 | ||
65 | short NewDate = 0; | |
66 | Tcl_HashTable DateCmds; | |
67 | int DateUpdateTime = 200; | |
68 | ||
6f214ac0 MG |
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); | |
76 | ||
6a5fa4e0 MG |
77 | |
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" | |
87 | ||
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), | |
96 | TK_CONFIG_MONO_ONLY}, | |
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, | |
110 | (char *) NULL, 0, 0} | |
111 | }; | |
112 | ||
113 | ||
114 | XDisplay *FindXDisplay(); | |
115 | ||
116 | ||
117 | static void | |
118 | DisplaySimDate(ClientData clientData) | |
119 | { | |
120 | SimDate *date = (SimDate *) clientData; | |
121 | Tk_Window tkwin = date->tkwin; | |
6a5fa4e0 MG |
122 | |
123 | date->flags &= ~VIEW_REDRAW_PENDING; | |
124 | //fprintf(stderr, "DisplaySimDate cleared VIEW_REDRAW_PENDING\n"); | |
125 | ||
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; | |
130 | } | |
131 | ||
132 | if (date->visible && (tkwin != NULL) && Tk_IsMapped(tkwin)) { | |
133 | DoUpdateDate(date); | |
134 | } | |
135 | } | |
136 | ||
137 | ||
138 | void | |
139 | DestroySimDate(ClientData clientData) | |
140 | { | |
141 | SimDate *date = (SimDate *) clientData; | |
142 | ||
143 | DestroyDate(date); | |
144 | } | |
145 | ||
146 | ||
6f214ac0 | 147 | void |
6a5fa4e0 MG |
148 | EventuallyRedrawDate(SimDate *date) |
149 | { | |
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( | |
155 | DateUpdateTime, | |
156 | DisplaySimDate, | |
157 | (ClientData) date); | |
158 | date->flags |= VIEW_REDRAW_PENDING; | |
159 | //fprintf(stderr, "EventuallyRedrawDate set VIEW_REDRAW_PENDING\n"); | |
160 | } | |
161 | } | |
162 | } | |
163 | ||
164 | ||
165 | void | |
166 | SimDateEventProc(ClientData clientData, XEvent *eventPtr) | |
167 | { | |
168 | SimDate *date = (SimDate *) clientData; | |
169 | ||
170 | if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { | |
171 | date->visible = 1; | |
172 | EventuallyRedrawDate(date); | |
173 | } else if (eventPtr->type == MapNotify) { | |
174 | date->visible = 1; | |
175 | } else if (eventPtr->type == UnmapNotify) { | |
176 | date->visible = 0; | |
177 | } else if (eventPtr->type == VisibilityNotify) { | |
178 | if (eventPtr->xvisibility.state == VisibilityFullyObscured) | |
179 | date->visible = 0; | |
180 | else | |
181 | date->visible = 1; | |
182 | } else if (eventPtr->type == ConfigureNotify) { | |
183 | DoResizeDate(date, | |
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)); | |
189 | date->tkwin = NULL; | |
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; | |
195 | } | |
196 | date->flags &= ~VIEW_REDRAW_PENDING; | |
197 | //fprintf(stderr, "SimDateEventProc cleared VIEW_REDRAW_PENDING\n"); | |
198 | } | |
199 | Tk_EventuallyFree((ClientData) date, DestroySimDate); | |
200 | } | |
201 | } | |
202 | ||
203 | ||
204 | static void | |
205 | ComputeDateGeometry(SimDate *date) | |
206 | { | |
207 | XCharStruct bbox; | |
208 | int dummy; | |
209 | unsigned int width, height; | |
210 | int charWidth; | |
211 | ||
212 | XTextExtents(date->fontPtr, "0", 1, | |
213 | &dummy, &dummy, &dummy, &bbox); | |
214 | charWidth = (bbox.lbearing + bbox.rbearing); | |
215 | ||
216 | if (date->width == 0) { | |
217 | char *maxString = "Date: MMM 1000000"; | |
218 | int maxStringLength = strlen(maxString); | |
219 | ||
220 | XTextExtents(date->fontPtr, maxString, maxStringLength, | |
221 | &dummy, &dummy, &dummy, &bbox); | |
222 | width = bbox.lbearing + bbox.rbearing; | |
223 | } else { | |
224 | width = date->width * charWidth; | |
225 | } | |
226 | ||
227 | height = date->fontPtr->ascent + date->fontPtr->descent; | |
228 | ||
229 | width += 2 * date->padX; | |
230 | height += 2 * date->padY; | |
231 | ||
232 | Tk_GeometryRequest( | |
233 | date->tkwin, | |
234 | (int) (width + (2 * date->borderWidth) + 2), | |
235 | (int) (height + (2 * date->borderWidth) + 2)); | |
236 | Tk_SetInternalBorder( | |
237 | date->tkwin, | |
238 | date->borderWidth); | |
239 | ||
240 | date->yearTabX = date->yearTab * charWidth; | |
241 | date->monthTabX = date->monthTab * charWidth; | |
242 | } | |
243 | ||
244 | ||
245 | int DateCmdconfigure(DATE_ARGS) | |
246 | { | |
247 | int result = TCL_OK; | |
248 | ||
249 | if (argc == 2) { | |
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); | |
255 | } else { | |
256 | result = ConfigureSimDate(interp, date, argc-2, argv+2, | |
257 | TK_CONFIG_ARGV_ONLY); | |
258 | } | |
259 | return TCL_OK; | |
260 | } | |
261 | ||
262 | ||
263 | int DateCmdposition(DATE_ARGS) | |
264 | { | |
6a5fa4e0 MG |
265 | if ((argc != 2) && (argc != 4)) { |
266 | return TCL_ERROR; | |
267 | } | |
268 | if (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)) { | |
271 | return TCL_ERROR; | |
272 | } | |
273 | } | |
274 | sprintf(interp->result, "%d %d", date->w_x, date->w_y); | |
275 | return TCL_OK; | |
276 | } | |
277 | ||
278 | ||
279 | int DateCmdsize(DATE_ARGS) | |
280 | { | |
281 | if ((argc != 2) && (argc != 4)) { | |
282 | return TCL_ERROR; | |
283 | } | |
284 | if (argc == 4) { | |
285 | int w, h; | |
286 | ||
287 | if (Tcl_GetInt(interp, argv[2], &w) != TCL_OK) { | |
288 | return TCL_ERROR; | |
289 | } | |
290 | if (Tcl_GetInt(interp, argv[3], &h) != TCL_OK) { | |
291 | return TCL_ERROR; | |
292 | } | |
293 | date->w_width = w; | |
294 | date->w_height = h; | |
295 | } | |
296 | sprintf(interp->result, "%d %d", date->w_width, date->w_height); | |
297 | return TCL_OK; | |
298 | } | |
299 | ||
300 | ||
301 | int DateCmdVisible(DATE_ARGS) | |
302 | { | |
303 | int visible; | |
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], &visible) != TCL_OK) || | |
312 | (visible < 0) || (visible > 1)) { | |
313 | Tcl_AppendResult(interp, " bogus args", (char *) NULL); | |
314 | return TCL_ERROR; | |
315 | } | |
316 | ||
317 | date->visible = visible; | |
318 | } | |
319 | ||
320 | sprintf(interp->result, "%d", date->visible); | |
321 | ||
322 | return TCL_OK; | |
323 | } | |
324 | ||
325 | ||
326 | int DateCmdReset(DATE_ARGS) | |
327 | { | |
6a5fa4e0 MG |
328 | if (argc != 2) { |
329 | Tcl_AppendResult(interp, "wrong # args", (char *) NULL); | |
330 | return TCL_ERROR; | |
331 | } | |
332 | ||
333 | date->reset = 1; | |
334 | ||
335 | // ComputeDateGeometry(date); // ??? | |
336 | ||
337 | EventuallyRedrawDate(date); | |
338 | ||
339 | return TCL_OK; | |
340 | } | |
341 | ||
342 | ||
343 | int DateCmdSet(DATE_ARGS) | |
344 | { | |
6a5fa4e0 MG |
345 | if (argc != 4) { |
346 | Tcl_AppendResult(interp, "wrong # args", (char *) NULL); | |
347 | return TCL_ERROR; | |
348 | } | |
349 | ||
350 | if ((Tcl_GetInt(interp, argv[2], &date->month) != TCL_OK) || | |
351 | (date->month < 0) || | |
352 | (date->month >= 12)) { | |
353 | Tcl_AppendResult(interp, " bogus args", (char *) NULL); | |
354 | return TCL_ERROR; | |
355 | } | |
356 | ||
357 | if ((Tcl_GetInt(interp, argv[3], &date->year) != TCL_OK) || | |
358 | (date->year < 0)) { | |
359 | Tcl_AppendResult(interp, " bogus args", (char *) NULL); | |
360 | return TCL_ERROR; | |
361 | } | |
362 | ||
363 | // ComputeDateGeometry(date); // ??? | |
364 | ||
365 | EventuallyRedrawDate(date); | |
366 | ||
367 | return TCL_OK; | |
368 | } | |
369 | ||
370 | ||
371 | int | |
372 | DoDateCmd(CLIENT_ARGS) | |
373 | { | |
374 | SimDate *date = (SimDate *) clientData; | |
375 | Tcl_HashEntry *ent; | |
376 | int result = TCL_OK; | |
377 | int (*cmd)(); | |
378 | ||
379 | if (argc < 2) { | |
380 | return TCL_ERROR; | |
381 | } | |
382 | ||
6f214ac0 | 383 | if ((ent = Tcl_FindHashEntry(&DateCmds, argv[1]))) { |
6a5fa4e0 MG |
384 | cmd = (int (*)())ent->clientData; |
385 | Tk_Preserve((ClientData) date); | |
386 | result = cmd(date, interp, argc, argv); | |
387 | Tk_Release((ClientData) date); | |
388 | } else { | |
389 | Tcl_AppendResult(interp, "unknown command name: \"", | |
390 | argv[0], " ", argv[1], "\".", (char *) NULL); | |
391 | result = TCL_ERROR; | |
392 | } | |
393 | return result; | |
394 | } | |
395 | ||
396 | ||
397 | int | |
398 | DateViewCmd(CLIENT_ARGS) | |
399 | { | |
400 | SimDate *date; | |
401 | Tk_Window tkwin = (Tk_Window) clientData; | |
402 | ||
403 | if (argc < 2) { | |
404 | Tcl_AppendResult(interp, "wrong # args: should be \"", | |
405 | argv[0], " pathName ?options?\"", (char *) NULL); | |
406 | return TCL_ERROR; | |
407 | } | |
408 | ||
409 | tkwin = Tk_CreateWindowFromPath(interp, tkwin, | |
410 | argv[1], (char *) NULL); | |
411 | if (tkwin == NULL) { | |
412 | return TCL_ERROR; | |
413 | } | |
414 | ||
415 | date = (SimDate *)ckalloc(sizeof (SimDate)); | |
416 | ||
417 | date->tkwin = tkwin; | |
418 | date->interp = interp; | |
419 | date->flags = 0; | |
420 | date->reset = 1; | |
421 | date->month = 0; | |
422 | date->year = 0; | |
423 | date->lastmonth = 0; | |
424 | date->lastyear = 0; | |
425 | ||
426 | Tk_SetClass(date->tkwin, "DateView"); | |
427 | Tk_CreateEventHandler(date->tkwin, | |
428 | VisibilityChangeMask | | |
429 | ExposureMask | | |
430 | StructureNotifyMask, | |
431 | SimDateEventProc, (ClientData) date); | |
432 | Tcl_CreateCommand(interp, Tk_PathName(date->tkwin), | |
433 | DoDateCmd, (ClientData) date, (void (*)()) NULL); | |
434 | ||
435 | /* | |
436 | Tk_MakeWindowExist(date->tkwin); | |
437 | */ | |
438 | ||
439 | if (getenv("XSYNCHRONIZE") != NULL) { | |
440 | XSynchronize(Tk_Display(tkwin), 1); | |
441 | } | |
442 | ||
443 | InitNewDate(date); | |
444 | DoNewDate(date); | |
445 | ||
446 | if (ConfigureSimDate(interp, date, argc-2, argv+2, 0) != TCL_OK) { | |
447 | /* XXX: destroy date */ | |
448 | Tk_DestroyWindow(date->tkwin); | |
449 | return TCL_ERROR; | |
450 | } | |
451 | ||
452 | interp->result = Tk_PathName(date->tkwin); | |
453 | return TCL_OK; | |
454 | } | |
455 | ||
456 | ||
457 | int | |
458 | ConfigureSimDate(Tcl_Interp *interp, SimDate *date, | |
459 | int argc, char **argv, int flags) | |
460 | { | |
461 | if (Tk_ConfigureWidget(interp, date->tkwin, DateConfigSpecs, | |
462 | argc, argv, (char *) date, flags) != TCL_OK) { | |
463 | return TCL_ERROR; | |
464 | } | |
465 | ||
466 | Tk_SetBackgroundFromBorder(date->tkwin, date->border); | |
467 | ||
468 | ComputeDateGeometry(date); | |
469 | ||
470 | EventuallyRedrawDate(date); | |
471 | ||
472 | return TCL_OK; | |
473 | } | |
474 | ||
475 | ||
6f214ac0 MG |
476 | void |
477 | date_command_init(void) | |
6a5fa4e0 | 478 | { |
6a5fa4e0 MG |
479 | Tcl_CreateCommand(tk_mainInterp, "dateview", DateViewCmd, |
480 | (ClientData)MainWindow, (void (*)()) NULL); | |
481 | ||
482 | Tcl_InitHashTable(&DateCmds, TCL_STRING_KEYS); | |
483 | ||
484 | #define DATE_CMD(name) HASHED_CMD(Date, name) | |
485 | ||
486 | DATE_CMD(configure); | |
487 | DATE_CMD(position); | |
488 | DATE_CMD(size); | |
489 | DATE_CMD(Visible); | |
490 | DATE_CMD(Reset); | |
491 | DATE_CMD(Set); | |
492 | } | |
493 | ||
494 | ||
6f214ac0 | 495 | void |
6a5fa4e0 MG |
496 | InitNewDate(SimDate *date) |
497 | { | |
6a5fa4e0 MG |
498 | date->next = NULL; |
499 | ||
500 | /* This stuff was initialized in our caller (DateCmd) */ | |
501 | /* date->tkwin = NULL; */ | |
502 | /* date->interp = NULL; */ | |
503 | /* date->flags = 0; */ | |
504 | ||
505 | date->x = NULL; | |
506 | date->visible = 0; | |
507 | date->w_x = date->w_y = 0; | |
508 | date->w_width = date->w_height = 0; | |
509 | date->pixmap = None; | |
510 | date->pixels = NULL; | |
511 | date->fontPtr = NULL; | |
512 | date->border = NULL; | |
513 | date->borderWidth = 0; | |
514 | date->padX = 0; | |
515 | date->padY = 0; | |
516 | date->width = 0; | |
517 | date->monthTab = 0; | |
518 | date->monthTabX = 0; | |
519 | date->yearTab = 0; | |
520 | date->yearTabX = 0; | |
521 | date->draw_date_token = 0; | |
522 | date->reset = 1; | |
523 | date->year = 0; | |
524 | date->month = 0; | |
525 | date->lastyear = 0; | |
526 | date->lastmonth = 0; | |
527 | ||
528 | date->x = FindXDisplay(date->tkwin); | |
529 | IncRefDisplay(date->x); | |
530 | ||
531 | date->pixels = date->x->pixels; | |
532 | date->fontPtr = NULL; | |
533 | ||
534 | DoResizeDate(date, 16, 16); | |
535 | } | |
536 | ||
537 | ||
6f214ac0 | 538 | void |
6a5fa4e0 MG |
539 | DestroyDate(SimDate *date) |
540 | { | |
541 | SimDate **gp; | |
542 | ||
543 | for (gp = &sim->date; | |
544 | (*gp) != NULL; | |
545 | gp = &((*gp)->next)) { | |
546 | if ((*gp) == date) { | |
547 | (*gp) = date->next; | |
548 | sim->dates--; | |
549 | break; | |
550 | } | |
551 | } | |
552 | ||
553 | if (date->pixmap != None) { | |
554 | XFreePixmap(date->x->dpy, date->pixmap); | |
555 | date->pixmap = None; | |
556 | } | |
557 | ||
558 | DecRefDisplay(date->x); | |
559 | ||
560 | ckfree((char *) date); | |
561 | } | |
562 | ||
563 | ||
6f214ac0 | 564 | void |
6a5fa4e0 MG |
565 | DoResizeDate(SimDate *date, int w, int h) |
566 | { | |
6a5fa4e0 MG |
567 | date->w_width = w; date->w_height = h; |
568 | ||
569 | if (date->pixmap != None) { | |
570 | XFreePixmap(date->x->dpy, date->pixmap); | |
571 | date->pixmap = None; | |
572 | } | |
573 | date->pixmap = XCreatePixmap(date->x->dpy, date->x->root, | |
574 | w, h, date->x->depth); | |
575 | if (date->pixmap == None) { | |
576 | fprintf(stderr, | |
577 | "Sorry, Micropolis can't create a pixmap on X display \"%s\".\n", | |
578 | date->x->display); | |
579 | sim_exit(1); // Just sets tkMustExit and ExitReturn | |
580 | return; | |
581 | } | |
582 | } | |
583 | ||
584 | ||
6f214ac0 | 585 | void |
6a5fa4e0 MG |
586 | DoNewDate(SimDate *date) |
587 | { | |
588 | sim->dates++; date->next = sim->date; sim->date = date; | |
589 | ||
590 | NewDate = 1; | |
591 | } | |
592 | ||
593 | ||
594 | #define BORDER 1 | |
595 | ||
6f214ac0 | 596 | void |
6a5fa4e0 MG |
597 | DoUpdateDate(SimDate *date) |
598 | { | |
599 | Display *dpy; | |
600 | GC gc; | |
601 | Pixmap pm; | |
602 | int *pix; | |
6f214ac0 | 603 | int w, h, x, y; |
6a5fa4e0 | 604 | int tx, ty; |
6a5fa4e0 MG |
605 | |
606 | if (!date->visible) { | |
607 | return; | |
608 | } | |
609 | ||
610 | dpy = date->x->dpy; | |
611 | gc = date->x->gc; | |
612 | pm = date->pixmap; | |
613 | pix = date->pixels; | |
614 | ||
615 | w = date->w_width; | |
616 | h = date->w_height; | |
617 | ||
618 | XSetFont(date->x->dpy, date->x->gc, date->fontPtr->fid); | |
619 | ||
620 | #if 0 | |
621 | if (date->x->color) { | |
622 | XSetForeground(dpy, gc, pix[COLOR_LIGHTGRAY]); | |
623 | } else { | |
624 | XSetForeground(dpy, gc, pix[COLOR_WHITE]); | |
625 | } | |
626 | #else | |
627 | XSetForeground(dpy, gc, Tk_3DBorderColor(date->border)->pixel); | |
628 | #endif | |
629 | ||
630 | XFillRectangle(dpy, pm, gc, 0, 0, w, h); | |
631 | ||
632 | tx = BORDER; ty = BORDER; | |
633 | ||
634 | if ((w -= (2 * BORDER)) < 1) w = 1; | |
635 | if ((h -= (2 * BORDER)) < 1) h = 1; | |
636 | ||
637 | x = date->borderWidth + date->padX + 1; | |
638 | y = date->borderWidth + date->padY + date->fontPtr->ascent; | |
639 | ||
640 | if (date->reset) { | |
641 | date->reset = 0; | |
642 | date->lastyear = date->year; | |
643 | date->lastmonth = date->month; | |
644 | } | |
645 | ||
646 | { | |
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; | |
653 | int yearsPassed; | |
654 | int monthsPassed; | |
655 | yearsPassed = | |
656 | (year - lastyear); | |
657 | if (yearsPassed < 0) yearsPassed = 1; | |
658 | if (yearsPassed > 9) yearsPassed = 9; | |
659 | monthsPassed = | |
660 | (month - lastmonth) + | |
661 | (12 * yearsPassed); | |
662 | ||
663 | if (monthsPassed > 11) monthsPassed = 11; | |
664 | if (monthsPassed == 1) monthsPassed = 0; | |
665 | if (monthsPassed) { | |
666 | int m = lastmonth; | |
667 | int i; | |
668 | ||
669 | XSetForeground(dpy, gc, pix[COLOR_DARKGRAY]); | |
670 | ||
671 | for (i = 0; i < monthsPassed; i++) { | |
672 | ||
673 | XDrawString(date->x->dpy, pm, date->x->gc, | |
674 | x + date->monthTabX, y, | |
675 | dateStr[m], | |
676 | strlen(dateStr[date->month])); | |
677 | ||
678 | m++; | |
679 | if (m == 12) m = 0; | |
680 | } | |
681 | ||
682 | if (year != lastyear) { | |
683 | int yy = lastyear; | |
684 | if ((year - yy) > 10) { | |
685 | yy = year - 10; | |
686 | } | |
687 | ||
688 | for (i = yy; i < year; i++) { | |
689 | sprintf( | |
690 | yearString, | |
691 | "%d", | |
692 | i); | |
693 | ||
694 | XDrawString(date->x->dpy, pm, date->x->gc, | |
695 | x + date->yearTabX, y, | |
696 | yearString, | |
697 | strlen(yearString)); | |
698 | } | |
699 | } | |
700 | ||
701 | EventuallyRedrawDate(date); | |
702 | } | |
703 | ||
704 | date->lastmonth = month; | |
705 | date->lastyear = year; | |
706 | ||
707 | XSetForeground(dpy, gc, pix[COLOR_BLACK]); | |
708 | ||
709 | XDrawString(date->x->dpy, pm, date->x->gc, | |
710 | x, y, | |
711 | dateString, | |
712 | strlen(dateString)); | |
713 | ||
714 | XDrawString(date->x->dpy, pm, date->x->gc, | |
715 | x + date->monthTabX, y, | |
716 | dateStr[date->month], | |
717 | strlen(dateStr[date->month])); | |
718 | ||
719 | sprintf( | |
720 | yearString, | |
721 | "%d", | |
722 | year); | |
723 | ||
724 | XDrawString(date->x->dpy, pm, date->x->gc, | |
725 | x + date->yearTabX, y, | |
726 | yearString, | |
727 | strlen(yearString)); | |
728 | } | |
729 | ||
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); | |
733 | } | |
734 | ||
735 |