]> git.zerfleddert.de Git - micropolis/blob - src/sim/w_editor.c
show description (including time limit) when hovering over a scenario
[micropolis] / src / sim / w_editor.c
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 }
Impressum, Datenschutz