]>
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 | 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 | } |