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