1 /* Copyright (C) 1992-1998 The Geometry Center
2 * Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips
3 *
4 * This file is part of Geomview.
5 *
6 * Geomview is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * Geomview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Geomview; see the file COPYING. If not, write
18 * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
19 * USA, or visit http://www.gnu.org.
20 */
21
22 #if HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 #if 0
27 static char copyright[] = "Copyright (C) 1992-1998 The Geometry Center\n\
28 Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips";
29 #endif
30
31
32 /* Authors: Stuart Levy, Tamara Munzner, Mark Phillips,
33 Celeste Fowler */
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <ctype.h>
40 #include <stdlib.h>
41 #include "lisp.h"
42 #include "lang.h"
43 #include "drawer.h"
44 #include "transform.h"
45 #include "ui.h"
46 #include "motion.h"
47 #include "event.h"
48 #include "comm.h"
49
50
51 char *shades[5] = {
52 "[0as] Constant", /* APF_CONSTANT */
53 "[1as] Flat", /* APF_FLAT */
54 "[2as] Smooth", /* APF_SMOOTH */
55 "[3as] CSmooth", /* APF_CSMOOTH */
56 "[4as] VCflat", /* APF_VCFLAT */
57 };
58
59 char *translucencies[3] = {
60 "[0mt] BSP-Tree Alpha Blending",
61 "[1mt] Screen Door",
62 "[2mt] Simple Alpha Blending"
63 };
64
65 char *norm[4] = {
66 "[0N] None", /* NONE */
67 "[1N] Individual", /* EACH */
68 "[2N] Sequence", /* ALL */
69 "[3N] Keep", /* KEEP */
70 };
71
72 char *proj[2] = {
73 "[0vp] Orthographic", /* ORTHOGRAPHIC */
74 "[1vp] Perspective", /* PERSPECTIVE */
75 };
76
77 char *spc[3] = {
78 "[me] Euclidean", /* EUCLIDEAN */
79 "[mh] Hyperbolic", /* HYPERBOLIC */
80 "[ms] Spherical", /* SPHERICAL */
81 };
82
83 char *mdl[3] = {
84 "[mv] Virtual", /* VIRTUAL */
85 "[mp] Projective", /* PROJECTIVE */
86 "[mc] Conformal", /* CONFORMALBALL */
87 };
88
89
90 char OBJROTATE[] = "[r] Rotate";
91 char OBJTRANSLATE[] = "[t] Translate";
92 char OBJZOOM[] = "[z] Cam Zoom";
93 char OBJSCALE[] = "[s] Geom Scale";
94 char OBJFLY[] = "[f] Cam Fly";
95 char OBJORBIT[] = "[o] Cam Orbit";
96 char LIGHTEDIT[] = "[le] Edit Lights";
97
98 /* in ui.c */
99
cui_init()100 void cui_init()
101 {
102
103 uistate.targetid = WORLDGEOM;
104 uistate.centerid = TARGETID;
105 uistate.bbox_center = 0;
106 uistate.targetgeom = 0; /* World geom is index 0 */
107 uistate.targetcam = INDEXOF(FOCUSID);
108 uistate.cam_wm_focus = 0; /* bad idea */
109 uistate.mode_count = 0;
110 uistate.emod_dir = NULL;
111 uistate.apoverride = ~0; /* Enable override by default */
112 uistate.inertia = 1; /* Enable inertia by default */
113 uistate.pick_invisible = 1; /* Pick invisible as well as visible objects? */
114
115 /*
116 * The order of these calls must be the same as the declared integers
117 * in ui.h!!
118 */
119 ui_install_mode(OBJROTATE, minterp_rotate, T_NONE);
120 ui_install_mode(OBJZOOM, minterp_zoom, T_CAM);
121 ui_install_mode(OBJTRANSLATE, minterp_translate, T_NONE);
122 ui_install_mode(OBJFLY, minterp_fly, T_CAM);
123 ui_install_mode(OBJORBIT, minterp_orbit, T_CAM);
124 ui_install_mode(OBJSCALE, minterp_scale, T_GEOM);
125 VVINIT(uistate.emod, emodule, 10);
126 vvzero(&uistate.emod);
127 uistate.savewhat = NOID;
128 uistate.cursor_still = UI_CURSOR_STILL;
129 uistate.cursor_twitch = UI_CURSOR_TWITCH;
130 uistate.longwhile = 2.5; /* Max credible inter-redraw interval */
131 uistate.backface = 0;
132 return;
133 }
134
ui_reinstall_mode(char * name,PFI proc,int type,int index)135 void ui_reinstall_mode(char *name, PFI proc, int type, int index)
136 {
137 uistate.modenames[index] = name;
138 uistate.modes[index] = proc;
139 uistate.modetype[index] = type;
140 }
141
ui_install_mode(char * name,PFI proc,int type)142 void ui_install_mode(char *name, PFI proc, int type)
143 {
144 if(uistate.mode_count >= MAXMODES) {
145 OOGLError(1, "Motion-mode table full (max %d entries)", MAXMODES);
146 uistate.mode_count = MAXMODES-1;
147 }
148 uistate.modenames[uistate.mode_count] = name;
149 uistate.modes[uistate.mode_count] = proc;
150 uistate.modetype[uistate.mode_count] = type;
151 ++uistate.mode_count;
152
153 D1PRINT(("ui_install_mode: name=%s, proc=%x\n", name, proc));
154
155 }
156
ui_uninstall_mode(char * name)157 void ui_uninstall_mode(char *name)
158 {
159 int i = ui_mode_index(name);
160
161 if (i<0) return;
162 --uistate.mode_count;
163 while (i<uistate.mode_count) {
164 uistate.modenames[i] = uistate.modenames[i+1];
165 uistate.modes[i] = uistate.modes[i+1];
166 uistate.modetype[i] = uistate.modetype[i+1];
167 i++;
168 }
169 }
170
171 /*
172 * Match names
173 */
ui_mode_index(char * name)174 int ui_mode_index(char *name)
175 {
176 int i;
177
178 for (i=0; i<uistate.mode_count; ++i) {
179 if(!strcasecmp(name, uistate.modenames[i]))
180 return i;
181 }
182 OOGLError(0, "ui_mode_index: unknown mode \"%s\"", name);
183 return 0;
184 }
185
ui_emodule_uninstall(int k)186 void ui_emodule_uninstall(int k)
187 {
188 emodule *em;
189 int i;
190 if(k < 0 || k >= VVCOUNT(uistate.emod))
191 return;
192 em = &VVEC(uistate.emod, emodule)[k];
193 for(i = k+1; i < VVCOUNT(uistate.emod); i++, em++)
194 *em = *(em+1);
195 VVCOUNT(uistate.emod)--;
196 uistate.emod_changed = k+1;
197 }
198
199 emodule *
ui_emodule_install(int before,char * ename,PFI func)200 ui_emodule_install(int before, char *ename, PFI func)
201 {
202 int i,k;
203 emodule *em, *emp;
204
205 if((k = ui_emodule_index(ename,NULL)) >= 0)
206 ui_emodule_uninstall(k);
207 k = VVCOUNT(uistate.emod)++;
208 vvneeds(&uistate.emod, VVCOUNT(uistate.emod));
209 if(before > k) before = k; else if(before < 0) before = 0;
210
211 /* Shift the part of emodule table below the insertion point down
212 one unit. Don't use bcopy() for this because it does not
213 correctly handle overlapping src and dst.
214 mbp Wed Sep 9 19:07:39 1992 */
215 em = VVEC(uistate.emod, emodule);
216 for (i=VVCOUNT(uistate.emod)-1, emp = &em[i]; i>before; i--, emp--)
217 *emp = *(emp-1);
218
219 em = &VVEC(uistate.emod, emodule)[before];
220 em->name = strdup(ename);
221 em->func = (PFV)func;
222 em->dir = uistate.emod_dir;
223 /* Other emodule fields zeroed */
224 uistate.emod_changed = before+1;
225 return em;
226 }
227
228 LDEFINE(emodule_clear, LVOID,
229 "(emodule-clear)\n\
230 Clears the geomview application (external module) browser.")
231 {
232 LDECLARE(("emodule-clear", LBEGIN,
233 LEND));
234
235 while (VVCOUNT(uistate.emod))
236 ui_emodule_uninstall(0);
237 return Lt;
238 }
239
240 int
ui_emodule_index(char * ename,emodule ** emp)241 ui_emodule_index(char *ename, emodule **emp)
242 {
243 int i;
244 emodule *em;
245 if(!emp) emp = &em;
246 for (i=0, em=VVEC(uistate.emod, emodule); i<VVCOUNT(uistate.emod); i++, em++)
247 if (strcasecmp(em->name, ename)==0) {
248 *emp = em;
249 return i;
250 }
251 *emp = NULL;
252 return -1;
253 }
254
255 /*-----------------------------------------------------------------------
256 * Function: set_ui_target
257 * Description: set the target of user actions
258 * Args: type: T_GEOM or T_CAM
259 * index: index of current geom or current cam
260 * Returns:
261 * Author: mbp
262 * Date: Thu Nov 21 14:04:28 1991
263 * Notes: equivalent to set_ui_target_id( ID(type, index) )
264 */
265 void
set_ui_target(int type,int index)266 set_ui_target(int type, int index)
267 {
268 uistate.targetid = ID(type, index);
269 switch (uistate.targettype = type) {
270 case T_GEOM:
271 uistate.targetgeom = index;
272 if (uistate.bbox_center && uistate.targetid != WORLDGEOM) {
273 make_center_from_bbox("CENTER", uistate.targetid);
274 }
275 break;
276 case T_CAM:
277 uistate.targetcam = index;
278 break;
279 }
280 }
281
282 void
set_ui_center(int id)283 set_ui_center(int id)
284 {
285 uistate.centerid = id;
286 }
287
288 void
set_ui_center_origin(int use_bbox_center)289 set_ui_center_origin(int use_bbox_center)
290 {
291 uistate.bbox_center = use_bbox_center != 0; /* boolean value */
292 if (uistate.bbox_center && uistate.targetid != WORLDGEOM) {
293 make_center_from_bbox("CENTER", uistate.targetid);
294 } else {
295 gv_ui_center(TARGETID);
296 }
297 }
298
299 void
set_ui_wm_focus(int cam_wm_focus)300 set_ui_wm_focus(int cam_wm_focus)
301 {
302 uistate.cam_wm_focus = cam_wm_focus != 0;
303 }
304
305 /*-----------------------------------------------------------------------
306 * Function: set_ui_target_id
307 * Description: set the target id of user actions
308 * Args: id: id to target
309 * Returns:
310 * Author: mbp
311 * Date: Thu Nov 21 14:05:33 1991
312 * Notes: equivalent to set_ui_target( TYPEOF(id), INDEXOF(id) )
313 */
314 void
set_ui_target_id(int id)315 set_ui_target_id(int id)
316 {
317 set_ui_target( TYPEOF(id), INDEXOF(id) );
318 }
319
320
ui_cleanup()321 void ui_cleanup()
322 {
323 int i;
324 for(i = VVCOUNT(uistate.emod); --i >= 0; ) {
325 if(VVEC(uistate.emod, emodule)[i].pid > 0) {
326 emodule_kill(&VVEC(uistate.emod, emodule)[i]);
327 }
328 }
329 gv_delete(ALLCAMS);
330 }
331
332 /* maybe replace this later with something more useful: */
ui_targeting()333 void ui_targeting()
334 {}
335
336
337 /**********************************************************************/
338
339 /* for debugging */
print_emodtable()340 void print_emodtable()
341 {
342 emodule *em;
343 int i;
344
345 for(i=0, em=VVEC(uistate.emod,emodule); i<VVCOUNT(uistate.emod); i++, em++) {
346 fprintf(stderr, "em[%2d] = %s\n", i, em->name);
347 }
348 return;
349 }
350
351 LDEFINE(cursor_still, LVOID,
352 "(cursor-still [INT])\n\
353 Sets the number of microseconds for which the cursor must not\n\
354 move to as holding still. If INT is not specified,\n\
355 the value will be reset to the default.")
356 {
357 uistate.cursor_still = UI_CURSOR_STILL;
358 LDECLARE(("cursor-still", LBEGIN,
359 LOPTIONAL,
360 LINT, &uistate.cursor_still,
361 LEND));
362 return Lt;
363 }
364
365 LDEFINE(cursor_twitch, LVOID,
366 "(cursor-twitch [INT])\n\
367 Sets the distance which the cursor must not move (in x or\n\
368 y) to as holding still. If INT is not specified,\n\
369 the value will be reset to the default.")
370 {
371 uistate.cursor_twitch = UI_CURSOR_TWITCH;
372 LDECLARE(("cursor-twitch", LBEGIN,
373 LOPTIONAL,
374 LINT, &uistate.cursor_twitch,
375 LEND));
376 return Lt;
377 }
378
379 LDEFINE(ap_override, LVOID,
380 "(ap-override [on|off])\n\
381 Selects whether appearance controls should override objects' own\n\
382 settings. On by default. With no arguments, returns current setting.")
383 {
384 Keyword kw = NOT_A_KEYWORD;
385
386 LDECLARE(("ap-override", LBEGIN,
387 LOPTIONAL,
388 LKEYWORD, &kw,
389 LEND));
390
391 if (kw == NOT_A_KEYWORD) {
392 Keyword on = uistate.apoverride ? ON_KEYWORD : OFF_KEYWORD;
393 return LNew(LKEYWORD, &on);
394 }
395 drawer_int(WORLDGEOM, DRAWER_APOVERRIDE, boolval("ap-override", kw));
396 return Lt;
397 }
398
399
400 int
uispace(int space)401 uispace(int space)
402 {
403 switch (space) {
404 case TM_EUCLIDEAN: return EUCLIDEAN;
405 case TM_HYPERBOLIC: return HYPERBOLIC;
406 case TM_SPHERICAL: return SPHERICAL;
407 }
408 return -1;
409 }
410
411 /*
412 * Local Variables: ***
413 * c-basic-offset: 2 ***
414 * End: ***
415 */
416