]>
Commit | Line | Data |
---|---|---|
1 | /* w_editor.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 | Tcl_HashTable EditorCmds; | |
66 | int DoOverlay = 2; | |
67 | int BobHeight = 8; | |
68 | ||
69 | ||
70 | extern Tk_ConfigSpec TileViewConfigSpecs[]; | |
71 | ||
72 | ||
73 | int EditorCmdconfigure(VIEW_ARGS) | |
74 | { | |
75 | int result = TCL_OK; | |
76 | ||
77 | if (argc == 2) { | |
78 | result = Tk_ConfigureInfo(interp, view->tkwin, TileViewConfigSpecs, | |
79 | (char *) view, (char *) NULL, 0); | |
80 | } else if (argc == 3) { | |
81 | result = Tk_ConfigureInfo(interp, view->tkwin, TileViewConfigSpecs, | |
82 | (char *) view, argv[2], 0); | |
83 | } else { | |
84 | result = ConfigureTileView(interp, view, argc-2, argv+2, | |
85 | TK_CONFIG_ARGV_ONLY); | |
86 | } | |
87 | return TCL_OK; | |
88 | } | |
89 | ||
90 | ||
91 | int EditorCmdposition(VIEW_ARGS) | |
92 | { | |
93 | if ((argc != 2) && (argc != 4)) { | |
94 | return TCL_ERROR; | |
95 | } | |
96 | if (argc == 4) { | |
97 | if ((Tcl_GetInt(interp, argv[2], &view->w_x) != TCL_OK) || | |
98 | (Tcl_GetInt(interp, argv[3], &view->w_y) != TCL_OK)) { | |
99 | return TCL_ERROR; | |
100 | } | |
101 | } | |
102 | sprintf(interp->result, "%d %d", view->w_x, view->w_y); | |
103 | return TCL_OK; | |
104 | } | |
105 | ||
106 | ||
107 | int EditorCmdsize(VIEW_ARGS) | |
108 | { | |
109 | if ((argc != 2) && (argc != 4)) { | |
110 | return TCL_ERROR; | |
111 | } | |
112 | if (argc == 4) { | |
113 | int w, h; | |
114 | ||
115 | if (Tcl_GetInt(interp, argv[2], &w) != TCL_OK) { | |
116 | return TCL_ERROR; | |
117 | } | |
118 | if (Tcl_GetInt(interp, argv[3], &h) != TCL_OK) { | |
119 | return TCL_ERROR; | |
120 | } | |
121 | view->w_width = w; | |
122 | view->w_height = h; | |
123 | } | |
124 | sprintf(interp->result, "%d %d", view->w_width, view->w_height); | |
125 | return TCL_OK; | |
126 | } | |
127 | ||
128 | ||
129 | int EditorCmdAutoGoto(VIEW_ARGS) | |
130 | { | |
131 | if ((argc != 2) && (argc != 3)) { | |
132 | return TCL_ERROR; | |
133 | } | |
134 | if (argc == 3) { | |
135 | int val; | |
136 | ||
137 | if (Tcl_GetInt(interp, argv[2], &val) != TCL_OK) { | |
138 | return TCL_ERROR; | |
139 | } | |
140 | view->auto_goto = val; | |
141 | view->auto_going = view->auto_x_goal = view->auto_y_goal = 0; | |
142 | } | |
143 | sprintf(interp->result, "%d", view->auto_goto); | |
144 | return TCL_OK; | |
145 | } | |
146 | ||
147 | ||
148 | int EditorCmdSound(VIEW_ARGS) | |
149 | { | |
150 | if ((argc != 2) && (argc != 3)) { | |
151 | return TCL_ERROR; | |
152 | } | |
153 | if (argc == 3) { | |
154 | int val; | |
155 | ||
156 | if (Tcl_GetInt(interp, argv[2], &val) != TCL_OK) { | |
157 | return TCL_ERROR; | |
158 | } | |
159 | view->sound = val; | |
160 | view->auto_going = view->auto_x_goal = view->auto_y_goal = 0; | |
161 | } | |
162 | sprintf(interp->result, "%d", view->sound); | |
163 | return TCL_OK; | |
164 | } | |
165 | ||
166 | ||
167 | int EditorCmdSkip(VIEW_ARGS) | |
168 | { | |
169 | if ((argc != 2) && (argc != 3)) { | |
170 | return TCL_ERROR; | |
171 | } | |
172 | if (argc == 3) { | |
173 | int val; | |
174 | ||
175 | if (Tcl_GetInt(interp, argv[2], &val) != TCL_OK) { | |
176 | return TCL_ERROR; | |
177 | } | |
178 | view->skip = view->skips = val; // XXX? why setting skips too? | |
179 | } | |
180 | sprintf(interp->result, "%d", view->skips); | |
181 | return TCL_OK; | |
182 | } | |
183 | ||
184 | ||
185 | int EditorCmdUpdate(VIEW_ARGS) | |
186 | { | |
187 | if (argc != 2) { | |
188 | return TCL_ERROR; | |
189 | } | |
190 | view->skip = 0; | |
191 | return TCL_OK; | |
192 | } | |
193 | ||
194 | ||
195 | int EditorCmdPan(VIEW_ARGS) | |
196 | { | |
197 | if ((argc != 2) && (argc != 4)) { | |
198 | return TCL_ERROR; | |
199 | } | |
200 | if (argc == 4) { | |
201 | int x, y; | |
202 | ||
203 | if (Tcl_GetInt(interp, argv[2], &x) != TCL_OK) { | |
204 | return TCL_ERROR; | |
205 | } | |
206 | if (Tcl_GetInt(interp, argv[3], &y) != TCL_OK) { | |
207 | return TCL_ERROR; | |
208 | } | |
209 | DoPanTo(view, x, y); Kick(); | |
210 | } | |
211 | sprintf(interp->result, "%d %d", view->pan_x, view->pan_y); | |
212 | return TCL_OK; | |
213 | } | |
214 | ||
215 | ||
216 | int EditorCmdToolConstrain(VIEW_ARGS) | |
217 | { | |
218 | int x = -1, y = -1, tx, ty; | |
219 | ||
220 | if (argc != 4) { | |
221 | return TCL_ERROR; | |
222 | } | |
223 | ||
224 | if (Tcl_GetInt(interp, argv[2], &x) != TCL_OK) { | |
225 | return TCL_ERROR; | |
226 | } | |
227 | if (Tcl_GetInt(interp, argv[3], &y) != TCL_OK) { | |
228 | return TCL_ERROR; | |
229 | } | |
230 | view->tool_x_const = -1; view->tool_y_const = -1; | |
231 | ViewToTileCoords(view, x, y, &tx, &ty); | |
232 | view->tool_x_const = (x == -1) ? -1 : tx; | |
233 | view->tool_y_const = (y == -1) ? -1 : ty; | |
234 | return TCL_OK; | |
235 | } | |
236 | ||
237 | ||
238 | int EditorCmdToolState(VIEW_ARGS) | |
239 | { | |
240 | if ((argc != 2) && (argc != 3)) { | |
241 | return TCL_ERROR; | |
242 | } | |
243 | if (argc == 3) { | |
244 | int state; | |
245 | ||
246 | if (Tcl_GetInt(interp, argv[2], &state) != TCL_OK) { | |
247 | return TCL_ERROR; | |
248 | } | |
249 | setWandState(view, state); | |
250 | } | |
251 | sprintf(interp->result, "%d", view->tool_state); | |
252 | return TCL_OK; | |
253 | } | |
254 | ||
255 | ||
256 | int EditorCmdToolMode(VIEW_ARGS) | |
257 | { | |
258 | if ((argc != 2) && (argc != 3)) { | |
259 | return TCL_ERROR; | |
260 | } | |
261 | if (argc == 3) { | |
262 | int mode; | |
263 | ||
264 | if (Tcl_GetInt(interp, argv[2], &mode) != TCL_OK) { | |
265 | return TCL_ERROR; | |
266 | } | |
267 | view->tool_mode = mode; | |
268 | } | |
269 | sprintf(interp->result, "%d", view->tool_mode); | |
270 | return TCL_OK; | |
271 | } | |
272 | ||
273 | ||
274 | int EditorCmdDoTool(VIEW_ARGS) | |
275 | { | |
276 | int tool, x, y; | |
277 | ||
278 | if (argc != 5) { | |
279 | return TCL_ERROR; | |
280 | } | |
281 | ||
282 | if ((Tcl_GetInt(interp, argv[2], &tool) != TCL_OK) || | |
283 | (tool < 0) || | |
284 | (tool > lastState) || | |
285 | (Tcl_GetInt(interp, argv[3], &x) != TCL_OK) || | |
286 | (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)) { | |
287 | return TCL_ERROR; | |
288 | } | |
289 | ||
290 | DoTool(view, tool, x, y); Kick(); | |
291 | return TCL_OK; | |
292 | } | |
293 | ||
294 | ||
295 | int EditorCmdToolDown(VIEW_ARGS) | |
296 | { | |
297 | int x, y; | |
298 | ||
299 | if (argc != 4) { | |
300 | return TCL_ERROR; | |
301 | } | |
302 | ||
303 | if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || | |
304 | (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { | |
305 | return TCL_ERROR; | |
306 | } | |
307 | ||
308 | ToolDown(view, x, y); Kick(); | |
309 | return TCL_OK; | |
310 | } | |
311 | ||
312 | ||
313 | int EditorCmdToolDrag(VIEW_ARGS) | |
314 | { | |
315 | int x, y; | |
316 | ||
317 | if (argc != 4) { | |
318 | return TCL_ERROR; | |
319 | } | |
320 | ||
321 | if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || | |
322 | (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { | |
323 | return TCL_ERROR; | |
324 | } | |
325 | ||
326 | ToolDrag(view, x, y); Kick(); | |
327 | return TCL_OK; | |
328 | } | |
329 | ||
330 | ||
331 | int EditorCmdToolUp(VIEW_ARGS) | |
332 | { | |
333 | int x, y; | |
334 | ||
335 | if (argc != 4) { | |
336 | return TCL_ERROR; | |
337 | } | |
338 | ||
339 | if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || | |
340 | (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { | |
341 | return TCL_ERROR; | |
342 | } | |
343 | ||
344 | ToolUp(view, x, y); Kick(); | |
345 | return TCL_OK; | |
346 | } | |
347 | ||
348 | ||
349 | int EditorCmdPanStart(VIEW_ARGS) | |
350 | { | |
351 | int x, y; | |
352 | ||
353 | if (argc != 4) { | |
354 | return TCL_ERROR; | |
355 | } | |
356 | ||
357 | if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || | |
358 | (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { | |
359 | return TCL_ERROR; | |
360 | } | |
361 | ||
362 | view->last_x = x; | |
363 | view->last_y = y; | |
364 | return TCL_OK; | |
365 | } | |
366 | ||
367 | ||
368 | int EditorCmdPanTo(VIEW_ARGS) | |
369 | { | |
370 | int x, y, dx, dy; | |
371 | ||
372 | if (argc != 4) { | |
373 | return TCL_ERROR; | |
374 | } | |
375 | ||
376 | if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || | |
377 | (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { | |
378 | return TCL_ERROR; | |
379 | } | |
380 | ||
381 | dx = (view->tool_x_const == -1) ? (view->last_x - x) : 0; | |
382 | dy = (view->tool_y_const == -1) ? (view->last_y - y) : 0; | |
383 | if (dx || dy) { | |
384 | view->last_x = x; | |
385 | view->last_y = y; | |
386 | DoPanBy(view, dx, dy); Kick(); | |
387 | } | |
388 | return TCL_OK; | |
389 | } | |
390 | ||
391 | ||
392 | int EditorCmdPanBy(VIEW_ARGS) | |
393 | { | |
394 | int dx, dy; | |
395 | ||
396 | if (argc != 4) { | |
397 | return TCL_ERROR; | |
398 | } | |
399 | ||
400 | if ((Tcl_GetInt(interp, argv[2], &dx) != TCL_OK) || | |
401 | (Tcl_GetInt(interp, argv[3], &dy) != TCL_OK)) { | |
402 | return TCL_ERROR; | |
403 | } | |
404 | ||
405 | DoPanBy(view, dx, dy); Kick(); | |
406 | return TCL_OK; | |
407 | } | |
408 | ||
409 | ||
410 | int EditorCmdTweakCursor(VIEW_ARGS) | |
411 | { | |
412 | int x, y; | |
413 | ||
414 | XWarpPointer (view->x->dpy, None, None, 0, 0, 0, 0, 0, 0); | |
415 | ||
416 | return TCL_OK; | |
417 | } | |
418 | ||
419 | ||
420 | int EditorCmdVisible(VIEW_ARGS) | |
421 | { | |
422 | int visible; | |
423 | ||
424 | if ((argc != 2) && (argc != 3)) { | |
425 | return TCL_ERROR; | |
426 | } | |
427 | ||
428 | if (argc == 3) { | |
429 | if ((Tcl_GetInt(interp, argv[2], &visible) != TCL_OK) || | |
430 | (visible < 0) || (visible > 1)) { | |
431 | return TCL_ERROR; | |
432 | } | |
433 | ||
434 | visible = visible && Tk_IsMapped(view->tkwin); | |
435 | view->visible = visible; | |
436 | } | |
437 | ||
438 | sprintf(interp->result, "%d", view->visible); | |
439 | return TCL_OK; | |
440 | } | |
441 | ||
442 | ||
443 | int EditorCmdKeyDown(VIEW_ARGS) | |
444 | { | |
445 | ||
446 | if (argc != 3) { | |
447 | return TCL_ERROR; | |
448 | } | |
449 | ||
450 | doKeyDown(view, argv[2][0]); | |
451 | return TCL_OK; | |
452 | } | |
453 | ||
454 | ||
455 | int EditorCmdKeyUp(VIEW_ARGS) | |
456 | { | |
457 | ||
458 | if (argc != 3) { | |
459 | return TCL_ERROR; | |
460 | } | |
461 | ||
462 | doKeyUp(view, argv[2][0]); | |
463 | return TCL_OK; | |
464 | } | |
465 | ||
466 | ||
467 | int EditorCmdTileCoord(VIEW_ARGS) | |
468 | { | |
469 | int x, y; | |
470 | ||
471 | if ((argc != 2) && (argc != 4)) { | |
472 | return TCL_ERROR; | |
473 | } | |
474 | ||
475 | if (Tcl_GetInt(interp, argv[2], &x) != TCL_OK) { | |
476 | return TCL_ERROR; | |
477 | } | |
478 | if (Tcl_GetInt(interp, argv[3], &y) != TCL_OK) { | |
479 | return TCL_ERROR; | |
480 | } | |
481 | ||
482 | ViewToTileCoords(view, x, y, &x, &y); | |
483 | ||
484 | sprintf(interp->result, "%d %d", x, y); | |
485 | return TCL_OK; | |
486 | } | |
487 | ||
488 | ||
489 | int EditorCmdChalkStart(VIEW_ARGS) | |
490 | { | |
491 | int x, y; | |
492 | ||
493 | if (argc != 4) { | |
494 | return TCL_ERROR; | |
495 | } | |
496 | ||
497 | if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || | |
498 | (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { | |
499 | return TCL_ERROR; | |
500 | } | |
501 | ||
502 | ChalkStart(view, x, y, COLOR_WHITE); | |
503 | return TCL_OK; | |
504 | } | |
505 | ||
506 | ||
507 | int EditorCmdChalkTo(VIEW_ARGS) | |
508 | { | |
509 | int x, y; | |
510 | ||
511 | if (argc != 4) { | |
512 | return TCL_ERROR; | |
513 | } | |
514 | ||
515 | if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || | |
516 | (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { | |
517 | return TCL_ERROR; | |
518 | } | |
519 | ||
520 | ChalkTo(view, x, y); | |
521 | return TCL_OK; | |
522 | } | |
523 | ||
524 | ||
525 | int EditorCmdAutoGoing(VIEW_ARGS) | |
526 | { | |
527 | int flag; | |
528 | ||
529 | if ((argc != 2) && (argc != 3)) { | |
530 | return TCL_ERROR; | |
531 | } | |
532 | ||
533 | if (argc == 3) { | |
534 | if ((Tcl_GetInt(interp, argv[2], &flag) != TCL_OK)) { | |
535 | return TCL_ERROR; | |
536 | } | |
537 | ||
538 | view->auto_going = flag; | |
539 | if (view->auto_goto == -1) | |
540 | view->auto_goto = 0; | |
541 | } | |
542 | ||
543 | sprintf(interp->result, "%d", view->auto_going); | |
544 | return TCL_OK; | |
545 | } | |
546 | ||
547 | ||
548 | int EditorCmdAutoSpeed(VIEW_ARGS) | |
549 | { | |
550 | int speed; | |
551 | ||
552 | if ((argc != 2) && (argc != 3)) { | |
553 | return TCL_ERROR; | |
554 | } | |
555 | ||
556 | if (argc == 3) { | |
557 | if ((Tcl_GetInt(interp, argv[2], &speed) != TCL_OK) || | |
558 | (speed < 1)) { | |
559 | return TCL_ERROR; | |
560 | } | |
561 | ||
562 | view->auto_speed = speed; | |
563 | } | |
564 | ||
565 | sprintf(interp->result, "%d", view->auto_speed); | |
566 | return TCL_OK; | |
567 | } | |
568 | ||
569 | ||
570 | int EditorCmdAutoGoal(VIEW_ARGS) | |
571 | { | |
572 | if ((argc != 2) && (argc != 4)) { | |
573 | return TCL_ERROR; | |
574 | } | |
575 | if (argc == 4) { | |
576 | int x, y, dx, dy; | |
577 | ||
578 | if (Tcl_GetInt(interp, argv[2], &x) != TCL_OK) { | |
579 | return TCL_ERROR; | |
580 | } | |
581 | if (Tcl_GetInt(interp, argv[3], &y) != TCL_OK) { | |
582 | return TCL_ERROR; | |
583 | } | |
584 | view->auto_x_goal = x; | |
585 | view->auto_y_goal = y; | |
586 | /* actually go there if more than a block away */ | |
587 | dx = view->pan_x - x; | |
588 | dy = view->pan_y - y; | |
589 | view->auto_going = (((dx * dx) + (dy * dy)) > (64 * 64)); | |
590 | if ((view->auto_going != 0) && | |
591 | (view->auto_goto == 0)) | |
592 | view->auto_goto = -1; | |
593 | } | |
594 | ||
595 | sprintf(interp->result, "%d %d", view->auto_x_goal, view->auto_y_goal); | |
596 | return TCL_OK; | |
597 | } | |
598 | ||
599 | ||
600 | int EditorCmdSU(VIEW_ARGS) | |
601 | { | |
602 | int su; | |
603 | ||
604 | if ((argc != 2) && (argc != 4)) { | |
605 | return TCL_ERROR; | |
606 | } | |
607 | ||
608 | if (argc == 4) { | |
609 | if ((strcmp(argv[3], "xyzzy") != 0) || | |
610 | (Tcl_GetInt(interp, argv[2], &su) != TCL_OK)) { | |
611 | return TCL_ERROR; | |
612 | } | |
613 | ||
614 | view->super_user = su; | |
615 | } | |
616 | ||
617 | sprintf(interp->result, "%d", view->super_user); | |
618 | return TCL_OK; | |
619 | } | |
620 | ||
621 | ||
622 | int EditorCmdShowMe(VIEW_ARGS) | |
623 | { | |
624 | int flag; | |
625 | ||
626 | if ((argc != 2) && (argc != 3)) { | |
627 | return TCL_ERROR; | |
628 | } | |
629 | ||
630 | if (argc == 3) { | |
631 | if (Tcl_GetInt(interp, argv[2], &flag) != TCL_OK) { | |
632 | return TCL_ERROR; | |
633 | } | |
634 | ||
635 | view->show_me = flag; | |
636 | } | |
637 | ||
638 | sprintf(interp->result, "%d", view->show_me); | |
639 | return TCL_OK; | |
640 | } | |
641 | ||
642 | ||
643 | int EditorCmdFollow(VIEW_ARGS) | |
644 | { | |
645 | int id; | |
646 | SimSprite *sprite; | |
647 | ||
648 | if ((argc != 2) && (argc != 3)) { | |
649 | return TCL_ERROR; | |
650 | } | |
651 | ||
652 | if (argc == 3) { | |
653 | view->follow = NULL; | |
654 | if (argv[2][0] != '\0') { | |
655 | for (sprite = sim->sprite; sprite != NULL; sprite = sprite->next) { | |
656 | if (strcmp(sprite->name, argv[2]) == 0) { | |
657 | view->follow = sprite; | |
658 | break; | |
659 | } | |
660 | } | |
661 | } | |
662 | ||
663 | if (view->follow != NULL) { | |
664 | HandleAutoGoto(view); | |
665 | } | |
666 | } | |
667 | ||
668 | sprintf(interp->result, "%s", | |
669 | (view->follow == NULL) ? "" : view->follow->name); | |
670 | return TCL_OK; | |
671 | } | |
672 | ||
673 | ||
674 | int EditorCmdShowOverlay(VIEW_ARGS) | |
675 | { | |
676 | int flag; | |
677 | ||
678 | if ((argc != 2) && (argc != 3)) { | |
679 | return TCL_ERROR; | |
680 | } | |
681 | ||
682 | if (argc == 3) { | |
683 | if ((Tcl_GetInt(interp, argv[2], &flag) != TCL_OK)) { | |
684 | return TCL_ERROR; | |
685 | } | |
686 | ||
687 | view->show_overlay = flag; | |
688 | } | |
689 | ||
690 | sprintf(interp->result, "%d", view->show_overlay); | |
691 | return TCL_OK; | |
692 | } | |
693 | ||
694 | ||
695 | int EditorCmdOverlayMode(VIEW_ARGS) | |
696 | { | |
697 | int flag; | |
698 | ||
699 | if ((argc != 2) && (argc != 3)) { | |
700 | return TCL_ERROR; | |
701 | } | |
702 | ||
703 | if (argc == 3) { | |
704 | if ((Tcl_GetInt(interp, argv[2], &flag) != TCL_OK)) { | |
705 | return TCL_ERROR; | |
706 | } | |
707 | ||
708 | view->overlay_mode = flag; | |
709 | } | |
710 | ||
711 | sprintf(interp->result, "%d", view->overlay_mode); | |
712 | return TCL_OK; | |
713 | } | |
714 | ||
715 | ||
716 | int EditorCmdDynamicFilter(VIEW_ARGS) | |
717 | { | |
718 | int val; | |
719 | ||
720 | if ((argc != 2) && (argc != 3)) { | |
721 | return TCL_ERROR; | |
722 | } | |
723 | ||
724 | if (argc == 3) { | |
725 | if ((Tcl_GetInt(interp, argv[2], &val) != TCL_OK)) { | |
726 | return TCL_ERROR; | |
727 | } | |
728 | ||
729 | view->dynamic_filter = val; | |
730 | } | |
731 | ||
732 | sprintf(interp->result, "%d", view->dynamic_filter); | |
733 | return TCL_OK; | |
734 | } | |
735 | ||
736 | ||
737 | int EditorCmdWriteJpeg(VIEW_ARGS) | |
738 | { | |
739 | int val; | |
740 | char *fileName = argv[2]; | |
741 | ||
742 | if (argc != 3) { | |
743 | return TCL_ERROR; | |
744 | } | |
745 | ||
746 | // Write a jpeg file of this view. | |
747 | ||
748 | return TCL_OK; | |
749 | } | |
750 | ||
751 | ||
752 | editor_command_init() | |
753 | { | |
754 | int new; | |
755 | extern int TileViewCmd(CLIENT_ARGS); | |
756 | ||
757 | Tcl_CreateCommand(tk_mainInterp, "editorview", TileViewCmd, | |
758 | (ClientData)MainWindow, (void (*)()) NULL); | |
759 | ||
760 | Tcl_InitHashTable(&EditorCmds, TCL_STRING_KEYS); | |
761 | ||
762 | #define EDITOR_CMD(name) HASHED_CMD(Editor, name) | |
763 | ||
764 | EDITOR_CMD(configure); | |
765 | EDITOR_CMD(position); | |
766 | EDITOR_CMD(size); | |
767 | EDITOR_CMD(AutoGoto); | |
768 | EDITOR_CMD(Sound); | |
769 | EDITOR_CMD(Skip); | |
770 | EDITOR_CMD(Update); | |
771 | EDITOR_CMD(Pan); | |
772 | EDITOR_CMD(ToolConstrain); | |
773 | EDITOR_CMD(ToolState); | |
774 | EDITOR_CMD(ToolMode); | |
775 | EDITOR_CMD(DoTool); | |
776 | EDITOR_CMD(ToolDown); | |
777 | EDITOR_CMD(ToolDrag); | |
778 | EDITOR_CMD(ToolUp); | |
779 | EDITOR_CMD(PanStart); | |
780 | EDITOR_CMD(PanTo); | |
781 | EDITOR_CMD(PanBy); | |
782 | EDITOR_CMD(TweakCursor); | |
783 | EDITOR_CMD(Visible); | |
784 | EDITOR_CMD(KeyDown); | |
785 | EDITOR_CMD(KeyUp); | |
786 | EDITOR_CMD(TileCoord); | |
787 | EDITOR_CMD(ChalkStart); | |
788 | EDITOR_CMD(ChalkTo); | |
789 | EDITOR_CMD(AutoGoing); | |
790 | EDITOR_CMD(AutoSpeed); | |
791 | EDITOR_CMD(AutoGoal); | |
792 | EDITOR_CMD(SU); | |
793 | EDITOR_CMD(ShowMe); | |
794 | EDITOR_CMD(Follow); | |
795 | EDITOR_CMD(ShowOverlay); | |
796 | EDITOR_CMD(OverlayMode); | |
797 | EDITOR_CMD(DynamicFilter); | |
798 | } | |
799 | ||
800 | ||
801 | int | |
802 | DoEditorCmd(CLIENT_ARGS) | |
803 | { | |
804 | SimView *view = (SimView *) clientData; | |
805 | Tcl_HashEntry *ent; | |
806 | int result = TCL_OK; | |
807 | int (*cmd)(); | |
808 | ||
809 | if (argc < 2) { | |
810 | return TCL_ERROR; | |
811 | } | |
812 | ||
813 | if (ent = Tcl_FindHashEntry(&EditorCmds, argv[1])) { | |
814 | cmd = (int (*)())ent->clientData; | |
815 | Tk_Preserve((ClientData) view); | |
816 | result = cmd(view, interp, argc, argv); | |
817 | Tk_Release((ClientData) view); | |
818 | } else { | |
819 | Tcl_AppendResult(interp, "unknown command name: \"", | |
820 | argv[0], " ", argv[1], "\".", (char *) NULL); | |
821 | result = TCL_ERROR; | |
822 | } | |
823 | return result; | |
824 | } | |
825 | ||
826 | ||
827 | ||
828 | /*************************************************************************/ | |
829 | ||
830 | ||
831 | DoNewEditor(SimView *view) | |
832 | { | |
833 | sim->editors++; view->next = sim->editor; sim->editor = view; | |
834 | view->invalid = 1; | |
835 | } | |
836 | ||
837 | ||
838 | DoUpdateEditor(SimView *view) | |
839 | { | |
840 | int dx, dy, i; | |
841 | ||
842 | view->updates++; | |
843 | ||
844 | if (!view->visible) { | |
845 | return; | |
846 | } | |
847 | ||
848 | if ((!ShakeNow) && | |
849 | // (!view->invalid) && | |
850 | (!view->update) && | |
851 | (sim_skips || | |
852 | view->skips)) { | |
853 | if (sim_skips) { | |
854 | if (sim_skip > 0) { | |
855 | return 0; | |
856 | } | |
857 | } else { | |
858 | if (view->skip > 0) { | |
859 | --view->skip; | |
860 | return 0; | |
861 | } else { | |
862 | view->skip = view->skips; | |
863 | } | |
864 | } | |
865 | } | |
866 | ||
867 | view->skips = 0; | |
868 | view->update = 0; | |
869 | ||
870 | HandleAutoGoto(view); | |
871 | ||
872 | if (DoAnimation && SimSpeed && !heat_steps && !TilesAnimated) { | |
873 | TilesAnimated = 1; | |
874 | animateTiles(); | |
875 | } | |
876 | ||
877 | if (view->invalid) { | |
878 | ||
879 | switch (view->type) { | |
880 | ||
881 | case X_Mem_View: | |
882 | MemDrawBeegMapRect(view, view->tile_x, view->tile_y, | |
883 | view->tile_width, view->tile_height); | |
884 | break; | |
885 | ||
886 | case X_Wire_View: | |
887 | WireDrawBeegMapRect(view, view->tile_x, view->tile_y, | |
888 | view->tile_width, view->tile_height); | |
889 | break; | |
890 | ||
891 | } | |
892 | ||
893 | XCopyArea(view->x->dpy, view->pixmap, view->pixmap2, view->x->gc, | |
894 | 0, 0, view->screen_width, view->screen_height, | |
895 | view->screen_x, view->screen_y); | |
896 | DrawOutside(view); | |
897 | if (PendingTool != -1) { | |
898 | DrawPending(view); | |
899 | } | |
900 | DrawObjects(view); | |
901 | if (view->show_overlay) { | |
902 | DrawOverlay(view); | |
903 | } | |
904 | } | |
905 | ||
906 | for (dx = dy = i = 0; i < ShakeNow; i++) { | |
907 | dx += Rand(16) - 8; | |
908 | dy += Rand(16) - 8; | |
909 | } | |
910 | ||
911 | XCopyArea(view->x->dpy, view->pixmap2, | |
912 | Tk_WindowId(view->tkwin), view->x->gc, | |
913 | 0, 0, view->w_width, view->w_height, dx, dy); | |
914 | ||
915 | DrawCursor(view); | |
916 | ||
917 | view->invalid = 0; | |
918 | } | |
919 | ||
920 | ||
921 | HandleAutoGoto(SimView *view) | |
922 | { | |
923 | if (view->follow != NULL) { | |
924 | int x = view->follow->x + view->follow->x_hot, | |
925 | y = view->follow->y + view->follow->y_hot; | |
926 | ||
927 | if ((x != view->pan_x) || | |
928 | (y != view->pan_y)) { | |
929 | DoPanTo(view, x, y); | |
930 | } | |
931 | } else if (view->auto_goto && | |
932 | view->auto_going && | |
933 | (view->tool_mode == 0)) { | |
934 | int dx, dy; | |
935 | int panx, pany, speed; | |
936 | double dist, sloth; | |
937 | ||
938 | speed = view->auto_speed; | |
939 | ||
940 | if (view->auto_going < 5) { | |
941 | sloth = ((double)view->auto_going) / 5.0; | |
942 | } else { | |
943 | sloth = 1.0; | |
944 | } | |
945 | ||
946 | dx = view->auto_x_goal - view->pan_x; | |
947 | dy = view->auto_y_goal - view->pan_y; | |
948 | ||
949 | dist = sqrt((double)((dx * dx) + (dy * dy))); | |
950 | ||
951 | if (dist < (speed * sloth)) { | |
952 | view->auto_going = 0; | |
953 | if (view->auto_goto == -1) | |
954 | view->auto_goto = 0; | |
955 | DoPanTo(view, view->auto_x_goal, view->auto_y_goal); | |
956 | NewMap = 1; | |
957 | DidStopPan(view); | |
958 | } else { | |
959 | double atan2(), cos(), sin(); | |
960 | double direction, vx, vy; | |
961 | double co, si; | |
962 | ||
963 | direction = (double)atan2((double)dy, (double)dx); | |
964 | co = (double)cos(direction); | |
965 | si = (double)sin(direction); | |
966 | vx = co * (double)speed; | |
967 | vy = si * (double)speed; | |
968 | ||
969 | vx *= sloth; vy *= sloth; | |
970 | speed *= sloth; | |
971 | ||
972 | vx += 0.5; vy += 0.5; | |
973 | ||
974 | DoPanBy(view, (int)(vx), (int)(vy)); | |
975 | view->auto_going++; | |
976 | } | |
977 | } | |
978 | } | |
979 | ||
980 | DrawOutside(SimView *view) | |
981 | { | |
982 | Pixmap pm = view->pixmap2; | |
983 | int left = (view->w_width / 2) - view->pan_x; | |
984 | int right = left + view->i_width; | |
985 | int top = (view->w_height / 2) - view->pan_y; | |
986 | int bottom = top + view->i_height; | |
987 | ||
988 | if ((top > 0) || (bottom < view->w_height) || | |
989 | (left > 0) || (right < view->w_width)) { | |
990 | if (view->x->color) { | |
991 | XSetForeground(view->x->dpy, view->x->gc, | |
992 | view->pixels[COLOR_BLACK]); | |
993 | } else { | |
994 | XSetForeground(view->x->dpy, view->x->gc, | |
995 | view->pixels[COLOR_WHITE]); | |
996 | } | |
997 | ||
998 | if (top > 0) | |
999 | XFillRectangle(view->x->dpy, pm, view->x->gc, | |
1000 | 0, 0, view->w_width, top); | |
1001 | if (bottom < view->w_height) | |
1002 | XFillRectangle(view->x->dpy, pm, view->x->gc, | |
1003 | 0, bottom, view->w_width, | |
1004 | view->w_height - bottom); | |
1005 | if (left > 0) | |
1006 | XFillRectangle(view->x->dpy, pm, view->x->gc, | |
1007 | 0, top, left, bottom - top); | |
1008 | if (right < view->w_width) | |
1009 | XFillRectangle(view->x->dpy, pm, view->x->gc, | |
1010 | right, top, view->w_width - right, bottom - top); | |
1011 | } | |
1012 | } | |
1013 | ||
1014 | ||
1015 | char CursorDashes[] = { 4, 4 }; | |
1016 | ||
1017 | DrawPending(SimView *view) | |
1018 | { | |
1019 | Pixmap pm = view->pixmap2; | |
1020 | int left = (view->w_width / 2) - view->pan_x; | |
1021 | int top = (view->w_height / 2) - view->pan_y; | |
1022 | int x, y, size; | |
1023 | char *iconname = NULL; | |
1024 | ||
1025 | x = (PendingX - toolOffset[PendingTool]) <<4; | |
1026 | y = (PendingY - toolOffset[PendingTool]) <<4; | |
1027 | size = toolSize[PendingTool] <<4; | |
1028 | x += left; y += top; | |
1029 | ||
1030 | XSetStipple(view->x->dpy, view->x->gc, view->x->gray50_stipple); | |
1031 | XSetTSOrigin(view->x->dpy, view->x->gc, 0, 0); | |
1032 | XSetForeground(view->x->dpy, view->x->gc, view->x->pixels[COLOR_BLACK]); | |
1033 | XSetFillStyle(view->x->dpy, view->x->gc, FillStippled); | |
1034 | XFillRectangle(view->x->dpy, pm, view->x->gc, | |
1035 | x, y, size, size); | |
1036 | XSetFillStyle(view->x->dpy, view->x->gc, FillSolid); | |
1037 | ||
1038 | switch (PendingTool) { | |
1039 | case residentialState: | |
1040 | iconname = "@images/res.xpm"; break; | |
1041 | case commercialState: | |
1042 | iconname = "@images/com.xpm"; break; | |
1043 | case industrialState: | |
1044 | iconname = "@images/ind.xpm"; break; | |
1045 | case fireState: | |
1046 | iconname = "@images/fire.xpm"; break; | |
1047 | case policeState: | |
1048 | iconname = "@images/police.xpm"; break; | |
1049 | case stadiumState: | |
1050 | iconname = "@images/stadium.xpm"; break; | |
1051 | case seaportState: | |
1052 | iconname = "@images/seaport.xpm"; break; | |
1053 | case powerState: | |
1054 | iconname = "@images/coal.xpm"; break; | |
1055 | case nuclearState: | |
1056 | iconname = "@images/nuclear.xpm"; break; | |
1057 | case airportState: | |
1058 | iconname = "@images/airport.xpm"; break; | |
1059 | default: | |
1060 | break; | |
1061 | } | |
1062 | ||
1063 | if (iconname != NULL) { | |
1064 | Pixmap icon = Tk_GetPixmap(view->interp, view->tkwin, iconname); | |
1065 | float f; | |
1066 | int i; | |
1067 | ||
1068 | gettimeofday(&now_time, NULL); | |
1069 | f = (2 * now_time.tv_usec / 1000000.0); | |
1070 | if (f > 1.0) f = 2.0 - f; | |
1071 | i = (int)(f * BobHeight * (Players - Votes)); | |
1072 | ||
1073 | if (icon != None) { | |
1074 | XCopyArea(view->x->dpy, icon, pm, view->x->gc, | |
1075 | 0, 0, size, size, x + i, y - i); | |
1076 | } | |
1077 | } | |
1078 | } | |
1079 | ||
1080 | ||
1081 | DrawCursor(SimView *view) | |
1082 | { | |
1083 | Pixmap pm = Tk_WindowId(view->tkwin); | |
1084 | int left = (view->w_width / 2) - view->pan_x; | |
1085 | int top = (view->w_height / 2) - view->pan_y; | |
1086 | int x, y, mode, size, offset, fg, bg, light, dark; | |
1087 | SimView *v; | |
1088 | ||
1089 | for (v = sim->editor; v != NULL; v = v->next) { | |
1090 | mode = v->tool_mode; | |
1091 | if ((v->show_me != 0) && | |
1092 | ((mode == -1) || v->tool_showing)) { | |
1093 | x = v->tool_x; y = v->tool_y; | |
1094 | if (mode == -1) { /* pan cursor */ | |
1095 | ||
1096 | x += left; y += top; | |
1097 | ||
1098 | XSetLineAttributes(view->x->dpy, view->x->gc, 3, | |
1099 | LineSolid, CapRound, JoinMiter); | |
1100 | XSetForeground(view->x->dpy, view->x->gc, | |
1101 | view->pixels[COLOR_BLACK]); | |
1102 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1103 | x - 6, y - 6, x + 6, y + 6); | |
1104 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1105 | x - 6, y + 6, x + 6, y - 6); | |
1106 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1107 | x - 8, y, x + 8, y); | |
1108 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1109 | x, y + 8, x, y - 8); | |
1110 | XSetLineAttributes(view->x->dpy, view->x->gc, 1, | |
1111 | LineSolid, CapRound, JoinMiter); | |
1112 | XSetForeground(view->x->dpy, view->x->gc, | |
1113 | view->pixels[COLOR_WHITE]); | |
1114 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1115 | x - 6, y - 6, x + 6, y + 6); | |
1116 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1117 | x - 6, y + 6, x + 6, y - 6); | |
1118 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1119 | x - 8, y, x + 8, y); | |
1120 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1121 | x, y + 8, x, y - 8); | |
1122 | XSetLineAttributes(view->x->dpy, view->x->gc, 1, | |
1123 | LineSolid, CapButt, JoinMiter); | |
1124 | ||
1125 | } else { /* edit cursor */ | |
1126 | ||
1127 | size = toolSize[v->tool_state]; | |
1128 | fg = toolColors[v->tool_state] & 0xff; | |
1129 | light = COLOR_WHITE; | |
1130 | dark = COLOR_BLACK; | |
1131 | if (mode == 1) { | |
1132 | int temp = dark; | |
1133 | dark = light; | |
1134 | light = temp; | |
1135 | } | |
1136 | switch (v->tool_state) { | |
1137 | ||
1138 | case chalkState: | |
1139 | x += left; y += top; | |
1140 | if (mode == 1) { | |
1141 | offset = 2; | |
1142 | } else { | |
1143 | offset = 0; | |
1144 | ||
1145 | if (view->x->color) { | |
1146 | XSetForeground(view->x->dpy, view->x->gc, | |
1147 | view->pixels[COLOR_MEDIUMGRAY]); | |
1148 | XFillArc(view->x->dpy, pm, view->x->gc, | |
1149 | x - 8, y + 7, 7, 7, 0, 360 * 64); | |
1150 | } else { | |
1151 | XSetStipple(view->x->dpy, view->x->gc, | |
1152 | view->x->gray50_stipple); | |
1153 | XSetTSOrigin(view->x->dpy, view->x->gc, 0, 0); | |
1154 | XSetForeground(view->x->dpy, view->x->gc, | |
1155 | view->x->pixels[COLOR_BLACK]); | |
1156 | XSetBackground(view->x->dpy, view->x->gc, | |
1157 | view->x->pixels[COLOR_WHITE]); | |
1158 | XSetFillStyle(view->x->dpy, view->x->gc, FillOpaqueStippled); | |
1159 | XFillArc(view->x->dpy, pm, view->x->gc, | |
1160 | x - 8, y + 7, 7, 7, 0, 360 * 64); | |
1161 | XSetFillStyle(view->x->dpy, view->x->gc, FillSolid); | |
1162 | } | |
1163 | } | |
1164 | ||
1165 | if (view->x->color) { | |
1166 | XSetLineAttributes(view->x->dpy, view->x->gc, 3, | |
1167 | LineSolid, CapRound, JoinMiter); | |
1168 | XSetForeground(view->x->dpy, view->x->gc, | |
1169 | view->pixels[COLOR_LIGHTGRAY]); | |
1170 | XFillArc(view->x->dpy, pm, view->x->gc, | |
1171 | x - 6 - offset, y + 5 + offset, 7, 7, 0, 360 * 64); | |
1172 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1173 | x + 13 - offset, y - 5 + offset, | |
1174 | x - 1 - offset, y + 9 + offset); | |
1175 | XSetForeground(view->x->dpy, view->x->gc, | |
1176 | view->pixels[COLOR_WHITE]); | |
1177 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1178 | x + 11 - offset, y - 7 + offset, | |
1179 | x - 3 - offset, y + 7 + offset); | |
1180 | XFillArc(view->x->dpy, pm, view->x->gc, | |
1181 | x + 8 - offset, y - 9 + offset, 7, 7, 0, 360 * 64); | |
1182 | XSetLineAttributes(view->x->dpy, view->x->gc, 1, | |
1183 | LineSolid, CapButt, JoinMiter); | |
1184 | } else { | |
1185 | XSetLineAttributes(view->x->dpy, view->x->gc, 3, | |
1186 | LineSolid, CapRound, JoinMiter); | |
1187 | XSetStipple(view->x->dpy, view->x->gc, | |
1188 | view->x->gray25_stipple); | |
1189 | XSetTSOrigin(view->x->dpy, view->x->gc, 0, 0); | |
1190 | XSetForeground(view->x->dpy, view->x->gc, | |
1191 | view->x->pixels[COLOR_BLACK]); | |
1192 | XSetBackground(view->x->dpy, view->x->gc, | |
1193 | view->x->pixels[COLOR_WHITE]); | |
1194 | XSetFillStyle(view->x->dpy, view->x->gc, FillOpaqueStippled); | |
1195 | XFillArc(view->x->dpy, pm, view->x->gc, | |
1196 | x - 6 - offset, y + 5 + offset, 7, 7, 0, 360 * 64); | |
1197 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1198 | x + 13 - offset, y - 5 + offset, | |
1199 | x - 1 - offset, y + 9 + offset); | |
1200 | XSetStipple(view->x->dpy, view->x->gc, | |
1201 | view->x->gray75_stipple); | |
1202 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1203 | x + 11 - offset, y - 7 + offset, | |
1204 | x - 3 - offset, y + 7 + offset); | |
1205 | XFillArc(view->x->dpy, pm, view->x->gc, | |
1206 | x + 8 - offset, y - 9 + offset, 7, 7, 0, 360 * 64); | |
1207 | XSetLineAttributes(view->x->dpy, view->x->gc, 1, | |
1208 | LineSolid, CapButt, JoinMiter); | |
1209 | XSetFillStyle(view->x->dpy, view->x->gc, FillSolid); | |
1210 | } | |
1211 | ||
1212 | break; | |
1213 | ||
1214 | case eraserState: | |
1215 | x += left; y += top; | |
1216 | if (mode == 1) { | |
1217 | offset = 0; | |
1218 | } else { | |
1219 | offset = 2; | |
1220 | ||
1221 | if (view->x->color) { | |
1222 | XSetForeground(view->x->dpy, view->x->gc, | |
1223 | view->pixels[COLOR_MEDIUMGRAY]); | |
1224 | XFillRectangle(view->x->dpy, pm, view->x->gc, | |
1225 | x - 8, y - 8, 16, 16); | |
1226 | } else { | |
1227 | XSetStipple(view->x->dpy, view->x->gc, | |
1228 | view->x->gray50_stipple); | |
1229 | XSetTSOrigin(view->x->dpy, view->x->gc, 0, 0); | |
1230 | XSetForeground(view->x->dpy, view->x->gc, | |
1231 | view->x->pixels[COLOR_BLACK]); | |
1232 | XSetBackground(view->x->dpy, view->x->gc, | |
1233 | view->x->pixels[COLOR_WHITE]); | |
1234 | XSetFillStyle(view->x->dpy, view->x->gc, FillOpaqueStippled); | |
1235 | XFillRectangle(view->x->dpy, pm, view->x->gc, | |
1236 | x - 8, y - 8, 16, 16); | |
1237 | XSetFillStyle(view->x->dpy, view->x->gc, FillSolid); | |
1238 | } | |
1239 | } | |
1240 | ||
1241 | if (view->x->color) { | |
1242 | XSetForeground(view->x->dpy, view->x->gc, | |
1243 | view->pixels[COLOR_LIGHTGRAY]); | |
1244 | } else { | |
1245 | XSetStipple(view->x->dpy, view->x->gc, | |
1246 | view->x->gray75_stipple); | |
1247 | XSetTSOrigin(view->x->dpy, view->x->gc, 0, 0); | |
1248 | XSetForeground(view->x->dpy, view->x->gc, | |
1249 | view->x->pixels[COLOR_BLACK]); | |
1250 | XSetBackground(view->x->dpy, view->x->gc, | |
1251 | view->x->pixels[COLOR_WHITE]); | |
1252 | XSetFillStyle(view->x->dpy, view->x->gc, FillOpaqueStippled); | |
1253 | } | |
1254 | ||
1255 | /* top */ | |
1256 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1257 | x - 8 + offset, y - 8 - offset, | |
1258 | x + 8 + offset, y - 8 - offset); | |
1259 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1260 | x - 7 + offset, y - 7 - offset, | |
1261 | x + 7 + offset, y - 7 - offset); | |
1262 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1263 | x - 6 + offset, y - 6 - offset, | |
1264 | x + 6 + offset, y - 6 - offset); | |
1265 | ||
1266 | /* left */ | |
1267 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1268 | x - 8 + offset, y - 8 - offset, | |
1269 | x - 8 + offset, y + 8 - offset); | |
1270 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1271 | x - 7 + offset, y - 7 - offset, | |
1272 | x - 7 + offset, y + 7 - offset); | |
1273 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1274 | x - 6 + offset, y - 6 - offset, | |
1275 | x - 6 + offset, y + 6 - offset); | |
1276 | ||
1277 | if (view->x->color) { | |
1278 | XSetForeground(view->x->dpy, view->x->gc, | |
1279 | view->pixels[COLOR_BLACK]); | |
1280 | } else { | |
1281 | XSetFillStyle(view->x->dpy, view->x->gc, FillSolid); | |
1282 | } | |
1283 | ||
1284 | /* bottom */ | |
1285 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1286 | x - 7 + offset, y + 7 - offset, | |
1287 | x + 8 + offset, y + 7 - offset); | |
1288 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1289 | x - 6 + offset, y + 6 - offset, | |
1290 | x + 7 + offset, y + 6 - offset); | |
1291 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1292 | x - 5 + offset, y + 5 - offset, | |
1293 | x + 6 + offset, y + 5 - offset); | |
1294 | ||
1295 | /* right */ | |
1296 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1297 | x + 7 + offset, y + 8 - offset, | |
1298 | x + 7 + offset, y - 7 - offset); | |
1299 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1300 | x + 6 + offset, y + 7 - offset, | |
1301 | x + 6 + offset, y - 6 - offset); | |
1302 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1303 | x + 5 + offset, y + 6 - offset, | |
1304 | x + 5 + offset, y - 5 - offset); | |
1305 | ||
1306 | if (view->x->color) { | |
1307 | XSetForeground(view->x->dpy, view->x->gc, | |
1308 | view->pixels[COLOR_DARKGRAY]); | |
1309 | XFillRectangle(view->x->dpy, pm, view->x->gc, | |
1310 | x - 5 + offset, y - 5 - offset, 10, 10); | |
1311 | } else { | |
1312 | XSetStipple(view->x->dpy, view->x->gc, | |
1313 | view->x->gray50_stipple); | |
1314 | XSetForeground(view->x->dpy, view->x->gc, | |
1315 | view->x->pixels[COLOR_BLACK]); | |
1316 | XSetBackground(view->x->dpy, view->x->gc, | |
1317 | view->x->pixels[COLOR_WHITE]); | |
1318 | XSetFillStyle(view->x->dpy, view->x->gc, FillOpaqueStippled); | |
1319 | XFillRectangle(view->x->dpy, pm, view->x->gc, | |
1320 | x - 5 + offset, y - 5 - offset, 10, 10); | |
1321 | XSetFillStyle(view->x->dpy, view->x->gc, FillSolid); | |
1322 | } | |
1323 | ||
1324 | break; | |
1325 | ||
1326 | default: | |
1327 | offset = toolOffset[v->tool_state]; | |
1328 | ||
1329 | bg = (toolColors[v->tool_state] >> 8) & 0xff; | |
1330 | ||
1331 | x = (x & ~15) - (offset <<4); | |
1332 | y = (y & ~15) - (offset <<4); | |
1333 | size <<= 4; | |
1334 | x += left; y += top; | |
1335 | ||
1336 | XSetForeground(view->x->dpy, view->x->gc, | |
1337 | view->pixels[dark]); | |
1338 | XDrawRectangle(view->x->dpy, pm, view->x->gc, | |
1339 | x - 1, y - 1, size + 4, size + 4); | |
1340 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1341 | x - 3, y + size + 3, | |
1342 | x - 1, y + size + 3); | |
1343 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1344 | x + size + 3, y - 3, | |
1345 | x + size + 3, y - 1); | |
1346 | ||
1347 | XSetForeground(view->x->dpy, view->x->gc, | |
1348 | view->pixels[light]); | |
1349 | XDrawRectangle(view->x->dpy, pm, view->x->gc, | |
1350 | x - 4, y - 4, size + 4, size + 4); | |
1351 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1352 | x - 4, y + size + 1, | |
1353 | x - 4, y + size + 3); | |
1354 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1355 | x + size + 1, y - 4, | |
1356 | x + size + 3, y - 4); | |
1357 | ||
1358 | if (view->x->color) { | |
1359 | if (fg == bg) { | |
1360 | XSetForeground(view->x->dpy, view->x->gc, | |
1361 | view->x->pixels[fg]); | |
1362 | XSetLineAttributes(view->x->dpy, view->x->gc, 2, | |
1363 | LineSolid, CapButt, JoinMiter); | |
1364 | } else { | |
1365 | XSetForeground(view->x->dpy, view->x->gc, | |
1366 | view->x->pixels[fg]); | |
1367 | XSetBackground(view->x->dpy, view->x->gc, | |
1368 | view->pixels[bg]); | |
1369 | ||
1370 | XSetLineAttributes(view->x->dpy, view->x->gc, 2, | |
1371 | LineDoubleDash, CapButt, JoinMiter); | |
1372 | XSetDashes(view->x->dpy, view->x->gc, 0, CursorDashes, 2); | |
1373 | } | |
1374 | } else { | |
1375 | XSetStipple(view->x->dpy, view->x->gc, | |
1376 | view->x->gray50_stipple); | |
1377 | XSetForeground(view->x->dpy, view->x->gc, | |
1378 | view->x->pixels[COLOR_BLACK]); | |
1379 | XSetBackground(view->x->dpy, view->x->gc, | |
1380 | view->x->pixels[COLOR_WHITE]); | |
1381 | XSetFillStyle(view->x->dpy, view->x->gc, FillOpaqueStippled); | |
1382 | XSetLineAttributes(view->x->dpy, view->x->gc, 2, | |
1383 | LineSolid, CapButt, JoinMiter); | |
1384 | } | |
1385 | ||
1386 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1387 | x - 2, y - 1, x - 2, y + size + 3); | |
1388 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1389 | x - 1, y + size + 2, x + size + 3, y + size + 2); | |
1390 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1391 | x + size + 2, y + size + 1, x + size + 2, y - 3); | |
1392 | XDrawLine(view->x->dpy, pm, view->x->gc, | |
1393 | x + size + 1, y - 2, x - 3, y - 2); | |
1394 | ||
1395 | if (!view->x->color) { | |
1396 | XSetFillStyle(view->x->dpy, view->x->gc, FillSolid); | |
1397 | } | |
1398 | XSetLineAttributes(view->x->dpy, view->x->gc, 1, | |
1399 | LineSolid, CapButt, JoinMiter); | |
1400 | ||
1401 | break; | |
1402 | } | |
1403 | } | |
1404 | } | |
1405 | } | |
1406 | } | |
1407 | ||
1408 | ||
1409 | TimeElapsed(struct timeval *elapsed, | |
1410 | struct timeval *start, | |
1411 | struct timeval *finish) | |
1412 | { | |
1413 | int usec = finish->tv_usec - start->tv_usec; | |
1414 | int sec = finish->tv_sec - start->tv_sec; | |
1415 | ||
1416 | while (usec < 0) { | |
1417 | usec += 1000000; | |
1418 | sec--; | |
1419 | } | |
1420 | elapsed->tv_usec = usec; | |
1421 | elapsed->tv_sec = sec; | |
1422 | } | |
1423 | ||
1424 | ||
1425 | ||
1426 | DrawOverlay(SimView *view) | |
1427 | { | |
1428 | int width = view->w_width; | |
1429 | int height = view->w_height; | |
1430 | int left = view->pan_x - (width / 2); | |
1431 | int top = view->pan_y - (height / 2); | |
1432 | int right = left + width; | |
1433 | int bottom = top + height; | |
1434 | int showing = 0; | |
1435 | Ink *ink; | |
1436 | struct timeval start, finished, elapsed; | |
1437 | ||
1438 | for (ink = sim->overlay; ink != NULL; ink = ink->next) { | |
1439 | if ((ink->bottom >= top) && (ink->top <= bottom) && | |
1440 | (ink->right >= left) && (ink->left <= right)) { | |
1441 | showing = 1; | |
1442 | break; | |
1443 | } | |
1444 | } | |
1445 | ||
1446 | if (!showing) return; | |
1447 | ||
1448 | /* overlay_mode state machine: | |
1449 | 0 => overlay invalid: | |
1450 | draw lines to pm => 1 | |
1451 | 1 => overlay stable: | |
1452 | sync, time draw lines to pm => 2 | |
1453 | 2 => overlay stable: | |
1454 | draw lines to ol, | |
1455 | sync, time clip ol to pm, | |
1456 | lines faster? => 3, | |
1457 | clipping faster? => 4 | |
1458 | 3 => lines faster: | |
1459 | draw lines to pm => 3 | |
1460 | 4 => clipping faster: | |
1461 | clip ol to pm => 4 | |
1462 | */ | |
1463 | ||
1464 | switch (view->overlay_mode) { | |
1465 | case 0: | |
1466 | DrawTheOverlay(view, view->x->gc, | |
1467 | view->pixmap2, view->pixels[COLOR_WHITE], | |
1468 | top, bottom, left, right, 0); | |
1469 | view->overlay_mode = 1; | |
1470 | break; | |
1471 | case 1: | |
1472 | XSync(view->x->dpy, False); | |
1473 | gettimeofday(&start, NULL); | |
1474 | DrawTheOverlay(view, view->x->gc, | |
1475 | view->pixmap2, view->pixels[COLOR_WHITE], | |
1476 | top, bottom, left, right, 0); | |
1477 | XSync(view->x->dpy, False); | |
1478 | gettimeofday(&finished, NULL); | |
1479 | TimeElapsed(&view->overlay_time, &start, &finished); | |
1480 | view->overlay_mode = 2; | |
1481 | break; | |
1482 | case 2: | |
1483 | XSetForeground(view->x->dpy, view->x->overlay_gc, 0); | |
1484 | XFillRectangle(view->x->dpy, view->overlay_pixmap, view->x->overlay_gc, | |
1485 | 0, 0, view->m_width, view->m_height); | |
1486 | DrawTheOverlay(view, view->x->overlay_gc, | |
1487 | view->overlay_pixmap, 1, | |
1488 | top, bottom, left, right, 1); | |
1489 | XSync(view->x->dpy, False); | |
1490 | gettimeofday(&start, NULL); | |
1491 | ClipTheOverlay(view); | |
1492 | XSync(view->x->dpy, False); | |
1493 | gettimeofday(&finished, NULL); | |
1494 | TimeElapsed(&elapsed, &start, &finished); | |
1495 | if ((elapsed.tv_sec > view->overlay_time.tv_sec) || | |
1496 | ((elapsed.tv_sec == view->overlay_time.tv_sec) && | |
1497 | ((elapsed.tv_usec > view->overlay_time.tv_usec)))) { | |
1498 | view->overlay_mode = 3; | |
1499 | } else { | |
1500 | view->overlay_mode = 4; | |
1501 | } | |
1502 | break; | |
1503 | case 3: | |
1504 | DrawTheOverlay(view, view->x->gc, | |
1505 | view->pixmap2, view->pixels[COLOR_WHITE], | |
1506 | top, bottom, left, right, 0); | |
1507 | break; | |
1508 | case 4: | |
1509 | ClipTheOverlay(view); | |
1510 | break; | |
1511 | } | |
1512 | } | |
1513 | ||
1514 | ||
1515 | DrawTheOverlay(SimView *view, GC gc, Pixmap pm, int color, | |
1516 | int top, int bottom, int left, int right, | |
1517 | int onoverlay) | |
1518 | { | |
1519 | Ink *ink; | |
1520 | ||
1521 | if (view->x->color) { | |
1522 | XSetForeground(view->x->dpy, gc, color); | |
1523 | XSetLineAttributes(view->x->dpy, gc, 3, | |
1524 | LineSolid, CapButt, JoinBevel); | |
1525 | } else { | |
1526 | if (!onoverlay) { | |
1527 | XSetStipple(view->x->dpy, gc, view->x->gray50_stipple); | |
1528 | XSetTSOrigin(view->x->dpy, gc, view->updates & 1, 0); | |
1529 | XSetBackground(view->x->dpy, gc, 0); | |
1530 | XSetFillStyle(view->x->dpy, gc, FillOpaqueStippled); | |
1531 | } | |
1532 | XSetForeground(view->x->dpy, gc, 1); | |
1533 | XSetLineAttributes(view->x->dpy, gc, 3, | |
1534 | LineSolid, CapButt, JoinBevel); | |
1535 | } | |
1536 | for (ink = sim->overlay; ink != NULL; ink = ink->next) { | |
1537 | if ((ink->bottom >= top) && (ink->top <= bottom) && | |
1538 | (ink->right >= left) && (ink->left <= right)) { | |
1539 | if (ink->length <= 1) { | |
1540 | XFillArc(view->x->dpy, pm, gc, | |
1541 | ink->x - 3, ink->y - 3, 6, 6, 0, 360 * 64); | |
1542 | } else { | |
1543 | ink->points[0].x = ink->x - left; | |
1544 | ink->points[0].y = ink->y - top; | |
1545 | XDrawLines(view->x->dpy, pm, gc, | |
1546 | ink->points, ink->length, CoordModePrevious); | |
1547 | } | |
1548 | } | |
1549 | } | |
1550 | if (!view->x->color) { | |
1551 | XSetFillStyle(view->x->dpy, gc, FillSolid); | |
1552 | } | |
1553 | XSetLineAttributes(view->x->dpy, gc, 1, | |
1554 | LineSolid, CapButt, JoinMiter); | |
1555 | } | |
1556 | ||
1557 | ||
1558 | ClipTheOverlay(SimView *view) | |
1559 | { | |
1560 | if (view->x->color) { | |
1561 | XSetForeground(view->x->dpy, view->x->gc, view->pixels[COLOR_WHITE]); | |
1562 | XSetFillStyle(view->x->dpy, view->x->gc, FillStippled); | |
1563 | XSetStipple(view->x->dpy, view->x->gc, view->overlay_pixmap); | |
1564 | XSetTSOrigin(view->x->dpy, view->x->gc, 0, 0); | |
1565 | XFillRectangle(view->x->dpy, view->pixmap2, view->x->gc, | |
1566 | 0, 0, view->w_width, view->w_height); | |
1567 | XSetFillStyle(view->x->dpy, view->x->gc, FillSolid); | |
1568 | } else { | |
1569 | XSetStipple(view->x->dpy, view->x->gc, view->x->gray50_stipple); | |
1570 | XSetTSOrigin(view->x->dpy, view->x->gc, view->updates & 1, 0); | |
1571 | XSetForeground(view->x->dpy, view->x->gc, view->pixels[COLOR_WHITE]); | |
1572 | XSetBackground(view->x->dpy, view->x->gc, view->pixels[COLOR_BLACK]); | |
1573 | XSetFillStyle(view->x->dpy, view->x->gc, FillOpaqueStippled); | |
1574 | XSetLineAttributes(view->x->dpy, view->x->gc, 3, | |
1575 | LineSolid, CapButt, JoinBevel); | |
1576 | XSetClipOrigin(view->x->dpy, view->x->gc, 0, 0); | |
1577 | XSetClipMask(view->x->dpy, view->x->gc, view->overlay_pixmap); | |
1578 | XFillRectangle(view->x->dpy, view->pixmap2, view->x->gc, | |
1579 | 0, 0, view->w_width, view->w_height); | |
1580 | XSetFillStyle(view->x->dpy, view->x->gc, FillSolid); | |
1581 | XSetClipMask(view->x->dpy, view->x->gc, None); | |
1582 | } | |
1583 | } |