1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: graphmac.c
6 * Interface for Apple Macintosh computers
7 * Written by: Steven M. Rubin, Static Free Software
8 *
9 * Copyright (c) 2000 Static Free Software.
10 *
11 * Electric(tm) is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * Electric(tm) is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Electric(tm); see the file COPYING. If not, write to
23 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24 * Boston, Mass 02111-1307, USA.
25 *
26 * Static Free Software
27 * 4119 Alpine Road
28 * Portola Valley, California 94028
29 * info@staticfreesoft.com
30 */
31
32 /* Macintosh things to do:
33 * Function keys and non-command keys should have menu listing on the right
34 * Component menu can be too tall:
35 * Always placed at (0,0), even if main screen is elsewhere
36 * Should add parameters to "getpaletteparameters" for use in "usrmisc.c"
37 * Implement tear-off menus
38 * Reimplement dialogs native
39 * Session logging
40 */
41 # ifdef __MWERKS__
42 # if __MWERKS__ >= 0x2100
43 # define NEWCODEWARRIOR 1
44 # endif
45 # endif
46 #include "global.h"
47 #include "database.h"
48 #include "egraphics.h"
49 #include "usr.h"
50 #include "eio.h"
51 #include "efunction.h"
52 #include "edialogs.h"
53 #include "usrdiacom.h"
54 #include "usrtrack.h"
55 #include "dblang.h"
56
57 #include <Controls.h>
58 #include <Devices.h>
59 #include <Dialogs.h>
60 #include <Fonts.h>
61 #include <Gestalt.h>
62 #include <LowMem.h>
63 #include <Menus.h>
64 #include <Retrace.h>
65 #include <Scrap.h>
66 #include <Script.h>
67 #include <signal.h>
68 #include <Sound.h>
69 #include <ToolUtils.h>
70 #include <unix.h>
71
72 #if LANGTCL
73 # include "dblang.h"
74 # include "tclMac.h"
75 #endif
76
77 /****** the messages window ******/
78 static WindowPtr gra_messageswindow; /* the scrolled messages window */
79 static BOOLEAN gra_messagesinfront; /* nonzero if messages is frontmost */
80 static INTBIG gra_linesInFolder; /* lines in text folder */
81 static INTBIG gra_messagesfont; /* font in messages window */
82 static INTBIG gra_messagesfontsize; /* size of font in messages window */
83 static INTBIG gra_messagesleft; /* left bound of messages window screen */
84 static INTBIG gra_messagesright; /* right bound of messages window screen */
85 static INTBIG gra_messagestop; /* top bound of messages window screen */
86 static INTBIG gra_messagesbottom; /* bottom bound of messages window screen */
87 static ControlHandle gra_vScroll; /* vertical scroll control in messages window */
88 static ControlHandle gra_hScroll; /* horizontal scroll control in messages window */
89 static TEHandle gra_TEH; /* text editing handle in messages window */
90 static ControlActionUPP gra_scrollvprocUPP; /* UPP for "gra_scrollvproc" */
91 static ControlActionUPP gra_scrollhprocUPP; /* UPP for "gra_scrollhproc" */
92 static GWorldPtr gra_textbuf = 0; /* temp buffer for displaying text */
93 static INTBIG gra_textbufwid = 0; /* width of text temp buffer */
94 static INTBIG gra_textbufhei = 0; /* height of text temp buffer */
95 static UCHAR1 **gra_textbufrowstart; /* row start array for text temp buffer */
96 static BOOLEAN gra_texttoosmall = FALSE; /* TRUE if text too small to draw */
97
98 /****** events ******/
99 #define CHARREAD 0377 /* character that was read */
100 #define ISKEYSTROKE 0400 /* set if key typed */
101 #define ISBUTTON 01000 /* set if button pushed (or released) */
102 #define BUTTONUP 02000 /* set if button was released */
103 #define SHIFTISDOWN 04000 /* set if shift key was held down */
104 #define COMMANDISDOWN 010000 /* set if command key was held down */
105 #define OPTIONISDOWN 020000 /* set if option key was held down */
106 #define CONTROLISDOWN 040000 /* set if control key was held down */
107 #define DOUBLECLICK 0100000 /* set if this is second click */
108 #define MOTION 0200000 /* set if mouse motion detected */
109 #define FILEREPLY 0400000 /* set if standard file reply detected */
110 #define WINDOWCHANGE 01000000 /* set if window moved and/or grown */
111 #define NOEVENT -1 /* set if nothing happened */
112 #define MENUEVENT BUTTONUP /* set if menu entry selected (values in cursor) */
113
114 #ifdef NEWCODEWARRIOR
115 # define SIGNALCAST __signal_func_ptr
116 #else
117 # define SIGNALCAST _Sigfun*
118 #endif
119
120 struct
121 {
122 INTBIG x;
123 INTBIG y;
124 INTBIG kind;
125 } gra_action;
126
127 static INTBIG gra_inputstate; /* current state of device input */
128 static INTBIG gra_inputspecial; /* current "special" keyboard value */
129 static INTBIG gra_lastclick; /* time of last click */
130 static INTBIG gra_lstcurx, gra_lstcury; /* current position of mouse */
131 static INTBIG gra_cursorx, gra_cursory; /* current position of mouse */
132 static WindowPtr gra_lastclickedwindow = 0; /* last window where mouse-down happened */
133 static WINDOWFRAME *gra_lastclickedwindowframe = NOWINDOWFRAME; /* last window frame where mouse-down happened */
134
135 //#define EVENTQUEUESIZE 100
136
137 //typedef struct
138 //{
139 // INTBIG cursorx, cursory; /* current position of mouse */
140 // INTBIG inputstate; /* current state of device input */
141 // INTBIG special; /* current "special" code for keyboard */
142 //} MYEVENTQUEUE;
143
144 //static MYEVENTQUEUE gra_eventqueue[EVENTQUEUESIZE];
145 //static MYEVENTQUEUE *gra_eventqueuehead; /* points to next event in queue */
146 //static MYEVENTQUEUE *gra_eventqueuetail; /* points to first free event in queue */
147
148 void gra_onint(void);
149
150 /****** timing ******/
151 #define FLUSHTICKS 120 /* ticks between display flushes */
152 #define MOTIONCHECK 2 /* ticks between mouse motion checks */
153 #define INTCHECK 30 /* MOTIONCHECKs between interrupt checks */
154 typedef struct VBLRect
155 {
156 VBLTask myVBLTask;
157 long vblA5;
158 } VBLRec;
159
160 static VBLRec gra_vblrec;
161 static INTBIG gra_checkcountdown; /* countdown to interrupt checks */
162 static BOOLEAN gra_motioncheck; /* true if mouse motion can be checked */
163 static BOOLEAN gra_cancheck; /* true if interrupt can be checked */
164 static UINTBIG gra_timestart;
165
166 /****** stuff for TCL/TK ******/
167 #if LANGTCL
168 Tcl_Interp *myTCLInterp;
169 #endif
170
171 /****** pulldown menus ******/
172 #define MENUSIZE 19 /* size of menu bar */
173 #define appleMENU 128 /* resource ID for Apple menu */
174 #define USERMENUBASE 130 /* base resource ID for other menus */
175 #define aboutMeCommand 1 /* menu entry for "About Electric..." item */
176
177 static INTBIG gra_lowmenu; /* low word of selected pulldown menu */
178 static INTBIG gra_highmenu; /* high word of selected pulldown menu */
179 static INTBIG gra_pulldownmenucount; /* number of pulldown menus */
180 static INTBIG gra_pulldownmenutotal = 0; /* number of pulldown menus allocated */
181 static BOOLEAN gra_tkmenusloaded = FALSE; /* nonzero if TK menus are built */
182 static MenuHandle *gra_pulldownmenus; /* the current pulldown menu handles */
183 static CHAR **gra_pulldowns; /* the current pulldown menus */
184 static MenuHandle gra_appleMenu; /* the Apple menu */
185
186 /****** mouse buttons ******/
187 #define BUTTONS 17 /* cannot exceed NUMBUTS in "usr.h" */
188
189 typedef struct
190 {
191 CHAR *name; /* button name */
192 INTBIG unique; /* number of letters that make it unique */
193 } BUTTONNAMES;
194
195 static BUTTONNAMES gra_buttonname[BUTTONS] =
196 { /* Shift Command Option Control */
197 x_("Button"), 1, /* */
198 x_("SButton"), 2, /* Shift */
199 x_("MButton"), 2, /* Command */
200 x_("SMButton"), 3, /* Shift Command */
201 x_("OButton"), 2, /* Option */
202 x_("SOButton"), 3, /* Shift Option */
203 x_("MOButton"), 3, /* Command Option */
204 x_("SMOButton"), 4, /* Shift Command Option */
205 x_("CButton"), 2, /* Control */
206 x_("SCButton"), 3, /* Shift Control */
207 x_("CMButton"), 3, /* Command Control */
208 x_("SCMButton"), 4, /* Shift Command Control */
209 x_("COButton"), 3, /* Option Control */
210 x_("SCOButton"), 4, /* Shift Option Control */
211 x_("CMOButton"), 4, /* Command Option Control */
212 x_("SCMOButton"), 5, /* Shift Command Option Control */
213 x_("DButton"), 2
214 };
215 static INTBIG gra_doubleclick; /* interval between double clicks */
216
217 /****** cursors ******/
218 enum {wantttyCURSOR = 129, penCURSOR, nullCURSOR, menulCURSOR, handCURSOR, techCURSOR,
219 lrCURSOR, udCURSOR};
220
221 static CursHandle gra_wantttyCurs; /* a "use the TTY" cursor */
222 static CursHandle gra_penCurs; /* a "draw with pen" cursor */
223 static CursHandle gra_nullCurs; /* a null cursor */
224 static CursHandle gra_menuCurs; /* a menu selection cursor */
225 static CursHandle gra_handCurs; /* a hand dragging cursor */
226 static CursHandle gra_techCurs; /* a technology edit cursor */
227 static CursHandle gra_ibeamCurs; /* a text edit cursor */
228 static CursHandle gra_lrCurs; /* a left/right cursor */
229 static CursHandle gra_udCurs; /* an up/down cursor */
230
231 /****** rectangle saving ******/
232 #define NOSAVEDBOX ((SAVEDBOX *)-1)
233
234 typedef struct Isavedbox
235 {
236 UCHAR1 *pix;
237 WINDOWPART *win;
238 INTBIG lx, hx, ly, hy;
239 INTBIG truelx, truehx;
240 struct Isavedbox *nextsavedbox;
241 } SAVEDBOX;
242
243 SAVEDBOX *gra_firstsavedbox = NOSAVEDBOX;
244
245 /****** dialogs ******/
246 #define aboutMeDLOG 128 /* resource ID for "About Electric" alert dialog */
247 #define errorALERT 130 /* resource ID for "error" alert dialog */
248 #define NAMERSRC 2000 /* resource ID for user name */
249 #define COMPANYRSRC 2001 /* resource ID for company name */
250 #define SPECIALRSRC 2002 /* resource ID for special instructions */
251 #define CHECKRSRC 2003 /* resource ID for checksum */
252 #define MAXSCROLLMULTISELECT 1000
253
254 /* the four scroller arrows */
255 #define UPARROW 0
256 #define DOWNARROW 1
257 #define LEFTARROW 2
258 #define RIGHTARROW 3
259
260 #define THUMBSIZE 16 /* width of the thumb area in scroll slider */
261 #define MAXSCROLLS 4 /* maximum scroll items in a dialog */
262 #define MAXLOCKS 3 /* maximum locked pairs of scroll lists */
263 #define MAXMATCH 50
264 #define MINSCROLLTICKS 2 /* minimum ticks between scrollbar slider arrows */
265 #define MINPAGETICKS 20 /* minimum ticks between scrollbar slider page shifts */
266
267 typedef void (*USERTYPE)(RECTAREA*, void*);
268
269 typedef struct
270 {
271 INTBIG count;
272 INTBIG current;
273 CHAR **namelist;
274 } POPUPDATA;
275
276 typedef struct
277 {
278 INTBIG scrollitem; /* item number of SCROLL area (-1 if none) */
279 RECTAREA userrect; /* position of SCROLL area */
280 INTBIG flags; /* state SCROLL area */
281 INTBIG vthumbpos; /* position of vertical thumb slider */
282 INTBIG hthumbpos; /* position of horizontal thumb slider */
283 INTBIG horizfactor; /* shift of horizontal text (0 to 100) */
284 INTBIG firstline; /* line number of top line */
285 INTBIG linesinfolder; /* number of lines displayable */
286 INTBIG whichlow; /* first currently highlighted line */
287 INTBIG whichhigh; /* last currently highlighted line */
288 INTBIG lineheight; /* height of line of text */
289 INTBIG lineoffset; /* offset to baseline for text */
290 CHAR **scrolllist; /* list of text lines */
291 INTBIG scrolllistsize; /* size of line list */
292 INTBIG scrolllistlen; /* number of valid lines/list */
293 } DSCROLL;
294
295 #define NOTDIALOG ((TDIALOG *)-1)
296
297 typedef struct Itdialog
298 {
299 DIALOG *dlgresaddr; /* address of this dialog */
300 INTBIG defaultbutton; /* default button */
301 WindowPtr theDialog;
302
303 /* for the scroll item */
304 INTBIG scrollcount; /* number of scroll items */
305 INTBIG curscroll; /* current scroll item */
306 DSCROLL scroll[MAXSCROLLS]; /* data structures for the scroll item(s) */
307 INTBIG numlocks, lock1[MAXLOCKS], lock2[MAXLOCKS], lock3[MAXLOCKS];
308
309 /* for the current edit text item */
310 INTBIG curitem; /* current edit item */
311 INTBIG editstart, editend; /* start/end selected text in edit item */
312 INTBIG firstch; /* first displayed character in edit item */
313 INTBIG opaqueitem; /* item number of opaque edit text */
314 INTBIG usertextsize; /* size of text in userdrawn fields */
315 INTBIG userdoubleclick; /* nonzero if double-click in user area returns OK */
316
317 /* information for this dialog */
318 INTBIG xoffset, yrev;
319 INTBIG revy; /* for reversing Y coordinates */
320 INTBIG slineheight; /* height of a line of scroll text */
321 INTBIG slineoffset; /* scroll text: distance up to baseline */
322 INTBIG lineheight; /* height of a line of other text */
323 INTBIG lineoffset; /* other text: distance up to baseline */
324 INTBIG firstupdate;
325 INTBIG curlineoffset;
326
327 /* during tracking */
328 RECTAREA rect; /* the current rectangle being tracked */
329 CHAR *msg;
330 POPUPDATA *pd; /* the current popup menu */
331 INTBIG cnt; /* the current entry count in the popup menu */
332 INTBIG sta; /* the current start point in the popup menu */
333 UINTBIG lastdiatime; /* time of last scrollbar slider button action */
334 INTBIG lastx, lasty;
335 INTBIG wasin, lbase, hbase, offset, ddata;
336
337 void (*diaeachdown)(INTBIG x, INTBIG y);
338 void (*modelessitemhit)(void *dia, INTBIG item);
339 struct Itdialog *nexttdialog; /* next in list of active dialogs */
340 } TDIALOG;
341
342 static TDIALOG *gra_firstactivedialog = NOTDIALOG;
343 static TDIALOG *gra_trackingdialog = 0;
344 static TDIALOG *gra_handlingdialog = NOTDIALOG; /* address of dialog handling this event */
345 static FileFilterUPP gra_fileFilterProcUPP;
346 static INTBIG gra_dialogstringpos;
347
348 /* prototypes for local routines */
349 static pascal Boolean gra_fileFilterProc(CInfoPBPtr pb, Ptr mydata);
350 static int gra_stringposascending(const void *e1, const void *e2);
351 static BOOLEAN gra_initdialog(DIALOG *dialog, TDIALOG *dia, BOOLEAN modeless);
352 static BOOLEAN gra_diaeachdownhandler(INTBIG x, INTBIG y);
353 static INTBIG gra_getnextcharacter(TDIALOG *dia, INTBIG oak, INTBIG x, INTBIG y, INTBIG chr,
354 INTBIG special, UINTBIG time, BOOLEAN shifted);
355 static void DTextCopy(TDIALOG *dia);
356 static void DTextCut(TDIALOG *dia);
357 static CHAR DTextPaste(TDIALOG *dia);
358 static BOOLEAN Dbuttondown(INTBIG x, INTBIG y);
359 static BOOLEAN Dcheckdown(INTBIG x, INTBIG y);
360 static void Dclear(TDIALOG *dia);
361 static void Dcorrectxy(TDIALOG *dia, INTBIG *x, INTBIG *y);
362 static void Ddonedialogwindow(TDIALOG *dia);
363 static void Ddoneedit(TDIALOG *dia);
364 static BOOLEAN Ddownarrow(INTBIG x, INTBIG y);
365 static BOOLEAN Ddownpage(INTBIG x, INTBIG y);
366 static BOOLEAN Ddragwin(INTBIG x, INTBIG y);
367 static void Ddragwindow(TDIALOG *dia, INTBIG x, INTBIG y);
368 static void Ddrawarrow(TDIALOG *dia, INTBIG sc, INTBIG which, INTBIG filled);
369 static void Ddrawbox(TDIALOG *dia, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy, GRAPHICS *which);
370 static void Ddrawcircle(TDIALOG *dia, RECTAREA *r, INTBIG dim);
371 static void Ddrawdisc(TDIALOG *dia, RECTAREA *r);
372 static void Ddrawhorizslider(TDIALOG *dia, INTBIG sc);
373 static void Ddrawitem(TDIALOG *dia, INTBIG type, RECTAREA *r, CHAR *msg, INTBIG dim);
374 static void Ddrawline(TDIALOG *dia, INTBIG xf, INTBIG yf, INTBIG xt, INTBIG yt);
375 static void Ddrawmsg(TDIALOG *dia, INTBIG sc, CHAR *msg, INTBIG which);
376 static void Ddrawpolygon(TDIALOG *dia, INTBIG *xv, INTBIG *yv, INTBIG count, INTBIG filled);
377 static void Ddrawpopupentries(TDIALOG *dia);
378 static void Ddrawrectframe(TDIALOG *dia, RECTAREA *r, INTBIG on, INTBIG dim);
379 static void Ddrawroundrectframe(TDIALOG *dia, RECTAREA *r, INTBIG arc, INTBIG dim);
380 static void Ddrawtext(TDIALOG *dia, CHAR *msg, INTBIG len, INTBIG x, INTBIG y, INTBIG dim);
381 static void Ddrawvertslider(TDIALOG *dia, INTBIG sc);
382 static void Deditbox(TDIALOG *dia, RECTAREA *r, INTBIG draw, INTBIG dim);
383 static BOOLEAN Deditdown(INTBIG x, INTBIG y);
384 static void Dforcedialog(TDIALOG *dia);
385 static INTBIG Dgetcolorindex(INTBIG r, INTBIG g, INTBIG b);
386 static INTBIG Dgeteditpos(TDIALOG *dia, RECTAREA *r, INTBIG x, INTBIG y, CHAR *msg);
387 static INTBIG Dgettextsize(TDIALOG *dia, CHAR *msg, INTBIG len);
388 static void Dgetwindowextent(TDIALOG *dia, INTBIG *ly, INTBIG *hy);
389 static void Dgrayrect(TDIALOG *dia, RECTAREA *r);
390 static INTBIG Dhandlepopup(TDIALOG *dia, RECTAREA *r, POPUPDATA *pd);
391 static void Dhighlight(TDIALOG *dia, INTBIG on);
392 static void Dhighlightrect(TDIALOG *dia, RECTAREA *r);
393 static BOOLEAN Dhscroll(INTBIG x, INTBIG y);
394 static void Dinsertstr(TDIALOG *dia, CHAR *insmsg);
395 static void Dinsetrect(RECTAREA *r, INTBIG amt);
396 static void Dintdrawrect(TDIALOG *dia, RECTAREA *rect, INTBIG r, INTBIG g, INTBIG b);
397 static void Dinvertbox(TDIALOG *dia, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy);
398 static void Dinvertentry(TDIALOG *dia, INTBIG sc, INTBIG on);
399 static void Dinvertrect(TDIALOG *dia, RECTAREA *r);
400 static void Dinvertrectframe(TDIALOG *dia, RECTAREA *r);
401 static void Dinvertroundrect(TDIALOG *dia, RECTAREA *r);
402 static BOOLEAN Dleftarrow(INTBIG x, INTBIG y);
403 static BOOLEAN Dleftpage(INTBIG x, INTBIG y);
404 static void Dnewdialogwindow(TDIALOG *dia, RECTAREA *r, CHAR *movable, BOOLEAN modeless);
405 static INTBIG Dneweditbase(TDIALOG *dia);
406 static void Dputicon(TDIALOG *dia, INTBIG x, INTBIG y, UCHAR1 *data);
407 static void Dredrawscroll(TDIALOG *dia, INTBIG sc);
408 static void Drestorerect(INTBIG sr);
409 static BOOLEAN Drightarrow(INTBIG x, INTBIG y);
410 static BOOLEAN Drightpage(INTBIG x, INTBIG y);
411 static INTBIG Dsaverect(TDIALOG *dia, RECTAREA *r);
412 static void Dsetscroll(TDIALOG *dia, INTBIG item, INTBIG value);
413 static void Dsyncvscroll(TDIALOG *dia, INTBIG item);
414 static void Dsethscroll(TDIALOG *dia, INTBIG sc);
415 static void Dsettextsmall(TDIALOG *dia, INTBIG sc);
416 static void Dsetvscroll(TDIALOG *dia, INTBIG sc);
417 static void Dshiftbits(TDIALOG *dia, RECTAREA *sr, RECTAREA *dr);
418 static void Dstuffmessage(TDIALOG *dia, CHAR *msg, RECTAREA *r, INTBIG dim);
419 static void Dstufftext(TDIALOG *dia, CHAR *msg, RECTAREA *r);
420 static void Dtextlocation(TDIALOG *dia, CHAR *msg, INTBIG len, RECTAREA *r, INTBIG *wid, INTBIG *line);
421 static void Dtrackcursor(TDIALOG *dia, INTBIG, INTBIG, BOOLEAN (*eachdown)(INTBIG, INTBIG));
422 static BOOLEAN Dtrackpopup(INTBIG x, INTBIG y);
423 static BOOLEAN Duparrow(INTBIG x, INTBIG y);
424 static BOOLEAN Duppage(INTBIG x, INTBIG y);
425 static BOOLEAN Dvscroll(INTBIG x, INTBIG y);
426 static INTBIG Dwaitforaction(TDIALOG *dia, INTBIG *x, INTBIG *y, INTBIG *chr, INTBIG *special, UINTBIG *time, BOOLEAN *shifted);
427 static INTBIG Dwhichitem(TDIALOG *dia, INTBIG x, INTBIG y);
428 static INTSML Dgetnextcharacter(TDIALOG *dia, INTBIG *itemHit);
429 /****** miscellaneous ******/
430 #define EFONT kFontIDHelvetica /* font in the editing window */
431 #define TFONT kFontIDCourier /* font in text editing */
432 #define SFONT kFontIDGeneva /* font for status at the bottom of editing windows */
433 #define MFONT 0 /* font in menus */
434 #define MSFONT kFontIDCourier /* font in the messages windows */
435 #define DFONT 0 /* font in dialogs */
436 #define DSFONT kFontIDCourier /* small font in dialog scroll areas */
437 #define SBARWIDTH 15 /* width of scroll bar at right of edit window */
438 #define SBARHEIGHT 15 /* height of scroll bar at bottom of edit window */
439 #define PALETTEWIDTH 80 /* width of palette */
440 #define FLOATINGHEADERSIZE 10 /* size of tool palette drag bar */
441 #define MAXSTATUSLINES 1 /* lines in status bar */
442 #define MAXLOCALSTRING 256 /* size of "gra_localstring" */
443
444 static FontInfo gra_curfontinfo; /* current font information */
445 static INTBIG gra_winoffleft; /* left offset of window contents to edge */
446 static INTBIG gra_winoffright; /* right offset of window contents to edge */
447 static INTBIG gra_winofftop; /* top offset of window contents to edge */
448 static INTBIG gra_winoffbottom; /* bottom offset of window contents to edge */
449 static INTBIG gra_floatwinoffleft; /* left offset for floating window contents to edge */
450 static INTBIG gra_floatwinoffright; /* right offset for floating window contents to edge */
451 static INTBIG gra_floatwinofftop; /* top offset for floating window contents to edge */
452 static INTBIG gra_floatwinoffbottom; /* bottom offset for floating window contents to edge */
453 static INTBIG gra_screenleft; /* left bound of any editor window screen */
454 static INTBIG gra_screenright; /* right bound of any editor window screen */
455 static INTBIG gra_screentop; /* top bound of any editor window screen */
456 static INTBIG gra_screenbottom; /* bottom bound of any editor window screen */
457 static GDHandle gra_origgdevh; /* the original graphics device */
458 static CHAR gra_localstring[MAXLOCALSTRING]; /* local string */
459 static INTBIG gra_logrecordindex = 0; /* count for session flushing */
460 static INTBIG gra_playbackmultiple = 0; /* count for multi-key playback */
461 static BOOLEAN gra_multiwindow; /* true if using multiple windows */
462 static void *gra_fileliststringarray = 0;
463 static INTBIG gra_windowframeindex = 0;
464 static INTBIG gra_numfaces = 0;
465 static CHAR **gra_facelist;
466 static INTBIG *gra_faceid;
467
468 /****** prototypes for local routines ******/
469 static BOOLEAN gra_addfiletolist(CHAR *file);
470 static void gra_adjusthtext(INTBIG);
471 static void gra_adjustvtext(void);
472 static void gra_applemenu(INTBIG);
473 static void gra_backup(void);
474 static BOOLEAN gra_buildwindow(WINDOWFRAME*, BOOLEAN);
475 static void gra_centermessage(CHAR*, INTBIG, INTBIG, INTBIG);
476 static void gra_fakemouseup(void);
477 static OSErr gra_findprocess(OSType typeToFind, OSType creatorToFind, ProcessSerialNumberPtr processSN,
478 ProcessInfoRecPtr infoRecToFill);
479 static void gra_getdevices(void);
480 static Rect *gra_geteditorwindowlocation(void);
481 CGrafPtr gra_getoffscreen(WINDOWPART *win);
482 static INTBIG gra_gettraptype(INTBIG);
483 CGrafPtr gra_getwindow(WINDOWPART *win);
484 static pascal OSErr gra_handleodoc(AppleEvent*, AppleEvent*, long);
485 static pascal OSErr gra_handlequit(AppleEvent*, AppleEvent*, long);
486 static void gra_hidemessageswindow(void);
487 static void gra_initfilelist(void);
488 static void gra_initializemenus(void);
489 static INTBIG gra_initializetcl(void);
490 static void gra_installvbl(void);
491 static CHAR *gra_macintoshinitialization(void);
492 static INTBIG gra_makebutton(INTBIG);
493 static BOOLEAN gra_makeeditwindow(WINDOWFRAME*);
494 static CHAR *gra_makefullname(CHAR*, INTBIG);
495 static CHAR *gra_makefullnamefromFSS(FSSpec theFSS);
496 static MenuHandle gra_makepdmenu(POPUPMENU*, INTBIG);
497 static CHAR *gra_makepstring(CHAR *string);
498 static void gra_mygrowwindow(WindowPtr, INTBIG, INTBIG, Rect*);
499 static void gra_nativemenudoone(INTBIG low, INTBIG high);
500 static void gra_nextevent(INTBIG, EventRecord*);
501 static INTBIG gra_numtoolboxtraps(void);
502 static BOOLEAN gra_onthiswindow(WindowPtr window, INTBIG left, INTBIG right, INTBIG top, INTBIG bottom);
503 static INTBIG gra_pulldownindex(POPUPMENU*);
504 static void gra_rebuildrowstart(WINDOWFRAME*);
505 static void gra_recachepixmap(PixPatHandle);
506 static void gra_redrawdisplay(WINDOWFRAME*);
507 static void gra_reloadmap(void);
508 static INTBIG gra_remakeeditwindow(WINDOWFRAME*);
509 static void gra_removewindowextent(RECTAREA *r, RECTAREA *er);
510 static void gra_savewindowsettings(void);
511 static pascal void gra_scrollhproc(ControlHandle, short);
512 static pascal void gra_scrollvproc(ControlHandle, short);
513 static void gra_setcurrentwindowframe(void);
514 void gra_setrect(WINDOWFRAME*, INTBIG, INTBIG, INTBIG, INTBIG);
515 static void gra_setuptextbuffer(INTBIG width, INTBIG height);
516 static void gra_setview(WindowPtr);
517 static void gra_setvscroll(void);
518 static BOOLEAN gra_showmessageswindow(void);
519 static void gra_showselect(void);
520 static BOOLEAN gra_trapavailable(INTBIG);
521 static void gra_waitforaction(INTBIG, EventRecord*);
522 static void Dredrawdialogwindow(TDIALOG *dia);
523 static CHAR *gra_systemfoldername(void);
524 void mac_settypecreator(CHAR *name, INTBIG type, INTBIG creator);
525 static void gra_activatewindow(WindowPtr, BOOLEAN);
526 static void gra_disposeoswindow(WindowPtr);
527 static void gra_dragfloatingwindow(WindowPtr, Point);
528 static void gra_drawosgraphics(WINDOWFRAME*);
529 static void gra_drawpalettedragbar(WINDOWFRAME *wf);
530 static void gra_frontnonfloatingwindow(WindowPtr *);
531 static WindowPtr gra_lastfloatingwindow(void);
532 static void gra_selectoswindow(WindowPtr);
533 static void gra_showallfloaters(BOOLEAN);
534
535 /******************** INITIALIZATION ********************/
536
main(void)537 void main(void)
538 {
539 short argc;
540 CHAR *argv[4], *progname;
541
542 /* initialize for the operating system */
543 progname = gra_macintoshinitialization();
544 argc = 1;
545 argv[0] = progname;
546
547 /* primary initialization of Electric */
548 osprimaryosinit();
549
550 /* secondary initialization of Electric */
551 ossecondaryinit(argc, argv);
552
553 #if LANGTCL
554 /* only need TCL, initialize later to get proper path */
555 if (gra_initializetcl() == TCL_ERROR)
556 error(_("gra_initializetcl failed: %s\n"), myTCLInterp->result);
557 #endif
558
559 /* now run Electric */
560 for(;;)
561 {
562 tooltimeslice();
563 }
564 }
565
566 /*
567 * routine to establish the default display
568 */
graphicsoptions(CHAR * name,INTBIG * argc,CHAR ** argv)569 void graphicsoptions(CHAR *name, INTBIG *argc, CHAR **argv)
570 {
571 /* set multiple window factor */
572 if (*argc > 0 && argv[0][estrlen(argv[0])-1] == '1') gra_multiwindow = FALSE; else
573 gra_multiwindow = TRUE;
574 us_erasech = BACKSPACEKEY;
575 us_killch = 025;
576 }
577 /*
578 * routine to initialize the display device. Creates status window if "messages" is true.
579 */
initgraphics(BOOLEAN messages)580 BOOLEAN initgraphics(BOOLEAN messages)
581 {
582 WINDOWFRAME *wf;
583 CHAR fontname[100];
584 Rect rstat, r;
585 INTBIG err;
586 short theFont;
587 long response;
588 Handle f;
589 CTabHandle iclut;
590 REGISTER INTBIG i;
591 RgnHandle grayrgn;
592
593 /* get double-click interval */
594 gra_doubleclick = GetDblTime();
595 gra_lastclick = 0;
596 gra_lstcurx = -1;
597
598 /* setup UPPs */
599 gra_scrollvprocUPP = NewControlActionProc(gra_scrollvproc);
600 gra_scrollhprocUPP = NewControlActionProc(gra_scrollhproc);
601 gra_fileFilterProcUPP = NewFileFilterProc(gra_fileFilterProc);
602 /* initialize menus */
603 gra_initializemenus();
604
605 /* get cursors */
606 gra_wantttyCurs = GetCursor(wantttyCURSOR);
607 gra_penCurs = GetCursor(penCURSOR);
608 gra_nullCurs = GetCursor(nullCURSOR);
609 gra_menuCurs = GetCursor(menulCURSOR);
610 gra_handCurs = GetCursor(handCURSOR);
611 gra_techCurs = GetCursor(techCURSOR);
612 gra_ibeamCurs = GetCursor(iBeamCursor);
613 gra_lrCurs = GetCursor(lrCURSOR);
614 gra_udCurs = GetCursor(udCURSOR);
615 us_normalcursor = NORMALCURSOR;
616
617 /* setup globals that describe location of windows */
618 gra_getdevices();
619
620 /* determine font and size of text in messages window */
621 f = GetResource('MPSR', 1004);
622 if (f == 0)
623 {
624 /* no window resource: use defaults */
625 gra_messagesfont = MSFONT;
626 gra_messagesfontsize = 12;
627 } else
628 {
629 HLock(f);
630
631 /* get messages window extent */
632 rstat.left = ((INTSML *)(*f))[0];
633 rstat.right = ((INTSML *)(*f))[1];
634 rstat.top = ((INTSML *)(*f))[2];
635 rstat.bottom = ((INTSML *)(*f))[3];
636
637 /* is the top of the messages window visible on this display? */
638 r.left = rstat.left+gra_winoffleft; r.right = rstat.right+gra_winoffright;
639 r.top = rstat.top+gra_winofftop; r.bottom = r.top + MENUSIZE;
640 grayrgn = GetGrayRgn();
641 if (RectInRgn(&r, grayrgn))
642 {
643 gra_messagesleft = rstat.left; gra_messagesright = rstat.right;
644 gra_messagestop = rstat.top; gra_messagesbottom = rstat.bottom;
645 }
646
647 /* get font and size */
648 gra_messagesfontsize = ((INTSML *)(*f))[8];
649 (void)estrcpy(&fontname[1], &((CHAR *)(*f))[18]);
650 fontname[0] = estrlen(&fontname[1]);
651 GetFNum((UCHAR1 *)fontname, &theFont);
652 gra_messagesfont = theFont;
653 HUnlock(f);
654 }
655
656 /* create the scrolling messages window */
657 gra_messageswindow = 0;
658 gra_TEH = 0;
659 if (messages)
660 {
661 if (gra_showmessageswindow()) error(_("Cannot create messages window"));
662 }
663
664 /* initialize the mouse */
665 if (gra_nullCurs != 0L) SetCursor(&(**gra_nullCurs)); else
666 SetCursor(&qd.arrow);
667 us_cursorstate = NULLCURSOR;
668 gra_inputstate = NOEVENT;
669 // gra_eventqueuehead = gra_eventqueuetail = gra_eventqueue;
670
671 /* create the CLUT for identity mapping on color displays */
672 iclut = (CTabHandle)NewHandle(2056);
673 if (iclut == 0) error(_("Cannot allocate identity color lookup table"));
674 (*iclut)->ctSeed = GetCTSeed();
675 (*iclut)->ctFlags = 0;
676 (*iclut)->ctSize = 255;
677 for(i=0; i<256; i++)
678 {
679 (*iclut)->ctTable[i].value = i;
680 (*iclut)->ctTable[i].rgb.red = i<<8;
681 (*iclut)->ctTable[i].rgb.green = i<<8;
682 (*iclut)->ctTable[i].rgb.blue = i<<8;
683 }
684
685 /* setup to handle input files via apple events */
686 err = Gestalt(gestaltAppleEventsAttr, &response);
687 if (err == 0 && ((response >> gestaltAppleEventsPresent) & 1) != 0)
688 {
689 /* apple events method */
690 err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
691 NewAEEventHandlerProc(gra_handleodoc), 0, 0);
692 err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
693 NewAEEventHandlerProc(gra_handlequit), 0, 0);
694 }
695
696 /* initialize vertical retrace manager to check for interrupts */
697 gra_installvbl();
698
699 /* create the first window frame */
700 if (!gra_multiwindow)
701 {
702 wf = (WINDOWFRAME *)emalloc((sizeof (WINDOWFRAME)), us_tool->cluster);
703 if (wf == 0) error(_("Cannot create Macintosh window info structure"));
704 wf->numvar = 0;
705 wf->windindex = gra_windowframeindex++;
706 el_firstwindowframe = el_curwindowframe = wf;
707 el_firstwindowframe->nextwindowframe = NOWINDOWFRAME;
708
709 /* load an editor window into this frame */
710 if (gra_buildwindow(el_curwindowframe, FALSE))
711 error(_("Cannot create Macintosh window info structure"));
712 }
713
714 /* catch interrupts */
715 (void)signal(SIGINT, (SIGNALCAST)gra_onint);
716
717 return(FALSE);
718 }
719
720 /*
721 * Routine to establish the library directories from the environment.
722 */
setupenvironment(void)723 void setupenvironment(void)
724 {
725 REGISTER void *infstr;
726
727 /* initialize system directories for library files */
728 infstr = initinfstr();
729 addstringtoinfstr(infstr, gra_systemfoldername());
730 addstringtoinfstr(infstr, LIBDIR);
731 (void)allocstring(&el_libdir, returninfstr(infstr), db_cluster);
732
733 /* set machine name */
734 nextchangequiet();
735 (void)setval((INTBIG)us_tool, VTOOL, x_("USER_machine"),
736 (INTBIG)x_("Macintosh"), VSTRING|VDONTSAVE);
737 }
738
setlibdir(CHAR * libdir)739 void setlibdir(CHAR *libdir)
740 {
741 CHAR *pp;
742 REGISTER void *infstr;
743
744 /* make sure UNIX '/' isn't in use */
745 for(pp = libdir; *pp != 0; pp++)
746 if (*pp == '/') *pp = DIRSEP;
747
748 infstr = initinfstr();
749 if (libdir[0] == ':')
750 {
751 pp = gra_systemfoldername();
752 } else
753 {
754 pp = currentdirectory();
755 }
756 addstringtoinfstr(infstr, pp);
757 addstringtoinfstr(infstr, libdir);
758 if (libdir[estrlen(libdir)-1] != DIRSEP) addtoinfstr(infstr, DIRSEP);
759 (void)reallocstring(&el_libdir, returninfstr(infstr), db_cluster);
760 }
761
762 /*
763 * Routine to examine the display devices available and to setup globals that describe
764 * the editing windows and messages window extents. On exit, the globals "gra_screenleft",
765 * "gra_screenright", "gra_screentop", and "gra_screenbottom" will describe the area
766 * for the editing windows and the variables "gra_messagesleft", "gra_messagesright",
767 * "gra_messagestop", and "gra_messagesbottom" will describe the messages window.
768 */
gra_getdevices(void)769 void gra_getdevices(void)
770 {
771 GDHandle gdevh, bestcgdevh, bestbwgdevh, curgdevh;
772 INTBIG totaldevices, iscolor, anycolor;
773 INTBIG bestcpixels, bestbwpixels, pixels, ys;
774
775 /* obtain the current device */
776 gra_origgdevh = GetGDevice();
777
778 /* find the devices */
779 bestcpixels = bestbwpixels = 0L;
780 totaldevices = anycolor = 0;
781 for(gdevh = GetDeviceList(); gdevh != 0L; gdevh = GetNextDevice(gdevh))
782 {
783 totaldevices++;
784
785 /* determine size of this display */
786 pixels = (*gdevh)->gdRect.right - (*gdevh)->gdRect.left;
787 ys = (*gdevh)->gdRect.bottom - (*gdevh)->gdRect.top;
788 pixels *= ys;
789
790 /* The low bit is set if the display is color */
791 iscolor = 1;
792 if (((*gdevh)->gdFlags&1) == 0) iscolor = 0;
793
794 /* color displays must be at least 8 bits deep */
795 if ((*(*gdevh)->gdPMap)->pixelSize < 8) iscolor = 0;
796
797 /* accumulate the best of each display type */
798 if (iscolor != 0)
799 {
800 if (pixels > bestcpixels || (pixels == bestcpixels && gdevh == gra_origgdevh))
801 {
802 bestcgdevh = gdevh;
803 bestcpixels = pixels;
804 }
805 } else
806 {
807 if (pixels > bestbwpixels || (pixels == bestbwpixels && gdevh == gra_origgdevh))
808 {
809 bestbwgdevh = gdevh;
810 bestbwpixels = pixels;
811 }
812 }
813 }
814
815 /* if there is a color device, choose it */
816 if (bestcpixels != 0) curgdevh = bestcgdevh; else
817 if (bestbwpixels != 0) curgdevh = bestbwgdevh; else
818 {
819 ParamText((UCHAR1 *)gra_makepstring(_("For some reason, Electric cannot find any displays on which to run.")), x_("\p"), x_("\p"), x_("\p"));
820 StopAlert(errorALERT, 0L);
821 exitprogram();
822 }
823
824 /* set the extent of the editing windows */
825 gra_screenleft = (*curgdevh)->gdRect.left;
826 gra_screenright = (*curgdevh)->gdRect.right;
827 gra_screentop = (*curgdevh)->gdRect.top;
828 gra_screenbottom = (*curgdevh)->gdRect.bottom;
829
830 /* set the extent of the messages window */
831 gra_messagesleft = gra_screenleft + PALETTEWIDTH + 1;
832 gra_messagesright = gra_screenright - PALETTEWIDTH - 1;
833 gra_messagestop = gra_screentop + MENUSIZE*3 + 2 +
834 (gra_screenbottom-(gra_screentop+MENUSIZE*2)) * 3 / 5;
835 gra_messagesbottom = gra_screenbottom;
836
837 /* if multiple displays exist, choose another for the messages window */
838 if (totaldevices > 1)
839 {
840 /* look for another screen to be used for the messages display */
841 for(gdevh = GetDeviceList(); gdevh != 0L; gdevh = GetNextDevice(gdevh))
842 if (gdevh != curgdevh)
843 {
844 INTBIG i, siz;
845 gra_messagesleft = (*gdevh)->gdRect.left;
846 gra_messagesright = (*gdevh)->gdRect.right;
847 gra_messagestop = (*gdevh)->gdRect.top;
848 gra_messagesbottom = (*gdevh)->gdRect.bottom;
849
850 i = (gra_messagesleft + gra_messagesright) / 2;
851 siz = (gra_messagesright - gra_messagesleft) * 2 / 5;
852 gra_messagesleft = i - siz; gra_messagesright = i + siz;
853 i = (gra_messagestop + gra_messagesbottom) / 2;
854 siz = (gra_messagesbottom - gra_messagestop) / 4;
855 gra_messagestop = i - siz; gra_messagesbottom = i + siz;
856 return;
857 }
858 }
859 }
860
gra_macintoshinitialization(void)861 CHAR *gra_macintoshinitialization(void)
862 {
863 long ppcresponse;
864 SysEnvRec ser;
865 ProcessSerialNumber psn;
866 ProcessInfoRec pinfo;
867 INTBIG sysversion;
868 CHAR processname[50];
869 static CHAR appname[50];
870 #if defined(__MWERKS__) && __MC68020__
871 long response;
872 #endif
873
874 MaxApplZone();
875 InitGraf(&qd.thePort);
876 InitFonts();
877 FlushEvents(everyEvent, 0);
878 InitWindows();
879 InitMenus();
880 TEInit();
881 InitDialogs(0L);
882 InitCursor();
883
884 /* must have system 7 */
885 SysEnvirons(2, &ser);
886 sysversion = (ser.systemVersion >> 8) & 0xFF;
887 if (sysversion < 7)
888 error(_("The Macintosh must be running system 7 or later"));
889 switch (sysversion)
890 {
891 case 7:
892 gra_winoffleft = 1; gra_winoffright = -2;
893 gra_winoffbottom = -2; gra_winofftop = MENUSIZE;
894 break;
895 default: /* works for system 9 */
896 gra_winoffleft = 6; gra_winoffright = -7;
897 gra_winoffbottom = -7; gra_winofftop = MENUSIZE+3;
898 break;
899 }
900 gra_floatwinoffleft = 1; gra_floatwinoffright = 1;
901 gra_floatwinofftop = 1; gra_floatwinoffbottom = 1;
902
903 /* see if this is a powerPC */
904 Gestalt(gestaltPPCToolboxAttr, &ppcresponse);
905
906 /* check for 020 if the code was compiled for it */
907 #if defined(__MWERKS__) && __MC68020__
908 Gestalt(gestaltProcessorType, &response);
909 if (ppcresponse == 0 &&
910 (response == gestalt68000 || response == gestalt68010))
911 error(_("The Macintosh must have a 68020 or better processor"));
912 #endif
913
914 /* check for floating point unit if the code was compiled for it */
915 #if defined(__MWERKS__) && __MC68881__
916 Gestalt(gestaltFPUType, &response);
917 if (ppcresponse == 0 && response == gestaltNoFPU)
918 error(_("The Macintosh must have a Floating Point Processor"));
919 #endif
920 /* determine "arguments" to the program */
921 pinfo.processInfoLength = sizeof (ProcessInfoRec);
922 pinfo.processName = (UCHAR1 *)processname;
923 pinfo.processAppSpec = 0;
924 GetCurrentProcess(&psn);
925 GetProcessInformation(&psn, &pinfo);
926 estrncpy(appname, (CHAR *)&pinfo.processName[1], pinfo.processName[0]);
927 appname[pinfo.processName[0]] = 0;
928 return(appname);
929 }
930
931 /*
932 * routine to determine whether a trap exists in the Mac
933 */
gra_trapavailable(INTBIG theTrap)934 BOOLEAN gra_trapavailable(INTBIG theTrap)
935 {
936 INTBIG ttype;
937 ttype = gra_gettraptype(theTrap);
938 if (ttype == ToolTrap)
939 {
940 theTrap &= 0x7FF;
941 if (theTrap >= gra_numtoolboxtraps()) return(FALSE);
942 }
943 return(NGetTrapAddress(theTrap, ttype) != NGetTrapAddress(0, ToolTrap));
944 }
945
946 /*
947 * support routine to determine what kind of trap this is
948 */
gra_gettraptype(INTBIG theTrap)949 INTBIG gra_gettraptype(INTBIG theTrap)
950 {
951 if ((theTrap&0x800) != 0) return(ToolTrap);
952 return(OSTrap);
953 }
954
955 /*
956 * support routine to determine how many Mac Toolbox traps are available
957 */
gra_numtoolboxtraps(void)958 INTBIG gra_numtoolboxtraps(void)
959 {
960 /* 0xA86E is "InitGraf" */
961 if (NGetTrapAddress(0xA86E, 1) == NGetTrapAddress(0xAA6E, 1)) return(0x200);
962 return(0x400);
963 }
964
965 #if LANGTCL
966
gra_initializetcl(void)967 INTBIG gra_initializetcl(void)
968 {
969 INTBIG err;
970 CHAR *newArgv[2];
971
972 /* set the program name/path */
973 newArgv[0] = x_("Electric");
974 newArgv[1] = NULL;
975 (void)Tcl_FindExecutable(newArgv[0]);
976
977 myTCLInterp = Tcl_CreateInterp();
978 if (myTCLInterp == 0) error(_("from Tcl_CreateInterp"));
979
980 /* tell Electric the TCL interpreter handle */
981 el_tclinterpreter(myTCLInterp);
982
983 /* Make command-line arguments available in the Tcl variables "argc" and "argv" */
984 Tcl_SetVar(myTCLInterp, x_("argv"), x_(""), TCL_GLOBAL_ONLY);
985 Tcl_SetVar(myTCLInterp, x_("argc"), x_("0"), TCL_GLOBAL_ONLY);
986 Tcl_SetVar(myTCLInterp, x_("argv0"), x_("electric"), TCL_GLOBAL_ONLY);
987
988 /* Set the "tcl_interactive" variable */
989 Tcl_SetVar(myTCLInterp, x_("tcl_interactive"), x_("1"), TCL_GLOBAL_ONLY);
990
991 /* initialize the interpreter */
992 err = Tcl_Init(myTCLInterp);
993 if (err != TCL_OK) error(_("(from Tcl_Init) %s"), myTCLInterp->result);
994
995 return(err);
996 }
997
998 #endif
999
1000 /******************** TERMINATION ********************/
1001
termgraphics(void)1002 void termgraphics(void)
1003 {
1004 REGISTER INTBIG i;
1005
1006 gra_termgraph();
1007 while (el_firstwindowframe != NOWINDOWFRAME)
1008 gra_disposeoswindow((WindowPtr)el_firstwindowframe->realwindow);
1009 if (gra_messageswindow != 0)
1010 gra_disposeoswindow(gra_messageswindow);
1011 for(i=0; i<gra_numfaces; i++) efree((CHAR *)gra_facelist[i]);
1012 if (gra_numfaces > 0)
1013 {
1014 efree((CHAR *)gra_facelist);
1015 efree((CHAR *)gra_faceid);
1016 }
1017
1018 if (gra_pulldownmenucount != 0)
1019 {
1020 efree((CHAR *)gra_pulldownmenus);
1021 for(i=0; i<gra_pulldownmenucount; i++) efree(gra_pulldowns[i]);
1022 efree((CHAR *)gra_pulldowns);
1023 }
1024 }
1025
1026 /*
1027 * routine to handle a "quit" Apple Event
1028 */
gra_handlequit(AppleEvent * theAppleEvent,AppleEvent * reply,long handlerRefCon)1029 pascal OSErr gra_handlequit(AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefCon)
1030 {
1031 if (us_preventloss(NOLIBRARY, 0, TRUE)) return(noErr);
1032 bringdown();
1033 return(noErr);
1034 }
1035
1036 /*
1037 * routine to quit the program. It unregisters the name first and then exits.
1038 */
exitprogram(void)1039 void exitprogram(void)
1040 {
1041 ExitToShell();
1042 }
1043
1044 /******************** WINDOW CONTROL ********************/
1045
1046 /*
1047 * Routine to create a new window frame (floating if "floating" nonzero).
1048 */
newwindowframe(BOOLEAN floating,RECTAREA * r)1049 WINDOWFRAME *newwindowframe(BOOLEAN floating, RECTAREA *r)
1050 {
1051 WINDOWFRAME *wf, *oldlisthead;
1052
1053 if (!gra_multiwindow) return(NOWINDOWFRAME);
1054
1055 /* allocate one */
1056 wf = (WINDOWFRAME *)emalloc((sizeof (WINDOWFRAME)), us_tool->cluster);
1057 if (wf == 0) return(NOWINDOWFRAME);
1058 wf->numvar = 0;
1059 wf->windindex = gra_windowframeindex++;
1060
1061 /* insert window-frame in linked list */
1062 oldlisthead = el_firstwindowframe;
1063 wf->nextwindowframe = el_firstwindowframe;
1064 el_firstwindowframe = wf;
1065
1066 /* load an editor window into this frame */
1067 if (gra_buildwindow(wf, floating))
1068 {
1069 efree((CHAR *)wf);
1070 el_firstwindowframe = oldlisthead;
1071 return(NOWINDOWFRAME);
1072 }
1073
1074 /* remember that this is the current window frame */
1075 if (!floating) el_curwindowframe = wf;
1076
1077 return(wf);
1078 }
1079
killwindowframe(WINDOWFRAME * wf)1080 void killwindowframe(WINDOWFRAME *wf)
1081 {
1082 if (gra_multiwindow)
1083 {
1084 /* kill the actual window, that will remove the frame, too */
1085 gra_disposeoswindow((WindowPtr)wf->realwindow);
1086 }
1087 }
1088
1089 /*
1090 * Routine to return the current window frame.
1091 */
getwindowframe(BOOLEAN canfloat)1092 WINDOWFRAME *getwindowframe(BOOLEAN canfloat)
1093 {
1094 return(el_curwindowframe);
1095 }
1096
1097 /*
1098 * routine to return size of window "win" in "wid" and "hei"
1099 */
getwindowframesize(WINDOWFRAME * wf,INTBIG * wid,INTBIG * hei)1100 void getwindowframesize(WINDOWFRAME *wf, INTBIG *wid, INTBIG *hei)
1101 {
1102 *wid = wf->swid;
1103 *hei = wf->shei;
1104 }
1105
1106 /*
1107 * Routine to get the extent of the messages window.
1108 */
getmessagesframeinfo(INTBIG * top,INTBIG * left,INTBIG * bottom,INTBIG * right)1109 void getmessagesframeinfo(INTBIG *top, INTBIG *left, INTBIG *bottom, INTBIG *right)
1110 {
1111 Rect r;
1112
1113 if (gra_messageswindow == 0)
1114 {
1115 *left = gra_messagesleft; *right = gra_messagesright;
1116 *top = gra_messagestop; *bottom = gra_messagesbottom;
1117 } else
1118 {
1119 r = (*((WindowPeek)gra_messageswindow)->strucRgn)->rgnBBox;
1120 *left = r.left+gra_winoffleft; *right = r.right+gra_winoffright;
1121 *top = r.top+gra_winofftop; *bottom = r.bottom+gra_winoffbottom;
1122 }
1123 }
1124
1125 /*
1126 * Routine to set the size and position of the messages window.
1127 */
setmessagesframeinfo(INTBIG top,INTBIG left,INTBIG bottom,INTBIG right)1128 void setmessagesframeinfo(INTBIG top, INTBIG left, INTBIG bottom, INTBIG right)
1129 {
1130 MoveWindow(gra_messageswindow, left, top, 0);
1131 SizeWindow(gra_messageswindow, right-left, bottom-top, 1);
1132 }
1133
1134 /*
1135 * Routine to return the current Macintosh window associated with Electric window "win".
1136 * This is only called from "ioplotmac.c"
1137 */
gra_getwindow(WINDOWPART * win)1138 CGrafPtr gra_getwindow(WINDOWPART *win)
1139 {
1140 return(win->frame->realwindow);
1141 }
1142
1143 /*
1144 * Routine to return the offscreen Macintosh buffer associated with Electric window "win".
1145 * This is only called from "ioplotmac.c"
1146 */
gra_getoffscreen(WINDOWPART * win)1147 CGrafPtr gra_getoffscreen(WINDOWPART *win)
1148 {
1149 return(win->frame->window);
1150 }
1151
sizewindowframe(WINDOWFRAME * wf,INTBIG wid,INTBIG hei)1152 void sizewindowframe(WINDOWFRAME *wf, INTBIG wid, INTBIG hei)
1153 {
1154 Rect fr;
1155
1156 fr = (*((WindowPeek)wf->realwindow)->strucRgn)->rgnBBox;
1157
1158 /* determine new window size */
1159 if (wf != NOWINDOWFRAME && wf->floating) hei += FLOATINGHEADERSIZE;
1160 if (wid == fr.right-fr.left && hei == fr.bottom-fr.top) return;
1161
1162 /* resize the window */
1163 SizeWindow((WindowRef)wf->realwindow, wid, hei, 1);
1164
1165 /* rebuild the offscreen windows */
1166 if (gra_remakeeditwindow(wf) > 0)
1167 {
1168 SizeWindow((WindowRef)wf->realwindow, fr.right-fr.left, fr.bottom-fr.top, 1);
1169 return;
1170 }
1171 gra_reloadmap();
1172
1173 SetPort((WindowPtr)wf->realwindow);
1174 EraseRect(&wf->realwindow->portRect);
1175 gra_drawosgraphics(wf);
1176 }
1177
movewindowframe(WINDOWFRAME * wf,INTBIG left,INTBIG top)1178 void movewindowframe(WINDOWFRAME *wf, INTBIG left, INTBIG top)
1179 {
1180 INTBIG oleft, otop;
1181 Rect fr;
1182
1183 fr = (*((WindowPeek)wf->realwindow)->strucRgn)->rgnBBox;
1184
1185 /* determine new window location */
1186 top += MENUSIZE+1;
1187 if (left == fr.left && top == fr.top) return;
1188 oleft = fr.left; otop = fr.top;
1189 MoveWindow((WindowRef)wf->realwindow, left, top, 0);
1190 }
1191
1192 /*
1193 * routine to grow window "w" to the new size of "wid" by "hei". If the grow fails,
1194 * reset the window to its former size in "formerrect".
1195 */
gra_mygrowwindow(WindowPtr w,INTBIG wid,INTBIG hei,Rect * formerrect)1196 void gra_mygrowwindow(WindowPtr w, INTBIG wid, INTBIG hei, Rect *formerrect)
1197 {
1198 REGISTER WINDOWFRAME *wf;
1199 Rect r;
1200 REGISTER INTBIG ret, top;
1201
1202 if (w == gra_messageswindow && gra_messageswindow != 0)
1203 {
1204 SetPort(w);
1205 InvalRect(&w->portRect);
1206
1207 gra_setview(w);
1208 HidePen();
1209 top = w->portRect.top;
1210 MoveControl(gra_vScroll, w->portRect.right-SBARWIDTH, top);
1211 SizeControl(gra_vScroll, SBARWIDTH+1, w->portRect.bottom-top-(SBARHEIGHT-2));
1212 MoveControl(gra_hScroll, w->portRect.left-1, w->portRect.bottom-SBARHEIGHT);
1213 SizeControl(gra_hScroll, w->portRect.right-w->portRect.left-(SBARWIDTH-2), SBARHEIGHT+1);
1214 ShowPen();
1215
1216 gra_setvscroll();
1217 gra_adjustvtext();
1218
1219 r = (*((WindowPeek)w)->strucRgn)->rgnBBox;
1220 gra_messagesleft = r.left+gra_winoffleft; gra_messagesright = r.right+gra_winoffright;
1221 gra_messagestop = r.top+gra_winofftop; gra_messagesbottom = r.bottom+gra_winoffbottom;
1222 /* remember window settings */
1223 gra_savewindowsettings();
1224 return;
1225 }
1226
1227 /* find the window */
1228 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
1229 if (w == (WindowPtr)wf->realwindow) break;
1230 if (wf == NOWINDOWFRAME) return;
1231
1232 /* rebuild the window pointers */
1233 ret = gra_remakeeditwindow(wf);
1234
1235 /* no change necessary */
1236 if (ret < 0) return;
1237
1238 /* change failed: move it back */
1239 if (ret > 0)
1240 {
1241 MoveWindow((WindowPtr)wf->realwindow, formerrect->left, formerrect->top, 0);
1242 SizeWindow((WindowPtr)wf->realwindow, formerrect->right-formerrect->left,
1243 formerrect->bottom-formerrect->top, 1);
1244 return;
1245 }
1246
1247 /* change succeeded, redraw the window */
1248 gra_reloadmap();
1249 SetPort((WindowPtr)wf->realwindow);
1250 EraseRect(&wf->realwindow->portRect);
1251 RectRgn(wf->realwindow->clipRgn, &wf->realwindow->portRect);
1252 gra_drawosgraphics(wf);
1253 gra_redrawdisplay(wf);
1254 }
1255
1256 /*
1257 * Routine to close the messages window if it is in front. Returns true if the
1258 * window was closed.
1259 */
closefrontmostmessages(void)1260 BOOLEAN closefrontmostmessages(void)
1261 {
1262 if (gra_messagesinfront)
1263 {
1264 gra_hidemessageswindow();
1265 return(TRUE);
1266 }
1267 return(FALSE);
1268 }
1269
1270 /*
1271 * Routine to bring window "win" to the front.
1272 */
bringwindowtofront(WINDOWFRAME * wf)1273 void bringwindowtofront(WINDOWFRAME *wf)
1274 {
1275 gra_selectoswindow((WindowPtr)wf->realwindow);
1276 }
1277
1278 /*
1279 * Routine to organize the windows according to "how" (0: tile horizontally,
1280 * 1: tile vertically, 2: cascade).
1281 */
adjustwindowframe(INTBIG how)1282 void adjustwindowframe(INTBIG how)
1283 {
1284 RECTAREA r, wr;
1285 Rect fr;
1286 REGISTER INTBIG children, child, sizex, sizey, left, right, top, bottom;
1287 REGISTER WINDOWFRAME *wf, *compmenu;
1288 GDHandle gdevh;
1289
1290 /* loop through the screens */
1291 for(gdevh = GetDeviceList(); gdevh != 0L; gdevh = GetNextDevice(gdevh))
1292 {
1293 left = (*gdevh)->gdRect.left;
1294 right = (*gdevh)->gdRect.right;
1295 top = (*gdevh)->gdRect.top;
1296 bottom = (*gdevh)->gdRect.bottom;
1297
1298 /* figure out how many windows need to be rearranged */
1299 children = 0;
1300 compmenu = 0;
1301 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
1302 {
1303 if (!gra_onthiswindow((WindowPtr)wf->realwindow, left, right, top, bottom)) continue;
1304 if (!wf->floating) children++; else
1305 compmenu = wf;
1306 }
1307 if (children <= 0) continue;
1308
1309 /* determine area for windows */
1310 r.left = left; r.right = right;
1311 r.top = top+MENUSIZE; r.bottom = bottom;
1312
1313 if (compmenu != NULL)
1314 {
1315 /* remove component menu from area of tiling */
1316 fr = (*((WindowPeek)compmenu->realwindow)->strucRgn)->rgnBBox;
1317 wr.left = fr.left; wr.right = fr.right;
1318 wr.top = fr.top; wr.bottom = fr.bottom;
1319 gra_removewindowextent(&r, &wr);
1320 }
1321 if (gra_messageswindow != 0)
1322 {
1323 if (gra_onthiswindow(gra_messageswindow, left, right, top, bottom))
1324 {
1325 /* remove messages menu from area of tiling */
1326 fr = (*((WindowPeek)gra_messageswindow)->strucRgn)->rgnBBox;
1327 wr.left = fr.left; wr.right = fr.right;
1328 wr.top = fr.top; wr.bottom = fr.bottom;
1329 gra_removewindowextent(&r, &wr);
1330 }
1331 }
1332 /* rearrange the windows */
1333 child = 0;
1334 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
1335 {
1336 if (!gra_onthiswindow((WindowPtr)wf->realwindow, left, right, top, bottom)) continue;
1337 if (wf->floating) continue;
1338 switch (how)
1339 {
1340 case 0: /* tile horizontally */
1341 wr.left = r.left;
1342 wr.right = r.right;
1343 sizey = (r.bottom - r.top) / children;
1344 wr.top = r.top + child*sizey;
1345 wr.bottom = wr.top + sizey;
1346 break;
1347 case 1: /* tile vertically */
1348 wr.top = r.top;
1349 wr.bottom = r.bottom;
1350 sizex = (r.right - r.left) / children;
1351 wr.left = r.left + child*sizex;
1352 wr.right = wr.left + sizex;
1353 break;
1354 case 2: /* cascade */
1355 sizex = (r.right - r.left) / children / 2;
1356 sizey = (r.bottom - r.top) / children / 2;
1357 wr.left = r.left + child*sizex;
1358 wr.right = wr.left + (r.right-r.left)/2;
1359 wr.top = r.top + child*sizey;
1360 wr.bottom = wr.top + (r.bottom-r.top)/2;
1361 break;
1362 }
1363 wr.top += gra_winofftop;
1364 wr.left += gra_winoffleft;
1365 wr.right += gra_winoffright;
1366 wr.bottom += gra_winoffbottom;
1367 MoveWindow((WindowPtr)wf->realwindow, wr.left, wr.top, 0);
1368 SizeWindow((WindowPtr)wf->realwindow, wr.right-wr.left,
1369 wr.bottom-wr.top, 1);
1370 fr = (*((WindowPeek)wf->realwindow)->strucRgn)->rgnBBox;
1371 gra_mygrowwindow((WindowPtr)wf->realwindow, wr.right-wr.left,
1372 wr.bottom-wr.top, &fr);
1373 child++;
1374 }
1375 }
1376 }
1377
1378 /*
1379 * Helper routine to determine whether window "window" is on the display bounded by "left",
1380 * "right", "top" and "bottom". Returns true if so.
1381 */
gra_onthiswindow(WindowPtr window,INTBIG left,INTBIG right,INTBIG top,INTBIG bottom)1382 BOOLEAN gra_onthiswindow(WindowPtr window, INTBIG left, INTBIG right, INTBIG top, INTBIG bottom)
1383 {
1384 Rect fr;
1385 REGISTER INTBIG pixels, onpixels;
1386
1387 fr = (*((WindowPeek)window)->strucRgn)->rgnBBox;
1388 pixels = (fr.right-fr.left) * (fr.bottom-fr.top);
1389 if (fr.left > right || fr.right < left ||
1390 fr.top > bottom || fr.bottom < top) return(FALSE);
1391 if (fr.left < left) fr.left = left;
1392 if (fr.right > right) fr.right = right;
1393 if (fr.top < top) fr.top = top;
1394 if (fr.bottom > bottom) fr.bottom = bottom;
1395 onpixels = (fr.right-fr.left) * (fr.bottom-fr.top);
1396 if (onpixels * 2 >= pixels) return(TRUE);
1397 return(FALSE);
1398 }
1399
1400 /*
1401 * Helper routine to remove the location of window "wnd" from the rectangle "r".
1402 */
gra_removewindowextent(RECTAREA * r,RECTAREA * er)1403 void gra_removewindowextent(RECTAREA *r, RECTAREA *er)
1404 {
1405 if (er->right-er->left > er->bottom-er->top)
1406 {
1407 /* horizontal occluding window */
1408 if (er->left >= r->right || er->right <= r->left) return;
1409 if (er->bottom - r->top < r->bottom - er->top)
1410 {
1411 /* occluding window on top */
1412 r->top = er->bottom;
1413 } else
1414 {
1415 /* occluding window on bottom */
1416 r->bottom = er->top;
1417 }
1418 } else
1419 {
1420 /* vertical occluding window */
1421 if (er->top >= r->bottom || er->bottom <= r->top) return;
1422 if (er->right - r->left < r->right - er->left)
1423 {
1424 /* occluding window on left */
1425 r->left = er->right;
1426 } else
1427 {
1428 /* occluding window on right */
1429 r->right = er->left;
1430 }
1431 }
1432 }
1433
1434 /*
1435 * routine to return the important pieces of information in placing the floating
1436 * palette with the fixed menu. The maximum screen size is placed in "wid" and
1437 * "hei", and the amount of space that is being left for this palette on the
1438 * side of the screen is placed in "palettewidth".
1439 */
getpaletteparameters(INTBIG * wid,INTBIG * hei,INTBIG * palettewidth)1440 void getpaletteparameters(INTBIG *wid, INTBIG *hei, INTBIG *palettewidth)
1441 {
1442 *hei = gra_screenbottom - (gra_screentop+MENUSIZE) - FLOATINGHEADERSIZE;
1443 *wid = gra_screenright - gra_screenleft;
1444 *palettewidth = PALETTEWIDTH;
1445 }
1446
1447 /*
1448 * Routine called when the component menu has moved to a different location
1449 * on the screen (left/right/top/bottom). Resets local state of the position.
1450 */
resetpaletteparameters(void)1451 void resetpaletteparameters(void)
1452 {
1453 }
1454
gra_geteditorwindowlocation(void)1455 Rect *gra_geteditorwindowlocation(void)
1456 {
1457 static Rect redit;
1458 static INTBIG offset = 0;
1459
1460 if (gra_multiwindow)
1461 {
1462 redit.top = offset + gra_screentop + MENUSIZE;
1463 redit.bottom = redit.top + (gra_screenbottom-(gra_screentop+MENUSIZE)) * 3 / 4;
1464 redit.left = offset + gra_screenleft + PALETTEWIDTH + 1;
1465 redit.right = redit.left + (gra_screenright-gra_screenleft-PALETTEWIDTH-1) * 4 / 5;
1466
1467 /* is the editing window visible on this display? */
1468 if (redit.bottom > gra_screenbottom || redit.right > gra_screenright)
1469 {
1470 offset = 0;
1471 redit.top = gra_screentop + MENUSIZE;
1472 redit.bottom = redit.top + (gra_screenbottom-(gra_screentop+MENUSIZE)) * 3 / 4;
1473 redit.left = gra_screenleft + PALETTEWIDTH + 1;
1474 redit.right = redit.left + (gra_screenright-gra_screenleft-PALETTEWIDTH-1) * 4 / 5;
1475 }
1476 offset += 30;
1477 } else
1478 {
1479 redit.top = gra_screentop + MENUSIZE;
1480 redit.bottom = gra_screenbottom;
1481 redit.left = gra_screenleft;
1482 redit.right = gra_screenright;
1483 }
1484 redit.top += MENUSIZE;
1485 return(&redit);
1486 }
1487
1488 /*
1489 * routine to build a new window frame
1490 */
gra_buildwindow(WINDOWFRAME * wf,BOOLEAN floating)1491 BOOLEAN gra_buildwindow(WINDOWFRAME *wf, BOOLEAN floating)
1492 {
1493 Rect redit;
1494 WindowPtr frontmost, wBehind;
1495 static BOOLEAN first = TRUE;
1496 WStateData *wst;
1497 INTBIG cy, ty, left, right, top, bottom;
1498 CHAR line[200];
1499 Handle name, company, special;
1500
1501 wf->floating = floating;
1502 if (!floating)
1503 {
1504 /* get editor window location */
1505 redit = *gra_geteditorwindowlocation();
1506
1507 /* deactivate any other nonfloating window that is current */
1508 gra_frontnonfloatingwindow(&frontmost);
1509 if (frontmost != 0) gra_activatewindow(frontmost, FALSE);
1510
1511 /* figure out which window to put this behind */
1512 wBehind = gra_lastfloatingwindow();
1513 if (wBehind == 0) wBehind = (WindowPtr)-1;
1514
1515 /* create the editing window */
1516 wf->realwindow = (CGrafPtr)NewCWindow(0L, &redit, x_("\p"), 0, zoomDocProc, wBehind, 1, 0L);
1517 } else
1518 {
1519 /* default palette window location */
1520 redit.top = gra_screentop + MENUSIZE + 2;
1521 redit.bottom = (gra_screentop+gra_screenbottom)/2;
1522 redit.left = gra_screenleft + 1;
1523 redit.right = redit.left + PALETTEWIDTH/2;
1524
1525 /* create the editing window */
1526 wf->realwindow = (CGrafPtr)NewCWindow(0L, &redit, x_("\p"), 0, plainDBox, (WindowRef)(-1L),
1527 1, 0L);
1528 }
1529
1530 if (wf->realwindow == 0) return(TRUE);
1531 ShowHide((WindowRef)wf->realwindow, 1);
1532 gra_frontnonfloatingwindow(&frontmost);
1533 gra_activatewindow((WindowRef)wf->realwindow, FALSE);
1534 gra_activatewindow(frontmost, TRUE);
1535 SetPort((WindowPtr)wf->realwindow);
1536 EraseRect(&wf->realwindow->portRect);
1537 gra_drawosgraphics(wf);
1538
1539 if (!floating)
1540 {
1541 if (first)
1542 {
1543 /* get user name/company/special message */
1544 name = GetResource('STR ', NAMERSRC);
1545 company = GetResource('STR ', COMPANYRSRC);
1546 special = GetResource('STR ', SPECIALRSRC);
1547 (void)estrcpy(line, _(" Version "));
1548 (void)estrcat(line, el_version);
1549 line[0] = estrlen(&line[1]);
1550
1551 /* display the welcome message */
1552 TextFont(0);
1553 TextSize(12);
1554 left = wf->realwindow->portRect.left;
1555 right = wf->realwindow->portRect.right;
1556 top = wf->realwindow->portRect.top;
1557 bottom = wf->realwindow->portRect.bottom;
1558 cy = (top+bottom) / 2;
1559 ty = (bottom-top) / 5;
1560 gra_centermessage(gra_makepstring(_("Electric Design System")), left, right, ty);
1561 gra_centermessage(line, left, right, ty+15);
1562 gra_centermessage(gra_makepstring(_("Licensed from Static Free Software")),
1563 left, right, ty+40);
1564 if (name == 0)
1565 gra_centermessage(gra_makepstring(_("***** UNKNOWN USER *****")), left, right, cy); else
1566 {
1567 HLock(name);
1568 gra_centermessage(*name, left, right, cy);
1569 HUnlock(name);
1570 }
1571 if (company == 0)
1572 gra_centermessage(gra_makepstring(_("***** UNKNOWN LOCATION *****")), left, right, cy+20); else
1573 {
1574 HLock(company);
1575 gra_centermessage(*company, left, right, cy+20);
1576 HUnlock(company);
1577 }
1578 if (special != 0)
1579 {
1580 HLock(special);
1581 gra_centermessage(*special, left, right, cy+40);
1582 HUnlock(special);
1583 }
1584
1585 gra_centermessage(gra_makepstring(_("Please wait for loading...")), left, right, bottom-30);
1586 }
1587 wst = (WStateData *) *(((WindowPeek)wf->realwindow)->dataHandle);
1588 wst->stdState.top = gra_screentop + MENUSIZE*2;
1589 wst->stdState.bottom = gra_screenbottom;
1590 wst->stdState.left = gra_screenleft + PALETTEWIDTH;
1591 wst->stdState.right = gra_screenright;
1592 }
1593
1594 /* build the offscreen buffer for the window */
1595 if (gra_makeeditwindow(wf))
1596 {
1597 DisposeWindow((WindowPtr)wf->realwindow);
1598 return(TRUE);
1599 }
1600
1601 /* load any map the first time to establish the map segment length */
1602 el_maplength = 256;
1603 SetGWorld(wf->realwindow, gra_origgdevh);
1604 if (!floating && first) us_getcolormap(el_curtech, COLORSDEFAULT, FALSE); else
1605 gra_reloadmap();
1606 first = FALSE;
1607
1608 /* want the editing window to be the primary one */
1609 SetPort((WindowPtr)wf->realwindow);
1610
1611 return(FALSE);
1612 }
1613
gra_centermessage(CHAR * msg,INTBIG left,INTBIG right,INTBIG y)1614 void gra_centermessage(CHAR *msg, INTBIG left, INTBIG right, INTBIG y)
1615 {
1616 INTBIG wid;
1617
1618 wid = StringWidth((UCHAR1 *)msg);
1619 MoveTo((left+right-wid)/2, y);
1620 DrawString((UCHAR1 *)msg);
1621 }
1622
1623 /*
1624 * Routine to redraw editing window "wf" due to a drag or grow
1625 */
gra_redrawdisplay(WINDOWFRAME * wf)1626 void gra_redrawdisplay(WINDOWFRAME *wf)
1627 {
1628 us_beginchanges();
1629 if (wf == NOWINDOWFRAME || wf->floating) us_drawmenu(0, wf); else
1630 us_drawmenu(-1, wf);
1631 us_redostatus(wf);
1632 us_endchanges(NOWINDOWPART);
1633 us_state |= HIGHLIGHTSET;
1634 us_showallhighlight();
1635 }
1636
1637 /*
1638 * Routine to allocate the offscreen buffer that corresponds with the window
1639 * "wf->realwindow". The buffer is 8-bits deep.
1640 * Returns true if memory cannot be allocated.
1641 */
gra_makeeditwindow(WINDOWFRAME * wf)1642 BOOLEAN gra_makeeditwindow(WINDOWFRAME *wf)
1643 {
1644 INTBIG height, bytes, i;
1645 UCHAR1 *addr;
1646 Rect r;
1647
1648 r = wf->realwindow->portRect;
1649 if (!wf->floating) r.bottom -= SBARHEIGHT; else
1650 r.bottom -= FLOATINGHEADERSIZE;
1651 if (NewGWorld(&wf->window, 8, &r, 0L, 0L, 0) != noErr)
1652 {
1653 ParamText((UCHAR1 *)gra_makepstring(_("Cannot create the offscreen window")), x_("\p"), x_("\p"), x_("\p"));
1654 Alert(errorALERT, 0L);
1655 return(TRUE);
1656 }
1657
1658 SetGWorld(wf->window, 0L);
1659 (void)LockPixels(wf->window->portPixMap);
1660 PenMode(patCopy);
1661 BackColor(0);
1662 EraseRect(&wf->window->portRect);
1663 UnlockPixels(wf->window->portPixMap);
1664 height = r.bottom - r.top;
1665 wf->rowstart = (UCHAR1 **)emalloc(height * SIZEOFINTBIG, us_tool->cluster);
1666 if (wf->rowstart == 0)
1667 {
1668 DisposeGWorld(wf->window);
1669 SetGWorld(wf->realwindow, gra_origgdevh);
1670 ParamText((UCHAR1 *)gra_makepstring(_("Cannot create the offscreen pointers")), x_("\p"), x_("\p"), x_("\p"));
1671 Alert(errorALERT, 0L);
1672 return(TRUE);
1673 }
1674
1675 bytes = (*wf->window->portPixMap)->rowBytes & 0x7FFF;
1676 addr = (UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap);
1677 for(i=0; i<height; i++)
1678 {
1679 wf->rowstart[i] = addr;
1680 addr += bytes;
1681 }
1682 SetGWorld(wf->realwindow, gra_origgdevh);
1683
1684 wf->swid = wf->window->portRect.right - wf->window->portRect.left;
1685 wf->shei = wf->window->portRect.bottom - wf->window->portRect.top;
1686 wf->revy = wf->shei - 1;
1687 wf->offscreendirty = FALSE;
1688 return(FALSE);
1689 }
1690
1691 /*
1692 * Routine to rebuild the offscreen buffer when its size or depth has changed.
1693 * Returns -1 if no change is necessary, 0 if the change was successful, and
1694 * 1 if the change failed (memory error).
1695 */
gra_remakeeditwindow(WINDOWFRAME * wf)1696 INTBIG gra_remakeeditwindow(WINDOWFRAME *wf)
1697 {
1698 INTBIG bytes, i, height;
1699 short res;
1700 UCHAR1 *addr, **newrowstart;
1701 Rect r;
1702
1703 /* quit now if there was no change */
1704 r = wf->realwindow->portRect;
1705 if (!wf->floating) r.bottom -= SBARHEIGHT; else
1706 r.bottom -= FLOATINGHEADERSIZE;
1707 height = r.bottom - r.top;
1708 if (wf->swid == r.right - r.left && wf->shei == height) return(-1);
1709
1710 /* reallocate rowstart array */
1711 newrowstart = (UCHAR1 **)emalloc(height * SIZEOFINTBIG, us_tool->cluster);
1712 if (newrowstart == 0)
1713 {
1714 ParamText((UCHAR1 *)gra_makepstring(_("Not enough memory to modify the window")), x_("\p"), x_("\p"), x_("\p"));
1715 Alert(errorALERT, 0L);
1716 return(1);
1717 }
1718
1719 res = UpdateGWorld(&wf->window, 8, &r, 0L, 0L, 0);
1720 if (res != noErr)
1721 {
1722 efree((CHAR *)newrowstart);
1723 ParamText((UCHAR1 *)gra_makepstring(_("Not enough memory to modify the window")), x_("\p"), x_("\p"), x_("\p"));
1724 Alert(errorALERT, 0L);
1725 return(1);
1726 }
1727
1728 /* this next line should not be needed (fixed in 7.0) */
1729 RectRgn(wf->window->clipRgn, &wf->window->portRect);
1730
1731 /* clear the new buffer */
1732 SetGWorld(wf->window, 0L);
1733 (void)LockPixels(wf->window->portPixMap);
1734 PenMode(patCopy);
1735 BackColor(0);
1736 EraseRect(&wf->window->portRect);
1737 UnlockPixels(wf->window->portPixMap);
1738 SetGWorld(wf->realwindow, gra_origgdevh);
1739
1740 /* load new row start array */
1741 bytes = (*wf->window->portPixMap)->rowBytes & 0x7FFF;
1742 addr = (UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap);
1743 for(i=0; i<height; i++)
1744 {
1745 newrowstart[i] = addr;
1746 addr += bytes;
1747 }
1748 efree((CHAR *)wf->rowstart);
1749 wf->rowstart = newrowstart;
1750
1751 wf->swid = wf->window->portRect.right - wf->window->portRect.left;
1752 wf->shei = wf->window->portRect.bottom - wf->window->portRect.top;
1753 wf->revy = wf->shei - 1;
1754 wf->offscreendirty = FALSE;
1755 return(0);
1756 }
1757
1758 /*
1759 * routine to rebuild the array "wf->rowstart". Since it points to the
1760 * image buffer, and since that buffer is a handle, the buffer can be moved by
1761 * the system for no good reason. Before using the array, each
1762 * routine should see if it is valid and call this to repair the array.
1763 */
gra_rebuildrowstart(WINDOWFRAME * wf)1764 void gra_rebuildrowstart(WINDOWFRAME *wf)
1765 {
1766 INTBIG height, bytes, i;
1767 UCHAR1 *addr;
1768 Rect r;
1769
1770 /* the array has moved: recompute it */
1771 addr = (UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap);
1772 r = wf->realwindow->portRect;
1773 if (!wf->floating) r.bottom -= SBARHEIGHT; else
1774 r.bottom -= FLOATINGHEADERSIZE;
1775 height = r.bottom - r.top;
1776 bytes = (*wf->window->portPixMap)->rowBytes & 0x7FFF;
1777 for(i=0; i<height; i++)
1778 {
1779 wf->rowstart[i] = addr;
1780 addr += bytes;
1781 }
1782 }
1783
gra_drawosgraphics(WINDOWFRAME * wf)1784 void gra_drawosgraphics(WINDOWFRAME *wf)
1785 {
1786 WindowPtr win;
1787
1788 /* figure out which window is being drawn */
1789 win = (WindowPtr)wf->realwindow;
1790 if (wf == NOWINDOWFRAME)
1791 {
1792 if (gra_messageswindow == 0) return;
1793 win = gra_messageswindow;
1794 }
1795
1796 if (wf == NOWINDOWFRAME || !wf->floating)
1797 {
1798 /* for all but menu, draw the grow icon */
1799 DrawGrowIcon(win);
1800 }
1801
1802 if (wf != NOWINDOWFRAME && wf->floating)
1803 {
1804 /* for floating windows, draw the small drag bar */
1805 gra_drawpalettedragbar(wf);
1806 }
1807 }
1808
gra_drawpalettedragbar(WINDOWFRAME * wf)1809 void gra_drawpalettedragbar(WINDOWFRAME *wf)
1810 {
1811 Rect r;
1812 Pattern thePat;
1813 WindowPtr win, frontWindow;
1814
1815 win = (WindowPtr)wf->realwindow;
1816 if (wf == NOWINDOWFRAME)
1817 {
1818 if (gra_messageswindow == 0) return;
1819 win = gra_messageswindow;
1820 }
1821
1822 SetPort(win);
1823 r = win->portRect;
1824 r.bottom = FLOATINGHEADERSIZE;
1825 EraseRect(&r);
1826 MoveTo(0, FLOATINGHEADERSIZE);
1827 LineTo(r.right, FLOATINGHEADERSIZE);
1828 gra_frontnonfloatingwindow(&frontWindow);
1829 if (win != gra_messageswindow || win == frontWindow)
1830 {
1831 /* draw the small drag bar */
1832 r = win->portRect;
1833 r.bottom = FLOATINGHEADERSIZE;
1834 GetIndPattern(&thePat, 0, 24);
1835 PenPat(&thePat);
1836 PaintRect(&r);
1837 PenPat(&qd.black);
1838
1839 /* now draw the close box */
1840 r.top = 2;
1841 r.bottom = FLOATINGHEADERSIZE-1;
1842 r.left = 4;
1843 r.right = FLOATINGHEADERSIZE+1;
1844 PenMode(patBic);
1845 PaintRect(&r);
1846 PenMode(patCopy);
1847 FrameRect(&r);
1848 }
1849 }
1850
1851 /******************** FLOATING WINDOW ROUTINES ********************/
1852
1853 /*
1854 * Routine to return the frontmost window that is NOT floating (zero if none).
1855 */
gra_frontnonfloatingwindow(WindowPtr * result)1856 void gra_frontnonfloatingwindow(WindowPtr *result)
1857 {
1858 WindowPeek theWindow, firstWindow;
1859 WINDOWFRAME *wf;
1860
1861 firstWindow = (WindowPeek)LMGetWindowList();
1862 for(theWindow = firstWindow; theWindow != 0; theWindow = theWindow->nextWindow)
1863 {
1864 /* see if this window is in the edit-window list */
1865 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
1866 if (wf->realwindow == (CGrafPtr)theWindow) break;
1867
1868 /* if not in the list, it must be messages or a dialog, and therefore valid */
1869 if (wf == NOWINDOWFRAME) break;
1870
1871 /* accept editor window only if it is nonfloating */
1872 if (!wf->floating) break;
1873 }
1874
1875 /* return what was found */
1876 *result = (WindowPtr)theWindow;
1877 }
1878
1879 /*
1880 * Routine to make all floating windows visible/invisible.
1881 */
gra_showallfloaters(BOOLEAN vis)1882 void gra_showallfloaters(BOOLEAN vis)
1883 {
1884 WINDOWFRAME *wf;
1885
1886 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
1887 {
1888 if (!wf->floating) continue;
1889 if (vis) ShowHide((WindowPtr)wf->realwindow, 1); else
1890 ShowHide((WindowPtr)wf->realwindow, 0);
1891 }
1892 }
1893
1894 /*
1895 * Routine to return the address of the last floating window. All normal
1896 * windows must go behind this.
1897 */
gra_lastfloatingwindow(void)1898 WindowPtr gra_lastfloatingwindow(void)
1899 {
1900 WindowPeek theWindow, firstWindow;
1901 WindowPtr last;
1902 WINDOWFRAME *wf;
1903
1904 last = 0;
1905 firstWindow = (WindowPeek)LMGetWindowList();
1906 for(theWindow = firstWindow; theWindow != 0; theWindow = theWindow->nextWindow)
1907 {
1908 /* see if this window is in the list */
1909 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
1910 if (wf->realwindow == (CGrafPtr)theWindow) break;
1911 if (wf == NOWINDOWFRAME) continue;
1912
1913 /* make sure it is floating */
1914 if (!wf->floating) continue;
1915
1916 /* floating window found: save its address */
1917 last = (WindowPtr)wf->realwindow;
1918 }
1919 return(last);
1920 }
1921
gra_dragfloatingwindow(WindowPtr windowToDrag,Point startPoint)1922 void gra_dragfloatingwindow(WindowPtr windowToDrag, Point startPoint)
1923 {
1924 Rect dragRect, r;
1925 GrafPtr savePort, windowManagerPort;
1926 RgnHandle dragRegion;
1927 INTBIG dragResult;
1928 INTBIG topLimit, newHorizontalWindowPosition, newVerticalWindowPosition,
1929 horizontalOffset, verticalOffset;
1930 WINDOWFRAME *wf;
1931
1932 /* see if this is an editor window */
1933 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
1934 if ((WindowPtr)wf->realwindow == windowToDrag) break;
1935
1936 /* adjust the top of the dragging rectangle so that it�s below the menu bar */
1937 dragRect = qd.screenBits.bounds;
1938 topLimit = GetMBarHeight();
1939 if (dragRect.top < topLimit) dragRect.top = topLimit;
1940 InsetRect(&dragRect, 4, 4);
1941
1942 /* Set up the Window Manager port */
1943 GetPort(&savePort);
1944 GetWMgrPort(&windowManagerPort);
1945 SetPort(windowManagerPort);
1946 SetClip(GetGrayRgn());
1947
1948 /* Create a region to drag */
1949 dragRegion = NewRgn();
1950
1951 r = (*((WindowPeek)windowToDrag)->strucRgn)->rgnBBox;
1952 RectRgn(dragRegion, &r);
1953
1954 /* Drag the window around */
1955 dragResult = DragGrayRgn(dragRegion, startPoint, &dragRect, &dragRect, noConstraint, nil);
1956
1957 /* Restore the port for coordinate conversion */
1958 SetPort(savePort);
1959
1960 if (dragResult != 0)
1961 {
1962 horizontalOffset = dragResult & 0xFFFF;
1963 verticalOffset = dragResult >> 16;
1964
1965 /* Only move it if it stayed inside the dragging box */
1966 if (verticalOffset != -32768)
1967 {
1968 r = (*((WindowPeek)windowToDrag)->strucRgn)->rgnBBox;
1969 if (wf != NOWINDOWFRAME && wf->floating)
1970 {
1971 newHorizontalWindowPosition = r.left + horizontalOffset + gra_floatwinoffleft;
1972 newVerticalWindowPosition = r.top + verticalOffset + gra_floatwinofftop;
1973 } else
1974 {
1975 newHorizontalWindowPosition = r.left + horizontalOffset + gra_winoffleft;
1976 newVerticalWindowPosition = r.top + verticalOffset + gra_winofftop;
1977 }
1978 MoveWindow(windowToDrag, newHorizontalWindowPosition, newVerticalWindowPosition, false);
1979 }
1980 }
1981
1982 /* Get rid of the dragging region */
1983 DisposeRgn(dragRegion);
1984
1985 /* if this is the messages window, adjust the bits */
1986 if (windowToDrag == gra_messageswindow)
1987 {
1988 r = (*((WindowPeek)windowToDrag)->strucRgn)->rgnBBox;
1989 gra_messagesleft = r.left+gra_winoffleft; gra_messagesright = r.right+gra_winoffright;
1990 gra_messagestop = r.top+gra_winofftop; gra_messagesbottom = r.bottom+gra_winoffbottom;
1991
1992 /* save new messages window settings */
1993 gra_savewindowsettings();
1994 }
1995 }
1996
gra_selectoswindow(WindowPtr windowToSelect)1997 void gra_selectoswindow(WindowPtr windowToSelect)
1998 {
1999 WindowPtr currentFrontWindow;
2000 WINDOWFRAME *wf;
2001 WindowPtr lastFloatingWindow;
2002
2003 /* handle floating windows specially */
2004 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
2005 if (wf->realwindow == (CGrafPtr)windowToSelect)
2006 {
2007 if (wf->floating)
2008 {
2009 BringToFront(windowToSelect);
2010 return;
2011 }
2012 break;
2013 }
2014
2015 /* quit now if this is already selected */
2016 gra_frontnonfloatingwindow(¤tFrontWindow);
2017 if (currentFrontWindow == windowToSelect) return;
2018
2019 /* deactivate current frontmost window */
2020 if (currentFrontWindow != 0) gra_activatewindow(currentFrontWindow, FALSE);
2021
2022 /* bring this window to the front */
2023 lastFloatingWindow = gra_lastfloatingwindow();
2024 if (lastFloatingWindow == 0) BringToFront(windowToSelect); else
2025 SendBehind(windowToSelect, lastFloatingWindow);
2026
2027 /* activate this one */
2028 gra_activatewindow(windowToSelect, TRUE);
2029 }
2030 /*
2031 * Routine to highlight and activate a window.
2032 */
gra_activatewindow(WindowPtr win,BOOLEAN active)2033 void gra_activatewindow(WindowPtr win, BOOLEAN active)
2034 {
2035 Rect r;
2036 WINDOWFRAME *wf;
2037
2038 HiliteWindow(win, active?1:0);
2039 if (win == gra_messageswindow && gra_messageswindow != 0)
2040 {
2041 if (active)
2042 {
2043 ShowControl(gra_vScroll);
2044 ShowControl(gra_hScroll);
2045 gra_messagesinfront = TRUE;
2046 } else
2047 {
2048 HideControl(gra_vScroll);
2049 HideControl(gra_hScroll);
2050 gra_messagesinfront = FALSE;
2051 }
2052 DrawGrowIcon(win);
2053 return;
2054 }
2055
2056 /* see if it is a standard edit window */
2057 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
2058 if ((WindowPtr)wf->realwindow == win) break;
2059 if (wf == NOWINDOWFRAME) return;
2060 if (wf->floating) return;
2061
2062 /* update the grow box in the edit window */
2063 r.right = win->portRect.right;
2064 r.left = r.right - 15;
2065 r.bottom = win->portRect.bottom;
2066 r.top = r.bottom - 15;
2067 RectRgn(win->clipRgn, &r);
2068 DrawGrowIcon(win);
2069 RectRgn(win->clipRgn, &win->portRect);
2070 }
2071
2072 /*
2073 * Routine to close a window.
2074 */
gra_disposeoswindow(WindowPtr win)2075 void gra_disposeoswindow(WindowPtr win)
2076 {
2077 WINDOWFRAME *wf, *lastwf;
2078 WindowPtr front;
2079
2080 /* find and remove the window frame from the list */
2081 lastwf = NOWINDOWFRAME;
2082 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
2083 {
2084 if (wf->realwindow == (CGrafPtr)win)
2085 {
2086 if (lastwf == NOWINDOWFRAME) el_firstwindowframe = wf->nextwindowframe; else
2087 lastwf->nextwindowframe = wf->nextwindowframe;
2088 DisposeGWorld(wf->window);
2089 wf->realwindow = 0;
2090 wf->window = 0;
2091 efree((CHAR *)wf);
2092 break;
2093 }
2094 lastwf = wf;
2095 }
2096
2097 /* deactivate, make invisible, and dispose */
2098 gra_activatewindow(win, FALSE);
2099 ShowHide(win, 0);
2100 DisposeWindow(win);
2101
2102 /* activate the next one (if there is) */
2103 gra_frontnonfloatingwindow(&front);
2104 if (front != 0) gra_activatewindow(front, TRUE);
2105
2106 /* determine current window frame */
2107 gra_setcurrentwindowframe();
2108 }
2109
2110 /*
2111 * routine to determine the current window frame and load the global "el_curwindowframe".
2112 */
gra_setcurrentwindowframe(void)2113 void gra_setcurrentwindowframe(void)
2114 {
2115 WindowPeek theWindow, firstWindow;
2116 WINDOWFRAME *wf;
2117 WINDOWPART *w;
2118
2119 el_curwindowframe = NOWINDOWFRAME;
2120 firstWindow = (WindowPeek)LMGetWindowList();
2121 for(theWindow = firstWindow; theWindow != 0; theWindow = theWindow->nextWindow)
2122 {
2123 /* see if this window is in the edit-window list */
2124 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
2125 if (wf->realwindow == (CGrafPtr)theWindow) break;
2126
2127 /* if not in the list, it must be a dialog */
2128 if (wf == NOWINDOWFRAME)
2129 {
2130 el_curwindowframe = wf;
2131 break;
2132 }
2133
2134 /* ignore floating windows */
2135 if (wf->floating) continue;
2136
2137 el_curwindowframe = wf;
2138
2139 /* see if the change of window frame invalidates the current window */
2140 if (el_curwindowpart == NOWINDOWPART || el_curwindowpart->frame != wf)
2141 {
2142 /* must choose new window (if not broadcasting) */
2143 if (db_broadcasting == 0)
2144 {
2145 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
2146 {
2147 if (w->frame == wf)
2148 {
2149 (void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)w,
2150 VWINDOWPART|VDONTSAVE);
2151 (void)setval((INTBIG)el_curlib, VLIBRARY, x_("curnodeproto"),
2152 (INTBIG)w->curnodeproto, VNODEPROTO);
2153 break;
2154 }
2155 }
2156 }
2157 }
2158 break;
2159 }
2160 }
2161
gra_savewindowsettings(void)2162 void gra_savewindowsettings(void)
2163 {
2164 Handle f;
2165 INTBIG i;
2166 CHAR line[256];
2167
2168 /* get the current font name and messages window location */
2169 GetFontName(gra_messagesfont, (UCHAR1 *)line);
2170
2171 /* remove any previous resource */
2172 f = GetResource('MPSR', 1004);
2173 if (f != 0) RemoveResource(f);
2174
2175 /* make a handle for this information */
2176 f = NewHandle(line[0]+19);
2177
2178 /* load the window location information */
2179 ((INTSML *)(*f))[0] = gra_messagesleft;
2180 ((INTSML *)(*f))[1] = gra_messagesright;
2181 ((INTSML *)(*f))[2] = gra_messagestop;
2182 ((INTSML *)(*f))[3] = gra_messagesbottom;
2183 ((INTSML *)(*f))[4] = 0;
2184 ((INTSML *)(*f))[5] = 0;
2185 ((INTSML *)(*f))[6] = 0;
2186 ((INTSML *)(*f))[7] = 0;
2187
2188 /* load the font information */
2189 ((INTSML *)(*f))[8] = gra_messagesfontsize;
2190 for(i=0; i<line[0]; i++) (*f)[i+18] = line[i+1];
2191 (*f)[line[0]+18] = 0;
2192
2193 /* write the resource */
2194 AddResource(f, 'MPSR', 1004, x_("\pWindow"));
2195 f = GetResource('MPSR', 1004);
2196 if (f != 0) WriteResource(f);
2197 }
2198
2199 /******************** MISCELLANEOUS EXTERNAL ROUTINES ********************/
2200
2201 /*
2202 * return true if the capabilities in "want" are present
2203 */
graphicshas(INTBIG want)2204 BOOLEAN graphicshas(INTBIG want)
2205 {
2206 /* cannot run subprocesses */
2207 if ((want&(CANRUNPROCESS|CANDOTHREADS)) != 0) return(FALSE);
2208
2209 if (!gra_multiwindow)
2210 {
2211 if ((want&CANUSEFRAMES) != 0) return(FALSE);
2212 }
2213
2214 /* popups can only be drawn if the mouse is down */
2215 if ((want&CANSHOWPOPUP) != 0)
2216 {
2217 if (!Button()) return(FALSE);
2218 }
2219
2220 return(TRUE);
2221 }
2222
2223 /*
2224 * Routine to make sound "sound". If sounds are turned off, no
2225 * sound is made (unless "force" is TRUE)
2226 */
ttybeep(INTBIG sound,BOOLEAN force)2227 void ttybeep(INTBIG sound, BOOLEAN force)
2228 {
2229 BOOLEAN soundinited = FALSE;
2230 Movie movie;
2231 short movieRefNum, resID = 0;
2232 OSErr err;
2233 CHAR filename[256];
2234 FSSpec fss;
2235
2236 if ((us_tool->toolstate & TERMBEEP) != 0 || force)
2237 {
2238 switch (sound)
2239 {
2240 case SOUNDBEEP:
2241 SysBeep(20);
2242 break;
2243 case SOUNDCLICK:
2244 if ((us_useroptions&NOEXTRASOUND) != 0) break;
2245 if (!soundinited)
2246 {
2247 esnprintf((CHAR *)&filename[1], 255, x_("%sclick.wav"), el_libdir);
2248 filename[0] = estrlen((CHAR *)&filename[1]);
2249 FSMakeFSSpec(0, 0, (UCHAR1 *)filename, &fss);
2250 err = EnterMovies();
2251 if (err != 0) return;
2252 err = OpenMovieFile(&fss, &movieRefNum, fsRdPerm);
2253 if (err != 0) return;
2254 err = NewMovieFromFile(&movie, movieRefNum, &resID, NULL, newMovieActive, NULL);
2255 if (err != 0) return;
2256 SetMovieVolume(movie, kFullVolume);
2257 soundinited = TRUE;
2258 }
2259 GoToBeginningOfMovie(movie);
2260 StartMovie(movie);
2261 while (!IsMovieDone(movie))
2262 {
2263 MoviesTask(movie, 0);
2264 err = GetMoviesError();
2265 }
2266 break;
2267 }
2268 }
2269 }
2270
error(CHAR * s,...)2271 void error(CHAR *s, ...)
2272 {
2273 va_list ap;
2274 CHAR line[256];
2275
2276 var_start(ap, s);
2277 evsnprintf(&line[1], 255, s, ap);
2278 va_end(ap);
2279 line[0] = estrlen(&line[1]);
2280 ParamText((UCHAR1 *)gra_makepstring(_("Error: ")), (UCHAR1 *)line, x_("\p"), x_("\p"));
2281 StopAlert(130, 0L);
2282 exitprogram();
2283 }
2284
2285 /*
2286 * Routine to get the environment variable "name" and return its value.
2287 */
egetenv(CHAR * name)2288 CHAR *egetenv(CHAR *name)
2289 {
2290 return(0);
2291 }
2292
2293 /*
2294 * Routine to get the current language that Electric speaks.
2295 */
elanguage(void)2296 CHAR *elanguage(void)
2297 {
2298 #ifdef INTERNATIONAL
2299 return(x_("fr"));
2300 #else
2301 return(x_("en"));
2302 #endif
2303 }
2304
2305 /*
2306 * Routine to fork a new process. Returns the child process number if this is the
2307 * parent thread. Returns 0 if this is the child thread.
2308 * Returns 1 if forking is not possible (process 1 is INIT on UNIX and can't possibly
2309 * be assigned to a normal process).
2310 */
efork(void)2311 INTBIG efork(void)
2312 {
2313 return(1);
2314 }
2315
2316 /*
2317 * Routine to run the string "command" in a shell.
2318 * Returns nonzero if the command cannot be run.
2319 */
esystem(CHAR * command)2320 INTBIG esystem(CHAR *command)
2321 {
2322 return(1);
2323 }
2324
2325 /*
2326 * Routine to execute the program "program" with the arguments "args"
2327 */
eexec(CHAR * program,CHAR * args[])2328 void eexec(CHAR *program, CHAR *args[])
2329 {
2330 }
2331
2332 /*
2333 * routine to send signal "signal" to process "process".
2334 */
ekill(INTBIG process)2335 INTBIG ekill(INTBIG process)
2336 {
2337 return(1);
2338 }
2339
2340 /*
2341 * routine to wait for the completion of child process "process"
2342 */
ewait(INTBIG process)2343 void ewait(INTBIG process)
2344 {
2345 }
2346 /*
2347 * Routine to return the number of processors on this machine.
2348 */
enumprocessors(void)2349 INTBIG enumprocessors(void)
2350 {
2351 return(1);
2352 }
2353
2354 /*
2355 * Routine to create a new thread that calls "function" with "argument".
2356 */
enewthread(void * (* function)(void *),void * argument)2357 void enewthread(void* (*function)(void*), void *argument)
2358 {
2359 }
2360
2361 /*
2362 * Routine that creates a mutual-exclusion object and returns it.
2363 */
emakemutex(void)2364 void *emakemutex(void)
2365 {
2366 return(0);
2367 }
2368
2369 /*
2370 * Routine that locks mutual-exclusion object "vmutex". If the object is already
2371 * locked, the routine blocks until it is unlocked.
2372 */
emutexlock(void * vmutex)2373 void emutexlock(void *vmutex)
2374 {
2375 }
2376
2377 /*
2378 * Routine that unlocks mutual-exclusion object "vmutex".
2379 */
emutexunlock(void * vmutex)2380 void emutexunlock(void *vmutex)
2381 {
2382 }
2383
2384 /*
2385 * Routine to determine the list of printers and return it.
2386 * The list terminates with a zero.
2387 */
eprinterlist(void)2388 CHAR **eprinterlist(void)
2389 {
2390 static CHAR *lplist[1];
2391
2392 lplist[0] = 0;
2393 return(lplist);
2394 }
2395
2396 /******************** TIMING ROUTINES ********************/
2397
2398 #if defined(powerc) || defined(__powerc)
gra_dovbl(VBLRec * recPtr)2399 static void gra_dovbl(VBLRec *recPtr)
2400 {
2401 long curA5;
2402
2403 curA5 = SetA5(recPtr->vblA5);
2404
2405 /* do the task */
2406 gra_motioncheck = TRUE;
2407 if (--gra_checkcountdown <= 0)
2408 {
2409 gra_checkcountdown = INTCHECK;
2410 gra_cancheck = TRUE;
2411 }
2412
2413 /* reset counter and global pointers */
2414 recPtr->myVBLTask.vblCount = MOTIONCHECK;
2415 curA5 = SetA5(curA5);
2416 }
2417 #else
2418 static pascal long GetVBLRec(void) = 0x2E88;
2419
gra_dovbl(void)2420 static void gra_dovbl(void)
2421 {
2422 long curA5;
2423 VBLRec *recPtr;
2424
2425 recPtr = (VBLRec *)GetVBLRec();
2426 curA5 = SetA5(recPtr->vblA5);
2427
2428 /* do the task */
2429 gra_motioncheck = TRUE;
2430 if (--gra_checkcountdown <= 0)
2431 {
2432 gra_checkcountdown = INTCHECK;
2433 gra_cancheck = TRUE;
2434 }
2435
2436 /* reset counter and global pointers */
2437 recPtr->myVBLTask.vblCount = MOTIONCHECK;
2438 curA5 = SetA5(curA5);
2439 }
2440 #endif
2441
gra_installvbl(void)2442 void gra_installvbl(void)
2443 {
2444 OSErr err;
2445
2446 gra_vblrec.myVBLTask.qType = vType;
2447 gra_vblrec.myVBLTask.vblAddr = NewVBLProc(gra_dovbl);
2448 gra_vblrec.myVBLTask.vblCount = MOTIONCHECK;
2449 gra_vblrec.myVBLTask.vblPhase = 0;
2450 gra_vblrec.vblA5 = SetCurrentA5();
2451 err = VInstall((QElemPtr)&gra_vblrec.myVBLTask);
2452 if (err == noErr) gra_cancheck = TRUE;
2453 gra_cancheck = FALSE;
2454 gra_motioncheck = FALSE;
2455 gra_checkcountdown = INTCHECK;
2456 }
2457
2458 /******************** MESSAGES WINDOW ROUTINES ********************/
2459
2460 /*
2461 * Routine to delete the messages window.
2462 */
gra_hidemessageswindow(void)2463 void gra_hidemessageswindow(void)
2464 {
2465 if (gra_messageswindow == 0) return;
2466 gra_disposeoswindow(gra_messageswindow);
2467 gra_messagesinfront = FALSE;
2468 gra_messageswindow = 0;
2469 }
2470
2471 /*
2472 * Routine to create the messages window.
2473 */
gra_showmessageswindow(void)2474 BOOLEAN gra_showmessageswindow(void)
2475 {
2476 Rect r;
2477 WindowPtr frontmost, wBehind;
2478
2479 if (gra_messageswindow == 0)
2480 {
2481 /* deactivate any other nonfloating window that is current */
2482 gra_frontnonfloatingwindow(&frontmost);
2483 if (frontmost != 0) gra_activatewindow(frontmost, FALSE);
2484
2485 /* figure out which window to put this behind */
2486 wBehind = gra_lastfloatingwindow();
2487 if (wBehind == 0) wBehind = (WindowPtr)-1;
2488
2489 r.left = gra_messagesleft; r.right = gra_messagesright;
2490 r.top = gra_messagestop; r.bottom = gra_messagesbottom;
2491 gra_messageswindow = (WindowPtr)NewWindow(0L, &r, (UCHAR1 *)gra_makepstring(_("Electric Messages")),
2492 1, documentProc, wBehind, 1, 0L);
2493 if (gra_messageswindow == 0) return(TRUE);
2494 SetPort(gra_messageswindow);
2495 EraseRect(&gra_messageswindow->portRect);
2496 TextFont(gra_messagesfont);
2497 TextSize(gra_messagesfontsize);
2498 r = gra_messageswindow->portRect;
2499 r.left = r.right - SBARWIDTH;
2500 r.right++;
2501 r.bottom -= 14;
2502 r.top += 1;
2503 gra_vScroll = NewControl((WindowRef)gra_messageswindow, &r, x_("\p"), 1, 0, 0, 0,
2504 scrollBarProc, 0L);
2505 if (gra_vScroll == 0) return(TRUE);
2506 r = gra_messageswindow->portRect;
2507 r.top = r.bottom - SBARHEIGHT;
2508 r.bottom++;
2509 r.right -= 14;
2510 r.left--;
2511 gra_hScroll = NewControl((WindowRef)gra_messageswindow, &r, x_("\p"), 1, 0, 0, 0,
2512 scrollBarProc, 0L);
2513 if (gra_hScroll == 0) return(TRUE);
2514 HideControl(gra_vScroll);
2515 HideControl(gra_hScroll);
2516 DrawGrowIcon((WindowRef)gra_messageswindow);
2517 SetControlMinimum(gra_hScroll, 0);
2518 SetControlMaximum(gra_hScroll, 90);
2519 }
2520 if (gra_TEH == 0)
2521 {
2522 r = gra_messageswindow->portRect;
2523 gra_TEH = TENew(&r, &r);
2524 if (gra_TEH == 0) return(TRUE);
2525 }
2526 gra_setview(gra_messageswindow);
2527 TEActivate(gra_TEH);
2528 return(FALSE);
2529 }
2530
gra_setview(WindowPtr w)2531 void gra_setview(WindowPtr w)
2532 {
2533 INTBIG width;
2534
2535 (*gra_TEH)->viewRect = w->portRect;
2536 (*gra_TEH)->viewRect.right -= SBARWIDTH;
2537 (*gra_TEH)->viewRect.bottom -= SBARHEIGHT;
2538 width = (*gra_TEH)->viewRect.right - (*gra_TEH)->viewRect.left;
2539 InsetRect(&(*gra_TEH)->viewRect, 4, 4);
2540 (*gra_TEH)->destRect = (*gra_TEH)->viewRect;
2541 gra_linesInFolder = ((*gra_TEH)->destRect.bottom - (*gra_TEH)->destRect.top) /
2542 (*gra_TEH)->lineHeight;
2543 (*gra_TEH)->destRect.bottom = (*gra_TEH)->destRect.top + (*gra_TEH)->lineHeight *
2544 gra_linesInFolder;
2545 (*gra_TEH)->destRect.left += 4;
2546 (*gra_TEH)->destRect.right = (*gra_TEH)->destRect.left + width*10;
2547 TECalText(gra_TEH);
2548 }
2549
gra_scrollvproc(ControlHandle theControl,short theCode)2550 pascal void gra_scrollvproc(ControlHandle theControl, short theCode)
2551 {
2552 INTBIG pageSize, scrollAmt;
2553
2554 if (theCode == 0) return;
2555 pageSize = ((*gra_TEH)->viewRect.bottom-(*gra_TEH)->viewRect.top) / (*gra_TEH)->lineHeight - 1;
2556 switch (theCode)
2557 {
2558 case kControlUpButtonPart: scrollAmt = -1; break;
2559 case kControlDownButtonPart: scrollAmt = 1; break;
2560 case kControlPageUpPart: scrollAmt = -pageSize; break;
2561 case kControlPageDownPart: scrollAmt = pageSize; break;
2562 }
2563 SetControlValue(theControl, GetControlValue(theControl)+scrollAmt);
2564 gra_adjustvtext();
2565 }
2566
gra_scrollhproc(ControlHandle theControl,short theCode)2567 pascal void gra_scrollhproc(ControlHandle theControl, short theCode)
2568 {
2569 INTBIG scrollAmt, pos, oldpos;
2570
2571 if (theCode == 0) return;
2572 switch (theCode)
2573 {
2574 case kControlUpButtonPart: scrollAmt = -1; break;
2575 case kControlDownButtonPart: scrollAmt = 1; break;
2576 case kControlPageUpPart: scrollAmt = -10; break;
2577 case kControlPageDownPart: scrollAmt = 10; break;
2578 }
2579 oldpos = GetControlValue(theControl);
2580 pos = oldpos + scrollAmt;
2581 if (pos < 0) pos = 0;
2582 if (pos > 90) pos = 90;
2583 SetControlValue(theControl, pos);
2584 gra_adjusthtext(oldpos);
2585 }
2586
gra_adjustvtext(void)2587 void gra_adjustvtext(void)
2588 {
2589 INTBIG oldScroll, newScroll, delta;
2590
2591 oldScroll = (*gra_TEH)->viewRect.top - (*gra_TEH)->destRect.top;
2592 newScroll = GetControlValue(gra_vScroll) * (*gra_TEH)->lineHeight;
2593 delta = oldScroll - newScroll;
2594 if (delta != 0) TEScroll(0, delta, gra_TEH);
2595 }
2596
gra_adjusthtext(INTBIG oldpos)2597 void gra_adjusthtext(INTBIG oldpos)
2598 {
2599 INTBIG pos, wid, delta;
2600
2601 pos = GetControlValue(gra_hScroll);
2602 wid = ((*gra_TEH)->viewRect.right - (*gra_TEH)->viewRect.left) / 10;
2603 delta = wid * (pos - oldpos);
2604 if (delta != 0) TEScroll(-delta, 0, gra_TEH);
2605 }
2606
gra_setvscroll(void)2607 void gra_setvscroll(void)
2608 {
2609 INTBIG n;
2610
2611 n = (*gra_TEH)->nLines - gra_linesInFolder + 1;
2612 if ((*gra_TEH)->teLength > 0 && (*((*gra_TEH)->hText))[(*gra_TEH)->teLength-1] != '\r') n++;
2613 SetControlMaximum(gra_vScroll, n > 0 ? n : 0);
2614 }
2615
gra_showselect(void)2616 void gra_showselect(void)
2617 {
2618 INTBIG topLine, bottomLine, theLine;
2619
2620 gra_setvscroll();
2621 gra_adjustvtext();
2622
2623 topLine = GetControlValue(gra_vScroll);
2624 bottomLine = topLine + gra_linesInFolder;
2625
2626 if ((*gra_TEH)->selStart < (*gra_TEH)->lineStarts[topLine] ||
2627 (*gra_TEH)->selStart >= (*gra_TEH)->lineStarts[bottomLine])
2628 {
2629 for (theLine = 0; (*gra_TEH)->selStart >= (*gra_TEH)->lineStarts[theLine]; theLine++) ;
2630 SetControlValue(gra_vScroll, theLine - gra_linesInFolder / 2);
2631 gra_adjustvtext();
2632 }
2633 }
2634
2635 /*
2636 * routine to cut text from the messages window if it is current. Returns true
2637 * if sucessful.
2638 */
cutfrommessages(void)2639 BOOLEAN cutfrommessages(void)
2640 {
2641 void io_maccopyhighlighted(void);
2642
2643 /* if a desk accessory wants the "cut" command, stop now */
2644 if (SystemEdit(2) != 0) return(TRUE);
2645
2646 if (gra_messagesinfront)
2647 {
2648 TECut(gra_TEH);
2649 ZeroScrap();
2650 TEToScrap();
2651 return(TRUE);
2652 }
2653 if (el_curwindowpart == NOWINDOWPART) return(FALSE);
2654 if ((el_curwindowpart->state&WINDOWTYPE) == DISPWINDOW)
2655 io_maccopyhighlighted();
2656 return(FALSE);
2657 }
2658
2659 /*
2660 * routine to copy text from the messages window if it is current. Returns true
2661 * if sucessful.
2662 */
copyfrommessages(void)2663 BOOLEAN copyfrommessages(void)
2664 {
2665 void io_maccopyhighlighted(void);
2666
2667 /* if a desk accessory wants the "copy" command, stop now */
2668 if (SystemEdit(3) != 0) return(TRUE);
2669
2670 if (gra_messagesinfront)
2671 {
2672 TECopy(gra_TEH);
2673 ZeroScrap();
2674 TEToScrap();
2675 return(TRUE);
2676 }
2677 if (el_curwindowpart == NOWINDOWPART) return(FALSE);
2678 if ((el_curwindowpart->state&WINDOWTYPE) == DISPWINDOW)
2679 io_maccopyhighlighted();
2680 return(FALSE);
2681 }
2682
2683 /*
2684 * routine to paste text to the messages window if it is current. Returns true
2685 * if sucessful.
2686 */
pastetomessages(void)2687 BOOLEAN pastetomessages(void)
2688 {
2689 /* if a desk accessory wants the "paste" command, stop now */
2690 if (SystemEdit(4) != 0) return(TRUE);
2691
2692 if (gra_messagesinfront)
2693 {
2694 TEFromScrap();
2695 TEPaste(gra_TEH);
2696 return(TRUE);
2697 }
2698 return(FALSE);
2699 }
2700
2701 /*
2702 * routine to get the contents of the system cut buffer
2703 */
getcutbuffer(void)2704 CHAR *getcutbuffer(void)
2705 {
2706 Handle sc;
2707 INTBIG scoffset, len, i;
2708 REGISTER void *infstr;
2709
2710 /* get cut buffer */
2711 sc = NewHandle(0);
2712 len = GetScrap(sc, 'TEXT', (long *)&scoffset);
2713 if (len < 0) ttyputerr(x_("Error %ld reading scrap"), len);
2714 infstr = initinfstr();
2715 for(i=0; i<len; i++) addtoinfstr(infstr, (*sc)[i]);
2716 return(returninfstr(infstr));
2717 }
2718
2719 /*
2720 * routine to set the contents of the system cut buffer to "msg"
2721 */
setcutbuffer(CHAR * msg)2722 void setcutbuffer(CHAR *msg)
2723 {
2724 INTBIG err;
2725
2726 ZeroScrap();
2727 err = PutScrap(estrlen(msg), 'TEXT', msg);
2728 if (err != 0) ttyputerr(x_("Error %ld copying to scrap"), err);
2729 }
2730
2731 static DIALOGITEM gra_fontdialogitems[] =
2732 {
2733 /* 1 */ {0, {136,192,160,256}, BUTTON, N_("OK")},
2734 /* 2 */ {0, {88,192,112,256}, BUTTON, N_("Cancel")},
2735 /* 3 */ {0, {8,24,24,56}, MESSAGE, N_("Font")},
2736 /* 4 */ {0, {24,200,40,232}, MESSAGE, N_("Size")},
2737 /* 5 */ {0, {32,24,160,184}, SCROLL, x_("")},
2738 /* 6 */ {0, {48,192,64,248}, EDITTEXT, x_("")}
2739 };
2740 DIALOG gra_fontdialog = {{50,75,219,340}, N_("Messages Window Font"), 0, 6, gra_fontdialogitems, 0, 0};
2741 /* special items for the font dialog: */
2742 #define DMSF_FONTLIST 5 /* Font list (scroll) */
2743 #define DMSF_FONTSIZE 6 /* Size (edit text) */
2744
setmessagesfont(void)2745 void setmessagesfont(void)
2746 {
2747 INTBIG itemHit, i, tot, which, fontnum;
2748 INTBIG typ, fonttype;
2749 short id;
2750 Handle f;
2751 CHAR line[256];
2752 FontInfo finfo;
2753 void *dia;
2754
2755 /* display the font dialog box */
2756 dia = DiaInitDialog(&gra_fontdialog);
2757 if (dia == 0) return;
2758 DiaInitTextDialog(dia, DMSF_FONTLIST, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1,
2759 SCSELMOUSE|SCDOUBLEQUIT);
2760
2761 /* if there are 'FONT's, then no names will be obtained by "GetResInfo" below!!! */
2762 fonttype = 'FOND';
2763 tot = CountResources(fonttype);
2764 if (tot == 0)
2765 {
2766 fonttype = 'FONT';
2767 tot = CountResources(fonttype);
2768 }
2769 which = fontnum = 0;
2770 for(i=1; i<=tot; i++)
2771 {
2772 SetResLoad(0);
2773 f = GetIndResource(fonttype, i);
2774 GetResInfo(f, &id, (ResType *)&typ, (UCHAR1 *)line);
2775 SetResLoad(1);
2776 if (line[0] == 0) continue;
2777 GetFNum((UCHAR1 *)line, &id);
2778 if (id == gra_messagesfont) which = fontnum;
2779 line[line[0]+1] = 0;
2780 DiaStuffLine(dia, DMSF_FONTLIST, &line[1]);
2781 fontnum++;
2782 }
2783 DiaSelectLine(dia, DMSF_FONTLIST, which);
2784 (void)esnprintf(line, 256, x_("%ld"), gra_messagesfontsize);
2785 DiaSetText(dia, -DMSF_FONTSIZE, line);
2786
2787 /* loop until done */
2788 for(;;)
2789 {
2790 itemHit = DiaNextHit(dia);
2791 if (itemHit == OK || itemHit == CANCEL) break;
2792 }
2793
2794 if (itemHit != CANCEL)
2795 {
2796 (void)estrcpy(&line[1], DiaGetScrollLine(dia, DMSF_FONTLIST, DiaGetCurLine(dia, DMSF_FONTLIST)));
2797 line[0] = estrlen(&line[1]);
2798 GetFNum((UCHAR1 *)line, &id);
2799 i = myatoi(DiaGetText(dia, DMSF_FONTSIZE));
2800 if (i != gra_messagesfontsize || id != gra_messagesfont)
2801 {
2802 if (gra_messageswindow == 0)
2803 {
2804 if (gra_showmessageswindow()) return;
2805 }
2806
2807 gra_messagesfontsize = i;
2808 gra_messagesfont = id;
2809 SetPort(gra_messageswindow);
2810 TextSize(i);
2811 TextFont(id);
2812 GetFontInfo(&finfo);
2813 (*gra_TEH)->txSize = i;
2814 (*gra_TEH)->txFont = id;
2815 (*gra_TEH)->fontAscent = finfo.ascent;
2816 (*gra_TEH)->lineHeight = finfo.ascent + finfo.descent + finfo.leading;
2817 gra_setview(gra_messageswindow);
2818 EraseRect(&gra_messageswindow->portRect);
2819 DrawControls(gra_messageswindow);
2820 DrawGrowIcon(gra_messageswindow);
2821 TEUpdate(&gra_messageswindow->portRect, gra_TEH);
2822
2823 /* save new messages window settings */
2824 gra_savewindowsettings();
2825 }
2826 }
2827 DiaDoneDialog(dia);
2828 }
2829
2830 /*
2831 * Routine to force the module to return with some event so that the user interface will
2832 * relinquish control and let a slice happen.
2833 */
forceslice(void)2834 void forceslice(void)
2835 {
2836 }
2837
2838 /*
2839 * Routine to put the string "s" into the messages window.
2840 * Pops up the messages window if "important" is true.
2841 */
putmessagesstring(CHAR * s,BOOLEAN important)2842 void putmessagesstring(CHAR *s, BOOLEAN important)
2843 {
2844 INTBIG len, insert;
2845 Rect r;
2846 GrafPtr savePort;
2847 WINDOWFRAME *wf;
2848
2849 len = estrlen(s);
2850 GetPort(&savePort);
2851 if (gra_messageswindow == 0)
2852 {
2853 if (!important) return;
2854 if (gra_showmessageswindow()) return;
2855 }
2856
2857 /* see if the messages window occludes any edit window */
2858 if (important)
2859 {
2860 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
2861 {
2862 if (SectRect(&(*((WindowPeek)gra_messageswindow)->strucRgn)->rgnBBox,
2863 &(*((WindowPeek)wf->realwindow)->strucRgn)->rgnBBox, &r) != 0)
2864 {
2865 gra_selectoswindow(gra_messageswindow);
2866 break;
2867 }
2868 }
2869 }
2870
2871 if ((*gra_TEH)->teLength > 30000)
2872 {
2873 /* cut out the top half of the buffer before it overflows */
2874 TESetSelect(0, 15000, gra_TEH);
2875 TEKey(BACKSPACEKEY, gra_TEH);
2876 insert = 32767;
2877 TESetSelect(insert, insert, gra_TEH);
2878 }
2879 TEInsert(s, len, gra_TEH);
2880 TEKey('\r', gra_TEH);
2881 insert = 32767;
2882 TESetSelect(insert, insert, gra_TEH);
2883 gra_showselect();
2884 SetPort(savePort);
2885 }
2886 /*
2887 * Routine to return the name of the key that ends a session from the messages window.
2888 */
getmessageseofkey(void)2889 CHAR *getmessageseofkey(void)
2890 {
2891 return(x_("^D"));
2892 }
2893
2894 /*
2895 * Routine to get a string from the scrolling messages window. Returns zero if end-of-file
2896 * (^D) is typed.
2897 */
getmessagesstring(CHAR * prompt)2898 CHAR *getmessagesstring(CHAR *prompt)
2899 {
2900 EventRecord theEvent;
2901 INTBIG start, end, i, j, ch;
2902 static CHAR outline[256];
2903
2904 if (gra_messageswindow == 0)
2905 {
2906 if (gra_showmessageswindow()) return(x_(""));
2907 }
2908 gra_selectoswindow(gra_messageswindow);
2909
2910 /* show the prompt */
2911 TESetSelect(32767, 32767, gra_TEH);
2912 TEInsert(prompt, estrlen(prompt), gra_TEH);
2913 TESetSelect(32767, 32767, gra_TEH);
2914 start = (*gra_TEH)->selStart;
2915 for(;;)
2916 {
2917 /* continue to force the messages window up */
2918 if (gra_messageswindow == 0)
2919 {
2920 if (gra_showmessageswindow()) return(x_(""));
2921 }
2922 gra_waitforaction(0, &theEvent);
2923 end = (*gra_TEH)->selStart-1;
2924 if (end < start) continue;
2925 ch = (*(*gra_TEH)->hText)[end];
2926 if (ch == '\r' || ch == 4) break;
2927 }
2928 TEKey(BACKSPACEKEY, gra_TEH);
2929 TEKey('\r', gra_TEH);
2930 if (ch == 4) return(0);
2931 j = 0;
2932 for(i=start; i<end; i++) outline[j++] = (*(*gra_TEH)->hText)[i];
2933 outline[j] = 0;
2934 return(outline);
2935 }
2936
2937 /*
2938 * Routine to remove the last character from the scrolling messages window.
2939 * Called from "usrterminal.c"
2940 */
gra_backup(void)2941 void gra_backup(void)
2942 {
2943 GrafPtr savePort;
2944
2945 GetPort(&savePort);
2946 if (gra_messageswindow == 0)
2947 {
2948 if (gra_showmessageswindow()) return;
2949 }
2950 TEKey(BACKSPACEKEY, gra_TEH);
2951 gra_showselect();
2952 SetPort(savePort);
2953 }
2954
2955 /*
2956 * Routine to clear all text from the messages window.
2957 */
clearmessageswindow(void)2958 void clearmessageswindow(void)
2959 {
2960 TESetSelect(0, 32767, gra_TEH);
2961 TEDelete(gra_TEH);
2962 }
2963
2964 /******************** STATUS BAR ROUTINES ********************/
2965
2966 /*
2967 * Routine to return the number of status lines on the display.
2968 */
ttynumstatuslines(void)2969 INTBIG ttynumstatuslines(void)
2970 {
2971 return(MAXSTATUSLINES);
2972 }
2973
2974 /*
2975 * Routine to display "message" in the status "field" of window "frame" (uses all windows
2976 * if "frame" is zero). If "cancrop" is false, field cannot be cropped and should be
2977 * replaced with "*" if there isn't room.
2978 */
ttysetstatusfield(WINDOWFRAME * mwwant,STATUSFIELD * sf,CHAR * message,BOOLEAN cancrop)2979 void ttysetstatusfield(WINDOWFRAME *mwwant, STATUSFIELD *sf, CHAR *message, BOOLEAN cancrop)
2980 {
2981 INTBIG len, i, width, winwid, startx, endx;
2982 Rect clear;
2983 REGISTER WINDOWFRAME *wf;
2984
2985 if (sf == 0) return;
2986 if (sf->line != 0 && sf->label[0] == 0) return;
2987
2988 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
2989 {
2990 if (wf->floating) continue;
2991 if (mwwant != NOWINDOWFRAME && mwwant != wf) continue;
2992
2993 /* construct the status line */
2994 len = estrlen(sf->label);
2995 if (len + estrlen(message) >= MAXLOCALSTRING-1)
2996 {
2997 estrcpy(&gra_localstring[1], sf->label);
2998 i = MAXLOCALSTRING - len - 2;
2999 estrncat(&gra_localstring[1], message, i);
3000 gra_localstring[MAXLOCALSTRING-1] = 0;
3001 } else
3002 {
3003 esnprintf(&gra_localstring[1], MAXLOCALSTRING-1, x_("%s%s"), sf->label, message);
3004 }
3005 len = estrlen(&gra_localstring[1]);
3006 while (len > 0 && gra_localstring[len] == ' ') gra_localstring[len--] = 0;
3007
3008 /* special case for window title */
3009 if (sf->line == 0)
3010 {
3011 gra_localstring[0] = estrlen(&gra_localstring[1]);
3012 SetWTitle((WindowPtr)wf->realwindow, (UCHAR1 *)gra_localstring);
3013 return;
3014 }
3015
3016 /* determine how much room there is for the status field */
3017 SetPort((WindowPtr)wf->realwindow);
3018 winwid = wf->realwindow->portRect.right - wf->realwindow->portRect.left - SBARWIDTH;
3019 startx = winwid * sf->startper / 100 + wf->realwindow->portRect.left;
3020 endx = winwid * sf->endper / 100 + wf->realwindow->portRect.left;
3021
3022 /* make sure the message fits */
3023 width = TextWidth(&gra_localstring[1], 0, len);
3024 if (width > endx-startx && !cancrop)
3025 {
3026 for(i=estrlen(sf->label); gra_localstring[i+1] != 0; i++)
3027 gra_localstring[i+1] = '*';
3028 }
3029 while (len > 0 && width > endx-startx)
3030 {
3031 len--;
3032 width = TextWidth(&gra_localstring[1], 0, len);
3033 }
3034
3035 /* display the field */
3036 TextFont(SFONT);
3037 TextSize(9);
3038 TextMode(srcOr);
3039 clear.left = startx;
3040 clear.right = endx;
3041 clear.bottom = wf->realwindow->portRect.bottom;
3042 clear.top = clear.bottom - SBARHEIGHT+1;
3043 EraseRect(&clear);
3044 if (len > 0)
3045 {
3046 MoveTo(startx, wf->realwindow->portRect.bottom-4);
3047 DrawText(&gra_localstring[1], 0, len);
3048 }
3049 }
3050 }
3051
3052 /*
3053 * Routine to free status field object "sf".
3054 */
ttyfreestatusfield(STATUSFIELD * sf)3055 void ttyfreestatusfield(STATUSFIELD *sf)
3056 {
3057 efree(sf->label);
3058 efree((CHAR *)sf);
3059 }
3060
3061 /******************** GRAPHICS CONTROL ROUTINES ********************/
3062
flushscreen(void)3063 void flushscreen(void)
3064 {
3065 WINDOWFRAME *wf;
3066 Rect dr, copyrect;
3067
3068 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
3069 {
3070 /* if screen has not changed, stop now */
3071 if (!wf->offscreendirty) continue;
3072 wf->offscreendirty = FALSE;
3073
3074 /* make sure region falls inside screen */
3075 SetPort((WindowPtr)wf->realwindow);
3076 copyrect.left = wf->copyleft; copyrect.right = wf->copyright;
3077 copyrect.top = wf->copytop; copyrect.bottom = wf->copybottom;
3078 if (copyrect.left < 0) copyrect.left = 0;
3079 if (copyrect.right > (*wf->window->portPixMap)->bounds.right)
3080 copyrect.right = (*wf->window->portPixMap)->bounds.right;
3081 if (copyrect.top < 0) copyrect.top = 0;
3082 if (copyrect.bottom > (*wf->window->portPixMap)->bounds.bottom)
3083 copyrect.bottom = (*wf->window->portPixMap)->bounds.bottom;
3084
3085 (void)LockPixels(wf->window->portPixMap);
3086 if (!wf->floating)
3087 {
3088 CopyBits((BitMap *)*(wf->window->portPixMap), (BitMap *)*wf->realwindow->portPixMap,
3089 ©rect, ©rect, srcCopy, 0L);
3090 } else
3091 {
3092 dr = copyrect;
3093 dr.top += FLOATINGHEADERSIZE;
3094 dr.bottom += FLOATINGHEADERSIZE;
3095 CopyBits((BitMap *)*(wf->window->portPixMap), (BitMap *)*wf->realwindow->portPixMap,
3096 ©rect, &dr, srcCopy, 0L);
3097 }
3098 UnlockPixels(wf->window->portPixMap);
3099 }
3100 }
3101
3102 /*
3103 * Routine to accumulate the rectangle of change to the offscreen PixMap
3104 */
gra_setrect(WINDOWFRAME * wf,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy)3105 void gra_setrect(WINDOWFRAME *wf, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy)
3106 {
3107 static INTBIG checktimefreq = 0;
3108
3109 if (wf->offscreendirty)
3110 {
3111 if (lx < wf->copyleft) wf->copyleft = lx;
3112 if (hx > wf->copyright) wf->copyright = hx;
3113 if (ly < wf->copytop) wf->copytop = ly;
3114 if (hy > wf->copybottom) wf->copybottom = hy;
3115 } else
3116 {
3117 wf->copyleft = lx; wf->copyright = hx;
3118 wf->copytop = ly; wf->copybottom = hy;
3119 wf->offscreendirty = TRUE;
3120 wf->starttime = TickCount();
3121 }
3122
3123 /* flush the screen every two seconds */
3124 checktimefreq++;
3125 if (checktimefreq > 10000)
3126 {
3127 checktimefreq = 0;
3128 if (TickCount() - wf->starttime > FLUSHTICKS) flushscreen();
3129 }
3130 }
3131
gra_reloadmap(void)3132 void gra_reloadmap(void)
3133 {
3134 REGISTER VARIABLE *varred, *vargreen, *varblue;
3135
3136 varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
3137 vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
3138 varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
3139 if (varred == NOVARIABLE || vargreen == NOVARIABLE || varblue == NOVARIABLE) return;
3140 colormapload((INTBIG *)varred->addr, (INTBIG *)vargreen->addr, (INTBIG *)varblue->addr, 0, 255);
3141 }
3142
colormapload(INTBIG * red,INTBIG * green,INTBIG * blue,INTBIG low,INTBIG high)3143 void colormapload(INTBIG *red, INTBIG *green, INTBIG *blue, INTBIG low, INTBIG high)
3144 {
3145 INTBIG i;
3146 CTabHandle clut;
3147 REGISTER WINDOWFRAME *wf;
3148 RGBColor fg, bg;
3149
3150 clut = 0;
3151 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
3152 {
3153 clut = (*wf->window->portPixMap)->pmTable;
3154 for(i=low; i<=high; i++)
3155 {
3156 (*clut)->ctTable[i].rgb.red = red[i-low] << 8;
3157 (*clut)->ctTable[i].rgb.green = green[i-low] << 8;
3158 (*clut)->ctTable[i].rgb.blue = blue[i-low] << 8;
3159 if (i == 255)
3160 {
3161 (*clut)->ctTable[i].rgb.red = (255-red[i-low]) << 8;
3162 (*clut)->ctTable[i].rgb.green = (255-green[i-low]) << 8;
3163 (*clut)->ctTable[i].rgb.blue = (255-blue[i-low]) << 8;
3164 }
3165 }
3166 (*clut)->ctSeed++;
3167
3168 /* mark the entire screen for redrawing */
3169 if (low == 0 && high == 255)
3170 gra_setrect(wf, 0, (*wf->window->portPixMap)->bounds.right, 0,
3171 (*wf->window->portPixMap)->bounds.bottom);
3172 }
3173
3174 /* recache table and all PixMaps */
3175 if (clut != 0) CTabChanged(clut);
3176
3177 /* set the messages window colors */
3178 if (low == 0 && high == 255 && gra_messageswindow != 0)
3179 {
3180 fg.red = red[CELLTXT] << 8;
3181 fg.green = green[CELLTXT] << 8;
3182 fg.blue = blue[CELLTXT] << 8;
3183 bg.red = red[0] << 8;
3184 bg.green = green[0] << 8;
3185 bg.blue = blue[0] << 8;
3186 SetPort(gra_messageswindow);
3187 RGBForeColor(&fg);
3188 RGBBackColor(&bg);
3189 InvalRect(&gra_messageswindow->portRect);
3190 }
3191 }
3192
3193 /*
3194 * helper routine to set the cursor shape to "state"
3195 */
setdefaultcursortype(INTBIG state)3196 void setdefaultcursortype(INTBIG state)
3197 {
3198 if (us_cursorstate == state) return;
3199
3200 switch (state)
3201 {
3202 case NORMALCURSOR:
3203 SetCursor(&qd.arrow);
3204 break;
3205 case WANTTTYCURSOR:
3206 if (gra_wantttyCurs != 0L) SetCursor(&(**gra_wantttyCurs)); else
3207 SetCursor(&qd.arrow);
3208 break;
3209 case PENCURSOR:
3210 if (gra_penCurs != 0L) SetCursor(&(**gra_penCurs)); else
3211 SetCursor(&qd.arrow);
3212 break;
3213 case NULLCURSOR:
3214 if (gra_nullCurs != 0L) SetCursor(&(**gra_nullCurs)); else
3215 SetCursor(&qd.arrow);
3216 break;
3217 case MENUCURSOR:
3218 if (gra_menuCurs != 0L) SetCursor(&(**gra_menuCurs)); else
3219 SetCursor(&qd.arrow);
3220 break;
3221 case HANDCURSOR:
3222 if (gra_handCurs != 0L) SetCursor(&(**gra_handCurs)); else
3223 SetCursor(&qd.arrow);
3224 break;
3225 case TECHCURSOR:
3226 if (gra_techCurs != 0L) SetCursor(&(**gra_techCurs)); else
3227 SetCursor(&qd.arrow);
3228 break;
3229 case IBEAMCURSOR:
3230 if (gra_ibeamCurs != 0L) SetCursor(&(**gra_ibeamCurs)); else
3231 SetCursor(&qd.arrow);
3232 break;
3233 case LRCURSOR:
3234 if (gra_lrCurs != 0L) SetCursor(&(**gra_lrCurs)); else
3235 SetCursor(&qd.arrow);
3236 break;
3237 case UDCURSOR:
3238 if (gra_udCurs != 0L) SetCursor(&(**gra_udCurs)); else
3239 SetCursor(&qd.arrow);
3240 break;
3241 }
3242 us_cursorstate = state;
3243 }
3244
3245 /*
3246 * Routine to change the default cursor (to indicate modes).
3247 */
setnormalcursor(INTBIG curs)3248 void setnormalcursor(INTBIG curs)
3249 {
3250 us_normalcursor = curs;
3251 }
3252
3253 /******************** LINE DRAWING ********************/
3254
screeninvertline(WINDOWPART * win,INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2)3255 void screeninvertline(WINDOWPART *win, INTBIG x1, INTBIG y1, INTBIG x2, INTBIG y2)
3256 {
3257 REGISTER WINDOWFRAME *wf;
3258
3259 /* make sure the image buffer has not moved */
3260 wf = win->frame;
3261 if ((UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap) != wf->rowstart[0])
3262 gra_rebuildrowstart(wf);
3263
3264 gra_invertline(win, x1, y1, x2, y2);
3265 }
screendrawline(WINDOWPART * win,INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2,GRAPHICS * desc,INTBIG texture)3266 void screendrawline(WINDOWPART *win, INTBIG x1, INTBIG y1, INTBIG x2, INTBIG y2, GRAPHICS *desc, INTBIG texture)
3267 {
3268 REGISTER WINDOWFRAME *wf;
3269
3270 /* make sure the image buffer has not moved */
3271 wf = win->frame;
3272 if ((UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap) != wf->rowstart[0])
3273 gra_rebuildrowstart(wf);
3274
3275 gra_drawline(win, x1, y1, x2, y2, desc, texture);
3276 }
3277
3278 /******************** POLYGON DRAWING ********************/
3279
3280 /*
3281 * routine to draw a polygon in the arrays (x, y) with "count" points.
3282 */
screendrawpolygon(WINDOWPART * win,INTBIG * x,INTBIG * y,INTBIG count,GRAPHICS * desc)3283 void screendrawpolygon(WINDOWPART *win, INTBIG *x, INTBIG *y, INTBIG count, GRAPHICS *desc)
3284 {
3285 REGISTER WINDOWFRAME *wf;
3286
3287 /* make sure the image buffer has not moved */
3288 wf = win->frame;
3289 if ((UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap) != wf->rowstart[0])
3290 gra_rebuildrowstart(wf);
3291
3292 gra_drawpolygon(win, x, y, count, desc);
3293 }
3294
3295 /******************** BOX DRAWING ********************/
3296
screendrawbox(WINDOWPART * win,INTBIG lowx,INTBIG highx,INTBIG lowy,INTBIG highy,GRAPHICS * desc)3297 void screendrawbox(WINDOWPART *win, INTBIG lowx, INTBIG highx, INTBIG lowy, INTBIG highy, GRAPHICS *desc)
3298 {
3299 REGISTER WINDOWFRAME *wf;
3300
3301 /* make sure the image buffer has not moved */
3302 wf = win->frame;
3303 if ((UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap) != wf->rowstart[0])
3304 gra_rebuildrowstart(wf);
3305
3306 gra_drawbox(win, lowx, highx, lowy, highy, desc);
3307 }
3308
3309 /*
3310 * routine to invert the bits in the box from (lowx, lowy) to (highx, highy)
3311 */
screeninvertbox(WINDOWPART * win,INTBIG lowx,INTBIG highx,INTBIG lowy,INTBIG highy)3312 void screeninvertbox(WINDOWPART *win, INTBIG lowx, INTBIG highx, INTBIG lowy, INTBIG highy)
3313 {
3314 Rect r;
3315 REGISTER WINDOWFRAME *wf;
3316
3317 wf = win->frame;
3318
3319 r.left = lowx; r.right = highx + 1;
3320 r.bottom = wf->revy-lowy + 1; r.top = wf->revy-highy;
3321
3322 /* prepare for graphics */
3323 SetGWorld(wf->window, 0L);
3324 (void)LockPixels(wf->window->portPixMap);
3325
3326 PenMode(patXor);
3327 PenPat((ConstPatternParam)&qd.black);
3328 PaintRect(&r);
3329
3330 UnlockPixels(wf->window->portPixMap);
3331 SetGWorld(wf->realwindow, gra_origgdevh);
3332
3333 gra_setrect(wf, lowx, highx + 1, wf->revy-highy, wf->revy-lowy + 1);
3334 }
3335
3336 /*
3337 * routine to move bits on the display starting with the area at
3338 * (sx,sy) and ending at (dx,dy). The size of the area to be
3339 * moved is "wid" by "hei".
3340 */
screenmovebox(WINDOWPART * win,INTBIG sx,INTBIG sy,INTBIG wid,INTBIG hei,INTBIG dx,INTBIG dy)3341 void screenmovebox(WINDOWPART *win, INTBIG sx, INTBIG sy, INTBIG wid, INTBIG hei, INTBIG dx, INTBIG dy)
3342 {
3343 Rect from, to;
3344 INTBIG xsize, ysize, x, y, dir, fromstart, frominc, tostart, toinc;
3345 REGISTER UCHAR1 *frombase, *tobase;
3346 REGISTER WINDOWFRAME *wf;
3347
3348 wf = win->frame;
3349
3350 /* make sure the image buffer has not moved */
3351 if ((UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap) != wf->rowstart[0])
3352 gra_rebuildrowstart(wf);
3353
3354 /* setup source rectangle */
3355 from.left = sx;
3356 from.right = from.left + wid;
3357 from.top = wf->revy + 1 - sy - hei;
3358 from.bottom = from.top + hei;
3359
3360 /* setup destination rectangle */
3361 to.left = dx;
3362 to.right = to.left + wid;
3363 to.top = wf->revy + 1 - dy - hei;
3364 to.bottom = to.top + hei;
3365
3366 /* determine size of bits to move */
3367 xsize = wid; ysize = hei;
3368
3369 /* determine direction of bit copy */
3370 if (from.left < to.left) dir = 1; else dir = 0;
3371 if (from.top < to.top)
3372 {
3373 fromstart = from.bottom-1; frominc = -1;
3374 tostart = to.bottom-1; toinc = -1;
3375 } else
3376 {
3377 fromstart = from.top; frominc = 1;
3378 tostart = to.top; toinc = 1;
3379 }
3380
3381 /* move the bits */
3382 if (dir == 0)
3383 {
3384 /* normal forward copy in X */
3385 for(y = 0; y < ysize; y++)
3386 {
3387 frombase = wf->rowstart[fromstart] + from.left;
3388 fromstart += frominc;
3389 tobase = wf->rowstart[tostart] + to.left;
3390 tostart += toinc;
3391 for(x = 0; x < xsize; x++) *tobase++ = *frombase++;
3392 }
3393 } else
3394 {
3395 /* reverse copy in X */
3396 for(y = 0; y < ysize; y++)
3397 {
3398 frombase = wf->rowstart[fromstart] + from.right;
3399 fromstart += frominc;
3400 tobase = wf->rowstart[tostart] + to.right;
3401 tostart += toinc;
3402 for(x = 0; x < xsize; x++) *tobase-- = *frombase--;
3403 }
3404 }
3405 gra_setrect(wf, to.left, to.right, to.top, to.bottom);
3406 }
3407
3408 /*
3409 * routine to save the contents of the box from "lx" to "hx" in X and from
3410 * "ly" to "hy" in Y. A code is returned that identifies this box for
3411 * overwriting and restoring. The routine returns -1 if there is a error.
3412 */
screensavebox(WINDOWPART * win,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy)3413 INTBIG screensavebox(WINDOWPART *win, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy)
3414 {
3415 SAVEDBOX *box;
3416 REGISTER INTBIG toindex, xsize, ysize;
3417 REGISTER INTBIG i, x, y, truelx, truehx;
3418 REGISTER WINDOWFRAME *wf;
3419
3420 wf = win->frame;
3421
3422 /* make sure the image buffer has not moved */
3423 if ((UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap) != wf->rowstart[0])
3424 gra_rebuildrowstart(wf);
3425
3426 truelx = lx; truehx = hx;
3427 i = ly; ly = wf->revy-hy; hy = wf->revy-i;
3428 xsize = hx-lx+1;
3429 ysize = hy-ly+1;
3430
3431 box = (SAVEDBOX *)emalloc((sizeof (SAVEDBOX)), us_tool->cluster);
3432 if (box == 0) return(-1);
3433 box->pix = (UCHAR1 *)emalloc(xsize * ysize, us_tool->cluster);
3434 if (box->pix == 0) return(-1);
3435 box->win = win;
3436 box->nextsavedbox = gra_firstsavedbox;
3437 gra_firstsavedbox = box;
3438 box->lx = lx; box->hx = hx;
3439 box->ly = ly; box->hy = hy;
3440 box->truelx = truelx; box->truehx = truehx;
3441
3442 /* move the bits */
3443 toindex = 0;
3444 for(y = ly; y <= hy; y++)
3445 {
3446 for(x = lx; x <= hx; x++)
3447 box->pix[toindex++] = wf->rowstart[y][x];
3448 }
3449
3450 return((INTBIG)box);
3451 }
3452
3453 /*
3454 * routine to shift the saved box "code" so that it is restored in a different location,
3455 * offset by (dx,dy)
3456 */
screenmovesavedbox(INTBIG code,INTBIG dx,INTBIG dy)3457 void screenmovesavedbox(INTBIG code, INTBIG dx, INTBIG dy)
3458 {
3459 REGISTER SAVEDBOX *box;
3460 REGISTER WINDOWFRAME *wf;
3461
3462 if (code == -1) return;
3463 box = (SAVEDBOX *)code;
3464 wf = box->win->frame;
3465 box->truelx += dx; box->truehx += dx;
3466 box->lx += dx; box->hx += dx;
3467 box->ly -= dy; box->hy -= dy;
3468 }
3469
3470 /*
3471 * routine to restore saved box "code" to the screen. "destroy" is:
3472 * 0 restore box, do not free memory
3473 * 1 restore box, free memory
3474 * -1 free memory
3475 */
screenrestorebox(INTBIG code,INTBIG destroy)3476 void screenrestorebox(INTBIG code, INTBIG destroy)
3477 {
3478 REGISTER SAVEDBOX *box, *lbox, *tbox;
3479 REGISTER INTBIG fromindex;
3480 REGISTER INTBIG x, y;
3481 REGISTER WINDOWFRAME *wf;
3482
3483 /* get the box */
3484 if (code == -1) return;
3485 box = (SAVEDBOX *)code;
3486 wf = box->win->frame;
3487
3488 /* move the bits */
3489 if (destroy >= 0)
3490 {
3491 /* make sure the image buffer has not moved */
3492 if ((UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap) != wf->rowstart[0])
3493 gra_rebuildrowstart(wf);
3494 fromindex = 0;
3495 for(y = box->ly; y <= box->hy; y++)
3496 for(x = box->lx; x <= box->hx; x++)
3497 wf->rowstart[y][x] = box->pix[fromindex++];
3498 gra_setrect(wf, box->truelx, box->truehx+1, box->ly, box->hy+1);
3499 }
3500
3501 /* destroy this box's memory if requested */
3502 if (destroy != 0)
3503 {
3504 lbox = NOSAVEDBOX;
3505 for(tbox = gra_firstsavedbox; tbox != NOSAVEDBOX; tbox = tbox->nextsavedbox)
3506 {
3507 if (tbox == box) break;
3508 lbox = tbox;
3509 }
3510 if (lbox == NOSAVEDBOX) gra_firstsavedbox = box->nextsavedbox; else
3511 lbox->nextsavedbox = box->nextsavedbox;
3512 efree((CHAR *)box->pix);
3513 efree((CHAR *)box);
3514 }
3515 }
3516
3517 /******************** TEXT DRAWING ********************/
3518
3519 /*
3520 * Routine to find face with name "facename" and to return
3521 * its index in list of used fonts. If font was not used before,
3522 * then it is appended to list of used fonts.
3523 * If font "facename" is not available on the system, -1 is returned.
3524 */
screenfindface(CHAR * facename)3525 INTBIG screenfindface(CHAR *facename)
3526 {
3527 INTBIG i;
3528
3529 for (i = 0; i < gra_numfaces; i++)
3530 if (namesame(facename, gra_facelist[i]) == 0) return(i);
3531 return(-1);
3532 }
3533
3534 /*
3535 * Routine to return the number of typefaces used (when "all" is FALSE)
3536 * or available on the system (when "all" is TRUE)
3537 * and to return their names in the array "list".
3538 * "screenfindface
3539 */
screengetfacelist(CHAR *** list,BOOLEAN all)3540 INTBIG screengetfacelist(CHAR ***list, BOOLEAN all)
3541 {
3542 Handle f;
3543 INTBIG i, tot;
3544 short id;
3545 INTBIG typ, fonttype;
3546 CHAR line[256];
3547
3548 if (gra_numfaces == 0)
3549 {
3550 fonttype = 'FOND';
3551 tot = CountResources(fonttype);
3552 if (tot == 0)
3553 {
3554 fonttype = 'FONT';
3555 tot = CountResources(fonttype);
3556 }
3557 gra_facelist = (CHAR **)emalloc((tot+1) * (sizeof (CHAR *)), us_tool->cluster);
3558 if (gra_facelist == 0) return(0);
3559 gra_faceid = (INTBIG *)emalloc((tot+1) * SIZEOFINTBIG, us_tool->cluster);
3560 if (gra_faceid == 0) return(0);
3561 (void)allocstring(&gra_facelist[0], _("DEFAULT FACE"), us_tool->cluster);
3562 gra_numfaces = 1;
3563 for(i=1; i<=tot; i++)
3564 {
3565 SetResLoad(0);
3566 f = GetIndResource(fonttype, i);
3567 GetResInfo(f, &id, (ResType *)&typ, (UCHAR1 *)line);
3568 SetResLoad(1);
3569 if (line[0] == 0) continue;
3570 GetFNum((UCHAR1 *)line, &id);
3571 line[line[0]+1] = 0;
3572 (void)allocstring(&gra_facelist[gra_numfaces], &line[1], us_tool->cluster);
3573 gra_faceid[gra_numfaces] = id;
3574 gra_numfaces++;
3575 }
3576 if (gra_numfaces > VTMAXFACE)
3577 {
3578 ttyputerr(_("Warning: found %ld fonts, but can only keep track of %d"), gra_numfaces,
3579 VTMAXFACE);
3580 gra_numfaces = VTMAXFACE;
3581 }
3582 }
3583 *list = gra_facelist;
3584 return(gra_numfaces);
3585 }
3586 /*
3587 * Routine to return the default typeface used on the screen.
3588 */
screengetdefaultfacename(void)3589 CHAR *screengetdefaultfacename(void)
3590 {
3591 return(x_("Helvetica"));
3592 }
3593
3594 INTBIG gra_textrotation = 0;
3595
screensettextinfo(WINDOWPART * win,TECHNOLOGY * tech,UINTBIG * descript)3596 void screensettextinfo(WINDOWPART *win, TECHNOLOGY *tech, UINTBIG *descript)
3597 {
3598 REGISTER INTBIG size, style, face;
3599 REGISTER INTBIG fontid;
3600 REGISTER WINDOWFRAME *wf;
3601 CHAR **facelist;
3602
3603 gra_texttoosmall = FALSE;
3604 size = TDGETSIZE(descript);
3605
3606 /* make sure the temp buffer exists */
3607 if (gra_textbuf == 0) gra_setuptextbuffer(100, 25);
3608
3609 /* set sizes in this buffer */
3610 SetGWorld(gra_textbuf, 0L);
3611 if (size == TXTEDITOR)
3612 {
3613 TextFont(TFONT);
3614 TextSize(10);
3615 gra_textrotation = 0;
3616 } else if (size == TXTMENU)
3617 {
3618 TextFont(MFONT);
3619 TextSize(12);
3620 gra_textrotation = 0;
3621 } else
3622 {
3623 size = truefontsize(size, win, tech);
3624 if (size < 1)
3625 {
3626 gra_texttoosmall = TRUE;
3627 wf = win->frame;
3628 SetGWorld(wf->realwindow, gra_origgdevh);
3629 return;
3630 }
3631 if (size < MINIMUMTEXTSIZE) size = MINIMUMTEXTSIZE;
3632 TextSize(size);
3633
3634 style = 0;
3635 if (TDGETITALIC(descript) != 0) style |= italic;
3636 if (TDGETBOLD(descript) != 0) style |= bold;
3637 if (TDGETUNDERLINE(descript) != 0) style |= underline;
3638 gra_textrotation = TDGETROTATION(descript);
3639 TextFace(style);
3640
3641 face = TDGETFACE(descript);
3642 fontid = EFONT;
3643 if (face > 0)
3644 {
3645 if (gra_numfaces == 0) (void)screengetfacelist(&facelist, FALSE);
3646 if (face < gra_numfaces)
3647 fontid = gra_faceid[face];
3648 }
3649 TextFont(fontid);
3650 }
3651 GetFontInfo(&gra_curfontinfo);
3652
3653 /* restore the world */
3654 wf = win->frame;
3655 SetGWorld(wf->realwindow, gra_origgdevh);
3656 }
3657
screengettextsize(WINDOWPART * win,CHAR * str,INTBIG * x,INTBIG * y)3658 void screengettextsize(WINDOWPART *win, CHAR *str, INTBIG *x, INTBIG *y)
3659 {
3660 REGISTER INTBIG wid, hei, len;
3661 REGISTER WINDOWFRAME *wf;
3662 if (gra_texttoosmall)
3663 {
3664 *x = *y = 0;
3665 return;
3666 }
3667
3668 /* make sure the temp buffer exists */
3669 if (gra_textbuf == 0) gra_setuptextbuffer(100, 25);
3670
3671 /* determine text size in this buffer */
3672 SetGWorld(gra_textbuf, 0L);
3673 len = estrlen(str);
3674 wid = TextWidth(str, 0, len);
3675 hei = gra_curfontinfo.ascent + gra_curfontinfo.descent;
3676 switch (gra_textrotation)
3677 {
3678 case 0: /* normal */
3679 *x = wid;
3680 *y = hei;
3681 break;
3682 case 1: /* 90 degrees counterclockwise */
3683 *x = -hei;
3684 *y = wid;
3685 break;
3686 case 2: /* 180 degrees */
3687 *x = -wid;
3688 *y = -hei;
3689 break;
3690 case 3: /* 90 degrees clockwise */
3691 *x = hei;
3692 *y = -wid;
3693 break;
3694 }
3695
3696 /* restore the world */
3697 wf = win->frame;
3698 SetGWorld(wf->realwindow, gra_origgdevh);
3699 }
3700
screendrawtext(WINDOWPART * win,INTBIG atx,INTBIG aty,CHAR * s,GRAPHICS * desc)3701 void screendrawtext(WINDOWPART *win, INTBIG atx, INTBIG aty, CHAR *s, GRAPHICS *desc)
3702 {
3703 REGISTER WINDOWFRAME *wf;
3704
3705 if (gra_texttoosmall) return;
3706
3707 /* make sure the image buffer has not moved */
3708 wf = win->frame;
3709 if ((UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap) != wf->rowstart[0])
3710 gra_rebuildrowstart(wf);
3711
3712 gra_drawtext(win, atx, aty, gra_textrotation, s, desc);
3713 }
3714
gettextbits(WINDOWPART * win,CHAR * msg,INTBIG * wid,INTBIG * hei,UCHAR1 *** rowstart)3715 BOOLEAN gettextbits(WINDOWPART *win, CHAR *msg, INTBIG *wid, INTBIG *hei, UCHAR1 ***rowstart)
3716 {
3717 REGISTER INTBIG len;
3718 Rect sr;
3719 REGISTER WINDOWFRAME *wf;
3720
3721 len = estrlen(msg);
3722 if (len == 0 || gra_texttoosmall)
3723 {
3724 *wid = *hei = 0;
3725 return(FALSE);
3726 }
3727
3728 wf = win->frame;
3729
3730 /* make sure the temp buffer exists */
3731 if (gra_textbuf == 0) gra_setuptextbuffer(100, 25);
3732
3733 /* determine string size */
3734 SetGWorld(gra_textbuf, 0L);
3735 *wid = TextWidth(msg, 0, len);
3736 *hei = gra_curfontinfo.ascent + gra_curfontinfo.descent;
3737
3738 /* make sure the temp buffer is big enough */
3739 gra_setuptextbuffer(*wid, *hei);
3740
3741 /* write to the temp buffer */
3742 sr.left = 0; sr.right = *wid;
3743 sr.top = 0; sr.bottom = *hei;
3744 EraseRect(&sr);
3745 TextMode(srcCopy);
3746 MoveTo(0, gra_curfontinfo.ascent);
3747 DrawText(msg, 0, len);
3748 SetGWorld(wf->realwindow, gra_origgdevh);
3749 *rowstart = gra_textbufrowstart;
3750 SetFontLock(1);
3751
3752 /* recache pointers if main window buffer moved */
3753 if ((UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap) != wf->rowstart[0])
3754 gra_rebuildrowstart(wf);
3755 return(FALSE);
3756 }
3757
gra_setuptextbuffer(INTBIG width,INTBIG height)3758 void gra_setuptextbuffer(INTBIG width, INTBIG height)
3759 {
3760 Rect r;
3761 REGISTER INTBIG i, bytes;
3762 REGISTER UCHAR1 *addr;
3763
3764 if (width <= gra_textbufwid && height <= gra_textbufhei) return;
3765
3766 r.left = 0;
3767 r.right = width;
3768 r.top = 0;
3769 r.bottom = height;
3770 if (gra_textbuf == 0)
3771 {
3772 NewGWorld(&gra_textbuf, 8, &r, 0L, 0L, 0);
3773 (void)LockPixels(gra_textbuf->portPixMap);
3774 } else
3775 {
3776 UpdateGWorld(&gra_textbuf, 8, &r, 0L, 0L, 0);
3777 (void)LockPixels(gra_textbuf->portPixMap);
3778 DisposePtr((Ptr)gra_textbufrowstart);
3779 }
3780 gra_textbufrowstart = (UCHAR1 **)NewPtr(height * (sizeof (UCHAR1 *)));
3781 bytes = (*gra_textbuf->portPixMap)->rowBytes & 0x7FFF;
3782 addr = (UCHAR1 *)GetPixBaseAddr(gra_textbuf->portPixMap);
3783 for(i=0; i<height; i++)
3784 {
3785 gra_textbufrowstart[i] = addr;
3786 addr += bytes;
3787 }
3788 gra_textbufwid = width; gra_textbufhei = height;
3789 }
3790
3791 /******************** CIRCLE DRAWING ********************/
3792
screendrawcircle(WINDOWPART * win,INTBIG atx,INTBIG aty,INTBIG radius,GRAPHICS * desc)3793 void screendrawcircle(WINDOWPART *win, INTBIG atx, INTBIG aty, INTBIG radius, GRAPHICS *desc)
3794 {
3795 REGISTER WINDOWFRAME *wf;
3796
3797 /* make sure the image buffer has not moved */
3798 wf = win->frame;
3799 if ((UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap) != wf->rowstart[0])
3800 gra_rebuildrowstart(wf);
3801
3802 gra_drawcircle(win, atx, aty, radius, desc);
3803 }
3804
screendrawthickcircle(WINDOWPART * win,INTBIG atx,INTBIG aty,INTBIG radius,GRAPHICS * desc)3805 void screendrawthickcircle(WINDOWPART *win, INTBIG atx, INTBIG aty, INTBIG radius,
3806 GRAPHICS *desc)
3807 {
3808 REGISTER WINDOWFRAME *wf;
3809
3810 /* make sure the image buffer has not moved */
3811 wf = win->frame;
3812 if ((UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap) != wf->rowstart[0])
3813 gra_rebuildrowstart(wf);
3814
3815 gra_drawthickcircle(win, atx, aty, radius, desc);
3816 }
3817
3818 /******************** DISC DRAWING ********************/
3819
3820 /*
3821 * routine to draw a filled-in circle at (atx,aty) with radius "radius"
3822 */
screendrawdisc(WINDOWPART * win,INTBIG atx,INTBIG aty,INTBIG radius,GRAPHICS * desc)3823 void screendrawdisc(WINDOWPART *win, INTBIG atx, INTBIG aty, INTBIG radius, GRAPHICS *desc)
3824 {
3825 REGISTER WINDOWFRAME *wf;
3826
3827 /* make sure the image buffer has not moved */
3828 wf = win->frame;
3829 if ((UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap) != wf->rowstart[0])
3830 gra_rebuildrowstart(wf);
3831
3832 gra_drawdisc(win, atx, aty, radius, desc);
3833 }
3834
3835 /******************** ARC DRAWING ********************/
3836
3837 /*
3838 * draws a thin arc centered at (centerx, centery), clockwise,
3839 * passing by (x1,y1) and (x2,y2)
3840 */
screendrawcirclearc(WINDOWPART * win,INTBIG centerx,INTBIG centery,INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2,GRAPHICS * desc)3841 void screendrawcirclearc(WINDOWPART *win, INTBIG centerx, INTBIG centery, INTBIG x1, INTBIG y1,
3842 INTBIG x2, INTBIG y2, GRAPHICS *desc)
3843 {
3844 REGISTER WINDOWFRAME *wf;
3845
3846 /* make sure the image buffer has not moved */
3847 wf = win->frame;
3848 if ((UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap) != wf->rowstart[0])
3849 gra_rebuildrowstart(wf);
3850
3851 gra_drawcirclearc(win, centerx, centery, x1, y1, x2, y2, FALSE, desc);
3852 }
3853
3854 /*
3855 * draws a thick arc centered at (centerx, centery), clockwise,
3856 * passing by (x1,y1) and (x2,y2)
3857 */
screendrawthickcirclearc(WINDOWPART * win,INTBIG centerx,INTBIG centery,INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2,GRAPHICS * desc)3858 void screendrawthickcirclearc(WINDOWPART *win, INTBIG centerx, INTBIG centery, INTBIG x1, INTBIG y1,
3859 INTBIG x2, INTBIG y2, GRAPHICS *desc)
3860 {
3861 REGISTER WINDOWFRAME *wf;
3862
3863 /* make sure the image buffer has not moved */
3864 wf = win->frame;
3865 if ((UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap) != wf->rowstart[0])
3866 gra_rebuildrowstart(wf);
3867
3868 gra_drawcirclearc(win, centerx, centery, x1, y1, x2, y2, TRUE, desc);
3869 }
3870
3871 /******************** GRID DRAWING ********************/
3872
3873 /*
3874 * grid drawing routine
3875 */
screendrawgrid(WINDOWPART * win,POLYGON * obj)3876 void screendrawgrid(WINDOWPART *win, POLYGON *obj)
3877 {
3878 REGISTER WINDOWFRAME *wf;
3879
3880 /* make sure the image buffer has not moved */
3881 wf = win->frame;
3882 if ((UCHAR1 *)GetPixBaseAddr(wf->window->portPixMap) != wf->rowstart[0])
3883 gra_rebuildrowstart(wf);
3884
3885 gra_drawgrid(win, obj);
3886 }
3887
3888 /******************** MOUSE CONTROL ********************/
3889
3890 /*
3891 * routine to return the number of buttons on the mouse
3892 */
buttoncount(void)3893 INTBIG buttoncount(void)
3894 {
3895 return(mini(BUTTONS, NUMBUTS));
3896 }
3897
3898 /*
3899 * routine to tell whether button "but" is a double-click
3900 */
doublebutton(INTBIG b)3901 BOOLEAN doublebutton(INTBIG b)
3902 {
3903 if (b == 16) return(TRUE);
3904 return(FALSE);
3905 }
3906
3907 /*
3908 * routine to tell whether button "but" is a context button (right)
3909 */
contextbutton(INTBIG b)3910 BOOLEAN contextbutton(INTBIG b)
3911 {
3912 if ((b%4) >= 2) return(TRUE);
3913 return(FALSE);
3914 }
3915
3916 /*
3917 * routine to tell whether button "but" has the "shift" key held
3918 */
shiftbutton(INTBIG b)3919 BOOLEAN shiftbutton(INTBIG b)
3920 {
3921 if ((b%2) == 1) return(TRUE);
3922 return(FALSE);
3923 }
3924
3925 /*
3926 * routine to tell whether button "but" is a "mouse wheel" button
3927 */
wheelbutton(INTBIG b)3928 BOOLEAN wheelbutton(INTBIG b)
3929 {
3930 return(FALSE);
3931 }
3932
3933 /*
3934 * routine to return the name of button "b" (from 0 to "buttoncount()").
3935 * The number of letters unique to the button is placed in "important".
3936 */
buttonname(INTBIG b,INTBIG * important)3937 CHAR *buttonname(INTBIG b, INTBIG *important)
3938 {
3939 *important = gra_buttonname[b].unique;
3940 return(gra_buttonname[b].name);
3941 }
3942
3943 /*
3944 * routine to convert from "gra_inputstate" (the typical input parameter)
3945 * to button numbers (the table "gra_buttonname")
3946 */
gra_makebutton(INTBIG state)3947 INTBIG gra_makebutton(INTBIG state)
3948 {
3949 INTBIG base;
3950
3951 if ((state&DOUBLECLICK) != 0) return(16);
3952 base = 0;
3953 if ((state&CONTROLISDOWN) != 0) base += 8;
3954 if ((state&OPTIONISDOWN) != 0) base += 4;
3955 if ((state&COMMANDISDOWN) != 0) base += 2;
3956 if ((state&SHIFTISDOWN) != 0) base++;
3957 return(base);
3958 }
3959
3960 /*
3961 * routine to wait for a button push and return its index (0 based) in "*but".
3962 * The coordinates of the cursor are placed in "*x" and "*y". If there is no
3963 * button push, the value of "*but" is negative.
3964 */
waitforbutton(INTBIG * x,INTBIG * y,INTBIG * but)3965 void waitforbutton(INTBIG *x, INTBIG *y, INTBIG *but)
3966 {
3967 EventRecord theEvent;
3968
3969 if (gra_inputstate != NOEVENT && (gra_inputstate&(ISBUTTON|BUTTONUP)) == ISBUTTON)
3970 {
3971 *but = gra_makebutton(gra_inputstate);
3972 *x = gra_cursorx;
3973 *y = gra_cursory;
3974 gra_inputstate = NOEVENT;
3975 if (us_cursorstate != IBEAMCURSOR) setdefaultcursortype(NULLCURSOR);
3976 return;
3977 }
3978
3979 gra_waitforaction(1, &theEvent);
3980
3981 if (gra_inputstate != NOEVENT && (gra_inputstate&(ISBUTTON|BUTTONUP)) == ISBUTTON)
3982 {
3983 *but = gra_makebutton(gra_inputstate);
3984 *x = gra_cursorx;
3985 *y = gra_cursory;
3986 gra_inputstate = NOEVENT;
3987 if (us_cursorstate != IBEAMCURSOR) setdefaultcursortype(NULLCURSOR);
3988 return;
3989 }
3990 *but = -1;
3991 }
3992
3993 /*
3994 * routine to do modal loop, calling "charhandler" for each typed key and "buttonhandler"
3995 * for each pushed button. The "charhandler" routine is called with the character value
3996 * that was typed. The "buttonhandler" routine is called with coordinates of cursor.
3997 * The "charhandler" and "buttonhandler" returns true to abort loop.
3998 * The value of "cursor" determines cursor appearance.
3999 */
modalloop(BOOLEAN (* charhandler)(INTSML chr,INTBIG special),BOOLEAN (* buttonhandler)(INTBIG x,INTBIG y,INTBIG but),INTBIG cursor)4000 void modalloop(BOOLEAN (*charhandler)(INTSML chr, INTBIG special),
4001 BOOLEAN (*buttonhandler)(INTBIG x, INTBIG y, INTBIG but), INTBIG cursor)
4002 {
4003 INTBIG oldnormalcursor, chr, x, y, but;
4004 INTBIG special;
4005
4006 /* set cursor */
4007 oldnormalcursor = us_normalcursor;
4008 setnormalcursor(cursor);
4009
4010 for (;;)
4011 {
4012 if (ttydataready())
4013 {
4014 chr = getnxtchar(&special);
4015 if ((*charhandler)(chr, special)) break;
4016 } else
4017 {
4018 waitforbutton(&x, &y, &but);
4019 if (but >= 0 && buttonhandler != 0)
4020 if ((*buttonhandler)(x, y, but)) break;
4021 }
4022 }
4023
4024 /* restore cursor */
4025 setnormalcursor(oldnormalcursor);
4026 }
4027
4028 /*
4029 * routine to track the cursor until a button is released, calling "whileup" for
4030 * each co-ordinate when the mouse moves before the first button push, calling
4031 * "whendown" once when the button goes down, calling "eachdown" for each
4032 * co-ordinate when the mouse moves after the button is pushed, calling
4033 * "eachchar" for each key that is typed at any time, and calling "done" once
4034 * when done. The "whendown" and "done" routines are called with no parameters;
4035 * "whileup" and "eachdown" are called with the X and Y coordinates of the
4036 * cursor; and "eachchar" is called with the X, Y, and character value that was
4037 * typed. The "whileup", "eachdown", and "eachchar" routines return nonzero to
4038 * abort tracking.
4039 * If "waitforpush" is true then the routine will wait for a button to
4040 * actually be pushed before tracking (otherwise it will begin tracking
4041 * immediately). The value of "purpose" determines what the cursor will look
4042 * like during dragging: 0 for normal (the standard cursor), 1 for drawing (a pen),
4043 * 2 for dragging (a hand), 3 for popup menu selection (a horizontal arrow), 4 for
4044 * hierarchical popup menu selection (arrow, stays at end).
4045 */
trackcursor(BOOLEAN waitforpush,BOOLEAN (* whileup)(INTBIG,INTBIG),void (* whendown)(void),BOOLEAN (* eachdown)(INTBIG,INTBIG),BOOLEAN (* eachchar)(INTBIG,INTBIG,INTSML),void (* done)(void),INTBIG purpose)4046 void trackcursor(BOOLEAN waitforpush, BOOLEAN (*whileup)(INTBIG, INTBIG), void (*whendown)(void),
4047 BOOLEAN (*eachdown)(INTBIG, INTBIG), BOOLEAN (*eachchar)(INTBIG, INTBIG, INTSML), void (*done)(void),
4048 INTBIG purpose)
4049 {
4050 REGISTER INTBIG action;
4051 REGISTER BOOLEAN keepon;
4052 EventRecord theEvent;
4053 /* change the cursor to an appropriate icon */
4054 switch (purpose)
4055 {
4056 case TRACKDRAWING: setdefaultcursortype(PENCURSOR); break;
4057 case TRACKDRAGGING: setdefaultcursortype(HANDCURSOR); break;
4058 case TRACKSELECTING:
4059 case TRACKHSELECTING: setdefaultcursortype(MENUCURSOR); break;
4060 }
4061
4062 /* now wait for a button to go down, if requested */
4063 keepon = FALSE;
4064 if (waitforpush)
4065 {
4066 while (!keepon)
4067 {
4068 gra_waitforaction(2, &theEvent);
4069 if (gra_inputstate == NOEVENT) continue;
4070 action = gra_inputstate;
4071 gra_inputstate = NOEVENT;
4072
4073 /* if button just went down, stop this loop */
4074 if ((action&ISBUTTON) != 0 && (action&BUTTONUP) == 0) break;
4075 if ((action&MOTION) != 0)
4076 {
4077 keepon = (*whileup)(gra_cursorx, gra_cursory);
4078 } else if ((action&ISKEYSTROKE) != 0 && gra_inputspecial == 0)
4079 {
4080 keepon = (*eachchar)(gra_cursorx, gra_cursory, (INTSML)(action&CHARREAD));
4081 }
4082 if (el_pleasestop != 0) keepon = TRUE;
4083 }
4084 }
4085
4086 /* button is now down, real tracking begins */
4087 if (!keepon)
4088 {
4089 (*whendown)();
4090 keepon = (*eachdown)(gra_cursorx, gra_cursory);
4091 }
4092
4093 /* now track while the button is down */
4094 while (!keepon)
4095 {
4096 gra_waitforaction(2, &theEvent);
4097 us_endchanges(NOWINDOWPART);
4098
4099 /* for each motion, report the coordinates */
4100 if (gra_inputstate == NOEVENT) continue;
4101 action = gra_inputstate;
4102 gra_inputstate = NOEVENT;
4103 if ((action&ISBUTTON) != 0 && (action&BUTTONUP) != 0) break;
4104 if ((action&MOTION) != 0)
4105 {
4106 keepon = (*eachdown)(gra_cursorx, gra_cursory);
4107 } else if ((action&ISKEYSTROKE) != 0 && gra_inputspecial == 0)
4108 {
4109 keepon = (*eachchar)(gra_cursorx, gra_cursory, (INTSML)(action&CHARREAD));
4110 }
4111 if (el_pleasestop != 0) keepon = TRUE;
4112 }
4113
4114 /* inform the user that all is done */
4115 (*done)();
4116
4117 /* restore the state of the world */
4118 if (purpose != TRACKHSELECTING) setdefaultcursortype(NULLCURSOR);
4119 }
4120
4121 /*
4122 * routine to read the current co-ordinates of the tablet and return them
4123 * in "*x" and "*y".
4124 */
readtablet(INTBIG * x,INTBIG * y)4125 void readtablet(INTBIG *x, INTBIG *y)
4126 {
4127 *x = gra_cursorx; *y = gra_cursory;
4128 }
4129
4130 /*
4131 * routine to turn off the cursor tracking if it is on
4132 */
stoptablet(void)4133 void stoptablet(void)
4134 {
4135 if (us_cursorstate != IBEAMCURSOR) setdefaultcursortype(NULLCURSOR);
4136 }
4137
4138 /******************** KEYBOARD CONTROL ********************/
4139
4140 /*
4141 * routine to get the next character from the keyboard
4142 */
getnxtchar(INTBIG * special)4143 INTSML getnxtchar(INTBIG *special)
4144 {
4145 REGISTER INTSML i;
4146 EventRecord theEvent;
4147
4148 if (gra_inputstate != NOEVENT && (gra_inputstate&ISKEYSTROKE) != 0)
4149 {
4150 i = gra_inputstate & CHARREAD;
4151 *special = gra_inputspecial;
4152 gra_inputstate = NOEVENT;
4153 return(i);
4154 }
4155 if (us_cursorstate != IBEAMCURSOR)
4156 setdefaultcursortype(WANTTTYCURSOR);
4157 for(;;)
4158 {
4159 gra_waitforaction(0, &theEvent);
4160 if (gra_inputstate != NOEVENT && (gra_inputstate&ISKEYSTROKE) != 0)
4161 break;
4162 }
4163 i = gra_inputstate & CHARREAD;
4164 *special = gra_inputspecial;
4165 gra_inputstate = NOEVENT;
4166 if (us_cursorstate != IBEAMCURSOR)
4167 setdefaultcursortype(NULLCURSOR);
4168 return(i);
4169 }
4170
checkforinterrupt(void)4171 void checkforinterrupt(void)
4172 {
4173 EventRecord theEvent;
4174 short oak;
4175
4176 if (el_pleasestop == 0 && gra_cancheck)
4177 {
4178 gra_cancheck = FALSE;
4179 oak = EventAvail(keyDownMask, &theEvent);
4180 if (oak != 0)
4181 {
4182 (void)GetNextEvent(keyDownMask, &theEvent);
4183 if (theEvent.what == keyDown)
4184 if ((theEvent.modifiers & cmdKey) != 0)
4185 if ((theEvent.message & charCodeMask) == '.')
4186 {
4187 ttyputmsg(_("Interrupted..."));
4188 el_pleasestop = 1;
4189 }
4190 }
4191 }
4192 }
4193
4194 /*
4195 * Routine to return which "bucky bits" are held down (shift, control, etc.)
4196 */
4197 #define KEYPRESSED(k) ((thekeys[k>>3] >> (k&7)) & 1)
getbuckybits(void)4198 INTBIG getbuckybits(void)
4199 {
4200 UCHAR1 thekeys[16];
4201 REGISTER INTBIG bits;
4202
4203 GetKeys((unsigned long *)thekeys);
4204 bits = 0;
4205 if (KEYPRESSED(0x38) != 0) bits |= SHIFTDOWN;
4206 if (KEYPRESSED(0x3B) != 0) bits |= CONTROLDOWN;
4207 if (KEYPRESSED(0x3A) != 0) bits |= OPTALTMETDOWN;
4208 if (KEYPRESSED(0x37) != 0) bits |= ACCELERATORDOWN;
4209 return(bits);
4210 }
4211
4212 /*
4213 * routine to tell whether data is waiting at the terminal. Returns true
4214 * if data is ready.
4215 */
ttydataready(void)4216 BOOLEAN ttydataready(void)
4217 {
4218 EventRecord theEvent;
4219
4220 /* see if something is already pending */
4221 if (gra_inputstate != NOEVENT)
4222 {
4223 if ((gra_inputstate&ISKEYSTROKE) != 0) return(TRUE);
4224 return(FALSE);
4225 }
4226
4227 /* wait for something and analyze it */
4228 gra_waitforaction(1, &theEvent);
4229 if (gra_inputstate != NOEVENT && (gra_inputstate&ISKEYSTROKE) != 0) return(TRUE);
4230 return(FALSE);
4231 }
4232
4233 /****************************** FILES ******************************/
4234
4235 /*
4236 * Routine to set the type and creator of file "name" to "type" and "creator"
4237 */
mac_settypecreator(CHAR * name,INTBIG type,INTBIG creator)4238 void mac_settypecreator(CHAR *name, INTBIG type, INTBIG creator)
4239 {
4240 FInfo finfo;
4241 CHAR pname[256];
4242
4243 (void)estrcpy(&pname[1], name);
4244 pname[0] = estrlen(name);
4245 (void)GetFInfo((UCHAR1 *)pname, 0, &finfo);
4246 finfo.fdType = type;
4247 finfo.fdCreator = creator;
4248 (void)SetFInfo((UCHAR1 *)pname, 0, &finfo);
4249 }
4250
4251 /*
4252 * Macintosh routine to return the name of the system folder
4253 */
gra_systemfoldername(void)4254 CHAR *gra_systemfoldername(void)
4255 {
4256 static CHAR foldername[256];
4257 CHAR thisname[256];
4258 INTBIG i, j, len;
4259 WDPBRec wpb;
4260 CInfoPBRec cpb;
4261 SysEnvRec sysenv;
4262
4263 /* get system folder reference number */
4264 SysEnvirons(2, &sysenv);
4265
4266 /* determine directory ID of system folder */
4267 wpb.ioNamePtr = (UCHAR1 *)foldername;
4268 wpb.ioVRefNum = sysenv.sysVRefNum;
4269 wpb.ioWDIndex = 0;
4270 wpb.ioWDProcID = 0L;
4271 wpb.ioWDVRefNum = wpb.ioVRefNum;
4272 i = PBGetWDInfo(&wpb, 0);
4273 if (i != noErr) return(x_(""));
4274
4275 /* find the name of the system folder */
4276 foldername[0] = 0;
4277 cpb.dirInfo.ioDrParID = wpb.ioWDDirID;
4278 for(j=0; ; j++)
4279 {
4280 cpb.dirInfo.ioNamePtr = (UCHAR1 *)thisname;
4281 cpb.dirInfo.ioVRefNum = wpb.ioWDVRefNum;
4282 cpb.dirInfo.ioFDirIndex = -1;
4283 cpb.dirInfo.ioDrDirID = cpb.dirInfo.ioDrParID;
4284 i = PBGetCatInfo(&cpb, 0);
4285 if (i != noErr) return(x_(""));
4286 len = thisname[0] + 1;
4287 if (j != 0) thisname[len++] = ':';
4288 for(i=0; i<foldername[0]; i++) thisname[len++] = foldername[i+1];
4289 thisname[len] = 0;
4290 for(i=0; i<len; i++) foldername[i+1] = thisname[i+1];
4291 foldername[0] = len-1;
4292 if (cpb.dirInfo.ioDrDirID == fsRtDirID) break;
4293 }
4294
4295 /* see if there is a folder with the name ":Preferences:Electric Files" added on */
4296 for(i=0; i<foldername[0]; i++) thisname[i+1] = foldername[i+1];
4297 thisname[foldername[0]+1] = 0;
4298 (void)estrcat(&thisname[1], x_(":Preferences:Electric Files"));
4299 thisname[0] = estrlen(&thisname[1]);
4300 cpb.dirInfo.ioNamePtr = (UCHAR1 *)thisname;
4301 cpb.dirInfo.ioVRefNum = wpb.ioWDVRefNum;
4302 cpb.dirInfo.ioFDirIndex = 0;
4303 i = PBGetCatInfo(&cpb, 0);
4304 if (i != noErr) return(&foldername[1]);
4305 if ((cpb.dirInfo.ioFlAttrib&16) == 0) return(&foldername[1]);
4306 (void)estrcpy(foldername, &thisname[1]);
4307 return(foldername);
4308 }
4309
4310 /*
4311 * Routine to convert a Pascal string file name in "thisname" and its volume
4312 * reference number in "refnum" into a full path name (and a C string).
4313 */
gra_makefullname(CHAR * thisname,INTBIG refnum)4314 CHAR *gra_makefullname(CHAR *thisname, INTBIG refnum)
4315 {
4316 INTBIG err, len, i;
4317 CInfoPBRec cpb;
4318 CHAR line[256];
4319 static CHAR sofar[256];
4320
4321 len = thisname[0];
4322 for(i=0; i<len; i++) sofar[i] = thisname[i+1];
4323 sofar[len] = 0;
4324 cpb.hFileInfo.ioVRefNum = refnum;
4325 cpb.hFileInfo.ioDirID = 0;
4326 cpb.hFileInfo.ioCompletion = 0L;
4327 cpb.hFileInfo.ioNamePtr = (StringPtr)line;
4328 cpb.hFileInfo.ioFDirIndex = -1;
4329 for(;;)
4330 {
4331 err = PBGetCatInfo(&cpb, 0);
4332 if (err != noErr) break;
4333 line[line[0]+1] = 0;
4334 estrcat(line, x_(":"));
4335 estrcat(line, sofar);
4336 estrcpy(sofar, &line[1]);
4337 if (cpb.hFileInfo.ioFlParID == 0) break;
4338 cpb.hFileInfo.ioDirID = cpb.hFileInfo.ioFlParID;
4339 }
4340 return(sofar);
4341 }
4342
4343 /*
4344 * Routine to convert a FSS specification in "theFSS" into a full path name
4345 * (and a C string).
4346 */
gra_makefullnamefromFSS(FSSpec theFSS)4347 CHAR *gra_makefullnamefromFSS(FSSpec theFSS)
4348 {
4349 DirInfo block;
4350 short len;
4351 static CHAR fileName[256];
4352 CHAR dirName[256];
4353 OSErr err;
4354
4355 if (theFSS.parID != 0)
4356 {
4357 theFSS.name[theFSS.name[0]+1] = 0;
4358 estrcpy(fileName, (CHAR *)&theFSS.name[1]);
4359 block.ioDrParID = theFSS.parID;
4360 block.ioNamePtr = (StringPtr)dirName;
4361 do {
4362 block.ioVRefNum = theFSS.vRefNum;
4363 block.ioFDirIndex = -1;
4364 block.ioDrDirID = block.ioDrParID;
4365 err = PBGetCatInfo((CInfoPBPtr)&block, 0);
4366 dirName[dirName[0]+1] = 0;
4367 len = estrlen(&dirName[1]);
4368 BlockMove(fileName, fileName + len+1, estrlen(fileName)+1);
4369 estrcpy(fileName, &dirName[1]);
4370 fileName[len] = ':';
4371 } while (block.ioDrDirID != 2);
4372 return(fileName);
4373 }
4374 /* no directory ID specified in FSS, use old name/vrefnum method */
4375 return(gra_makefullname((CHAR *)theFSS.name, theFSS.vRefNum));
4376 }
4377
4378 /*
4379 * File filter for binary library files. Accepts "Elec" type files or those
4380 * that end with ".elib".
4381 */
gra_fileFilterProc(CInfoPBPtr pb,Ptr mydata)4382 pascal Boolean gra_fileFilterProc(CInfoPBPtr pb, Ptr mydata)
4383 {
4384 INTBIG pos;
4385 UCHAR1 *str;
4386
4387 if ((pb->hFileInfo.ioFlAttrib&ioDirMask) != 0) return(0);
4388 str = pb->hFileInfo.ioNamePtr;
4389 pos = str[0];
4390 if (str[pos-4] == '.' && str[pos-3] == 'e' && str[pos-2] == 'l' && str[pos-1] == 'i' &&
4391 str[pos] == 'b') return(0);
4392 if (pb->hFileInfo.ioFlFndrInfo.fdType == 'Elec') return(0);
4393 return(1);
4394 }
4395
4396 /*
4397 * Routine to prompt for multiple files of type "filetype", giving the
4398 * message "msg". Returns a string that contains all of the file names,
4399 * separated by the NONFILECH (a character that cannot be in a file name).
4400 */
multifileselectin(CHAR * msg,INTBIG filetype)4401 CHAR *multifileselectin(CHAR *msg, INTBIG filetype)
4402 {
4403 return(fileselect(msg, filetype, x_("")));
4404 }
4405
4406 /*
4407 * Routine to display a standard file prompt dialog and return the selected file.
4408 * The prompt message is in "msg" and the kind of file is in "filetype". The default
4409 * output file name is in "defofile" (only used if "filetype" is negative).
4410 */
fileselect(CHAR * msg,INTBIG filetype,CHAR * defofile)4411 CHAR *fileselect(CHAR *msg, INTBIG filetype, CHAR *defofile)
4412 {
4413 SFTypeList myTypes;
4414 static Point SFwhere = {90, 82};
4415 INTBIG len;
4416 REGISTER INTBIG i;
4417 CHAR save;
4418 StandardFileReply reply;
4419 WindowPtr savewin;
4420 WDPBRec wdpb;
4421 CHAR leng, ofile[256], prompt[256];
4422
4423 if (us_logplay != NULL)
4424 {
4425 (void)xfread((UCHAR1 *)&gra_action, 1, sizeof (gra_action), us_logplay);
4426 if ((gra_action.kind&0xFFFF) != FILEREPLY) gra_localstring[0] = 0; else
4427 {
4428 (void)xfread((UCHAR1 *)&leng, 1, 1, us_logplay);
4429 len = leng;
4430 (void)xfread((UCHAR1 *)gra_localstring, 1, len, us_logplay);
4431 gra_localstring[len] = 0;
4432 }
4433 } else
4434 {
4435 estrcpy(&prompt[1], msg);
4436 prompt[0] = estrlen(msg);
4437 GetPort(&savewin);
4438 if ((filetype&FILETYPEWRITE) == 0)
4439 {
4440 /* input file selection */
4441 /* ParamText((UCHAR1 *)prompt, "\p", "\p", "\p"); */
4442 if ((filetype&FILETYPE) == io_filetypeblib)
4443 {
4444 /* special case for Electric binary libraries */
4445 /* SFGetFile(SFwhere, prompt, gra_fileFilterProcUPP, -1, myTypes,
4446 0, &sfreply); */
4447 StandardGetFile(gra_fileFilterProcUPP, -1, myTypes, &reply);
4448 } else
4449 {
4450 /* standard file input */
4451 /* SFGetFile(SFwhere, prompt, 0, -1, myTypes, 0, &sfreply); */
4452 StandardGetFile(0, -1, myTypes, &reply);
4453 }
4454 } else
4455 {
4456 /* output file selection */
4457 for(i = estrlen(defofile)-1; i > 0; i--)
4458 if (defofile[i] == ':') break;
4459 if (i > 0)
4460 {
4461 /* there is a ":" in the path, set the default directory */
4462 i++;
4463 save = defofile[i];
4464 defofile[i] = 0;
4465 (void)estrcpy(&ofile[1], defofile);
4466 ofile[0] = estrlen(defofile);
4467 wdpb.ioNamePtr = (StringPtr)ofile;
4468 PBHSetVol(&wdpb, 0);
4469 defofile[i] = save;
4470 defofile = &defofile[i];
4471 }
4472 (void)estrcpy(&ofile[1], defofile);
4473 ofile[0] = estrlen(defofile);
4474 StandardPutFile((UCHAR1 *)prompt, (UCHAR1 *)ofile, &reply);
4475 }
4476 SetPort(savewin);
4477 if (reply.sfGood == 0) gra_localstring[0] = 0; else
4478 (void)estrcpy(gra_localstring, gra_makefullnamefromFSS(reply.sfFile));
4479 }
4480 /* log this result if logging */
4481 if (us_logrecord != NULL)
4482 {
4483 gra_action.kind = FILEREPLY;
4484 (void)xfwrite((UCHAR1 *)&gra_action, 1, sizeof (gra_action), us_logrecord);
4485 leng = estrlen(gra_localstring);
4486 (void)xfwrite((UCHAR1 *)&leng, 1, 1, us_logrecord);
4487 len = leng;
4488 (void)xfwrite((UCHAR1 *)gra_localstring, 1, len, us_logrecord);
4489 gra_logrecordindex++;
4490 if (gra_logrecordindex >= us_logflushfreq)
4491 {
4492 /* flush the session log file */
4493 gra_logrecordindex = 0;
4494 xflushbuf(us_logrecord);
4495 }
4496 }
4497 return(gra_localstring);
4498 }
4499
4500 /*
4501 * routine to handle an "open document" Apple Event and read a library
4502 */
gra_handleodoc(AppleEvent * theAppleEvent,AppleEvent * reply,long handlerRefCon)4503 pascal OSErr gra_handleodoc(AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefCon)
4504 {
4505 FSSpec myFSS;
4506 AEDescList docList;
4507 OSErr err;
4508 CHAR *argv[3];
4509 long sindex, itemsInList;
4510 Size actualSize;
4511 AEKeyword keywd;
4512 DescType returnedType;
4513
4514 /* get the direct parameter, a descriptor list, and put it into a doclist */
4515 err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &docList);
4516 if (err) return(err);
4517
4518 /* check for missing parameters */
4519 err = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr, typeWildCard,
4520 &returnedType, nil, 0, &actualSize);
4521 if (err != errAEDescNotFound)
4522 {
4523 if (!err) return(errAEEventNotHandled);
4524 return(err);
4525 }
4526
4527 /* count the number of descriptor records in the list */
4528 err = AECountItems(&docList, &itemsInList);
4529
4530 /*
4531 * now get each descriptor record from the list, coerce the returned data to
4532 * an FSSpec record, and open the associated file
4533 */
4534 for(sindex = 1; sindex <= itemsInList; sindex++)
4535 {
4536 err = AEGetNthPtr(&docList, sindex, typeFSS, &keywd, &returnedType,
4537 (Ptr)&myFSS, sizeof(myFSS), &actualSize);
4538 if (err) return(err);
4539 us_beginchanges();
4540 argv[0] = x_("read");
4541 argv[1] = gra_makefullnamefromFSS(myFSS);
4542 argv[2] = x_("make-current");
4543 us_library(3, argv);
4544 if (el_curwindowpart != NOWINDOWPART)
4545 us_ensurepropertechnology(el_curwindowpart->curnodeproto, 0, TRUE);
4546 us_endchanges(NOWINDOWPART);
4547 }
4548 err = AEDisposeDesc(&docList);
4549
4550 return(noErr);
4551 }
4552
4553 /*
4554 * Helper routine to initialize the list of files in a directory.
4555 */
gra_initfilelist(void)4556 void gra_initfilelist(void)
4557 {
4558 if (gra_fileliststringarray == 0)
4559 {
4560 gra_fileliststringarray = newstringarray(db_cluster);
4561 if (gra_fileliststringarray == 0) return;
4562 }
4563 clearstrings(gra_fileliststringarray);
4564 }
4565
4566 /*
4567 * Helper routine to add "file" to the list of files in a directory.
4568 * Returns true on error.
4569 */
gra_addfiletolist(CHAR * file)4570 BOOLEAN gra_addfiletolist(CHAR *file)
4571 {
4572 addtostringarray(gra_fileliststringarray, file);
4573 return(FALSE);
4574 }
4575
4576 /*
4577 * Routine to search for all of the files/directories in directory "directory" and
4578 * return them in the array of strings "filelist". Returns the number of files found.
4579 */
filesindirectory(CHAR * directory,CHAR *** filelist)4580 INTBIG filesindirectory(CHAR *directory, CHAR ***filelist)
4581 {
4582 INTBIG err, i;
4583 INTBIG dirid, len;
4584 CHAR file[256];
4585 CInfoPBRec cinfo;
4586
4587 if (*directory == 0) dirid = 0; else
4588 {
4589 (void)estrcpy(&file[1], directory);
4590 file[0] = estrlen(directory);
4591 SetVol((UCHAR1 *)file, 0);
4592 cinfo.hFileInfo.ioCompletion = 0L;
4593 cinfo.hFileInfo.ioNamePtr = (StringPtr)file;
4594 cinfo.hFileInfo.ioVRefNum = 0;
4595 cinfo.hFileInfo.ioFDirIndex = 0;
4596 cinfo.hFileInfo.ioDirID = 0L;
4597 err = PBGetCatInfo(&cinfo, 0);
4598 if (err != noErr) return(0);
4599 dirid = cinfo.hFileInfo.ioDirID;
4600 }
4601
4602 gra_initfilelist();
4603 for(i=1; ; i++)
4604 {
4605 cinfo.hFileInfo.ioCompletion = 0L;
4606 cinfo.hFileInfo.ioNamePtr = (StringPtr)file;
4607 cinfo.hFileInfo.ioVRefNum = 0;
4608 cinfo.hFileInfo.ioFDirIndex = i;
4609 cinfo.hFileInfo.ioDirID = dirid;
4610 err = PBGetCatInfo(&cinfo, 0);
4611 if (err != noErr) break;
4612 file[file[0]+1] = 0;
4613 if (gra_addfiletolist(&file[1])) return(0);
4614 }
4615
4616 *filelist = getstringarray(gra_fileliststringarray, &len);
4617 return(len);
4618 }
4619
4620 /* routine to convert a path name with "~" to a real path */
truepath(CHAR * line)4621 CHAR *truepath(CHAR *line)
4622 {
4623 /* only have tilde parsing on UNIX */
4624 return(line);
4625 }
4626
4627 /*
4628 * Routine to return the full path to file "file".
4629 */
fullfilename(CHAR * file)4630 CHAR *fullfilename(CHAR *file)
4631 {
4632 REGISTER CHAR *pt;
4633 static CHAR fullfile[256];
4634
4635 /* see if there is a ':' anywhere in the file name */
4636 for(pt = file; *pt != 0; pt++)
4637 if (*pt == ':') break;
4638
4639 /* if it has a colon but does not begin with one, it is a full path already */
4640 if (*pt == ':' && *file != ':') return(file);
4641
4642 /* make it a full path */
4643 estrcpy(fullfile, currentdirectory());
4644 estrcat(fullfile, file);
4645 return(fullfile);
4646 }
4647
4648 /*
4649 * routine to rename file "file" to "newfile"
4650 * returns nonzero on error
4651 */
erename(CHAR * file,CHAR * newfile)4652 INTBIG erename(CHAR *file, CHAR *newfile)
4653 {
4654 CHAR oldname[256], newname[256];
4655
4656 estrcpy(&oldname[1], file);
4657 oldname[0] = estrlen(file);
4658 estrcpy(&newname[1], newfile);
4659 newname[0] = estrlen(newfile);
4660 if (Rename((UCHAR1 *)oldname, 0, (UCHAR1 *)newname) == 0) return(0);
4661 return(1);
4662 }
4663
4664 /*
4665 * routine to delete file "file"
4666 */
eunlink(CHAR * file)4667 INTBIG eunlink(CHAR *file)
4668 {
4669 CHAR filename[256];
4670
4671 estrcpy(&filename[1], file);
4672 filename[0] = estrlen(file);
4673 if (HDelete(0, 0, (UCHAR1 *)filename) == 0) return(0);
4674 return(-1);
4675 }
4676
4677 /*
4678 * Routine to return information about the file or directory "name":
4679 * 0: does not exist
4680 * 1: is a file
4681 * 2: is a directory
4682 * 3: is a locked file (read-only)
4683 */
fileexistence(CHAR * name)4684 INTBIG fileexistence(CHAR *name)
4685 {
4686 struct stat buf;
4687 Str255 fname;
4688 ParamBlockRec pb;
4689
4690 if (stat(name, &buf) < 0) return(0);
4691 if ((buf.st_mode & S_IFMT) == S_IFDIR) return(2);
4692
4693 /* a file: see if it is writable */
4694 estrcpy((CHAR *)&fname[1], name);
4695 fname[0] = estrlen(name);
4696 pb.fileParam.ioNamePtr = fname;
4697 pb.fileParam.ioVRefNum = 0;
4698 pb.fileParam.ioFVersNum = 0;
4699 pb.fileParam.ioFDirIndex = 0;
4700 if (PBGetFInfo(&pb, 0) != 0) return(1);
4701 if ((pb.fileParam.ioFlAttrib&1) == 0) return(1);
4702 return(3);
4703 }
4704
4705 /*
4706 * Routine to create a directory.
4707 * Returns true on error.
4708 */
createdirectory(CHAR * dirname)4709 BOOLEAN createdirectory(CHAR *dirname)
4710 {
4711 FSSpec fsp;
4712 long dir;
4713 INTBIG err;
4714 CHAR pname[256];
4715
4716 estrcpy(&pname[1], dirname);
4717 pname[0] = estrlen(dirname);
4718 err = FSMakeFSSpec(0, 0, (UCHAR1 *)pname, &fsp);
4719 if (err != noErr && err != fnfErr) return(TRUE);
4720 err = FSpDirCreate(&fsp, smSystemScript, &dir);
4721 if (err != noErr && err != dupFNErr) return(TRUE);
4722 return(FALSE);
4723 }
4724
4725 /*
4726 * Routine to return the current directory name
4727 */
currentdirectory(void)4728 CHAR *currentdirectory(void)
4729 {
4730 return(gra_makefullname((CHAR *)x_("\p"), 0));
4731 }
4732
4733 /*
4734 * Routine to return the home directory (returns 0 if it doesn't exist)
4735 */
hashomedir(void)4736 CHAR *hashomedir(void)
4737 {
4738 return(0);
4739 }
4740
4741 /*
4742 * Routine to return the path to the "options" library.
4743 */
optionsfilepath(void)4744 CHAR *optionsfilepath(void)
4745 {
4746 REGISTER void *infstr;
4747
4748 infstr = initinfstr();
4749 addstringtoinfstr(infstr, el_libdir);
4750 addstringtoinfstr(infstr, x_("electricoptions.elib"));
4751 return(returninfstr(infstr));
4752 }
4753
4754 /*
4755 * Routine to obtain the modification date on file "filename".
4756 */
filedate(CHAR * filename)4757 time_t filedate(CHAR *filename)
4758 {
4759 struct stat buf;
4760 time_t thetime;
4761
4762 stat(filename, &buf);
4763 thetime = buf.st_mtime;
4764 thetime -= machinetimeoffset();
4765 return(thetime);
4766 }
4767
4768 /*
4769 * Routine to lock a resource called "lockfilename" by creating such a file
4770 * if it doesn't exist. Returns true if successful, false if unable to
4771 * lock the file.
4772 */
lockfile(CHAR * lockfilename)4773 BOOLEAN lockfile(CHAR *lockfilename)
4774 {
4775 INTBIG err;
4776 FSSpec fsp;
4777 CHAR pname[256];
4778
4779 estrcpy(&pname[1], lockfilename);
4780 pname[0] = estrlen(lockfilename);
4781 err = FSMakeFSSpec(0, 0, (UCHAR1 *)pname, &fsp);
4782 err = FSpCreate(&fsp, 'Elec', 'Lock', smSystemScript);
4783 if (err == noErr) return(TRUE);
4784 return(FALSE);
4785 }
4786
4787 /*
4788 * Routine to unlock a resource called "lockfilename" by deleting such a file.
4789 */
unlockfile(CHAR * lockfilename)4790 void unlockfile(CHAR *lockfilename)
4791 {
4792 FSSpec fsp;
4793 CHAR pname[256];
4794
4795 estrcpy(&pname[1], lockfilename);
4796 pname[0] = estrlen(lockfilename);
4797 FSMakeFSSpec(0, 0, (UCHAR1 *)pname, &fsp);
4798 FSpDelete(&fsp);
4799 }
4800
4801 /*
4802 * Routine to show file "document" in a browser window.
4803 * Returns true if the operation cannot be done.
4804 *
4805 * This routine is taken from "FinderOpenSel" by:
4806 * C.K. Haun <TR>
4807 * Apple Developer Tech Support
4808 * April 1992, Cupertino, CA USA
4809 * Of course, Copyright 1991-1992, Apple Computer Inc.
4810 */
browsefile(CHAR * document)4811 BOOLEAN browsefile(CHAR *document)
4812 {
4813 BOOLEAN launch;
4814 AppleEvent aeEvent, aeReply;
4815 AEDesc aeDirDesc, listElem;
4816 FSSpec dirSpec, procSpec;
4817 AEDesc fileList;
4818 OSErr myErr;
4819 ProcessSerialNumber process;
4820 AliasHandle DirAlias, FileAlias;
4821 FSSpec theFileToOpen;
4822 ProcessInfoRec infoRec;
4823 Str31 processName;
4824 Str255 pname;
4825 static AEDesc myAddressDesc;
4826 static BOOLEAN gotFinderAddress = FALSE;
4827
4828 /* get the FSSpec of the file */
4829 launch = TRUE;
4830 estrcpy((CHAR *)&pname[1], document);
4831 pname[0] = estrlen(document);
4832 FSMakeFSSpec(0, 0, pname, &theFileToOpen);
4833
4834 /* we are working locally, find the finder on this machine */
4835 if (!gotFinderAddress)
4836 {
4837 infoRec.processInfoLength = sizeof(ProcessInfoRec);
4838 infoRec.processName = (StringPtr)&processName;
4839 infoRec.processAppSpec = &procSpec;
4840 myErr = gra_findprocess('FNDR', 'MACS', &process, &infoRec);
4841 if (myErr != noErr) return(TRUE);
4842 myErr = AECreateDesc(typeProcessSerialNumber, (Ptr)&process, sizeof(process), &myAddressDesc);
4843 if (myErr != noErr) return(TRUE);
4844 gotFinderAddress = TRUE;
4845 }
4846
4847 /* Create the FinderEvent */
4848 if (launch)
4849 {
4850 myErr = AECreateAppleEvent('FNDR', 'sope', &myAddressDesc,
4851 kAutoGenerateReturnID, kAnyTransactionID, &aeEvent);
4852 } else
4853 {
4854 myErr = AECreateAppleEvent('FNDR', 'srev', &myAddressDesc,
4855 kAutoGenerateReturnID, kAnyTransactionID, &aeEvent);
4856 }
4857 if (myErr != noErr) return(TRUE);
4858
4859 /*
4860 * Now we build all the bits of an OpenSelection event. Basically, we need to create
4861 * an alias for the item to open, and an alias to the parent folder (directory) of that
4862 * item. We can also pass a list of files if we want.
4863 */
4864
4865 /* make a spec for the parent folder */
4866 FSMakeFSSpec(theFileToOpen.vRefNum, theFileToOpen.parID, nil, &dirSpec);
4867 NewAlias(nil, &dirSpec, &DirAlias);
4868
4869 /* Create alias for file */
4870 NewAlias(nil, &theFileToOpen, &FileAlias);
4871
4872 /* Create the file list */
4873 myErr = AECreateList(nil, 0, false, &fileList);
4874
4875 /* create the folder descriptor */
4876 HLock((Handle)DirAlias);
4877 AECreateDesc(typeAlias, (Ptr)*DirAlias, GetHandleSize((Handle)DirAlias), &aeDirDesc);
4878 HUnlock((Handle)DirAlias);
4879 if ((myErr = AEPutParamDesc(&aeEvent, keyDirectObject, &aeDirDesc)) == noErr)
4880 {
4881 /* done with the desc, kill it */
4882 AEDisposeDesc(&aeDirDesc);
4883
4884 /* create the file descriptor and add to aliasList */
4885 HLock((Handle)FileAlias);
4886 AECreateDesc(typeAlias, (Ptr)*FileAlias, GetHandleSize((Handle)FileAlias), &listElem);
4887 HLock((Handle)FileAlias);
4888 myErr = AEPutDesc(&fileList, 0, &listElem);
4889 }
4890 if (myErr == noErr)
4891 {
4892 AEDisposeDesc(&listElem);
4893
4894 /* Add the file alias list to the event */
4895 myErr = AEPutParamDesc(&aeEvent, 'fsel', &fileList);
4896 AEDisposeDesc(&fileList);
4897
4898 if (myErr == noErr)
4899 myErr = AESend(&aeEvent, &aeReply, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
4900 kAENormalPriority, kAEDefaultTimeout, nil, nil);
4901 if (!launch)
4902 SetFrontProcess(&process);
4903 }
4904 AEDisposeDesc(&aeEvent);
4905
4906 if ((Handle)DirAlias)
4907 DisposeHandle((Handle)DirAlias);
4908 if ((Handle)FileAlias)
4909 DisposeHandle((Handle)FileAlias);
4910 return(FALSE);
4911 }
4912
4913 /* This runs through the process list looking for the indicated application */
gra_findprocess(OSType typeToFind,OSType creatorToFind,ProcessSerialNumberPtr processSN,ProcessInfoRecPtr infoRecToFill)4914 OSErr gra_findprocess(OSType typeToFind, OSType creatorToFind, ProcessSerialNumberPtr processSN,
4915 ProcessInfoRecPtr infoRecToFill)
4916 {
4917 ProcessSerialNumber tempPSN;
4918 OSErr myErr = noErr;
4919 tempPSN.lowLongOfPSN = kNoProcess;
4920 processSN->lowLongOfPSN = kNoProcess;
4921 processSN->highLongOfPSN = kNoProcess;
4922 do
4923 {
4924 myErr = GetNextProcess(processSN);
4925 if (myErr != noErr) break;
4926 GetProcessInformation(processSN, infoRecToFill);
4927 }
4928 while (infoRecToFill->processSignature != creatorToFind ||
4929 infoRecToFill->processType != typeToFind);
4930 return(myErr);
4931 }
4932
4933 /****************************** CHANNELS ******************************/
4934
4935 /*
4936 * routine to create a pipe connection between the channels in "channels"
4937 */
epipe(int channels[2])4938 INTBIG epipe(int channels[2])
4939 {
4940 return(0);
4941 }
4942
4943 /*
4944 * Routine to set channel "channel" into an appropriate mode for single-character
4945 * interaction (i.e. break mode).
4946 */
setinteractivemode(int channel)4947 void setinteractivemode(int channel)
4948 {
4949 }
4950
4951 /*
4952 * Routine to replace channel "channel" with a pointer to file "file".
4953 * Returns a pointer to the original channel.
4954 */
channelreplacewithfile(int channel,CHAR * file)4955 INTBIG channelreplacewithfile(int channel, CHAR *file)
4956 {
4957 return(0);
4958 }
4959
4960 /*
4961 * Routine to replace channel "channel" with new channel "newchannel".
4962 * Returns a pointer to the original channel.
4963 */
channelreplacewithchannel(int channel,int newchannel)4964 INTBIG channelreplacewithchannel(int channel, int newchannel)
4965 {
4966 return(0);
4967 }
4968
4969 /*
4970 * Routine to restore channel "channel" to the pointer that was returned
4971 * by "channelreplacewithfile" or "channelreplacewithchannel" (and is in "saved").
4972 */
channelrestore(int channel,INTBIG saved)4973 void channelrestore(int channel, INTBIG saved)
4974 {
4975 }
4976
4977 /*
4978 * Routine to read "count" bytes from channel "channel" into "addr".
4979 * Returns the number of bytes read.
4980 */
eread(int channel,UCHAR1 * addr,INTBIG count)4981 INTBIG eread(int channel, UCHAR1 *addr, INTBIG count)
4982 {
4983 return(0);
4984 }
4985
4986 /*
4987 * Routine to write "count" bytes to channel "channel" from "addr".
4988 * Returns the number of bytes written.
4989 */
ewrite(int channel,UCHAR1 * addr,INTBIG count)4990 INTBIG ewrite(int channel, UCHAR1 *addr, INTBIG count)
4991 {
4992 return(0);
4993 }
4994
4995 /*
4996 * routine to close a channel in "channel"
4997 */
eclose(int channel)4998 INTBIG eclose(int channel)
4999 {
5000 return(0);
5001 }
5002
5003 /*************************** TIME ROUTINES ***************************/
5004
5005 /*
5006 * The Macintosh uses an "epoch" of January 1, 1904.
5007 * All other machines use an "epoch" of January 1, 1970.
5008 * This means that time on the Macintosh is off by 66 years.
5009 * Specifically, there were 17 leap years between 1904 and 1970, so
5010 * there were 66*365+17 = 24107 days
5011 * Since each day has 24*60*60 = 86400 seconds in it, there were
5012 * 24107 * 86400 = 2,082,844,800 seconds difference between epochs.
5013 *
5014 * There is an extra "gotcha". MSL (the Metrowerks Library) uses an epoch
5015 * of January 1, 1900! So if this is MSL, add another 4 years to the epoch:
5016 * (365*4 = 1460 * 86400 = 126,144,000
5017 *
5018 * However, since Macintosh systems deal with local time and other
5019 * systems deal with GMT time, the Mac must also offset by the time zone.
5020 */
5021 #define MACEPOCHOFFSET 2082844800
5022 #define MSLEPOCHOFFSET 126144000
5023
5024 /*
5025 * This routine returns the amount to add to the operating-system time
5026 * to adjust for a common time format.
5027 */
machinetimeoffset(void)5028 time_t machinetimeoffset(void)
5029 {
5030 static time_t offset;
5031 static BOOLEAN offsetcomputed = FALSE;
5032 UINTBIG timezoneoffset;
5033 INTBIG gmtoffset;
5034 MachineLocation ml;
5035
5036 if (!offsetcomputed)
5037 {
5038 offsetcomputed = TRUE;
5039 offset = MACEPOCHOFFSET;
5040 #ifdef __MSL__
5041 offset += MSLEPOCHOFFSET;
5042 #endif
5043 ReadLocation(&ml);
5044 timezoneoffset = ml.u.gmtDelta & 0xFFFFFF;
5045 gmtoffset = timezoneoffset & 0x7FFFFF;
5046 if ((timezoneoffset & 0x800000) != 0)
5047 gmtoffset = (~0x7FFFFF) | gmtoffset;
5048 offset += gmtoffset;
5049 }
5050 return(offset);
5051 }
5052
5053 /* returns the time at which the current event occurred */
eventtime(void)5054 UINTBIG eventtime(void)
5055 {
5056 return(ticktime());
5057 }
5058
5059 /* returns the current time in 60ths of a second */
ticktime(void)5060 UINTBIG ticktime(void)
5061 {
5062 return(TickCount());
5063 }
5064
5065 /* returns the double-click interval in 60ths of a second */
doubleclicktime(void)5066 INTBIG doubleclicktime(void)
5067 {
5068 return(gra_doubleclick);
5069 }
5070
5071 /*
5072 * Routine to wait "ticks" sixtieths of a second and then return.
5073 */
gotosleep(INTBIG ticks)5074 void gotosleep(INTBIG ticks)
5075 {
5076 #ifdef NEWCODEWARRIOR
5077 unsigned long l;
5078
5079 Delay(ticks, &l);
5080 #else
5081 long l;
5082
5083 Delay(ticks, &l);
5084 #endif
5085 }
5086
5087 /*
5088 * Routine to start counting time.
5089 */
starttimer(void)5090 void starttimer(void)
5091 {
5092 gra_timestart = clock();
5093 }
5094
5095 /*
5096 * Routine to stop counting time and return the number of elapsed seconds
5097 * since the last call to "starttimer()".
5098 */
endtimer(void)5099 float endtimer(void)
5100 {
5101 float seconds;
5102 UINTBIG thistime;
5103
5104 thistime = clock();
5105 seconds = ((float)(thistime - gra_timestart)) / 60.0;
5106 return(seconds);
5107 }
5108
5109 /*************************** EVENT ROUTINES ***************************/
5110
5111 /*
5112 * Hack routine that writes a fake "mouse up" event to the session logging file. This
5113 * is necessary because certain toolbox routines (i.e. TEClick) track the
5114 * mouse while it is down in order to handle selection of text. Since this tracking
5115 * cannot be obtained and logged, a fake "SHIFT mouse" is logged after the routine finishes
5116 * so that the text selection is effected in the same way
5117 */
gra_fakemouseup(void)5118 void gra_fakemouseup(void)
5119 {
5120 Point p;
5121
5122 if (us_logrecord == NULL) return;
5123 GetMouse(&p);
5124 gra_action.kind = ISBUTTON | SHIFTISDOWN;
5125 gra_action.x = p.h;
5126 gra_action.y = p.v;
5127 if (xfwrite((UCHAR1 *)&gra_action, 1, sizeof (gra_action), us_logrecord) == 0)
5128 {
5129 ttyputerr(_("Error writing session log file: recording disabled"));
5130 logfinishrecord();
5131 }
5132 gra_logrecordindex++;
5133 if (gra_logrecordindex >= us_logflushfreq)
5134 {
5135 /* flush the session log file */
5136 gra_logrecordindex = 0;
5137 xflushbuf(us_logrecord);
5138 }
5139 }
5140
5141 /*
5142 * helper routine to wait for some keyboard or mouse input. The value of "nature" is:
5143 * 0 allow mouse, keyboard
5144 * 1 allow mouse, keyboard, pulldown menus
5145 * 2 allow mouse, keyboard, pulldown menus, motion
5146 */
gra_waitforaction(INTBIG nature,EventRecord * theEvent)5147 void gra_waitforaction(INTBIG nature, EventRecord *theEvent)
5148 {
5149 REGISTER INTBIG err;
5150 static INTBIG last_cursorx, last_cursory;
5151 REGISTER BOOLEAN saveevent;
5152 static INTBIG fakewhen = 0;
5153 Rect r, fr;
5154
5155 if (us_logplay != NULL)
5156 {
5157 if (EventAvail(updateMask | activMask, theEvent) != 0)
5158 {
5159 gra_nextevent(4, theEvent);
5160 return;
5161 }
5162 flushscreen();
5163 err = xfread((UCHAR1 *)&gra_action, 1, sizeof (gra_action), us_logplay);
5164 if (stopping(STOPREASONPLAYBACK)) err = 0;
5165 if (err != 0)
5166 {
5167 if (gra_playbackmultiple <= 0)
5168 {
5169 gra_playbackmultiple = 0;
5170 for(;;)
5171 {
5172 gra_inputstate = NOEVENT;
5173 gra_nextevent(0, theEvent);
5174 if (gra_inputstate == NOEVENT) continue;
5175 if ((gra_inputstate&ISKEYSTROKE) == 0) continue;
5176 if ((gra_inputstate&CHARREAD) < '0' || (gra_inputstate&CHARREAD) > '9') break;
5177 gra_playbackmultiple = gra_playbackmultiple * 10 + (gra_inputstate&CHARREAD) - '0';
5178 }
5179 if (gra_inputstate != NOEVENT && (gra_inputstate&CHARREAD) == 'q')
5180 err = 0;
5181 }
5182 gra_playbackmultiple--;
5183
5184 /* allow Command-. to interrupt long playbacks */
5185 if ((gra_playbackmultiple%10) == 9)
5186 {
5187 if (EventAvail(keyDownMask, theEvent) != 0)
5188 {
5189 (void)WaitNextEvent(keyDownMask, theEvent, 0, 0);
5190 if ((theEvent->modifiers & cmdKey) != 0 &&
5191 (theEvent->message & charCodeMask) == '.')
5192 gra_playbackmultiple = 0;
5193 }
5194 }
5195
5196 gra_inputstate = gra_action.kind & 0xFFFF;
5197 gra_cursorx = gra_action.x;
5198 gra_cursory = gra_action.y;
5199 us_state &= ~GOTXY;
5200 if (gra_inputstate == MENUEVENT)
5201 {
5202 (void)xfread((UCHAR1 *)&gra_action, 1, sizeof (gra_action), us_logplay);
5203 gra_lowmenu = gra_action.x;
5204 gra_highmenu = gra_action.y;
5205 } else if (gra_inputstate == WINDOWCHANGE)
5206 {
5207 (void)xfread((UCHAR1 *)&r, 1, sizeof (r), us_logplay);
5208 fr = (*((WindowPeek)el_curwindowframe->realwindow)->strucRgn)->rgnBBox;
5209 MoveWindow((WindowPtr)el_curwindowframe->realwindow, r.left, r.top, 0);
5210 SizeWindow((WindowPtr)el_curwindowframe->realwindow, r.right-r.left,
5211 r.bottom-r.top, 1);
5212 gra_mygrowwindow((WindowPtr)el_curwindowframe->realwindow, r.right-r.left,
5213 r.bottom-r.top, &fr);
5214 }
5215 }
5216
5217 /* convert to an event */
5218 fakewhen += gra_doubleclick + 1;
5219 theEvent->what = nullEvent;
5220 theEvent->when = fakewhen;
5221 theEvent->modifiers = 0;
5222 if ((gra_inputstate&SHIFTISDOWN) != 0) theEvent->modifiers |= shiftKey;
5223 if ((gra_inputstate&COMMANDISDOWN) != 0) theEvent->modifiers |= cmdKey;
5224 if ((gra_inputstate&OPTIONISDOWN) != 0) theEvent->modifiers |= optionKey;
5225 if ((gra_inputstate&CONTROLISDOWN) != 0) theEvent->modifiers |= controlKey;
5226 if ((gra_inputstate&BUTTONUP) != 0) theEvent->modifiers |= btnState;
5227 theEvent->where.h = gra_cursorx;
5228 theEvent->where.v = el_curwindowframe->revy - gra_cursory;
5229 if ((gra_inputstate&ISKEYSTROKE) != 0)
5230 {
5231 theEvent->what = keyDown;
5232 theEvent->message = gra_inputstate & CHARREAD;
5233 } else if ((gra_inputstate&ISBUTTON) != 0)
5234 {
5235 if ((gra_inputstate&BUTTONUP) == 0) theEvent->what = mouseDown; else
5236 theEvent->what = mouseUp;
5237 if ((gra_inputstate&DOUBLECLICK) != 0)
5238 {
5239 theEvent->when--;
5240 fakewhen--;
5241 }
5242 }
5243 /* stop now if end of playback file */
5244 if (err == 0)
5245 {
5246 ttyputmsg(_("End of session playback file"));
5247 xclose(us_logplay);
5248 us_logplay = NULL;
5249 return;
5250 }
5251 } else
5252 {
5253 flushscreen();
5254 gra_nextevent(nature, theEvent);
5255 }
5256
5257 if (us_logrecord != NULL && gra_inputstate != NOEVENT)
5258 {
5259 saveevent = TRUE;
5260 if ((gra_inputstate&MOTION) != 0)
5261 {
5262 if (gra_cursorx == last_cursorx && gra_cursory == last_cursory) saveevent = FALSE;
5263 }
5264 if (saveevent)
5265 {
5266 gra_action.kind = gra_inputstate;
5267 gra_action.x = last_cursorx = gra_cursorx;
5268 gra_action.y = last_cursory = gra_cursory;
5269 if (xfwrite((UCHAR1 *)&gra_action, 1, sizeof (gra_action), us_logrecord) == 0)
5270 {
5271 ttyputerr(_("Error writing session log file: recording disabled"));
5272 logfinishrecord();
5273 }
5274 if (gra_inputstate == MENUEVENT)
5275 {
5276 gra_action.x = gra_lowmenu;
5277 gra_action.y = gra_highmenu;
5278 (void)xfwrite((UCHAR1 *)&gra_action, 1, sizeof (gra_action), us_logrecord);
5279 } else if (gra_inputstate == WINDOWCHANGE)
5280 {
5281 if (el_curwindowframe != NOWINDOWFRAME)
5282 {
5283 r = (*((WindowPeek)el_curwindowframe->realwindow)->strucRgn)->rgnBBox;
5284 (void)xfwrite((UCHAR1 *)&r, 1, sizeof (r), us_logrecord);
5285 }
5286 }
5287 gra_logrecordindex++;
5288 if (gra_logrecordindex >= us_logflushfreq)
5289 {
5290 /* flush the session log file */
5291 gra_logrecordindex = 0;
5292 xflushbuf(us_logrecord);
5293 }
5294 }
5295 }
5296
5297 /* deal with special event types */
5298 if (gra_inputstate == MENUEVENT)
5299 {
5300 if (gra_highmenu == appleMENU && gra_lowmenu == 1)
5301 {
5302 gra_applemenu(gra_lowmenu);
5303 } else gra_nativemenudoone(gra_lowmenu, gra_highmenu);
5304 gra_inputstate = NOEVENT;
5305 } else if (gra_inputstate == WINDOWCHANGE) gra_inputstate = NOEVENT;
5306 }
5307
5308 /*
5309 * Routine to get the next Electric input action and set the global "gra_inputstate"
5310 * accordingly. The value of "nature" is:
5311 * 0 allow mouse, keyboard (no window switching)
5312 * 1 allow mouse, keyboard, pulldown menus
5313 * 2 allow mouse, keyboard, motion
5314 * 4 allow update and activate events only
5315 */
gra_nextevent(INTBIG nature,EventRecord * theEvent)5316 void gra_nextevent(INTBIG nature, EventRecord *theEvent)
5317 {
5318 INTBIG oak, cntlCode, x, y, stroke, oldpos, findres, inmenu, item;
5319 INTBIG key, theResult, xv, yv, lx, hx, ly, hy, modifiers, special;
5320 WStateData *wst;
5321 REGISTER WINDOWPART *w;
5322 REGISTER EDITOR *e;
5323 REGISTER VARIABLE *var;
5324 CHAR *par[1], *str, lastchar;
5325 static BOOLEAN firstwupdate = TRUE;
5326 WindowPtr theWindow, win, frontWindow;
5327 Rect r, fr;
5328 ControlHandle theControl;
5329 TDIALOG *dia;
5330 WINDOWFRAME *wf;
5331 static BOOLEAN overrodestatus = FALSE;
5332 COMMANDBINDING commandbinding;
5333 extern INTBIG sim_window_wavexbar;
5334
5335 gra_inputstate = NOEVENT;
5336 HiliteMenu(0);
5337 if (gra_messageswindow != 0) TEIdle(gra_TEH);
5338 if (nature == 4) oak = WaitNextEvent(updateMask | activMask, theEvent, 0, 0); else
5339 oak = WaitNextEvent(everyEvent, theEvent, 0, 0);
5340 if (oak == 0 && nature != 4 && gra_motioncheck)
5341 {
5342 gra_motioncheck = FALSE;
5343 oak = theEvent->what = app3Evt;
5344 if (Button())
5345 {
5346 theEvent->modifiers |= btnState;
5347 } else
5348 {
5349 theEvent->modifiers &= ~btnState;
5350 }
5351 }
5352 if (oak == 0)
5353 {
5354 if (nature != 2)
5355 {
5356 if (FindWindow(theEvent->where, &theWindow) != inContent)
5357 setdefaultcursortype(NORMALCURSOR);
5358 }
5359 return;
5360 }
5361 if (oak != 0) switch (theEvent->what)
5362 {
5363 case mouseUp:
5364 if (el_curwindowframe != NOWINDOWFRAME)
5365 {
5366 SetPort((WindowPtr)el_curwindowframe->realwindow);
5367 GlobalToLocal(&theEvent->where);
5368 gra_cursorx = theEvent->where.h;
5369 gra_cursory = el_curwindowframe->revy - theEvent->where.v;
5370 us_state &= ~GOTXY;
5371 }
5372 gra_inputstate = ISBUTTON | BUTTONUP;
5373 us_state |= DIDINPUT;
5374 break;
5375 case mouseDown:
5376 switch (FindWindow(theEvent->where, &theWindow))
5377 {
5378 case inMenuBar:
5379 if (nature != 1) break;
5380 key = MenuSelect(theEvent->where);
5381 if (HiWord(key) == appleMENU && LoWord(key) != 1)
5382 {
5383 gra_applemenu(LoWord(key));
5384 return;
5385 }
5386 gra_highmenu = HiWord(key);
5387 gra_lowmenu = LoWord(key);
5388 gra_inputstate = MENUEVENT;
5389 return;
5390 case inSysWindow:
5391 SystemClick(theEvent, theWindow);
5392 break;
5393 case inContent:
5394 SetPort(theWindow);
5395 GlobalToLocal(&theEvent->where);
5396
5397 /* determine which editor window was hit */
5398 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
5399 if ((WindowPtr)wf->realwindow == theWindow) break;
5400 gra_lastclickedwindow = theWindow;
5401 gra_lastclickedwindowframe = wf;
5402
5403 /* handle clicks in title bar of floating windows */
5404 if (wf != NOWINDOWFRAME && wf->floating && theEvent->where.v < FLOATINGHEADERSIZE)
5405 {
5406 if (theEvent->where.v >= 2 && theEvent->where.v <= 8 &&
5407 theEvent->where.h >= 4 && theEvent->where.h <= 10)
5408 {
5409 /* click in close box: turn off floating window */
5410 par[0] = x_("off");
5411 us_menu(1, par);
5412 } else
5413 {
5414 /* click in drag bar: move it */
5415 LocalToGlobal(&theEvent->where);
5416 gra_dragfloatingwindow(theWindow, theEvent->where);
5417 }
5418 break;
5419 }
5420
5421 gra_frontnonfloatingwindow(&frontWindow);
5422 if (theWindow != frontWindow)
5423 {
5424 /* click in new window: see if it is allowed */
5425 if (nature == 0)
5426 {
5427 ttybeep(SOUNDBEEP, TRUE);
5428 break;
5429 }
5430
5431 /* select this one as the frontmost window */
5432 gra_selectoswindow(theWindow);
5433 gra_setcurrentwindowframe();
5434
5435 /* when reentering edit window, force proper cursor */
5436 if (wf == NOWINDOWFRAME) break;
5437 oak = us_cursorstate;
5438 us_cursorstate++;
5439 setdefaultcursortype(oak);
5440 }
5441
5442 /* special case to ensure that "el_curwindowframe" gets floating window */
5443 if (el_curwindowframe != NOWINDOWFRAME && el_curwindowframe->floating)
5444 gra_setcurrentwindowframe();
5445 if (wf != NOWINDOWFRAME && wf->floating) el_curwindowframe = wf;
5446
5447 if (theWindow == gra_messageswindow && gra_messageswindow != 0)
5448 {
5449 cntlCode = FindControl(theEvent->where, theWindow, &theControl);
5450 if (cntlCode == kControlIndicatorPart)
5451 {
5452 oldpos = GetControlValue(theControl);
5453 TrackControl(theControl, theEvent->where, 0L);
5454 if (theControl == gra_vScroll) gra_adjustvtext(); else
5455 gra_adjusthtext(oldpos);
5456 break;
5457 }
5458 if (cntlCode == kControlUpButtonPart || cntlCode == kControlDownButtonPart ||
5459 cntlCode == kControlPageUpPart || cntlCode == kControlPageDownPart)
5460 {
5461 if (theControl == gra_vScroll)
5462 TrackControl(theControl, theEvent->where, gra_scrollvprocUPP); else
5463 TrackControl(theControl, theEvent->where, gra_scrollhprocUPP);
5464 break;
5465 }
5466 TEClick(theEvent->where, (theEvent->modifiers&shiftKey) != 0, gra_TEH);
5467 gra_fakemouseup();
5468 break;
5469 }
5470
5471 /* ignore clicks in the messages area at the bottom */
5472 if (wf != NOWINDOWFRAME && !wf->floating &&
5473 theEvent->where.v >= theWindow->portRect.bottom - SBARHEIGHT) break;
5474
5475 /* handle clicks in modeless dialogs */
5476 if (wf == NOWINDOWFRAME)
5477 {
5478 for(dia = gra_firstactivedialog; dia != NOTDIALOG; dia = dia->nexttdialog)
5479 if (dia->theDialog == theWindow) break;
5480 if (dia != NOTDIALOG && dia->modelessitemhit != 0)
5481 {
5482 gra_cursorx = theEvent->where.h;
5483 gra_cursory = theEvent->where.v;
5484 oak = 1;
5485 if (theEvent->when - gra_doubleclick < gra_lastclick &&
5486 abs(gra_cursorx-gra_lstcurx) < 5 && abs(gra_cursory-gra_lstcury) < 5)
5487 {
5488 oak = 5;
5489 gra_lastclick = theEvent->when - gra_doubleclick - 1;
5490 } else gra_lastclick = theEvent->when;
5491 gra_lstcurx = gra_cursorx; gra_lstcury = gra_cursory;
5492 item = gra_getnextcharacter(dia, oak, gra_cursorx, gra_cursory,
5493 0, 0, theEvent->when, FALSE);
5494 if (item >= 0) (*dia->modelessitemhit)(dia, item);
5495 break;
5496 }
5497 }
5498
5499 /* create the "click" event */
5500 gra_inputstate = ISBUTTON;
5501 if ((theEvent->modifiers&shiftKey) != 0) gra_inputstate |= SHIFTISDOWN;
5502 if ((theEvent->modifiers&cmdKey) != 0) gra_inputstate |= COMMANDISDOWN;
5503 if ((theEvent->modifiers&optionKey) != 0) gra_inputstate |= OPTIONISDOWN;
5504 if ((theEvent->modifiers&controlKey) != 0) gra_inputstate |= CONTROLISDOWN;
5505 gra_cursorx = theEvent->where.h;
5506 if (wf == NOWINDOWFRAME) gra_cursory = theEvent->where.v; else
5507 {
5508 gra_cursory = wf->revy - theEvent->where.v;
5509 if (wf->floating) gra_cursory += FLOATINGHEADERSIZE;
5510 }
5511 us_state &= ~GOTXY;
5512 if (theEvent->when - gra_doubleclick < gra_lastclick &&
5513 (gra_inputstate & (SHIFTISDOWN|COMMANDISDOWN|OPTIONISDOWN|CONTROLISDOWN)) == 0 &&
5514 abs(gra_cursorx-gra_lstcurx) < 5 && abs(gra_cursory-gra_lstcury) < 5)
5515 {
5516 gra_inputstate |= DOUBLECLICK;
5517 gra_lastclick = theEvent->when - gra_doubleclick - 1;
5518 } else gra_lastclick = theEvent->when;
5519 gra_lstcurx = gra_cursorx; gra_lstcury = gra_cursory;
5520 us_state |= DIDINPUT;
5521 break;
5522 case inDrag:
5523 if (theWindow != FrontWindow() && nature == 0)
5524 {
5525 ttybeep(SOUNDBEEP, TRUE);
5526 break;
5527 }
5528 gra_selectoswindow(theWindow);
5529 gra_setcurrentwindowframe();
5530 gra_dragfloatingwindow(theWindow, theEvent->where);
5531 break;
5532 case inGrow:
5533 SetPort(theWindow);
5534 SetRect(&r, 80, 80, qd.screenBits.bounds.right+500,
5535 qd.screenBits.bounds.bottom+500);
5536 fr = (*((WindowPeek)theWindow)->strucRgn)->rgnBBox;
5537 theResult = GrowWindow(theWindow, theEvent->where, &r);
5538 if (theResult != 0)
5539 {
5540 SizeWindow(theWindow, LoWord(theResult), HiWord(theResult), 1);
5541 gra_mygrowwindow(theWindow, LoWord(theResult), HiWord(theResult), &fr);
5542 }
5543 gra_inputstate = WINDOWCHANGE;
5544 break;
5545 case inZoomIn:
5546 if (TrackBox(theWindow, theEvent->where, inZoomIn) == 0) break;
5547 SetPort(theWindow);
5548 EraseRect(&theWindow->portRect);
5549 wst = (WStateData *) *(((WindowPeek)theWindow)->dataHandle);
5550 fr = (*((WindowPeek)theWindow)->strucRgn)->rgnBBox;
5551 MoveWindow(theWindow, wst->userState.left, wst->userState.top, 0);
5552 SizeWindow(theWindow, wst->userState.right-wst->userState.left,
5553 wst->userState.bottom-wst->userState.top, 1);
5554 gra_mygrowwindow(theWindow, wst->userState.right-wst->userState.left,
5555 wst->userState.bottom-wst->userState.top, &fr);
5556 gra_inputstate = WINDOWCHANGE;
5557 break;
5558 case inZoomOut:
5559 if (TrackBox(theWindow, theEvent->where, inZoomOut) == 0) break;
5560 SetPort(theWindow);
5561 EraseRect(&theWindow->portRect);
5562 wst = (WStateData *) *(((WindowPeek)theWindow)->dataHandle);
5563 fr = (*((WindowPeek)theWindow)->strucRgn)->rgnBBox;
5564 MoveWindow(theWindow, wst->stdState.left, wst->stdState.top, 0);
5565 SizeWindow(theWindow, wst->stdState.right-wst->stdState.left,
5566 wst->stdState.bottom-wst->stdState.top, 1);
5567 gra_mygrowwindow(theWindow, wst->stdState.right-wst->stdState.left,
5568 wst->stdState.bottom-wst->stdState.top, &fr);
5569 gra_inputstate = WINDOWCHANGE;
5570 break;
5571 case inGoAway:
5572 SetPort(theWindow);
5573 if (TrackGoAway(theWindow, theEvent->where) == 0) break;
5574 if (theWindow == gra_messageswindow && gra_messageswindow != 0)
5575 {
5576 gra_hidemessageswindow();
5577 } else if (el_curwindowframe != NOWINDOWFRAME &&
5578 theWindow == (WindowPtr)el_curwindowframe->realwindow)
5579 {
5580 par[0] = x_("delete");
5581 us_window(1, par);
5582 } else
5583 {
5584 /* determine which editor window was hit */
5585 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
5586 if ((WindowPtr)wf->realwindow == theWindow) break;
5587 if (wf != NOWINDOWFRAME) gra_disposeoswindow(theWindow); else
5588 gra_disposeoswindow(theWindow);
5589 }
5590 break;
5591 }
5592 break;
5593 case keyDown:
5594 case autoKey:
5595 special = 0;
5596 switch ((theEvent->message&keyCodeMask) >> 8)
5597 {
5598 case 122: special = SPECIALKEYDOWN|(SPECIALKEYF1<<SPECIALKEYSH); break;
5599 case 120: special = SPECIALKEYDOWN|(SPECIALKEYF2<<SPECIALKEYSH); break;
5600 case 99: special = SPECIALKEYDOWN|(SPECIALKEYF3<<SPECIALKEYSH); break;
5601 case 118: special = SPECIALKEYDOWN|(SPECIALKEYF4<<SPECIALKEYSH); break;
5602 case 96: special = SPECIALKEYDOWN|(SPECIALKEYF5<<SPECIALKEYSH); break;
5603 case 97: special = SPECIALKEYDOWN|(SPECIALKEYF6<<SPECIALKEYSH); break;
5604 case 98: special = SPECIALKEYDOWN|(SPECIALKEYF7<<SPECIALKEYSH); break;
5605 case 100: special = SPECIALKEYDOWN|(SPECIALKEYF8<<SPECIALKEYSH); break;
5606 case 101: special = SPECIALKEYDOWN|(SPECIALKEYF9<<SPECIALKEYSH); break;
5607 case 109: special = SPECIALKEYDOWN|(SPECIALKEYF10<<SPECIALKEYSH); break;
5608 case 103: special = SPECIALKEYDOWN|(SPECIALKEYF11<<SPECIALKEYSH); break;
5609 case 111: special = SPECIALKEYDOWN|(SPECIALKEYF12<<SPECIALKEYSH); break;
5610 }
5611 if (special != 0) stroke = 0; else
5612 {
5613 stroke = (theEvent->message & charCodeMask) & CHARREAD;
5614 if (stroke == 0) break;
5615 }
5616 if (el_curwindowframe != NOWINDOWFRAME)
5617 {
5618 SetPort((WindowPtr)el_curwindowframe->realwindow);
5619 GlobalToLocal(&theEvent->where);
5620 gra_cursorx = theEvent->where.h;
5621 gra_cursory = el_curwindowframe->revy - theEvent->where.v;
5622 us_state &= ~GOTXY;
5623 }
5624 modifiers = theEvent->modifiers;
5625
5626 /* arrows are special */
5627 if (stroke >= 034 && stroke <= 037)
5628 {
5629 switch (stroke)
5630 {
5631 case 034: special = SPECIALKEYDOWN|(SPECIALKEYARROWL<<SPECIALKEYSH); break;
5632 case 035: special = SPECIALKEYDOWN|(SPECIALKEYARROWR<<SPECIALKEYSH); break;
5633 case 036: special = SPECIALKEYDOWN|(SPECIALKEYARROWU<<SPECIALKEYSH); break;
5634 case 037: special = SPECIALKEYDOWN|(SPECIALKEYARROWD<<SPECIALKEYSH); break;
5635 }
5636 if ((modifiers&shiftKey) != 0) special |= SHIFTDOWN;
5637 }
5638 if ((modifiers&cmdKey) != 0) special |= ACCELERATORDOWN;
5639
5640 /* see if this goes to a modeless dialog */
5641 gra_frontnonfloatingwindow(&theWindow);
5642 for(dia = gra_firstactivedialog; dia != NOTDIALOG; dia = dia->nexttdialog)
5643 if (dia->theDialog == theWindow) break;
5644 if (dia != NOTDIALOG && dia->modelessitemhit != 0)
5645 {
5646 if ((special&ACCELERATORDOWN) != 0)
5647 {
5648 if (stroke == 'c')
5649 {
5650 DTextCopy(dia);
5651 break;
5652 }
5653 if (stroke == 'x')
5654 {
5655 DTextCut(dia);
5656 stroke = BACKSPACEKEY;
5657 special = 0;
5658 } else if (stroke == 'v')
5659 {
5660 stroke = DTextPaste(dia);
5661 if (stroke == 0) break;
5662 special = 0;
5663 }
5664 }
5665 item = gra_getnextcharacter(dia, 0, theEvent->where.h, theEvent->where.v,
5666 stroke, special, theEvent->when, (special&SHIFTDOWN) != 0);
5667 if (item >= 0) (*dia->modelessitemhit)(dia, item);
5668 break;
5669 }
5670
5671 if ((modifiers & cmdKey) != 0)
5672 {
5673 if (stroke == '.')
5674 {
5675 el_pleasestop = 2;
5676 return;
5677 }
5678 if (nature == 1)
5679 {
5680 /* handle cut/copy/paste specially in dialogs */
5681 if (gra_handlingdialog != NOTDIALOG)
5682 {
5683 if (stroke == 'c')
5684 {
5685 DTextCopy(gra_handlingdialog);
5686 break;
5687 }
5688 if (stroke == 'x')
5689 {
5690 DTextCut(gra_handlingdialog);
5691 gra_inputstate = BACKSPACEKEY & CHARREAD;
5692 us_state |= DIDINPUT;
5693 break;
5694 }
5695 if (stroke == 'v')
5696 {
5697 lastchar = DTextPaste(gra_handlingdialog);
5698 if (lastchar != 0)
5699 {
5700 gra_inputstate = lastchar & CHARREAD;
5701 us_state |= DIDINPUT;
5702 }
5703 break;
5704 }
5705 break;
5706 }
5707 gra_inputstate = stroke | ISKEYSTROKE;
5708 gra_inputspecial = special;
5709 us_state |= DIDINPUT;
5710 break;
5711 }
5712 }
5713 gra_frontnonfloatingwindow(&frontWindow);
5714 if (gra_messageswindow == frontWindow && gra_messageswindow != 0 && special == 0)
5715 {
5716 TESetSelect(32767, 32767, gra_TEH);
5717 TEKey(stroke, gra_TEH);
5718 gra_showselect();
5719 break;
5720 }
5721 gra_inputstate = stroke | ISKEYSTROKE;
5722 gra_inputspecial = special;
5723 us_state |= DIDINPUT;
5724 break;
5725
5726 case activateEvt:
5727 /* only interested in activation, not deactivation */
5728 if ((theEvent->modifiers&activeFlag) == 0) break;
5729
5730 /* ignore messages window */
5731 win = (WindowPtr)theEvent->message;
5732 if (win == gra_messageswindow && gra_messageswindow != 0) break;
5733
5734 /* ignore editor windows */
5735 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
5736 if ((WindowPtr)wf->realwindow == win) break;
5737 if (wf != NOWINDOWFRAME) break;
5738
5739 /* probably a dialog, just process it */
5740 SetPort(win);
5741 InvalRect(&win->portRect);
5742 break;
5743
5744 case updateEvt:
5745 win = (WindowPtr)theEvent->message;
5746 SetPort(win);
5747 BeginUpdate(win);
5748 if (win == gra_messageswindow && gra_messageswindow != 0)
5749 {
5750 EraseRect(&win->portRect);
5751 DrawControls(win);
5752 DrawGrowIcon(win);
5753 TEUpdate(&win->portRect, gra_TEH);
5754 EndUpdate(win);
5755 break;
5756 }
5757
5758 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
5759 if ((WindowPtr)wf->realwindow == win) break;
5760 if (wf != NOWINDOWFRAME)
5761 {
5762 if (!firstwupdate)
5763 {
5764 gra_drawosgraphics(wf);
5765 if (!wf->floating)
5766 gra_setrect(wf, (*wf->window->portPixMap)->bounds.right-SBARWIDTH-1,
5767 (*wf->window->portPixMap)->bounds.right-SBARWIDTH+1,
5768 0, (*wf->window->portPixMap)->bounds.bottom);
5769 r = (*wf->realwindow->visRgn)->rgnBBox;
5770 if (wf->floating)
5771 {
5772 r.top -= FLOATINGHEADERSIZE;
5773 r.bottom -= FLOATINGHEADERSIZE;
5774 }
5775 gra_setrect(wf, r.left, r.right, r.top, r.bottom);
5776
5777 if (!wf->floating) us_redostatus(wf);
5778 }
5779 firstwupdate = FALSE;
5780 }
5781
5782 /* probably a dialog, just process it */
5783 SetPort(win);
5784 for(dia = gra_firstactivedialog; dia != NOTDIALOG; dia = dia->nexttdialog)
5785 if (dia->theDialog == win) break;
5786 if (dia != NOTDIALOG)
5787 Dredrawdialogwindow(dia);
5788 EndUpdate(win);
5789 break;
5790
5791 case app3Evt:
5792 /* see if this happened in an editor window */
5793 findres = FindWindow(theEvent->where, &theWindow);
5794 if (theWindow == 0)
5795 {
5796 if ((theEvent->modifiers&btnState) == 0) break;
5797 wf = el_curwindowframe;
5798 } else
5799 {
5800 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
5801 if ((WindowPtr)wf->realwindow == theWindow) break;
5802 SetPort(theWindow);
5803 }
5804 GlobalToLocal(&theEvent->where);
5805
5806 /* report the menu if over one */
5807 inmenu = 0;
5808 if (wf != NOWINDOWFRAME && (theEvent->modifiers&btnState) == 0 && wf->floating)
5809 {
5810 gra_cursorx = theEvent->where.h;
5811 gra_cursory = wf->revy - theEvent->where.v;
5812 us_state &= ~GOTXY;
5813 x = (gra_cursorx-us_menulx) / us_menuxsz;
5814 y = (gra_cursory-us_menuly) / us_menuysz;
5815 if (x >= 0 && y >= 0 && x < us_menux && y < us_menuy)
5816 {
5817 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_menu_key);
5818 if (var != NOVARIABLE)
5819 {
5820 if (us_menupos <= 1) str = ((CHAR **)var->addr)[y * us_menux + x]; else
5821 str = ((CHAR **)var->addr)[x * us_menuy + y];
5822 us_parsebinding(str, &commandbinding);
5823 if (*commandbinding.command != 0)
5824 {
5825 if (commandbinding.nodeglyph != NONODEPROTO)
5826 {
5827 ttysetstatusfield(NOWINDOWFRAME, us_statusarc, describearcproto(us_curarcproto), TRUE);
5828 ttysetstatusfield(NOWINDOWFRAME, us_statusnode, us_describemenunode(&commandbinding), TRUE);
5829 inmenu = 1;
5830 overrodestatus = TRUE;
5831 }
5832 if (commandbinding.arcglyph != NOARCPROTO)
5833 {
5834 ttysetstatusfield(NOWINDOWFRAME, us_statusarc, describearcproto(commandbinding.arcglyph), TRUE);
5835 if (us_curnodeproto == NONODEPROTO) str = x_(""); else
5836 str = describenodeproto(us_curnodeproto);
5837 ttysetstatusfield(NOWINDOWFRAME, us_statusnode, str, TRUE);
5838 inmenu = 1;
5839 overrodestatus = TRUE;
5840 }
5841 }
5842 us_freebindingparse(&commandbinding);
5843 }
5844 }
5845 }
5846 if (inmenu == 0 && overrodestatus)
5847 {
5848 ttysetstatusfield(NOWINDOWFRAME, us_statusarc, describearcproto(us_curarcproto), TRUE);
5849 if (us_curnodeproto == NONODEPROTO) str = x_(""); else
5850 str = describenodeproto(us_curnodeproto);
5851 ttysetstatusfield(NOWINDOWFRAME, us_statusnode, str, TRUE);
5852 overrodestatus = FALSE;
5853 }
5854 if (nature == 2)
5855 {
5856 /* handle cursor motion */
5857 gra_cursorx = theEvent->where.h;
5858 if (wf == NOWINDOWFRAME) gra_cursory = theEvent->where.v; else
5859 gra_cursory = wf->revy - theEvent->where.v;
5860 us_state &= ~GOTXY;
5861 gra_inputstate = MOTION;
5862 if ((theEvent->modifiers&btnState) != 0) gra_inputstate |= BUTTONUP;
5863 return;
5864 }
5865 /* checkout the cursor position */
5866 if (findres == inContent)
5867 {
5868 if (theWindow == gra_messageswindow && gra_messageswindow != 0)
5869 {
5870 if (theEvent->where.h > theWindow->portRect.right - SBARWIDTH ||
5871 theEvent->where.v > theWindow->portRect.bottom - SBARHEIGHT)
5872 setdefaultcursortype(NORMALCURSOR); else
5873 setdefaultcursortype(IBEAMCURSOR);
5874 return;
5875 }
5876 if (wf == NOWINDOWFRAME || theWindow != (WindowPtr)wf->realwindow)
5877 {
5878 setdefaultcursortype(NORMALCURSOR);
5879 return;
5880 }
5881 x = theEvent->where.h;
5882 if (wf == NOWINDOWFRAME) y = theEvent->where.v; else
5883 y = wf->revy - theEvent->where.v;
5884 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
5885 {
5886 if (w->frame != wf) continue;
5887
5888 /* see if the cursor is over a window partition separator */
5889 us_gettruewindowbounds(w, &lx, &hx, &ly, &hy);
5890 if (x >= lx-1 && x <= lx+1 && y > ly+1 && y < hy-1 &&
5891 us_hasotherwindowpart(lx-10, y, w))
5892 {
5893 setdefaultcursortype(LRCURSOR);
5894 return;
5895 } else if (x >= hx-1 && x <= hx+1 && y > ly+1 && y < hy-1 &&
5896 us_hasotherwindowpart(hx+10, y, w))
5897 {
5898 setdefaultcursortype(LRCURSOR);
5899 return;
5900 } else if (y >= ly-1 && y <= ly+1 && x > lx+1 && x < hx-1 &&
5901 us_hasotherwindowpart(x, ly-10, w))
5902 {
5903 setdefaultcursortype(UDCURSOR);
5904 return;
5905 } else if (y >= hy-1 && y <= hy+1 && x > lx+1 && x < hx-1 &&
5906 us_hasotherwindowpart(x, hy+10, w))
5907 {
5908 setdefaultcursortype(UDCURSOR);
5909 return;
5910 }
5911
5912 if (x < w->uselx || x > w->usehx || y < w->usely || y > w->usehy) continue;
5913 if ((w->state&WINDOWTYPE) == WAVEFORMWINDOW)
5914 {
5915 xv = muldiv(x - w->uselx, w->screenhx - w->screenlx,
5916 w->usehx - w->uselx) + w->screenlx;
5917 yv = muldiv(y - w->usely, w->screenhy - w->screenly,
5918 w->usehy - w->usely) + w->screenly;
5919 if (abs(xv - sim_window_wavexbar) < 2 && yv >= 560)
5920 {
5921 setdefaultcursortype(LRCURSOR);
5922 return;
5923 }
5924 }
5925 if ((w->state&WINDOWTYPE) == POPTEXTWINDOW ||
5926 (w->state&WINDOWTYPE) == TEXTWINDOW)
5927 {
5928 e = w->editor;
5929 if ((e->state&EDITORTYPE) == PACEDITOR)
5930 {
5931 if (x > w->usehx - SBARWIDTH || y < w->usely + SBARHEIGHT || y >= e->revy)
5932 setdefaultcursortype(NORMALCURSOR); else
5933 setdefaultcursortype(IBEAMCURSOR);
5934 return;
5935 }
5936 } else if ((us_tool->toolstate&SHOWXY) != 0)
5937 {
5938 xv = x; yv = y;
5939 xv = muldiv(xv - w->uselx, w->screenhx - w->screenlx,
5940 w->usehx - w->uselx) + w->screenlx;
5941 yv = muldiv(yv - w->usely, w->screenhy - w->screenly,
5942 w->usehy - w->usely) + w->screenly;
5943 gridalign(&xv, &yv, 1, w->curnodeproto);
5944 us_setcursorpos(wf, xv, yv);
5945 }
5946 }
5947 setdefaultcursortype(us_normalcursor);
5948 return;
5949 }
5950 setdefaultcursortype(NORMALCURSOR);
5951 return;
5952
5953 case kHighLevelEvent:
5954 (void)AEProcessAppleEvent(theEvent);
5955 break;
5956
5957 case osEvt:
5958 switch ((theEvent->message >> 24) & 0xFF)
5959 {
5960 case suspendResumeMessage:
5961 if ((theEvent->message&resumeFlag) == 0)
5962 {
5963 /* suspend the application */
5964 gra_frontnonfloatingwindow(&theWindow);
5965 if (theWindow != 0) gra_activatewindow(theWindow, FALSE);
5966 gra_showallfloaters(FALSE);
5967 } else
5968 {
5969 /* resume the application */
5970 gra_frontnonfloatingwindow(&theWindow);
5971 if (theWindow != 0) gra_activatewindow(theWindow, TRUE);
5972 gra_showallfloaters(TRUE);
5973 }
5974 break;
5975 }
5976 }
5977 }
5978
5979 /* handle interrupts */
gra_onint(void)5980 void gra_onint(void)
5981 {
5982 (void)signal(SIGINT, (SIGNALCAST)gra_onint);
5983 el_pleasestop = 1;
5984 ttyputerr(_("Interrupted..."));
5985 }
5986
5987 /*************************** SESSION LOGGING ROUTINES ***************************/
5988
5989 /*
5990 * routine to begin playback of session logging file "file". The routine
5991 * returns true if there is an error.
5992 */
logplayback(CHAR * file)5993 BOOLEAN logplayback(CHAR *file)
5994 {
5995 REGISTER INTBIG comcount;
5996 CHAR *filename;
5997
5998 us_logplay = xopen(file, us_filetypelog, x_(""), &filename);
5999 if (us_logplay == NULL) return(TRUE);
6000 ttyputmsg(_("Type any key to playback the next step in the log file"));
6001 ttyputmsg(_("Type a number followed by 'x' to playback that many steps"));
6002 ttyputmsg(_("Type 'q' to terminate playback"));
6003
6004 comcount = filesize(us_logplay) / (sizeof (gra_action));
6005 ttyputmsg(_("There are no more than %ld steps to playback"), comcount);
6006 gra_playbackmultiple = comcount;
6007 return(FALSE);
6008 }
6009
6010 /*
6011 * routine to create a session logging file
6012 */
logstartrecord(void)6013 void logstartrecord(void)
6014 {
6015 #if 0 /* no session logging on Macintosh yet */
6016 us_logrecord = xcreate(ELECTRICLOG, us_filetypelog, 0, 0);
6017 #else
6018 us_logrecord = NULL;
6019 #endif
6020 }
6021
6022 /*
6023 * routine to terminate session logging
6024 */
logfinishrecord(void)6025 void logfinishrecord(void)
6026 {
6027 if (us_logrecord != NULL) xclose(us_logrecord);
6028 us_logrecord = NULL;
6029 }
6030
6031 /****************************** MENUS ******************************/
6032
gra_initializemenus(void)6033 void gra_initializemenus(void)
6034 {
6035 CHAR aboutelectric[100];
6036
6037 gra_pulldownmenucount = 0;
6038 gra_appleMenu = NewMenu(appleMENU, x_("\p\024"));
6039 estrcpy(&aboutelectric[1], _("About Electric"));
6040 estrcat(&aboutelectric[1], x_("..."));
6041 aboutelectric[0] = estrlen(&aboutelectric[1]);
6042 AppendMenu(gra_appleMenu, (UCHAR1 *)aboutelectric);
6043 InsertMenu(gra_appleMenu, 0);
6044 DrawMenuBar();
6045 AppendResMenu(gra_appleMenu, 'DRVR');
6046 }
6047
6048 /*
6049 * routine to handle the Apple menu, including the "About Electric..." dialog
6050 */
gra_applemenu(INTBIG sindex)6051 void gra_applemenu(INTBIG sindex)
6052 {
6053 Str255 name;
6054 GrafPtr savePort;
6055
6056 GetPort(&savePort);
6057 if (sindex == aboutMeCommand)
6058 {
6059 (void)us_aboutdlog();
6060 } else
6061 {
6062 GetMenuItemText(gra_appleMenu, sindex, name);
6063 (void)OpenDeskAcc(name);
6064 }
6065 SetPort(savePort);
6066 }
6067
getacceleratorstrings(CHAR ** acceleratorstring,CHAR ** acceleratorprefix)6068 void getacceleratorstrings(CHAR **acceleratorstring, CHAR **acceleratorprefix)
6069 {
6070 *acceleratorstring = x_("Cmd");
6071 *acceleratorprefix = x_("Cmd-");
6072 }
6073
getinterruptkey(void)6074 CHAR *getinterruptkey(void)
6075 {
6076 return(_("Command-."));
6077 }
6078
nativepopupmenu(POPUPMENU ** menu,BOOLEAN header,INTBIG left,INTBIG top)6079 INTBIG nativepopupmenu(POPUPMENU **menu, BOOLEAN header, INTBIG left, INTBIG top)
6080 {
6081 INTBIG ret, len, i, j, index, menuid, submenus, submenubaseindex, submenuindex;
6082 CHAR myline[256], origline[256], submenu[4], *pt;
6083 MenuHandle thismenu, subpopmenu;
6084 Point p;
6085 REGISTER USERCOM *uc;
6086 REGISTER POPUPMENUITEM *mi;
6087 REGISTER POPUPMENU *themenu;
6088
6089 themenu = *menu;
6090 if (gra_lastclickedwindow != 0) SetPort(gra_lastclickedwindow); else
6091 SetPort((WindowPtr)el_firstwindowframe->realwindow);
6092 if (left < 0 && top < 0)
6093 {
6094 p.h = gra_cursorx;
6095 if (gra_lastclickedwindowframe == NOWINDOWFRAME) p.v = gra_cursory; else
6096 p.v = gra_lastclickedwindowframe->revy - gra_cursory;
6097 } else
6098 {
6099 p.h = left; p.v = top;
6100 LocalToGlobal(&p);
6101 }
6102
6103 estrcpy(&myline[1], us_stripampersand(themenu->header));
6104 myline[0] = estrlen(&myline[1]);
6105 thismenu = NewMenu(2048, (UCHAR1 *)myline);
6106 if (thismenu == 0) return(-1);
6107
6108 /* remember the first submenu for this popup */
6109 submenubaseindex = gra_pulldownmenucount;
6110
6111 /* load the menus */
6112 submenus = 0;
6113 for(i=0; i<themenu->total; i++)
6114 {
6115 mi = &themenu->list[i];
6116 mi->changed = FALSE;
6117 if (*mi->attribute == 0)
6118 {
6119 (void)estrcpy(myline, x_(" (-"));
6120 myline[0] = estrlen(&myline[1]);
6121 AppendMenu(thismenu, (UCHAR1 *)myline);
6122 } else
6123 {
6124 /* quote illegal characters */
6125 pt = origline;
6126 for(j=0; mi->attribute[j] != 0; j++)
6127 {
6128 if (mi->attribute[j] == '&') continue;
6129 if (mi->attribute[j] == '(') *pt++ = '{'; else
6130 if (mi->attribute[j] == ')') *pt++ = '}'; else
6131 *pt++ = mi->attribute[j];
6132 }
6133 *pt = 0;
6134
6135 uc = mi->response;
6136 if (uc != NOUSERCOM && uc->menu != NOPOPUPMENU)
6137 {
6138 submenuindex = gra_pulldownindex(uc->menu);
6139 if (submenuindex < 0) return(-1);
6140 subpopmenu = gra_pulldownmenus[submenuindex];
6141 InsertMenu(subpopmenu, -1);
6142 myline[1] = '!'; myline[2] = USERMENUBASE+submenuindex;
6143 (void)estrcpy(&myline[3], origline);
6144 submenu[0] = '/'; submenu[1] = 0x1B; submenu[2] = 0;
6145 (void)estrcat(&myline[1], submenu);
6146 myline[0] = estrlen(&myline[1]);
6147 AppendMenu(thismenu, (UCHAR1 *)myline);
6148 submenus++;
6149 } else
6150 {
6151 /* insert command title */
6152 pt = origline;
6153 if (pt[0] == '>' && pt[1] == ' ')
6154 {
6155 myline[1] = '!';
6156 myline[2] = 022;
6157 (void)estrcpy(&myline[3], &pt[2]);
6158 len = estrlen(myline);
6159 if (myline[len-2] == ' ' && myline[len-1] == '<') myline[len-2] = 0;
6160 } else (void)estrcpy(&myline[1], pt);
6161 myline[0] = estrlen(&myline[1]);
6162 AppendMenu(thismenu, (UCHAR1 *)myline);
6163 }
6164 }
6165 }
6166
6167 /* run the popup menu */
6168 InsertMenu(thismenu, -1);
6169 ret = PopUpMenuSelect(thismenu, p.v, p.h, 1);
6170
6171 /* delete the memory */
6172 DeleteMenu(2048);
6173 DisposeMenu(thismenu);
6174 for(j=0; j<submenus; j++)
6175 {
6176 DeleteMenu(j+submenubaseindex+USERMENUBASE);
6177 DisposeMenu(gra_pulldownmenus[j+submenubaseindex]);
6178 }
6179
6180 /* restore base of submenus in use */
6181 gra_pulldownmenucount = submenubaseindex;
6182
6183 /* determine selection */
6184 menuid = HiWord(ret);
6185 if (menuid == 0) return(-1);
6186 if (menuid != 2048)
6187 {
6188 index = menuid-USERMENUBASE;
6189 j = 0;
6190 for(i=0; i<themenu->total; i++)
6191 {
6192 mi = &themenu->list[i];
6193 if (*mi->attribute == 0) continue;
6194 uc = mi->response;
6195 if (uc == NOUSERCOM || uc->menu == NOPOPUPMENU) continue;
6196 if (j == index-submenubaseindex) break;
6197 j++;
6198 }
6199 if (i >= themenu->total) return(-1);
6200 *menu = uc->menu;
6201 }
6202 return(LoWord(ret) - 1);
6203 }
6204
gra_nativemenudoone(INTBIG low,INTBIG high)6205 void gra_nativemenudoone(INTBIG low, INTBIG high)
6206 {
6207 INTBIG i, j;
6208 POPUPMENU *pm;
6209 BOOLEAN verbose;
6210
6211 i = high - USERMENUBASE;
6212 if (i >= 0 && i < gra_pulldownmenucount)
6213 {
6214 pm = us_getpopupmenu(gra_pulldowns[i]);
6215 j = abs(low) - 1;
6216 if (j >= 0 && j < pm->total)
6217 {
6218 us_state |= DIDINPUT;
6219 us_state &= ~GOTXY;
6220 setdefaultcursortype(NULLCURSOR);
6221 us_forceeditchanges();
6222 if ((us_tool->toolstate&ECHOBIND) != 0) verbose = TRUE; else
6223 verbose = FALSE;
6224 us_execute(pm->list[j].response, verbose, TRUE, TRUE);
6225 db_setcurrenttool(us_tool);
6226 setactivity(pm->list[j].attribute);
6227 }
6228 }
6229 HiliteMenu(0);
6230 }
6231 /* routine to redraw entry "sindex" of popupmenu "pm" because it changed */
nativemenurename(POPUPMENU * pm,INTBIG sindex)6232 void nativemenurename(POPUPMENU *pm, INTBIG sindex)
6233 {
6234 INTBIG i, submenuindex, cmdchar, j, k, boundspecial;
6235 INTSML boundkey;
6236 CHAR line[100], *pt;
6237 USERCOM *uc;
6238
6239 for(i=0; i<gra_pulldownmenucount; i++)
6240 if (namesame(gra_pulldowns[i], pm->name) == 0) break;
6241 if (i >= gra_pulldownmenucount) return;
6242
6243 /* make sure the menu didn't change size */
6244 j = CountMItems(gra_pulldownmenus[i]);
6245 if (pm->total != j)
6246 {
6247 if (pm->total > j)
6248 {
6249 /* must add new entries */
6250 for(k=j; k<pm->total; k++)
6251 AppendMenu(gra_pulldownmenus[i], x_("\pX"));
6252 } else
6253 {
6254 /* must delete extra entries */
6255 for(k=pm->total; k<j; k++)
6256 DeleteMenuItem(gra_pulldownmenus[i], pm->total);
6257 }
6258 }
6259
6260 uc = pm->list[sindex].response;
6261 (void)estrcpy(&line[1], us_stripampersand(pm->list[sindex].attribute));
6262 if (uc->active < 0)
6263 {
6264 if (gra_pulldownmenus[i] != 0)
6265 DisableItem(gra_pulldownmenus[i], sindex+1);
6266 if (*pm->list[sindex].attribute == 0) (void)estrcpy(line, x_(" -"));
6267 } else
6268 {
6269 if (gra_pulldownmenus[i] != 0)
6270 EnableItem(gra_pulldownmenus[i], sindex+1);
6271 }
6272
6273 line[0] = estrlen(&line[1]);
6274 pt = line;
6275 if (pt[pt[0]] == '<') pt[0]--;
6276 if (pt[1] != '>')
6277 {
6278 if (gra_pulldownmenus[i] != 0)
6279 CheckItem(gra_pulldownmenus[i], sindex+1, 0);
6280 } else
6281 {
6282 pt[1] = pt[0] - 1;
6283 pt++;
6284 if (gra_pulldownmenus[i] != 0)
6285 CheckItem(gra_pulldownmenus[i], sindex+1, 1);
6286 }
6287 pt[pt[0]+1] = 0;
6288 cmdchar = 0;
6289 for(j=pt[0]; j > 0; j--) if (pt[j] == '/' || pt[j] == '\\') break;
6290 if (pt[j] == '/' || pt[j] == '\\')
6291 {
6292 (void)us_getboundkey(&pt[j], &boundkey, &boundspecial);
6293 if ((boundspecial&ACCELERATORDOWN) == 0)
6294 esnprintf(&pt[j], 100-j, x_("\t%s"), us_describeboundkey(boundkey, boundspecial, 1));
6295 }
6296 if (gra_pulldownmenus[i] != 0)
6297 {
6298 SetMenuItemText(gra_pulldownmenus[i], sindex+1, (UCHAR1 *)pt);
6299 SetItemCmd(gra_pulldownmenus[i], sindex+1, cmdchar);
6300 }
6301
6302 /* see if this command is another menu */
6303 if (uc->menu != NOPOPUPMENU)
6304 {
6305 for(submenuindex=0; submenuindex<gra_pulldownmenucount; submenuindex++)
6306 if (namesame(gra_pulldowns[submenuindex], uc->menu->name) == 0) break;
6307 if (submenuindex < gra_pulldownmenucount)
6308 {
6309 if (gra_pulldownmenus[i] != 0)
6310 {
6311 SetItemCmd(gra_pulldownmenus[i], sindex+1, 0x1B);
6312 SetItemMark(gra_pulldownmenus[i], sindex+1, USERMENUBASE+submenuindex);
6313 }
6314 }
6315 }
6316 }
6317
6318 /*
6319 * Routine to establish the "count" pulldown menu names in "par" as the pulldown menu bar.
6320 * Returns true on error.
6321 */
nativemenuload(INTBIG count,CHAR * par[])6322 void nativemenuload(INTBIG count, CHAR *par[])
6323 {
6324 REGISTER INTBIG i, menuindex;
6325 REGISTER POPUPMENU *pm;
6326 POPUPMENU *pulls[25];
6327
6328 /* build the pulldown menu bar */
6329 for(i=0; i<count; i++)
6330 {
6331 pm = us_getpopupmenu(par[i]);
6332 if (pm == NOPOPUPMENU) continue;
6333 pulls[i] = pm;
6334 menuindex = gra_pulldownindex(pm);
6335 if (menuindex < 0) continue;
6336 InsertMenu(gra_pulldownmenus[menuindex], 0);
6337 }
6338 DrawMenuBar();
6339 }
6340
6341 /*
6342 * Routine to create a pulldown menu from popup menu "pm".
6343 * Returns an index to the table of pulldown menus (-1 on error).
6344 */
gra_pulldownindex(POPUPMENU * pm)6345 INTBIG gra_pulldownindex(POPUPMENU *pm)
6346 {
6347 REGISTER INTBIG i, sindex, newtotal;
6348 MenuHandle *newpulldownmenus;
6349 CHAR **newpulldowns;
6350
6351 /* see if it is in the list already */
6352 for(i=0; i<gra_pulldownmenucount; i++)
6353 if (namesame(gra_pulldowns[i], pm->name) == 0) return(i);
6354
6355 /* make room for the new menu */
6356 if (gra_pulldownmenucount >= gra_pulldownmenutotal)
6357 {
6358 newtotal = gra_pulldownmenutotal * 2;
6359 if (newtotal < gra_pulldownmenucount) newtotal = gra_pulldownmenucount + 5;
6360
6361 newpulldownmenus = (MenuHandle *)emalloc(newtotal *
6362 (sizeof (MenuHandle)), us_tool->cluster);
6363 if (newpulldownmenus == 0) return(-1);
6364 newpulldowns = (CHAR **)emalloc(newtotal *
6365 (sizeof (CHAR *)), us_tool->cluster);
6366 if (newpulldowns == 0) return(-1);
6367 for(i=0; i<gra_pulldownmenucount; i++)
6368 {
6369 newpulldownmenus[i] = gra_pulldownmenus[i];
6370 newpulldowns[i] = gra_pulldowns[i];
6371 }
6372 if (gra_pulldownmenutotal > 0)
6373 {
6374 efree((CHAR *)gra_pulldownmenus);
6375 efree((CHAR *)gra_pulldowns);
6376 }
6377 gra_pulldownmenus = newpulldownmenus;
6378 gra_pulldowns = newpulldowns;
6379 gra_pulldownmenutotal = newtotal;
6380 }
6381
6382 sindex = gra_pulldownmenucount++;
6383 (void)allocstring(&gra_pulldowns[sindex], pm->name, us_tool->cluster);
6384 gra_pulldownmenus[sindex] = gra_makepdmenu(pm, USERMENUBASE+sindex);
6385 if (gra_pulldownmenus[sindex] == 0) return(-1);
6386 return(sindex);
6387 }
6388
6389 /*
6390 * Routine to create pulldown menu number "value" from the popup menu in "pm" and return
6391 * the menu handle.
6392 */
gra_makepdmenu(POPUPMENU * pm,INTBIG value)6393 MenuHandle gra_makepdmenu(POPUPMENU *pm, INTBIG value)
6394 {
6395 REGISTER INTBIG i, j, submenuindex, len;
6396 INTBIG boundspecial;
6397 INTSML boundkey;
6398 CHAR myline[256], attrib[256], *pt;
6399 REGISTER USERCOM *uc;
6400 REGISTER POPUPMENUITEM *mi;
6401 MenuHandle thismenu;
6402 CHAR submenu[4];
6403
6404 estrcpy(&myline[1], us_stripampersand(pm->header));
6405 myline[0] = estrlen(&myline[1]);
6406 thismenu = NewMenu(value, (UCHAR1 *)myline);
6407 if (thismenu == 0) return(0);
6408
6409 /* build the actual menu */
6410 for(i=0; i<pm->total; i++)
6411 {
6412 mi = &pm->list[i];
6413
6414 /* quote illegal characters */
6415 pt = attrib;
6416 for(j=0; mi->attribute[j] != 0; j++)
6417 {
6418 if (mi->attribute[j] == '&') continue;
6419 if (mi->attribute[j] == '(') *pt++ = '{'; else
6420 if (mi->attribute[j] == ')') *pt++ = '}'; else
6421 *pt++ = mi->attribute[j];
6422 }
6423 *pt = 0;
6424
6425 uc = mi->response;
6426 if (uc->active < 0)
6427 {
6428 (void)estrcpy(myline, x_(" ("));
6429 if (*attrib == 0) (void)estrcat(myline, x_("-")); else
6430 (void)estrcat(myline, attrib);
6431 myline[0] = estrlen(&myline[1]);
6432 AppendMenu(thismenu, (UCHAR1 *)myline);
6433 continue;
6434 }
6435
6436 /* see if this command is another menu */
6437 if (uc->menu != NOPOPUPMENU)
6438 {
6439 submenuindex = gra_pulldownindex(uc->menu);
6440 if (submenuindex < 0) continue;
6441 InsertMenu(gra_pulldownmenus[submenuindex], -1);
6442 myline[1] = '!'; myline[2] = USERMENUBASE+submenuindex;
6443 (void)estrcpy(&myline[3], attrib);
6444 submenu[0] = '/'; submenu[1] = 0x1B; submenu[2] = 0;
6445 (void)estrcat(&myline[1], submenu);
6446 myline[0] = estrlen(&myline[1]);
6447 AppendMenu(thismenu, (UCHAR1 *)myline);
6448 continue;
6449 }
6450
6451 /* insert command title */
6452 pt = attrib;
6453 len = estrlen(pt) - 1;
6454 if (pt[len] == '<') pt[len] = 0;
6455 for(j=estrlen(pt)-1; j > 0; j--) if (pt[j] == '/' || pt[j] == '\\') break;
6456 if (pt[j] == '/' || pt[j] == '\\')
6457 {
6458 (void)us_getboundkey(&pt[j], &boundkey, &boundspecial);
6459 if ((boundspecial&ACCELERATORDOWN) == 0)
6460 esnprintf(&pt[j], 256-j, x_("\t%s"), us_describeboundkey(boundkey, boundspecial, 1));
6461 }
6462 if (pt[0] == '>')
6463 {
6464 myline[1] = '!';
6465 myline[2] = 022;
6466 (void)estrcpy(&myline[3], &pt[1]);
6467 } else (void)estrcpy(&myline[1], pt);
6468 myline[0] = estrlen(&myline[1]);
6469 AppendMenu(thismenu, (UCHAR1 *)myline);
6470 }
6471 return(thismenu);
6472 }
6473
6474 /****************************** DIALOGS ******************************/
6475
6476 /*
6477 * Routine to initialize a dialog described by "dialog".
6478 * Returns true if dialog cannot be initialized.
6479 */
DiaInitDialog(DIALOG * dialog)6480 void *DiaInitDialog(DIALOG *dialog)
6481 {
6482 TDIALOG *dia;
6483
6484 dia = (TDIALOG *)emalloc(sizeof (TDIALOG), db_cluster);
6485 if (dia == 0) return(0);
6486 if (gra_initdialog(dialog, dia, FALSE)) return(0);
6487 return(dia);
6488 }
6489
6490 /*
6491 * Routine to initialize dialog "dialog" in modeless style, calling
6492 * "itemhit" for each hit.
6493 */
DiaInitDialogModeless(DIALOG * dialog,void (* itemhit)(void * dia,INTBIG item))6494 void *DiaInitDialogModeless(DIALOG *dialog, void (*itemhit)(void *dia, INTBIG item))
6495 {
6496 TDIALOG *dia;
6497
6498 dia = (TDIALOG *)emalloc(sizeof (TDIALOG), db_cluster);
6499 if (dia == 0) return(0);
6500 if (gra_initdialog(dialog, dia, TRUE)) return(0);
6501 dia->modelessitemhit = itemhit;
6502 return(dia);
6503 }
6504
6505 /*
6506 * Routine to initialize a dialog described by "dialog".
6507 * Returns true if dialog cannot be initialized.
6508 */
gra_initdialog(DIALOG * dialog,TDIALOG * dia,BOOLEAN modeless)6509 BOOLEAN gra_initdialog(DIALOG *dialog, TDIALOG *dia, BOOLEAN modeless)
6510 {
6511 INTBIG itemtype, i, pureitemtype, amt, j;
6512 RECTAREA r;
6513 CHAR *save, *line;
6514 POPUPDATA *pd;
6515
6516 /* add this to the list of active dialogs */
6517 dia->nexttdialog = gra_firstactivedialog;
6518 gra_firstactivedialog = dia;
6519
6520 /* be sure the dialog is translated */
6521 DiaTranslate(dialog);
6522
6523 /* initialize dialog data structures */
6524 dia->defaultbutton = OK;
6525 dia->dlgresaddr = dialog;
6526 dia->curitem = -1;
6527 dia->opaqueitem = -1;
6528 dia->usertextsize = 10;
6529 dia->userdoubleclick = 0;
6530 dia->lastdiatime = 0;
6531 dia->numlocks = 0;
6532 for(i=0; i<MAXSCROLLS; i++)
6533 {
6534 dia->scroll[i].scrollitem = -1;
6535 dia->scroll[i].horizfactor = 0;
6536 dia->scroll[i].scrolllistlen = 0;
6537 dia->scroll[i].scrolllistsize = 0;
6538 }
6539 dia->curscroll = 0;
6540 dia->scrollcount = 0;
6541 dia->firstch = 0;
6542 dia->modelessitemhit = 0;
6543
6544 #ifdef INTERNATIONAL
6545 /* compute size of some items to automatically scale them */
6546 SetPort(gra_messageswindow);
6547 TextFont(DFONT);
6548 TextSize(12);
6549 for(i=0; i<dialog->items; i++)
6550 {
6551 INTBIG offset;
6552 itemtype = dialog->list[i].type & ITEMTYPE;
6553 r = dia->dlgresaddr->list[i].r;
6554 switch (itemtype)
6555 {
6556 case DEFBUTTON:
6557 case BUTTON:
6558 case CHECK:
6559 case RADIO:
6560 case MESSAGE:
6561 if (itemtype == BUTTON || itemtype == DEFBUTTON) offset = 8; else
6562 if (itemtype == CHECK || itemtype == RADIO) offset = 16; else
6563 offset = 5;
6564 line = dialog->list[i].msg;
6565 j = TextWidth(line, 0, estrlen(line));
6566 amt = (j + offset) - (r.right - r.left);
6567 if (amt > 0)
6568 {
6569 INTBIG ycenter, k, shiftamt[100];
6570 for(j = 0; j < dialog->items; j++) shiftamt[j] = 0;
6571 for(j=0; j<dialog->items; j++)
6572 {
6573 if (j == i) continue;
6574 if (dialog->list[j].r.left >= dialog->list[i].r.right &&
6575 dialog->list[j].r.left < dialog->list[i].r.right+amt)
6576 {
6577 shiftamt[j] = amt;
6578 ycenter = (dialog->list[j].r.top + dialog->list[j].r.bottom) / 2;
6579 for(k=0; k<dialog->items; k++)
6580 {
6581 if (k == i || k == j) continue;
6582 if (dialog->list[k].r.right < dialog->list[j].r.left) continue;
6583 if (dialog->list[k].r.top < ycenter &&
6584 dialog->list[k].r.bottom > ycenter)
6585 shiftamt[k] = amt;
6586 }
6587 }
6588 }
6589 dia->dlgresaddr->list[i].r.right += amt;
6590 for(j = 0; j < dialog->items; j++)
6591 {
6592 dialog->list[j].r.left += shiftamt[j];
6593 dialog->list[j].r.right += shiftamt[j];
6594 }
6595 }
6596 break;
6597 }
6598 }
6599 #endif
6600 for(i=0; i<dialog->items; i++)
6601 {
6602 j = dia->dlgresaddr->list[i].r.right + 5;
6603 if (j < dialog->windowRect.right - dialog->windowRect.left) continue;
6604 dialog->windowRect.right = dialog->windowRect.left + j;
6605 }
6606 /* make the window */
6607 Dnewdialogwindow(dia, &dialog->windowRect, dialog->movable, modeless);
6608
6609 /* find the default button */
6610 for(i=0; i<dialog->items; i++)
6611 {
6612 itemtype = dia->dlgresaddr->list[i].type;
6613 if ((itemtype&ITEMTYPE) == DEFBUTTON)
6614 dia->defaultbutton = i+1;
6615 }
6616
6617 /* loop through all of the dialog entries, drawing them */
6618 for(i=0; i<dialog->items; i++)
6619 {
6620 /* draw the item */
6621 itemtype = dia->dlgresaddr->list[i].type;
6622 pureitemtype = itemtype & ITEMTYPE;
6623 line = dia->dlgresaddr->list[i].msg;
6624 r = dia->dlgresaddr->list[i].r;
6625
6626 if (pureitemtype == EDITTEXT)
6627 {
6628 if (dia->curitem == -1) dia->curitem = i;
6629 }
6630 if (pureitemtype == SCROLL || pureitemtype == SCROLLMULTI)
6631 {
6632 if (dia->scrollcount < MAXSCROLLS)
6633 dia->scroll[dia->scrollcount++].scrollitem = i;
6634 }
6635 if (pureitemtype == MESSAGE || pureitemtype == EDITTEXT ||
6636 pureitemtype == BUTTON || pureitemtype == DEFBUTTON ||
6637 pureitemtype == CHECK || pureitemtype == RADIO)
6638 {
6639 amt = estrlen(line) + 1;
6640 if (pureitemtype == CHECK || pureitemtype == RADIO) amt++;
6641 save = (CHAR *)emalloc(amt * SIZEOFCHAR, el_tempcluster);
6642 if (save == 0) return(TRUE);
6643 if (pureitemtype == CHECK || pureitemtype == RADIO)
6644 {
6645 (void)estrcpy(&save[1], line);
6646 save[0] = 0;
6647 } else (void)estrcpy(save, line);
6648 dia->dlgresaddr->list[i].data = (INTBIG)save;
6649 } else if (pureitemtype == POPUP)
6650 {
6651 pd = (POPUPDATA *)emalloc(sizeof (POPUPDATA), el_tempcluster);
6652 if (pd == 0) return(TRUE);
6653 pd->count = 0;
6654 dia->dlgresaddr->list[i].data = (INTBIG)pd;
6655 line = (CHAR *)pd;
6656 } else if (pureitemtype == ICON)
6657 {
6658 dia->dlgresaddr->list[i].data = (INTBIG)line;
6659 } else dia->dlgresaddr->list[i].data = 0;
6660
6661 Ddrawitem(dia, itemtype, &r, line, 0);
6662
6663 /* highlight the default button */
6664 if (i == dia->defaultbutton-1 &&
6665 (itemtype == BUTTON || itemtype == DEFBUTTON)) Dhighlightrect(dia, &r);
6666 }
6667 if (dia->curitem >= 0)
6668 {
6669 dia->editstart = 0;
6670 dia->editend = estrlen(dia->dlgresaddr->list[dia->curitem].msg);
6671 Dhighlight(dia, 1);
6672 }
6673 dia->firstupdate = 1;
6674 return(FALSE);
6675 }
6676
6677 /*
6678 * Routine to handle actions and return the next item hit.
6679 */
DiaNextHit(void * vdia)6680 INTBIG DiaNextHit(void *vdia)
6681 {
6682 INTBIG chr, itemHit, oak, x, y, special;
6683 UINTBIG time;
6684 BOOLEAN shifted;
6685 TDIALOG *dia;
6686
6687 dia = (TDIALOG *)vdia;
6688 for(;;)
6689 {
6690 /* if interrupted, stop dialog */
6691 if (el_pleasestop != 0) return(CANCEL);
6692
6693 /* get the next event, ignore fluff */
6694 oak = Dwaitforaction(dia, &x, &y, &chr, &special, &time, &shifted);
6695 itemHit = gra_getnextcharacter(dia, oak, x, y, chr, special, time, shifted);
6696 if (itemHit == -1) continue;
6697 break;
6698 }
6699 return(itemHit);
6700 }
6701
DiaDoneDialog(void * vdia)6702 void DiaDoneDialog(void *vdia)
6703 {
6704 INTBIG i, j, type, puretype;
6705 POPUPDATA *oldpd;
6706 TDIALOG *dia, *ldia, *odia;
6707
6708 dia = (TDIALOG *)vdia;
6709
6710 /* remove this from the list of active dialogs */
6711 ldia = NOTDIALOG;
6712 for(odia = gra_firstactivedialog; odia != NOTDIALOG; odia = odia->nexttdialog)
6713 {
6714 if (odia == dia) break;
6715 ldia = odia;
6716 }
6717 if (odia != NOTDIALOG)
6718 {
6719 if (ldia == NOTDIALOG) gra_firstactivedialog = dia->nexttdialog; else
6720 ldia->nexttdialog = dia->nexttdialog;
6721 }
6722
6723 /* free all the edit text and message buffers */
6724 for(i=0; i<dia->dlgresaddr->items; i++)
6725 {
6726 type = dia->dlgresaddr->list[i].type;
6727 puretype = type & ITEMTYPE;
6728 if (puretype == POPUP)
6729 {
6730 oldpd = (POPUPDATA *)dia->dlgresaddr->list[i].data;
6731 for(j=0; j<oldpd->count; j++) efree((CHAR *)oldpd->namelist[j]);
6732 if (oldpd->count > 0) efree((CHAR *)oldpd->namelist);
6733 }
6734 if (puretype == MESSAGE || puretype == EDITTEXT || puretype == POPUP ||
6735 puretype == BUTTON || puretype == DEFBUTTON ||
6736 puretype == RADIO || puretype == CHECK)
6737 efree((CHAR *)dia->dlgresaddr->list[i].data);
6738 }
6739
6740 /* free all items in the scroll area */
6741 for(i=0; i<dia->scrollcount; i++)
6742 {
6743 for(j=0; j<dia->scroll[i].scrolllistlen; j++)
6744 efree((CHAR *)dia->scroll[i].scrolllist[j]);
6745 if (dia->scroll[i].scrolllistsize > 0) efree((CHAR *)dia->scroll[i].scrolllist);
6746 }
6747 Ddonedialogwindow(dia);
6748
6749 /* redraw all other dialogs */
6750 for(odia = gra_firstactivedialog; odia != NOTDIALOG; odia = odia->nexttdialog)
6751 Dredrawdialogwindow(odia);
6752
6753 /* free the "dia" structure */
6754 efree((CHAR *)dia);
6755 }
6756
6757 /*
6758 * Routine to change the size of the dialog
6759 */
DiaResizeDialog(void * vdia,INTBIG wid,INTBIG hei)6760 void DiaResizeDialog(void *vdia, INTBIG wid, INTBIG hei)
6761 {
6762 TDIALOG *dia;
6763
6764 dia = (TDIALOG *)vdia;
6765 SizeWindow((WindowRef)dia->theDialog, wid, hei, 1);
6766 }
6767
6768 /*
6769 * Force the dialog to be visible.
6770 */
DiaBringToTop(void * vdia)6771 void DiaBringToTop(void *vdia)
6772 {
6773 TDIALOG *dia;
6774
6775 dia = (TDIALOG *)vdia;
6776 }
6777
6778 /*
6779 * Routine to set the text in item "item" to "msg"
6780 */
DiaSetText(void * vdia,INTBIG item,CHAR * msg)6781 void DiaSetText(void *vdia, INTBIG item, CHAR *msg)
6782 {
6783 INTBIG highlight, type, puretype, oldcur, dim;
6784 INTBIG amt;
6785 CHAR *save, *pt;
6786 RECTAREA r;
6787 TDIALOG *dia;
6788
6789 dia = (TDIALOG *)vdia;
6790
6791 /* determine whether item is highlighted */
6792 highlight = 0;
6793 if (item < 0)
6794 {
6795 item = -item;
6796 highlight = 1;
6797 }
6798 item--;
6799 if (item < 0 || item >= dia->dlgresaddr->items) return;
6800 type = dia->dlgresaddr->list[item].type;
6801 puretype = type & ITEMTYPE;
6802
6803 /* special case when renaming buttons */
6804 if (puretype == BUTTON || puretype == DEFBUTTON ||
6805 puretype == CHECK || puretype == RADIO)
6806 {
6807 /* save the new string */
6808 amt = estrlen(msg)+1;
6809 if (puretype == CHECK || puretype == RADIO) amt++;
6810 save = (CHAR *)emalloc(amt * SIZEOFCHAR, el_tempcluster);
6811 if (save == 0) return;
6812 if (puretype == CHECK || puretype == RADIO)
6813 {
6814 (void)estrcpy(&save[1], msg);
6815 save[0] = ((CHAR *)dia->dlgresaddr->list[item].data)[0];
6816 } else (void)estrcpy(save, msg);
6817 efree((CHAR *)dia->dlgresaddr->list[item].data);
6818 dia->dlgresaddr->list[item].data = (INTBIG)save;
6819
6820 r = dia->dlgresaddr->list[item].r;
6821 if ((type&INACTIVE) != 0) dim = 1; else dim = 0;
6822 Dintdrawrect(dia, &r, 255, 255, 255);
6823 Ddrawitem(dia, type, &r, msg, dim);
6824 if (puretype == RADIO && ((CHAR *)dia->dlgresaddr->list[item].data)[0] != 0)
6825 {
6826 /* draw the circle in a selected radio button */
6827 r.right = r.left + 12;
6828 r.top = (r.top + r.bottom) / 2 - 6;
6829 r.bottom = r.top + 12;
6830 Dinsetrect(&r, 3);
6831 Ddrawdisc(dia, &r);
6832 }
6833 if (puretype == CHECK && ((CHAR *)dia->dlgresaddr->list[item].data)[0] != 0)
6834 {
6835 /* draw the "X" in a selected check box */
6836 r.right = r.left + 12;
6837 r.top = (r.top + r.bottom) / 2 - 6;
6838 r.bottom = r.top + 12;
6839 Ddrawline(dia, r.left, r.top, r.right-1, r.bottom-1);
6840 Ddrawline(dia, r.left, r.bottom-1, r.right-1, r.top);
6841 }
6842 return;
6843 }
6844
6845 /* convert copyright character sequence */
6846 for(pt = msg; *pt != 0; pt++) if (estrncmp(pt, x_("(c)"), 3) == 0)
6847 {
6848 (void)estrcpy(pt, x_("\251")); /* "copyright" character */
6849 (void)estrcpy(&pt[1], &pt[3]);
6850 break;
6851 }
6852
6853 /* handle messages and edit text */
6854 oldcur = dia->curitem; Ddoneedit(dia);
6855 if (puretype == MESSAGE || puretype == EDITTEXT)
6856 {
6857 /* save the new string */
6858 amt = estrlen(msg)+1;
6859 save = (CHAR *)emalloc(amt * SIZEOFCHAR, el_tempcluster);
6860 if (save == 0) return;
6861 (void)estrcpy(save, msg);
6862 efree((CHAR *)dia->dlgresaddr->list[item].data);
6863 dia->dlgresaddr->list[item].data = (INTBIG)save;
6864
6865 /* redisplay the item */
6866 if (puretype == MESSAGE)
6867 Dstuffmessage(dia, msg, &dia->dlgresaddr->list[item].r, 0); else
6868 Dstufftext(dia, msg, &dia->dlgresaddr->list[item].r);
6869 if (puretype == EDITTEXT)
6870 {
6871 if (highlight != 0)
6872 {
6873 Ddoneedit(dia);
6874 oldcur = item;
6875 dia->editstart = 0;
6876 dia->editend = estrlen(msg);
6877 dia->firstch = 0;
6878 } else if (oldcur == item)
6879 {
6880 dia->editstart = dia->editend = estrlen(msg);
6881 }
6882 }
6883 }
6884 dia->curitem = oldcur;
6885 Dhighlight(dia, 1);
6886 }
6887
6888 /*
6889 * Routine to return the text in item "item"
6890 */
DiaGetText(void * vdia,INTBIG item)6891 CHAR *DiaGetText(void *vdia, INTBIG item)
6892 {
6893 INTBIG type;
6894 POPUPDATA *pd;
6895 TDIALOG *dia;
6896
6897 dia = (TDIALOG *)vdia;
6898 item--;
6899 if (item < 0 || item >= dia->dlgresaddr->items) return(x_(""));
6900 type = dia->dlgresaddr->list[item].type & ITEMTYPE;
6901 if (type == POPUP)
6902 {
6903 pd = (POPUPDATA *)dia->dlgresaddr->list[item].data;
6904 return(pd->namelist[pd->current]);
6905 }
6906 if (type == MESSAGE || type == EDITTEXT ||
6907 type == BUTTON || type == DEFBUTTON)
6908 return((CHAR *)dia->dlgresaddr->list[item].data);
6909 if (type == CHECK || type == RADIO)
6910 return(&((CHAR *)dia->dlgresaddr->list[item].data)[1]);
6911 return(0);
6912 }
6913
6914 /*
6915 * Routine to set the value in item "item" to "value"
6916 */
DiaSetControl(void * vdia,INTBIG item,INTBIG value)6917 void DiaSetControl(void *vdia, INTBIG item, INTBIG value)
6918 {
6919 INTBIG type;
6920 RECTAREA r;
6921 TDIALOG *dia;
6922
6923 dia = (TDIALOG *)vdia;
6924 item--;
6925 if (item < 0 || item >= dia->dlgresaddr->items) return;
6926 type = dia->dlgresaddr->list[item].type & ITEMTYPE;
6927 r = dia->dlgresaddr->list[item].r;
6928 if (type == CHECK)
6929 {
6930 /* check box */
6931 r.right = r.left + 12;
6932 r.top = (r.top + r.bottom) / 2 - 6;
6933 r.bottom = r.top + 12;
6934 Dintdrawrect(dia, &r, 255, 255, 255);
6935 Ddrawrectframe(dia, &r, 1, 0);
6936 if (value != 0)
6937 {
6938 Ddrawline(dia, r.left, r.top, r.right-1, r.bottom-1);
6939 Ddrawline(dia, r.left, r.bottom-1, r.right-1, r.top);
6940 }
6941 ((CHAR *)dia->dlgresaddr->list[item].data)[0] = (CHAR)value;
6942 } else if (type == RADIO)
6943 {
6944 /* radio button */
6945 r.right = r.left + 12;
6946 r.top = (r.top + r.bottom) / 2 - 6;
6947 r.bottom = r.top + 12;
6948 Dintdrawrect(dia, &r, 255, 255, 255);
6949 Ddrawcircle(dia, &r, 0);
6950 if (value != 0)
6951 {
6952 Dinsetrect(&r, 3);
6953 Ddrawdisc(dia, &r);
6954 }
6955 ((CHAR *)dia->dlgresaddr->list[item].data)[0] = (CHAR)value;
6956 }
6957 }
6958
6959 /*
6960 * Routine to return the value in item "item"
6961 */
DiaGetControl(void * vdia,INTBIG item)6962 INTBIG DiaGetControl(void *vdia, INTBIG item)
6963 {
6964 INTBIG type;
6965 TDIALOG *dia;
6966
6967 dia = (TDIALOG *)vdia;
6968 item--;
6969 if (item < 0 || item >= dia->dlgresaddr->items) return(0);
6970 type = dia->dlgresaddr->list[item].type & ITEMTYPE;
6971 if (type == CHECK || type == RADIO)
6972 return((INTBIG)((CHAR *)dia->dlgresaddr->list[item].data)[0]);
6973 return(0);
6974 }
6975
6976 /*
6977 * Routine to check item "item" to make sure that there is
6978 * text in it. If so, it returns true. Otherwise it beeps and returns false.
6979 */
DiaValidEntry(void * vdia,INTBIG item)6980 BOOLEAN DiaValidEntry(void *vdia, INTBIG item)
6981 {
6982 CHAR *msg;
6983 TDIALOG *dia;
6984
6985 dia = (TDIALOG *)vdia;
6986 msg = DiaGetText(dia, item);
6987 while (*msg == ' ' || *msg == '\t') msg++;
6988 if (*msg != 0) return(TRUE);
6989 ttybeep(SOUNDBEEP, TRUE);
6990 return(FALSE);
6991 }
6992
6993 /*
6994 * Routine to dim item "item"
6995 */
DiaDimItem(void * vdia,INTBIG item)6996 void DiaDimItem(void *vdia, INTBIG item)
6997 {
6998 CHAR *msg;
6999 INTBIG type;
7000 RECTAREA r;
7001 TDIALOG *dia;
7002 dia = (TDIALOG *)vdia;
7003 item--;
7004 if (item < 0 || item >= dia->dlgresaddr->items) return;
7005 if (item == dia->curitem) Ddoneedit(dia);
7006 dia->dlgresaddr->list[item].type |= INACTIVE;
7007 type = dia->dlgresaddr->list[item].type;
7008 r = dia->dlgresaddr->list[item].r;
7009 msg = (CHAR *)dia->dlgresaddr->list[item].data;
7010 if ((type&ITEMTYPE) == CHECK || (type&ITEMTYPE) == RADIO) msg++;
7011 Ddrawitem(dia, type, &r, msg, 1);
7012 }
7013
7014 /*
7015 * Routine to un-dim item "item"
7016 */
DiaUnDimItem(void * vdia,INTBIG item)7017 void DiaUnDimItem(void *vdia, INTBIG item)
7018 {
7019 CHAR *msg;
7020 INTBIG type;
7021 RECTAREA r;
7022 TDIALOG *dia;
7023
7024 dia = (TDIALOG *)vdia;
7025 item--;
7026 if (item < 0 || item >= dia->dlgresaddr->items) return;
7027 dia->dlgresaddr->list[item].type &= ~INACTIVE;
7028 type = dia->dlgresaddr->list[item].type;
7029 r = dia->dlgresaddr->list[item].r;
7030 msg = (CHAR *)dia->dlgresaddr->list[item].data;
7031 if ((type&ITEMTYPE) == CHECK || (type&ITEMTYPE) == RADIO) msg++;
7032 Ddrawitem(dia, type, &r, msg, 0);
7033
7034 /* if undimming selected radio button, redraw disc */
7035 if ((type&ITEMTYPE) == RADIO && ((CHAR *)dia->dlgresaddr->list[item].data)[0] != 0)
7036 {
7037 r.right = r.left + 9;
7038 r.left += 3;
7039 r.top = (r.top + r.bottom) / 2 - 3;
7040 r.bottom = r.top + 6;
7041 Ddrawdisc(dia, &r);
7042 }
7043 }
7044
7045 /*
7046 * Routine to change item "item" to be a message rather
7047 * than editable text
7048 */
DiaNoEditControl(void * vdia,INTBIG item)7049 void DiaNoEditControl(void *vdia, INTBIG item)
7050 {
7051 TDIALOG *dia;
7052
7053 dia = (TDIALOG *)vdia;
7054 item--;
7055 if (item < 0 || item >= dia->dlgresaddr->items) return;
7056 if (item == dia->curitem) Ddoneedit(dia);
7057 dia->dlgresaddr->list[item].type = MESSAGE;
7058 Deditbox(dia, &dia->dlgresaddr->list[item].r, 0, 0);
7059 }
7060
7061 /*
7062 * Routine to change item "item" to be editable text rather
7063 * than a message
7064 */
DiaEditControl(void * vdia,INTBIG item)7065 void DiaEditControl(void *vdia, INTBIG item)
7066 {
7067 TDIALOG *dia;
7068
7069 dia = (TDIALOG *)vdia;
7070 item--;
7071 if (item < 0 || item >= dia->dlgresaddr->items) return;
7072 dia->dlgresaddr->list[item].type = EDITTEXT;
7073 Deditbox(dia, &dia->dlgresaddr->list[item].r, 1, 0);
7074 }
7075
DiaOpaqueEdit(void * vdia,INTBIG item)7076 void DiaOpaqueEdit(void *vdia, INTBIG item)
7077 {
7078 TDIALOG *dia;
7079
7080 dia = (TDIALOG *)vdia;
7081 item--;
7082 if (item < 0 || item >= dia->dlgresaddr->items) return;
7083 if (dia->dlgresaddr->list[item].type != EDITTEXT) return;
7084 dia->opaqueitem = item;
7085 }
7086
7087 /*
7088 * Routine to cause item "item" to be the default button
7089 */
DiaDefaultButton(void * vdia,INTBIG item)7090 void DiaDefaultButton(void *vdia, INTBIG item)
7091 {
7092 INTBIG olddefault;
7093 INTBIG itemtype, dim;
7094 RECTAREA r;
7095 CHAR *line;
7096 TDIALOG *dia;
7097
7098 dia = (TDIALOG *)vdia;
7099 if (item == dia->defaultbutton) return;
7100 olddefault = dia->defaultbutton - 1;
7101 dia->defaultbutton = item;
7102
7103 /* redraw the old item without highlighting */
7104 itemtype = dia->dlgresaddr->list[olddefault].type;
7105 r = dia->dlgresaddr->list[olddefault].r;
7106 Dinsetrect(&r, -4); r.right++;
7107 Dintdrawrect(dia, &r, 255, 255, 255);
7108 Dinsetrect(&r, 4); r.right--;
7109 line = (CHAR *)dia->dlgresaddr->list[olddefault].data;
7110 if ((itemtype&INACTIVE) != 0) dim = 1; else dim = 0;
7111 Ddrawitem(dia, itemtype, &r, line, dim);
7112
7113 /* highlight the new default button */
7114 r = dia->dlgresaddr->list[item-1].r;
7115 Dhighlightrect(dia, &r);
7116 }
7117
7118 /*
7119 * Routine to change the icon in item "item" to be the 32x32 bitmap (128 bytes) at "addr".
7120 */
DiaChangeIcon(void * vdia,INTBIG item,UCHAR1 * addr)7121 void DiaChangeIcon(void *vdia, INTBIG item, UCHAR1 *addr)
7122 {
7123 INTBIG type;
7124 RECTAREA r;
7125 TDIALOG *dia;
7126
7127 dia = (TDIALOG *)vdia;
7128 item--;
7129 if (item < 0 || item >= dia->dlgresaddr->items) return;
7130 type = dia->dlgresaddr->list[item].type;
7131 if ((type&ITEMTYPE) != ICON) return;
7132 dia->dlgresaddr->list[item].data = (INTBIG)addr;
7133 r = dia->dlgresaddr->list[item].r;
7134 Ddrawitem(dia, type, &r, (CHAR *)addr, 0);
7135 }
7136
7137 /*
7138 * Routine to change item "item" into a popup with "count" entries
7139 * in "names".
7140 */
DiaSetPopup(void * vdia,INTBIG item,INTBIG count,CHAR ** names)7141 void DiaSetPopup(void *vdia, INTBIG item, INTBIG count, CHAR **names)
7142 {
7143 POPUPDATA *pd;
7144 INTBIG i, type;
7145 TDIALOG *dia;
7146
7147 dia = (TDIALOG *)vdia;
7148 item--;
7149 if (item < 0 || item >= dia->dlgresaddr->items) return;
7150 type = dia->dlgresaddr->list[item].type;
7151 if ((type&ITEMTYPE) != POPUP) return;
7152
7153 /* copy into a POPUPDATA structure */
7154 pd = (POPUPDATA *)dia->dlgresaddr->list[item].data;
7155 for(i=0; i<pd->count; i++) efree((CHAR *)pd->namelist[i]);
7156 if (pd->count > 0) efree((CHAR *)pd->namelist);
7157 pd->count = count;
7158 pd->current = 0;
7159 pd->namelist = (CHAR **)emalloc(count * (sizeof (CHAR *)), el_tempcluster);
7160 if (pd->namelist == 0) return;
7161 for(i=0; i<count; i++)
7162 {
7163 pd->namelist[i] = (CHAR *)emalloc((estrlen(names[i])+1) * SIZEOFCHAR,
7164 el_tempcluster);
7165 if (pd->namelist[i] == 0) return;
7166 (void)estrcpy(pd->namelist[i], names[i]);
7167 }
7168
7169 /* display the popup */
7170 Ddrawitem(dia, POPUP, &dia->dlgresaddr->list[item].r, (CHAR *)pd, 0);
7171 }
7172
7173 /*
7174 * Routine to change popup item "item" so that the current entry is "entry".
7175 */
DiaSetPopupEntry(void * vdia,INTBIG item,INTBIG entry)7176 void DiaSetPopupEntry(void *vdia, INTBIG item, INTBIG entry)
7177 {
7178 POPUPDATA *pd;
7179 INTBIG type;
7180 TDIALOG *dia;
7181
7182 dia = (TDIALOG *)vdia;
7183 item--;
7184 if (item < 0 || item >= dia->dlgresaddr->items) return;
7185 type = dia->dlgresaddr->list[item].type;
7186 if ((type&ITEMTYPE) != POPUP) return;
7187 pd = (POPUPDATA *)dia->dlgresaddr->list[item].data;
7188 if (entry < 0 || entry >= pd->count) return;
7189 pd->current = entry;
7190
7191 Ddrawitem(dia, POPUP, &dia->dlgresaddr->list[item].r, (CHAR *)pd,
7192 type&INACTIVE);
7193 }
7194
7195 /*
7196 * Routine to return the current item in popup menu item "item".
7197 */
DiaGetPopupEntry(void * vdia,INTBIG item)7198 INTBIG DiaGetPopupEntry(void *vdia, INTBIG item)
7199 {
7200 POPUPDATA *pd;
7201 TDIALOG *dia;
7202
7203 dia = (TDIALOG *)vdia;
7204 item--;
7205 if (item < 0 || item >= dia->dlgresaddr->items) return(0);
7206 if ((dia->dlgresaddr->list[item].type&ITEMTYPE) != POPUP) return(0);
7207 pd = (POPUPDATA *)dia->dlgresaddr->list[item].data;
7208 return(pd->current);
7209 }
7210
DiaInitTextDialog(void * vdia,INTBIG item,BOOLEAN (* toplist)(CHAR **),CHAR * (* nextinlist)(void),void (* donelist)(void),INTBIG sortpos,INTBIG flags)7211 void DiaInitTextDialog(void *vdia, INTBIG item, BOOLEAN (*toplist)(CHAR **), CHAR *(*nextinlist)(void),
7212 void (*donelist)(void), INTBIG sortpos, INTBIG flags)
7213 {
7214 DSCROLL *scr;
7215 INTBIG sc;
7216 TDIALOG *dia;
7217
7218 dia = (TDIALOG *)vdia;
7219 item--;
7220 if (item < 0 || item >= dia->dlgresaddr->items) return;
7221 for(sc=0; sc<dia->scrollcount; sc++) if (dia->scroll[sc].scrollitem == item) break;
7222 if (sc >= dia->scrollcount) return;
7223 scr = &dia->scroll[sc];
7224
7225 /* save information about this scroll area */
7226 scr->flags = flags;
7227 if ((scr->flags&SCSMALLFONT) != 0)
7228 {
7229 scr->lineheight = dia->slineheight;
7230 scr->lineoffset = dia->slineoffset;
7231 } else
7232 {
7233 scr->lineheight = dia->lineheight;
7234 scr->lineoffset = dia->lineoffset;
7235 }
7236
7237 /* compute size of actual area (not including scroll bars) */
7238 scr->userrect = dia->dlgresaddr->list[item].r;
7239 scr->userrect.right -= 14;
7240 if ((scr->flags&SCHORIZBAR) != 0) scr->userrect.bottom -= 14;
7241 scr->linesinfolder = (scr->userrect.bottom - scr->userrect.top) / scr->lineheight;
7242
7243 /* draw sliders */
7244 Ddrawvertslider(dia, sc);
7245 if ((scr->flags&SCHORIZBAR) != 0) Ddrawhorizslider(dia, sc);
7246
7247 /* load the text */
7248 scr->scrolllistlen = 0;
7249 DiaLoadTextDialog(dia, item+1, toplist, nextinlist, donelist, sortpos);
7250 }
7251
DiaLoadTextDialog(void * vdia,INTBIG item,BOOLEAN (* toplist)(CHAR **),CHAR * (* nextinlist)(void),void (* donelist)(void),INTBIG sortpos)7252 void DiaLoadTextDialog(void *vdia, INTBIG item, BOOLEAN (*toplist)(CHAR **), CHAR *(*nextinlist)(void),
7253 void (*donelist)(void), INTBIG sortpos)
7254 {
7255 INTBIG i, items, sc;
7256 CHAR *next, **list, line[256];
7257 DSCROLL *scr;
7258 TDIALOG *dia;
7259
7260 dia = (TDIALOG *)vdia;
7261 item--;
7262 if (item < 0 || item >= dia->dlgresaddr->items) return;
7263 for(sc=0; sc<dia->scrollcount; sc++) if (dia->scroll[sc].scrollitem == item) break;
7264 if (sc >= dia->scrollcount) return;
7265 scr = &dia->scroll[sc];
7266
7267 /* deallocate all former items in the list */
7268 for(i=0; i<scr->scrolllistlen; i++) efree((CHAR *)scr->scrolllist[i]);
7269 scr->scrolllistlen = 0;
7270 scr->firstline = 0;
7271
7272 /* count the number of items to be put in the text editor */
7273 line[0] = 0;
7274 next = line;
7275 (void)(*toplist)(&next);
7276 for(items=0; ; items++) if ((*nextinlist)() == 0) break;
7277 (*donelist)();
7278
7279 /* allocate space for the strings */
7280 if (items > 0)
7281 {
7282 list = (CHAR **)emalloc(items * (sizeof (CHAR *)), el_tempcluster);
7283 if (list == 0) return;
7284 }
7285
7286 /* get the list */
7287 line[0] = 0;
7288 next = line;
7289 (void)(*toplist)(&next);
7290 for(i=0; i<items; i++)
7291 {
7292 next = (*nextinlist)();
7293 if (next == 0) next = x_("???");
7294 list[i] = (CHAR *)emalloc((estrlen(next)+1) * SIZEOFCHAR, el_tempcluster);
7295 if (list[i] == 0) return;
7296 estrcpy(list[i], next);
7297 }
7298 (*donelist)();
7299
7300 /* sort the list */
7301 if (sortpos >= 0)
7302 {
7303 gra_dialogstringpos = sortpos;
7304 esort(list, items, sizeof (CHAR *), gra_stringposascending);
7305 }
7306
7307 /* stuff the list into the text editor */
7308 scr->whichlow = -1;
7309 Dinsetrect(&scr->userrect, 1);
7310 Dintdrawrect(dia, &scr->userrect, 255, 255, 255);
7311 Dinsetrect(&scr->userrect, -1);
7312 for(i=0; i<items; i++) DiaStuffLine(dia, item+1, list[i]);
7313 Dsetvscroll(dia, sc);
7314 if (scr->scrolllistlen > 0) DiaSelectLine(dia, item+1, 0);
7315
7316 /* deallocate the list */
7317 if (items > 0)
7318 {
7319 for(i=0; i<items; i++) efree((CHAR *)list[i]);
7320 efree((CHAR *)list);
7321 }
7322 }
7323
7324 /*
7325 * Routine to stuff line "line" at the end of the edit buffer.
7326 */
DiaStuffLine(void * vdia,INTBIG item,CHAR * line)7327 void DiaStuffLine(void *vdia, INTBIG item, CHAR *line)
7328 {
7329 CHAR **newlist, *pt;
7330 INTBIG i, sc;
7331 DSCROLL *scr;
7332 TDIALOG *dia;
7333
7334 dia = (TDIALOG *)vdia;
7335 item--;
7336 if (item < 0 || item >= dia->dlgresaddr->items) return;
7337 for(sc=0; sc<dia->scrollcount; sc++) if (dia->scroll[sc].scrollitem == item) break;
7338 if (sc >= dia->scrollcount) return;
7339 scr = &dia->scroll[sc];
7340
7341 if (scr->scrolllistlen >= scr->scrolllistsize)
7342 {
7343 newlist = (CHAR **)emalloc((scr->scrolllistsize+10) * (sizeof (CHAR *)),
7344 el_tempcluster);
7345 if (newlist == 0) return;
7346 for(i=0; i<scr->scrolllistlen; i++) newlist[i] = scr->scrolllist[i];
7347 if (scr->scrolllistsize != 0) efree((CHAR *)scr->scrolllist);
7348 scr->scrolllist = newlist;
7349 scr->scrolllistsize += 10;
7350 }
7351 pt = (CHAR *)emalloc((estrlen(line)+1) * SIZEOFCHAR, el_tempcluster);
7352 if (pt == 0) return;
7353 (void)estrcpy(pt, line);
7354 if (scr->scrolllistlen < scr->firstline+scr->linesinfolder)
7355 Ddrawmsg(dia, sc, line, scr->scrolllistlen);
7356 scr->scrolllist[scr->scrolllistlen++] = pt;
7357 }
7358
7359 /*
7360 * Routine to select line "line" of scroll item "item".
7361 */
DiaSelectLine(void * vdia,INTBIG item,INTBIG l)7362 void DiaSelectLine(void *vdia, INTBIG item, INTBIG l)
7363 {
7364 INTBIG lines[1];
7365 TDIALOG *dia;
7366
7367 dia = (TDIALOG *)vdia;
7368 lines[0] = l;
7369 DiaSelectLines(dia, item, 1, lines);
7370 }
7371
7372 /*
7373 * Routine to select "count" lines in "lines" of scroll item "item".
7374 */
DiaSelectLines(void * vdia,INTBIG item,INTBIG count,INTBIG * lines)7375 void DiaSelectLines(void *vdia, INTBIG item, INTBIG count, INTBIG *lines)
7376 {
7377 INTBIG n, sc, whichlow, whichhigh, i;
7378 DSCROLL *scr;
7379 TDIALOG *dia;
7380
7381 dia = (TDIALOG *)vdia;
7382 item--;
7383 if (item < 0 || item >= dia->dlgresaddr->items) return;
7384 for(sc=0; sc<dia->scrollcount; sc++) if (dia->scroll[sc].scrollitem == item) break;
7385 if (sc >= dia->scrollcount) return;
7386 scr = &dia->scroll[sc];
7387 if (count == 0)
7388 {
7389 Dinvertentry(dia, sc, 0);
7390 scr->whichlow = -1;
7391 return;
7392 }
7393
7394 whichlow = whichhigh = lines[0];
7395 for(i=1; i<count; i++)
7396 {
7397 if (lines[i] < whichlow) whichlow = lines[i];
7398 if (lines[i] > whichhigh) whichhigh = lines[i];
7399 }
7400
7401 /* if the new line is visible, simply shift the highlighting */
7402 if (whichhigh-scr->firstline >= 0 && whichlow-scr->firstline < scr->linesinfolder)
7403 {
7404 Dinvertentry(dia, sc, 0);
7405 } else
7406 {
7407 /* must shift the buffer */
7408 if (whichlow < 0) Dinvertentry(dia, sc, 0); else
7409 {
7410 n = whichlow - scr->linesinfolder/2;
7411 if (n > scr->scrolllistlen-scr->linesinfolder)
7412 n = scr->scrolllistlen-scr->linesinfolder;
7413 if (n < 0) n = 0;
7414 scr->firstline = n;
7415 Dredrawscroll(dia, sc);
7416 }
7417 }
7418 scr->whichlow = whichlow;
7419 scr->whichhigh = whichhigh;
7420 Dinvertentry(dia, sc, 1);
7421 Dsetvscroll(dia, sc);
7422 }
7423
7424 /*
7425 * Returns the currently selected line in the scroll list "item".
7426 */
DiaGetCurLine(void * vdia,INTBIG item)7427 INTBIG DiaGetCurLine(void *vdia, INTBIG item)
7428 {
7429 INTBIG sc;
7430 TDIALOG *dia;
7431
7432 dia = (TDIALOG *)vdia;
7433 item--;
7434 if (item < 0 || item >= dia->dlgresaddr->items) return(-1);
7435 for(sc=0; sc<dia->scrollcount; sc++)
7436 if (dia->scroll[sc].scrollitem == item) return(dia->scroll[sc].whichlow);
7437 return(-1);
7438 }
7439
7440 /*
7441 * Returns the currently selected lines in the scroll list "item". The returned
7442 * array is terminated with -1.
7443 */
DiaGetCurLines(void * vdia,INTBIG item)7444 INTBIG *DiaGetCurLines(void *vdia, INTBIG item)
7445 {
7446 static INTBIG sellist[MAXSCROLLMULTISELECT];
7447 INTBIG sc, i, j;
7448 TDIALOG *dia;
7449
7450 dia = (TDIALOG *)vdia;
7451 item--;
7452 sellist[0] = -1;
7453 if (item < 0 || item >= dia->dlgresaddr->items) return(sellist);
7454 for(sc=0; sc<dia->scrollcount; sc++)
7455 {
7456 if (dia->scroll[sc].scrollitem == item)
7457 {
7458 j = 0;
7459 for(i=dia->scroll[sc].whichlow; i <= dia->scroll[sc].whichhigh; i++)
7460 sellist[j++] = i;
7461 sellist[j] = -1;
7462 }
7463 }
7464 return(sellist);
7465 }
7466
DiaGetNumScrollLines(void * vdia,INTBIG item)7467 INTBIG DiaGetNumScrollLines(void *vdia, INTBIG item)
7468 {
7469 static CHAR buf[500];
7470 DSCROLL *scr;
7471 INTBIG sc;
7472 TDIALOG *dia;
7473
7474 dia = (TDIALOG *)vdia;
7475 item--;
7476 if (item < 0 || item >= dia->dlgresaddr->items) return(0);
7477 for(sc=0; sc<dia->scrollcount; sc++) if (dia->scroll[sc].scrollitem == item) break;
7478 if (sc >= dia->scrollcount) return(0);
7479 scr = &dia->scroll[sc];
7480 return(scr->scrolllistlen);
7481 }
7482
DiaGetScrollLine(void * vdia,INTBIG item,INTBIG l)7483 CHAR *DiaGetScrollLine(void *vdia, INTBIG item, INTBIG l)
7484 {
7485 INTBIG sc;
7486 TDIALOG *dia;
7487
7488 dia = (TDIALOG *)vdia;
7489 item--;
7490 if (item < 0 || item >= dia->dlgresaddr->items) return(x_(""));
7491 for(sc=0; sc<dia->scrollcount; sc++)
7492 if (dia->scroll[sc].scrollitem == item)
7493 {
7494 if (l < 0 || l >= dia->scroll[sc].scrolllistlen) break;
7495 return(dia->scroll[sc].scrolllist[l]);
7496 }
7497 return(x_(""));
7498 }
7499
DiaSetScrollLine(void * vdia,INTBIG item,INTBIG l,CHAR * msg)7500 void DiaSetScrollLine(void *vdia, INTBIG item, INTBIG l, CHAR *msg)
7501 {
7502 CHAR *ins;
7503 INTBIG sc;
7504 DSCROLL *scr;
7505 TDIALOG *dia;
7506
7507 dia = (TDIALOG *)vdia;
7508 item--;
7509 if (item < 0 || item >= dia->dlgresaddr->items) return;
7510 for(sc=0; sc<dia->scrollcount; sc++) if (dia->scroll[sc].scrollitem == item) break;
7511 if (sc >= dia->scrollcount) return;
7512 scr = &dia->scroll[sc];
7513
7514 if (l >= scr->scrolllistlen) DiaStuffLine(dia, item+1, msg); else
7515 {
7516 ins = (CHAR *)emalloc((estrlen(msg)+1) * SIZEOFCHAR, el_tempcluster);
7517 if (ins == 0) return;
7518 (void)estrcpy(ins, msg);
7519 efree((CHAR *)scr->scrolllist[l]);
7520 scr->scrolllist[l] = ins;
7521 }
7522 Dredrawscroll(dia, sc);
7523 Dinvertentry(dia, sc, 1);
7524 Dsetvscroll(dia, sc);
7525 }
7526
DiaSynchVScrolls(void * vdia,INTBIG item1,INTBIG item2,INTBIG item3)7527 void DiaSynchVScrolls(void *vdia, INTBIG item1, INTBIG item2, INTBIG item3)
7528 {
7529 TDIALOG *dia;
7530
7531 dia = (TDIALOG *)vdia;
7532 if (item1 <= 0 || item1 > dia->dlgresaddr->items) return;
7533 if (item2 <= 0 || item2 > dia->dlgresaddr->items) return;
7534 if (item3 < 0 || item3 > dia->dlgresaddr->items) return;
7535 if (dia->numlocks >= MAXLOCKS) return;
7536 dia->lock1[dia->numlocks] = item1 - 1;
7537 dia->lock2[dia->numlocks] = item2 - 1;
7538 dia->lock3[dia->numlocks] = item3 - 1;
7539 dia->numlocks++;
7540 }
7541
DiaUnSynchVScrolls(void * vdia)7542 void DiaUnSynchVScrolls(void *vdia)
7543 {
7544 TDIALOG *dia;
7545
7546 dia = (TDIALOG *)vdia;
7547 dia->numlocks = 0;
7548 }
7549
DiaItemRect(void * vdia,INTBIG item,RECTAREA * rect)7550 void DiaItemRect(void *vdia, INTBIG item, RECTAREA *rect)
7551 {
7552 TDIALOG *dia;
7553
7554 dia = (TDIALOG *)vdia;
7555 item--;
7556 if (item < 0 || item >= dia->dlgresaddr->items) return;
7557 *rect = dia->dlgresaddr->list[item].r;
7558 Dforcedialog(dia);
7559 }
7560
DiaPercent(void * vdia,INTBIG item,INTBIG p)7561 void DiaPercent(void *vdia, INTBIG item, INTBIG p)
7562 {
7563 RECTAREA r;
7564 INTBIG type;
7565 TDIALOG *dia;
7566
7567 dia = (TDIALOG *)vdia;
7568 item--;
7569 if (item < 0 || item >= dia->dlgresaddr->items) return;
7570 type = dia->dlgresaddr->list[item].type;
7571 if ((type&ITEMTYPE) != PROGRESS) return;
7572 r = dia->dlgresaddr->list[item].r;
7573 if (p == 0)
7574 {
7575 Dintdrawrect(dia, &r, 255, 255, 255);
7576 Ddrawrectframe(dia, &r, 1, 0);
7577 return;
7578 }
7579 r.left++;
7580 r.right = r.left + (r.right-1-r.left)*p/100;
7581 r.top++; r.bottom--;
7582 Dgrayrect(dia, &r);
7583 flushscreen();
7584 }
7585
DiaRedispRoutine(void * vdia,INTBIG item,void (* routine)(RECTAREA *,void *))7586 void DiaRedispRoutine(void *vdia, INTBIG item, void (*routine)(RECTAREA*, void*))
7587 {
7588 INTBIG type;
7589 TDIALOG *dia;
7590
7591 dia = (TDIALOG *)vdia;
7592 item--;
7593 if (item < 0 || item >= dia->dlgresaddr->items) return;
7594 type = dia->dlgresaddr->list[item].type;
7595 if ((type&ITEMTYPE) != USERDRAWN) return;
7596 dia->dlgresaddr->list[item].data = (INTBIG)routine;
7597 }
7598
DiaAllowUserDoubleClick(void * vdia)7599 void DiaAllowUserDoubleClick(void *vdia)
7600 {
7601 TDIALOG *dia;
7602
7603 dia = (TDIALOG *)vdia;
7604 dia->userdoubleclick = 1;
7605 }
7606
DiaDrawRect(void * vdia,INTBIG item,RECTAREA * rect,INTBIG r,INTBIG g,INTBIG b)7607 void DiaDrawRect(void *vdia, INTBIG item, RECTAREA *rect, INTBIG r, INTBIG g, INTBIG b)
7608 {
7609 TDIALOG *dia;
7610
7611 dia = (TDIALOG *)vdia;
7612 Dintdrawrect(dia, rect, r, g, b);
7613 }
7614
DiaInvertRect(void * vdia,INTBIG item,RECTAREA * r)7615 void DiaInvertRect(void *vdia, INTBIG item, RECTAREA *r)
7616 {
7617 TDIALOG *dia;
7618
7619 dia = (TDIALOG *)vdia;
7620 Dinvertrect(dia, r);
7621 }
7622
DiaFrameRect(void * vdia,INTBIG item,RECTAREA * r)7623 void DiaFrameRect(void *vdia, INTBIG item, RECTAREA *r)
7624 {
7625 TDIALOG *dia;
7626
7627 dia = (TDIALOG *)vdia;
7628 Dintdrawrect(dia, r, 255, 255, 255);
7629 Ddrawrectframe(dia, r, 1, 0);
7630 }
7631
DiaDrawLine(void * vdia,INTBIG item,INTBIG fx,INTBIG fy,INTBIG tx,INTBIG ty,INTBIG mode)7632 void DiaDrawLine(void *vdia, INTBIG item, INTBIG fx, INTBIG fy, INTBIG tx, INTBIG ty, INTBIG mode)
7633 {
7634 TDIALOG *dia;
7635
7636 dia = (TDIALOG *)vdia;
7637 SetPort(dia->theDialog);
7638 switch (mode)
7639 {
7640 case DLMODEON: PenMode(patCopy); break;
7641 case DLMODEOFF: PenMode(patBic); break;
7642 case DLMODEINVERT: PenMode(patXor); break;
7643
7644 }
7645 MoveTo(fx, fy);
7646 LineTo(tx, ty);
7647 PenMode(patCopy);
7648 }
7649
DiaFillPoly(void * vdia,INTBIG item,INTBIG * x,INTBIG * y,INTBIG count,INTBIG r,INTBIG g,INTBIG b)7650 void DiaFillPoly(void *vdia, INTBIG item, INTBIG *x, INTBIG *y, INTBIG count, INTBIG r, INTBIG g, INTBIG b)
7651 {
7652 RGBColor color, oldcolor;
7653 TDIALOG *dia;
7654
7655 dia = (TDIALOG *)vdia;
7656 color.red = r << 8;
7657 color.green = g << 8;
7658 color.blue = b << 8;
7659 SetPort(dia->theDialog);
7660 GetForeColor(&oldcolor);
7661 RGBForeColor(&color);
7662 Ddrawpolygon(dia, x, y, count, 1);
7663 RGBForeColor(&oldcolor);
7664 }
7665
DiaPutText(void * vdia,INTBIG item,CHAR * msg,INTBIG x,INTBIG y)7666 void DiaPutText(void *vdia, INTBIG item, CHAR *msg, INTBIG x, INTBIG y)
7667 {
7668 FontInfo fontinfo;
7669 TDIALOG *dia;
7670
7671 dia = (TDIALOG *)vdia;
7672 SetPort(dia->theDialog);
7673 TextFont(DSFONT);
7674 TextSize(dia->usertextsize);
7675 GetFontInfo(&fontinfo);
7676 MoveTo(x, y + fontinfo.ascent);
7677 DrawText(msg, 0, estrlen(msg));
7678 }
7679
DiaSetTextSize(void * vdia,INTBIG size)7680 void DiaSetTextSize(void *vdia, INTBIG size)
7681 {
7682 TDIALOG *dia;
7683
7684 dia = (TDIALOG *)vdia;
7685 dia->usertextsize = size;
7686 }
7687
DiaGetTextInfo(void * vdia,CHAR * msg,INTBIG * wid,INTBIG * hei)7688 void DiaGetTextInfo(void *vdia, CHAR *msg, INTBIG *wid, INTBIG *hei)
7689 {
7690 FontInfo fontinfo;
7691 TDIALOG *dia;
7692
7693 dia = (TDIALOG *)vdia;
7694 SetPort(dia->theDialog);
7695 TextFont(DSFONT);
7696 TextSize(dia->usertextsize);
7697 GetFontInfo(&fontinfo);
7698 *wid = TextWidth(msg, 0, estrlen(msg));
7699 *hei = fontinfo.ascent + fontinfo.descent;
7700 }
7701
DiaTrackCursor(void * vdia,void (* eachdown)(INTBIG x,INTBIG y))7702 void DiaTrackCursor(void *vdia, void (*eachdown)(INTBIG x, INTBIG y))
7703 {
7704 gra_trackingdialog = (TDIALOG *)vdia;
7705 gra_trackingdialog->diaeachdown = eachdown;
7706 trackcursor(FALSE, us_nullup, us_nullvoid, gra_diaeachdownhandler,
7707 us_nullchar, us_nullvoid, TRACKNORMAL);
7708 }
7709
gra_diaeachdownhandler(INTBIG ox,INTBIG oy)7710 BOOLEAN gra_diaeachdownhandler(INTBIG ox, INTBIG oy)
7711 {
7712 INTBIG x, y;
7713
7714 DiaGetMouse(gra_trackingdialog, &x, &y);
7715 (void)((*gra_trackingdialog->diaeachdown)(x, y));
7716 return(FALSE);
7717 }
7718
DiaGetMouse(void * vdia,INTBIG * x,INTBIG * y)7719 void DiaGetMouse(void *vdia, INTBIG *x, INTBIG *y)
7720 {
7721 TDIALOG *dia;
7722
7723 dia = (TDIALOG *)vdia;
7724 readtablet(x, y);
7725 }
7726
7727 /****************************** DIALOG SUPPORT ******************************/
7728
7729 /*
7730 * Routine to parse the next input event and return the affected item.
7731 * If the routine returns -1, nothing has happened.
7732 */
gra_getnextcharacter(TDIALOG * dia,INTBIG oak,INTBIG x,INTBIG y,INTBIG chr,INTBIG special,UINTBIG time,BOOLEAN shifted)7733 INTBIG gra_getnextcharacter(TDIALOG *dia, INTBIG oak, INTBIG x, INTBIG y, INTBIG chr,
7734 INTBIG special, UINTBIG time, BOOLEAN shifted)
7735 {
7736 RECTAREA r;
7737 CHAR *msg;
7738 INTBIG thumbval;
7739 static CHAR match[MAXMATCH];
7740 static INTBIG matchpos = 0;
7741 static UINTBIG lasttime = 0;
7742 INTBIG i, j, type, which, v, t, n, sc, newfirst, item;
7743 INTBIG selitems[MAXSCROLLMULTISELECT];
7744 DSCROLL *scr;
7745 POPUPDATA *pd;
7746 CHAR ch[2];
7747
7748 if (oak == 1 || oak == 5)
7749 {
7750 /* hit in the window: find the item */
7751 item = Dwhichitem(dia, x, y);
7752 if (item == 0) return(-1);
7753 type = dia->dlgresaddr->list[item-1].type;
7754 r = dia->dlgresaddr->list[item-1].r;
7755
7756 if ((type&ITEMTYPE) == MESSAGE || (type&INACTIVE) != 0) return(-1);
7757
7758 /* if the item is a popup menu, display it and track */
7759 if ((type&ITEMTYPE) == POPUP)
7760 {
7761 pd = (POPUPDATA *)dia->dlgresaddr->list[item-1].data;
7762 i = Dhandlepopup(dia, &r, pd);
7763 if (i == pd->current) return(-1);
7764 pd->current = i;
7765 Ddrawitem(dia, POPUP, &dia->dlgresaddr->list[item-1].r, (CHAR *)pd, 0);
7766 return(item);
7767 }
7768
7769 /* items under the user's control are given to the user */
7770 if (type == USERDRAWN)
7771 {
7772 /* double click in user selects and returns */
7773 if (oak == 5 && dia->userdoubleclick != 0)
7774 {
7775 item = dia->defaultbutton;
7776 }
7777 return(item);
7778 }
7779 /* if the item is edit text, make it the current one */
7780 if (type == EDITTEXT)
7781 {
7782 if (dia->curitem != item - 1) Ddoneedit(dia); else Dhighlight(dia, 0);
7783 dia->curitem = item - 1;
7784 msg = (CHAR *)dia->dlgresaddr->list[item-1].data;
7785 i = Dgeteditpos(dia, &r, x, y, msg);
7786 if (oak == 5)
7787 {
7788 /* look for a full word about position "base" */
7789 for(dia->editstart=i-1; dia->editstart>=0; dia->editstart--)
7790 if (!isalnum(msg[dia->editstart])) break;
7791 dia->editstart++;
7792 for(dia->editend = dia->editstart; msg[dia->editend] != 0; dia->editend++)
7793 if (!isalnum(msg[dia->editend])) break;
7794 Dhighlight(dia, 1);
7795 } else
7796 {
7797 dia->editstart = dia->editend = i;
7798 Dhighlight(dia, 1);
7799 }
7800 dia->lbase = dia->editstart; dia->hbase = dia->editend;
7801 dia->rect = r;
7802 dia->msg = msg;
7803 Dtrackcursor(dia, x, y, Deditdown);
7804 return(item);
7805 }
7806
7807 /* if the item is a button, reverse it and track */
7808 if (type == BUTTON || type == DEFBUTTON)
7809 {
7810 r.left++; r.right--;
7811 r.top++; r.bottom--;
7812 Dinvertroundrect(dia, &r);
7813 dia->rect = r;
7814 dia->wasin = 1;
7815 Dtrackcursor(dia, x, y, Dbuttondown);
7816 if (dia->wasin == 0) return(-1);
7817 Dinvertroundrect(dia, &r);
7818 return(item);
7819 }
7820 /* if the item is a check, outline it and track */
7821 if (type == CHECK)
7822 {
7823 dia->rect = r;
7824 r.right = r.left + 11; r.left++;
7825 r.top = (r.top + r.bottom) / 2 - 5;
7826 r.bottom = r.top + 10;
7827 Ddrawrectframe(dia, &r, 1, 0);
7828 dia->wasin = 1;
7829 dia->ddata = ((CHAR *)dia->dlgresaddr->list[item-1].data)[0];
7830 Dtrackcursor(dia, x, y, Dcheckdown);
7831 if (dia->wasin == 0) return(-1);
7832 Ddrawrectframe(dia, &r, 0, 0);
7833 if (dia->ddata != 0)
7834 {
7835 Ddrawline(dia, r.left, r.top, r.right-1, r.bottom-1);
7836 Ddrawline(dia, r.left, r.bottom-1, r.right-1, r.top);
7837 }
7838 return(item);
7839 }
7840
7841 /* if the item is a scroll area, select a line */
7842 if (type == SCROLL || type == SCROLLMULTI)
7843 {
7844 for(sc=0; sc<dia->scrollcount; sc++)
7845 if (dia->scroll[sc].scrollitem == item - 1) break;
7846 if (sc >= dia->scrollcount) return(-1);
7847 scr = &dia->scroll[dia->curscroll=sc];
7848
7849 if (x > scr->userrect.right)
7850 {
7851 /* cursor in vertical slider */
7852 if (scr->scrolllistlen <= scr->linesinfolder) return(-1);
7853 if (y > scr->userrect.bottom-16)
7854 {
7855 /* the down arrow */
7856 Ddrawarrow(dia, sc, DOWNARROW, 1);
7857 Dtrackcursor(dia, x, y, Ddownarrow);
7858 Ddrawarrow(dia, sc, DOWNARROW, 0);
7859 Dsyncvscroll(dia, item-1);
7860 return(-1);
7861 }
7862 if (y < scr->userrect.top+16)
7863 {
7864 /* the up arrow */
7865 Ddrawarrow(dia, sc, UPARROW, 1);
7866 Dtrackcursor(dia, x, y, Duparrow);
7867 Ddrawarrow(dia, sc, UPARROW, 0);
7868 Dsyncvscroll(dia, item-1);
7869 return(-1);
7870 }
7871 if (y > scr->vthumbpos+THUMBSIZE/2 && y <= scr->userrect.bottom-16)
7872 {
7873 /* scroll down one page */
7874 Dtrackcursor(dia, x, y, Ddownpage);
7875 Dsyncvscroll(dia, item-1);
7876 return(-1);
7877 }
7878 if (y < scr->vthumbpos-THUMBSIZE/2 && y >= scr->userrect.top+16)
7879 {
7880 /* scroll up one page */
7881 Dtrackcursor(dia, x, y, Duppage);
7882 Dsyncvscroll(dia, item-1);
7883 return(-1);
7884 }
7885 if (y >= scr->vthumbpos-THUMBSIZE/2 && y <= scr->vthumbpos+THUMBSIZE/2)
7886 {
7887 /* drag slider appropriately */
7888 v = y; t = scr->vthumbpos;
7889 dia->rect = dia->dlgresaddr->list[item-1].r;
7890 dia->rect.left = dia->rect.right - 14;
7891 dia->rect.right--;
7892 dia->rect.top = scr->vthumbpos - THUMBSIZE/2;
7893 dia->rect.bottom = scr->vthumbpos + THUMBSIZE/2;
7894 Dinvertrectframe(dia, &dia->rect);
7895 dia->offset = t-v;
7896 Dtrackcursor(dia, x, y, Dvscroll);
7897 dia->rect.top = scr->vthumbpos - THUMBSIZE/2;
7898 dia->rect.bottom = scr->vthumbpos + THUMBSIZE/2;
7899 Dinvertrectframe(dia, &dia->rect);
7900 r = scr->userrect;
7901 r.top += 16; r.bottom -= 16;
7902 thumbval = scr->vthumbpos - r.top - THUMBSIZE/2;
7903 thumbval *= scr->scrolllistlen - scr->linesinfolder;
7904 thumbval /= r.bottom - r.top - THUMBSIZE;
7905 i = thumbval;
7906 if (i < 0) i = 0;
7907 if (i == scr->firstline) return(-1);
7908 scr->firstline = i;
7909 Dredrawscroll(dia, sc);
7910 Dinvertentry(dia, sc, 1);
7911 Dsetvscroll(dia, sc);
7912 Dsyncvscroll(dia, item-1);
7913 return(-1);
7914 }
7915 } else if (y > scr->userrect.bottom)
7916 {
7917 /* cursor in horizontal slider */
7918 if (x > scr->userrect.right-16)
7919 {
7920 /* the right arrow */
7921 Ddrawarrow(dia, sc, RIGHTARROW, 1);
7922 Dtrackcursor(dia, x, y, Drightarrow);
7923 Ddrawarrow(dia, sc, RIGHTARROW, 0);
7924 return(-1);
7925 }
7926 if (x < scr->userrect.left+16)
7927 {
7928 /* the left arrow */
7929 Ddrawarrow(dia, sc, LEFTARROW, 1);
7930 Dtrackcursor(dia, x, y, Dleftarrow);
7931 Ddrawarrow(dia, sc, LEFTARROW, 0);
7932 return(-1);
7933 }
7934 if (x > scr->hthumbpos+THUMBSIZE/2 && x <= scr->userrect.right-16)
7935 {
7936 /* scroll right one page */
7937 Dtrackcursor(dia, x, y, Drightpage);
7938 return(-1);
7939 }
7940 if (x < scr->hthumbpos-THUMBSIZE/2 && x >= scr->userrect.left+16)
7941 {
7942 /* scroll left one page */
7943 Dtrackcursor(dia, x, y, Dleftpage);
7944 return(-1);
7945 }
7946 if (x >= scr->hthumbpos-THUMBSIZE/2 && x <= scr->hthumbpos+THUMBSIZE/2)
7947 {
7948 /* drag slider appropriately */
7949 v = x; t = scr->hthumbpos;
7950 dia->rect = dia->dlgresaddr->list[item-1].r;
7951 dia->rect.top = dia->rect.bottom - 14;
7952 dia->rect.bottom--;
7953 dia->rect.left = scr->hthumbpos - THUMBSIZE/2;
7954 dia->rect.right = scr->hthumbpos + THUMBSIZE/2;
7955 Dinvertrectframe(dia, &dia->rect);
7956 dia->offset = t - v;
7957 Dtrackcursor(dia, x, y, Dhscroll);
7958 dia->rect.left = scr->hthumbpos - THUMBSIZE/2;
7959 dia->rect.right = scr->hthumbpos + THUMBSIZE/2;
7960 Dinvertrectframe(dia, &dia->rect);
7961 r = scr->userrect;
7962 r.left += 16; r.right -= 16;
7963 thumbval = scr->hthumbpos - r.left - THUMBSIZE/2;
7964 thumbval *= 100;
7965 thumbval /= r.right - r.left - THUMBSIZE;
7966 i = thumbval;
7967 if (i < 0) i = 0;
7968 if (i == scr->horizfactor) return(-1);
7969 scr->horizfactor = i;
7970 Dredrawscroll(dia, sc);
7971 Dinvertentry(dia, sc, 1);
7972 Dsethscroll(dia, sc);
7973 return(-1);
7974 }
7975 } else
7976 {
7977 /* double click in scroll selects and returns */
7978 if (oak == 5 && scr->scrolllistlen > 0 && (scr->flags&SCDOUBLEQUIT) != 0)
7979 return(dia->defaultbutton);
7980
7981 if ((scr->flags&SCSELMOUSE) != 0)
7982 {
7983 /* cursor in list: select an entry */
7984 which = y - r.top;
7985 which /= scr->lineheight;
7986 which += scr->firstline;
7987 if (which >= scr->scrolllistlen) which = scr->scrolllistlen - 1;
7988 if (type == SCROLLMULTI && shifted && scr->whichlow >= 0)
7989 {
7990 if (which < scr->whichlow)
7991 {
7992 j = 0;
7993 for(i=which; i<= scr->whichhigh; i++)
7994 selitems[j++] = i;
7995 DiaSelectLines(dia, item, j, selitems);
7996 } else if (which > scr->whichhigh)
7997 {
7998 j = 0;
7999 for(i=scr->whichlow; i<= which; i++)
8000 selitems[j++] = i;
8001 DiaSelectLines(dia, item, j, selitems);
8002 } else
8003 {
8004 if (which - scr->whichlow < scr->whichhigh - which)
8005 {
8006 j = 0;
8007 for(i=which; i<= scr->whichhigh; i++)
8008 selitems[j++] = i;
8009 DiaSelectLines(dia, item, j, selitems);
8010 } else
8011 {
8012 j = 0;
8013 for(i=scr->whichlow; i<= which; i++)
8014 selitems[j++] = i;
8015 DiaSelectLines(dia, item, j, selitems);
8016 }
8017 }
8018
8019 } else
8020 {
8021 DiaSelectLine(dia, item, which);
8022 }
8023 if ((scr->flags&SCREPORT) == 0) return(-1);
8024 }
8025 }
8026 }
8027 return(item);
8028 }
8029
8030 /* get the character, return immediately if special */
8031 if (oak != 0) return(-1);
8032 if (chr == ESCKEY) return(CANCEL);
8033 if (chr == '\n' || chr == '\r' || chr == CTRLCKEY) return(dia->defaultbutton);
8034
8035 /* handle arrow positioning */
8036 if ((special&SPECIALKEYDOWN) != 0)
8037 {
8038 switch ((special&SPECIALKEY)>>SPECIALKEYSH)
8039 {
8040 case SPECIALKEYARROWL:
8041 if (dia->curitem < 0) return(-1);
8042 Dhighlight(dia, 0);
8043 dia->editstart--;
8044 if (dia->editstart < 0) dia->editstart = 0;
8045 dia->editend = dia->editstart;
8046 newfirst = Dneweditbase(dia);
8047 if (dia->firstch != newfirst)
8048 {
8049 dia->firstch = newfirst;
8050 msg = (CHAR *)dia->dlgresaddr->list[dia->curitem].data;
8051 Dstufftext(dia, msg, &dia->dlgresaddr->list[dia->curitem].r);
8052 }
8053 Dhighlight(dia, 1);
8054 return(-1);
8055 case SPECIALKEYARROWR:
8056 if (dia->curitem < 0) return(-1);
8057 Dhighlight(dia, 0);
8058 msg = (CHAR *)dia->dlgresaddr->list[dia->curitem].data;
8059 if (msg[dia->editend] != 0) dia->editend++;
8060 dia->editstart = dia->editend;
8061 newfirst = Dneweditbase(dia);
8062 if (dia->firstch != newfirst)
8063 {
8064 dia->firstch = newfirst;
8065 Dstufftext(dia, msg, &dia->dlgresaddr->list[dia->curitem].r);
8066 }
8067 Dhighlight(dia, 1);
8068 return(-1);
8069 case SPECIALKEYARROWD:
8070 if (dia->scrollcount <= 0) return(-1);
8071 scr = &dia->scroll[sc = dia->curscroll];
8072 if (scr->scrolllistlen <= 0) return(-1);
8073 if (scr->whichlow >= scr->scrolllistlen-1) return(-1);
8074 item = scr->scrollitem + 1;
8075 DiaSelectLine(dia, item, scr->whichlow+1);
8076 if ((scr->flags&SCREPORT) == 0) return(-1);
8077 return(item);
8078 case SPECIALKEYARROWU:
8079 if (dia->scrollcount <= 0) return(-1);
8080 scr = &dia->scroll[sc = dia->curscroll];
8081 if (scr->scrolllistlen <= 0) return(-1);
8082 if (scr->whichlow <= 0) return(-1);
8083 item = scr->scrollitem + 1;
8084 DiaSelectLine(dia, item, scr->whichlow-1);
8085 if ((scr->flags&SCREPORT) == 0) return(-1);
8086 return(item);
8087 }
8088 }
8089
8090 /* tab to next edit text item */
8091 if (chr == TABKEY)
8092 {
8093 type = 0;
8094 for(i=dia->curitem+1; i<dia->dlgresaddr->items; i++)
8095 {
8096 type = dia->dlgresaddr->list[i].type;
8097 if (type == EDITTEXT) break;
8098 }
8099 if (type != EDITTEXT)
8100 {
8101 for(i=0; i<dia->curitem; i++)
8102 {
8103 type = dia->dlgresaddr->list[i].type;
8104 if (type == EDITTEXT) break;
8105 }
8106 }
8107 if (type != EDITTEXT) return(-1);
8108 Ddoneedit(dia);
8109 dia->curitem = i;
8110 dia->editstart = 0;
8111 msg = (CHAR *)dia->dlgresaddr->list[i].data;
8112 dia->editend = estrlen(msg);
8113 dia->firstch = 0;
8114 Dhighlight(dia, 1);
8115 return(-1);
8116 }
8117
8118 if (dia->curitem < 0 && dia->scrollcount > 0 &&
8119 (dia->scroll[dia->curscroll].flags&SCSELKEY) != 0)
8120 {
8121 /* use key to select line in scroll area */
8122 scr = &dia->scroll[sc=dia->curscroll];
8123 item = scr->scrollitem + 1;
8124 if (chr >= 'A' && chr <= 'Z') chr += 040;
8125
8126 /* if it has been more than a second, reset the match string */
8127 if (time - lasttime > 60) matchpos = 0;
8128 lasttime = time;
8129
8130 /* add this character to the match string */
8131 if (matchpos < MAXMATCH)
8132 {
8133 match[matchpos] = chr;
8134 matchpos++;
8135 }
8136
8137 /* find that string */
8138 for(which = 0; which < scr->scrolllistlen; which++)
8139 {
8140 for(i=0; i<matchpos; i++)
8141 {
8142 n = scr->scrolllist[which][i];
8143 if (n >= 'A' && n <= 'Z') n += 040;
8144 if (match[i] != n) break;
8145 }
8146 if (i >= matchpos)
8147 {
8148 DiaSelectLine(dia, item, which);
8149 break;
8150 }
8151 }
8152 if ((scr->flags&SCREPORT) == 0) return(-1);
8153 return(item);
8154 }
8155
8156 /* handle delete/backspace key */
8157 if ((chr == BACKSPACEKEY || chr == DELETEKEY) && dia->curitem >= 0)
8158 {
8159 if (dia->editstart == dia->editend && dia->editstart > 0)
8160 dia->editstart--;
8161 chr = 0;
8162 }
8163
8164 /* insert character into edit text */
8165 ch[0] = chr; ch[1] = 0;
8166 Dinsertstr(dia, ch);
8167 return(dia->curitem + 1);
8168 }
8169
Dbuttondown(INTBIG x,INTBIG y)8170 BOOLEAN Dbuttondown(INTBIG x, INTBIG y)
8171 {
8172 INTBIG in;
8173 TDIALOG *dia;
8174
8175 dia = gra_trackingdialog;
8176 if (x < dia->rect.left || x > dia->rect.right || y < dia->rect.top || y > dia->rect.bottom)
8177 in = 0; else
8178 in = 1;
8179 if (in != dia->wasin)
8180 Dinvertroundrect(dia, &dia->rect);
8181 dia->wasin = in;
8182 return(FALSE);
8183 }
8184
Dtrackpopup(INTBIG x,INTBIG y)8185 BOOLEAN Dtrackpopup(INTBIG x, INTBIG y)
8186 {
8187 INTBIG which;
8188 RECTAREA r;
8189 TDIALOG *dia;
8190
8191 dia = gra_trackingdialog;
8192 if (x < dia->rect.left || x > dia->rect.right || y < dia->rect.top || y > dia->rect.bottom)
8193 which = -1; else
8194 {
8195 which = (y - dia->rect.top - 1) / dia->lineheight;
8196 if (which >= dia->cnt-dia->sta) which = dia->cnt-dia->sta-1;
8197
8198 }
8199 if (which != dia->wasin)
8200 {
8201 r.left = dia->rect.left + 1;
8202 r.right = dia->rect.right - 1;
8203 if (dia->wasin >= 0)
8204 {
8205 r.top = dia->rect.top + (dia->wasin * dia->lineheight) + 1;
8206 r.bottom = r.top + dia->lineheight;
8207 Dinvertrect(dia, &r);
8208 }
8209
8210 /* special case if in the "up" arrow */
8211 if (which == 0 && dia->sta != 0)
8212 {
8213 dia->sta--; dia->cnt--;
8214 Ddrawpopupentries(dia);
8215 dia->wasin = -1;
8216 return(FALSE);
8217 }
8218
8219 /* special case if in the "down" arrow */
8220 if (which == dia->cnt-dia->sta-1 && dia->cnt != dia->pd->count)
8221 {
8222 dia->sta++; dia->cnt++;
8223 Ddrawpopupentries(dia);
8224 dia->wasin = -1;
8225 return(FALSE);
8226 }
8227
8228 if (which >= 0)
8229 {
8230 r.top = dia->rect.top + (which * dia->lineheight) + 1;
8231 r.bottom = r.top + dia->lineheight;
8232 Dinvertrect(dia, &r);
8233 }
8234
8235 dia->wasin = which;
8236 }
8237 return(FALSE);
8238 }
8239
Dcheckdown(INTBIG x,INTBIG y)8240 BOOLEAN Dcheckdown(INTBIG x, INTBIG y)
8241 {
8242 INTBIG in;
8243 RECTAREA r;
8244 TDIALOG *dia;
8245
8246 dia = gra_trackingdialog;
8247 if (x < dia->rect.left || x > dia->rect.right || y < dia->rect.top || y > dia->rect.bottom)
8248 in = 0; else
8249 in = 1;
8250 if (in != dia->wasin)
8251 {
8252 r = dia->rect;
8253 r.right = r.left + 11; r.left++;
8254 r.top = (r.top + r.bottom) / 2 - 5;
8255 r.bottom = r.top + 10;
8256 if (in != 0) Ddrawrectframe(dia, &r, 1, 0); else
8257 {
8258 Ddrawrectframe(dia, &r, 0, 0);
8259 if (dia->ddata != 0)
8260 {
8261 Ddrawline(dia, r.left, r.top, r.right-1, r.bottom-1);
8262 Ddrawline(dia, r.left, r.bottom-1, r.right-1, r.top);
8263 }
8264 }
8265 }
8266 dia->wasin = in;
8267 return(FALSE);
8268 }
8269
Deditdown(INTBIG x,INTBIG y)8270 BOOLEAN Deditdown(INTBIG x, INTBIG y)
8271 {
8272 INTBIG l, h, pos, wid, len, prevpos, basepos;
8273 CHAR *msg;
8274 TDIALOG *dia;
8275
8276 dia = gra_trackingdialog;
8277
8278 /* shift the text if the cursor moves outside the field */
8279 if (dia->rect.bottom-dia->rect.top < dia->lineheight*2)
8280 {
8281 if (y < dia->rect.top || y > dia->rect.bottom) return(FALSE);
8282
8283 /* scroll horizontally if there is only 1 line in the edit field */
8284 if (x < dia->rect.left && dia->firstch > 0)
8285 {
8286 Dhighlight(dia, 0);
8287 dia->firstch--;
8288 Dstufftext(dia, dia->msg, &dia->rect);
8289 Dhighlight(dia, 1);
8290 gotosleep(10);
8291 return(FALSE);
8292 }
8293 if (x > dia->rect.right && dia->firstch < dia->editend-1)
8294 {
8295 Dhighlight(dia, 0);
8296 dia->firstch++;
8297 Dstufftext(dia, dia->msg, &dia->rect);
8298 Dhighlight(dia, 1);
8299 gotosleep(10);
8300 return(FALSE);
8301 }
8302 } else
8303 {
8304 if (x < dia->rect.left || x > dia->rect.right) return(FALSE);
8305
8306 /* scroll vertically if there are multiple lines in the field */
8307 if (y < dia->rect.top && dia->firstch > 0)
8308 {
8309 msg = dia->msg;
8310 prevpos = 0;
8311 basepos = 0;
8312 while (*msg != 0)
8313 {
8314 for(len = estrlen(msg); len>0; len--)
8315 {
8316 wid = Dgettextsize(dia, msg, len);
8317 if (wid < dia->rect.right-dia->rect.left-2) break;
8318 }
8319 if (len == 0) break;
8320 basepos += len;
8321 if (basepos == dia->firstch) break;
8322 prevpos += len;
8323 msg += len;
8324 }
8325 Dhighlight(dia, 0);
8326 dia->firstch = prevpos;
8327 Dstufftext(dia, dia->msg, &dia->rect);
8328 Dhighlight(dia, 1);
8329 gotosleep(30);
8330 return(FALSE);
8331 }
8332 if (y > dia->rect.bottom && dia->firstch < dia->editend-1)
8333 {
8334 msg = &dia->msg[dia->firstch];
8335 for(len = estrlen(msg); len>0; len--)
8336 {
8337 wid = Dgettextsize(dia, msg, len);
8338 if (wid < dia->rect.right-dia->rect.left-2) break;
8339 }
8340 if (len == estrlen(msg)) return(FALSE);
8341 Dhighlight(dia, 0);
8342 dia->firstch += len;
8343 Dstufftext(dia, dia->msg, &dia->rect);
8344 Dhighlight(dia, 1);
8345 gotosleep(30);
8346 return(FALSE);
8347 }
8348 }
8349
8350 pos = Dgeteditpos(dia, &dia->rect, x, y, dia->msg);
8351 l = dia->lbase; h = dia->hbase;
8352 if (pos > h) h = pos;
8353 if (pos < l) l = pos;
8354 if (l != dia->editstart || h != dia->editend)
8355 {
8356 Dhighlight(dia, 0);
8357 dia->editstart = l; dia->editend = h;
8358 Dhighlight(dia, 1);
8359 }
8360 return(FALSE);
8361 }
8362
Ddownarrow(INTBIG x,INTBIG y)8363 BOOLEAN Ddownarrow(INTBIG x, INTBIG y)
8364 {
8365 short sc;
8366 DSCROLL *scr;
8367 short i;
8368 RECTAREA r, fr, tr;
8369 UINTBIG thisdiatime;
8370 TDIALOG *dia;
8371
8372 dia = gra_trackingdialog;
8373
8374 /* limit the speed of the button */
8375 thisdiatime = ticktime();
8376 if (thisdiatime - dia->lastdiatime < MINSCROLLTICKS) return(FALSE);
8377 dia->lastdiatime = thisdiatime;
8378
8379 scr = &dia->scroll[sc=dia->curscroll];
8380 if (scr->scrolllistlen-scr->firstline <= scr->linesinfolder) return(TRUE);
8381
8382 /* remove highlighting */
8383 Dinvertentry(dia, sc, 1);
8384
8385 /* shift screen pointer */
8386 scr->firstline++;
8387
8388 /* shift the window contents up by 1 line (scr->lineheight) */
8389 r = scr->userrect;
8390 fr.left = r.left+1; fr.right = r.right-1;
8391 fr.top = r.top+1+scr->lineheight; fr.bottom = r.bottom-1;
8392 tr.left = r.left+1; tr.right = r.right-1;
8393 tr.top = r.top+1; tr.bottom = r.bottom-1-scr->lineheight;
8394 Dshiftbits(dia, &fr, &tr);
8395
8396 /* fill in a new last line */
8397 fr.top = r.bottom-1-scr->lineheight; fr.bottom = r.bottom-1;
8398 Dintdrawrect(dia, &fr, 255, 255, 255);
8399 i = scr->firstline + scr->linesinfolder - 1;
8400 if (i < scr->scrolllistlen)
8401 Ddrawmsg(dia, sc, scr->scrolllist[i], i-scr->firstline);
8402
8403 /* restore highlighting */
8404 Dinvertentry(dia, sc, 1);
8405
8406 /* redo thumb position */
8407 Dsetvscroll(dia, sc);
8408 return(FALSE);
8409 }
8410
Duparrow(INTBIG x,INTBIG y)8411 BOOLEAN Duparrow(INTBIG x, INTBIG y)
8412 {
8413 INTBIG sc;
8414 DSCROLL *scr;
8415 RECTAREA r, fr, tr;
8416 UINTBIG thisdiatime;
8417 TDIALOG *dia;
8418
8419 dia = gra_trackingdialog;
8420
8421 /* limit the speed of the button */
8422 thisdiatime = ticktime();
8423 if (thisdiatime - dia->lastdiatime < MINSCROLLTICKS) return(FALSE);
8424 dia->lastdiatime = thisdiatime;
8425
8426 scr = &dia->scroll[sc=dia->curscroll];
8427 if (scr->firstline <= 0) return(TRUE);
8428
8429 /* remove highlighting */
8430 Dinvertentry(dia, sc, 1);
8431
8432 /* shift screen pointer */
8433 scr->firstline--;
8434
8435 /* shift the window contents down by 1 line (scr->lineheight) */
8436 r = scr->userrect;
8437 fr.left = r.left+1; fr.right = r.right-1;
8438 fr.top = r.top+1; fr.bottom = r.bottom-1-scr->lineheight;
8439
8440 tr.left = r.left+1; tr.right = r.right-1;
8441 tr.top = r.top+1+scr->lineheight; tr.bottom = r.bottom-1;
8442 Dshiftbits(dia, &fr, &tr);
8443
8444 /* fill in a new top line */
8445 fr.top = r.top+1; fr.bottom = r.top+1+scr->lineheight;
8446 Dintdrawrect(dia, &fr, 255, 255, 255);
8447 Ddrawmsg(dia, sc, scr->scrolllist[scr->firstline], 0);
8448
8449 /* restore highlighting */
8450 Dinvertentry(dia, sc, 1);
8451
8452 /* redo thumb position */
8453 Dsetvscroll(dia, sc);
8454 return(FALSE);
8455 }
8456
Ddownpage(INTBIG x,INTBIG y)8457 BOOLEAN Ddownpage(INTBIG x, INTBIG y)
8458 {
8459 INTBIG sc;
8460 DSCROLL *scr;
8461 UINTBIG thisdiatime;
8462 TDIALOG *dia;
8463
8464 dia = gra_trackingdialog;
8465
8466 /* limit the speed of the button */
8467 thisdiatime = ticktime();
8468 if (thisdiatime - dia->lastdiatime < MINPAGETICKS) return(FALSE);
8469 dia->lastdiatime = thisdiatime;
8470
8471 scr = &dia->scroll[sc=dia->curscroll];
8472 if (y <= scr->vthumbpos+THUMBSIZE/2 || y > scr->userrect.bottom-16) return(TRUE);
8473 if (scr->scrolllistlen-scr->firstline <= scr->linesinfolder) return(TRUE);
8474 scr->firstline += scr->linesinfolder-1;
8475 if (scr->scrolllistlen-scr->firstline <= scr->linesinfolder)
8476 scr->firstline = scr->scrolllistlen-scr->linesinfolder;
8477 Dredrawscroll(dia, sc);
8478 Dinvertentry(dia, sc, 1);
8479 Dsetvscroll(dia, sc);
8480 return(FALSE);
8481 }
8482
Duppage(INTBIG x,INTBIG y)8483 BOOLEAN Duppage(INTBIG x, INTBIG y)
8484 {
8485 INTBIG sc;
8486 DSCROLL *scr;
8487 UINTBIG thisdiatime;
8488 TDIALOG *dia;
8489
8490 dia = gra_trackingdialog;
8491
8492 /* limit the speed of the button */
8493 thisdiatime = ticktime();
8494 if (thisdiatime - dia->lastdiatime < MINPAGETICKS) return(FALSE);
8495 dia->lastdiatime = thisdiatime;
8496
8497 scr = &dia->scroll[sc=dia->curscroll];
8498 if (y >= scr->vthumbpos-THUMBSIZE/2 || y < scr->userrect.top+16) return(TRUE);
8499 if (scr->firstline <= 0) return(TRUE);
8500 scr->firstline -= scr->linesinfolder-1;
8501 if (scr->firstline < 0) scr->firstline = 0;
8502 Dredrawscroll(dia, sc);
8503 Dinvertentry(dia, sc, 1);
8504 Dsetvscroll(dia, sc);
8505 return(FALSE);
8506 }
8507
Dvscroll(INTBIG x,INTBIG y)8508 BOOLEAN Dvscroll(INTBIG x, INTBIG y)
8509 {
8510 INTBIG l, sc;
8511 DSCROLL *scr;
8512 TDIALOG *dia;
8513
8514 dia = gra_trackingdialog;
8515 scr = &dia->scroll[sc=dia->curscroll];
8516 l = scr->vthumbpos;
8517 scr->vthumbpos = y + dia->offset;
8518 if (scr->vthumbpos < scr->userrect.top+16+THUMBSIZE/2)
8519 scr->vthumbpos = scr->userrect.top+16+THUMBSIZE/2;
8520 if (scr->vthumbpos > scr->userrect.bottom-16-THUMBSIZE/2)
8521 scr->vthumbpos = scr->userrect.bottom-16-THUMBSIZE/2;
8522 if (scr->vthumbpos == l) return(FALSE);
8523 dia->rect.top = l - THUMBSIZE/2;
8524 dia->rect.bottom = l + THUMBSIZE/2;
8525 Dinvertrectframe(dia, &dia->rect);
8526 dia->rect.top = scr->vthumbpos - THUMBSIZE/2;
8527 dia->rect.bottom = scr->vthumbpos + THUMBSIZE/2;
8528 Dinvertrectframe(dia, &dia->rect);
8529 return(FALSE);
8530 }
8531
Drightarrow(INTBIG x,INTBIG y)8532 BOOLEAN Drightarrow(INTBIG x, INTBIG y)
8533 {
8534 INTBIG sc;
8535 DSCROLL *scr;
8536 UINTBIG thisdiatime;
8537 TDIALOG *dia;
8538
8539 dia = gra_trackingdialog;
8540
8541 /* limit the speed of the button */
8542 thisdiatime = ticktime();
8543 if (thisdiatime - dia->lastdiatime < MINSCROLLTICKS) return(FALSE);
8544 dia->lastdiatime = thisdiatime;
8545
8546 scr = &dia->scroll[sc=dia->curscroll];
8547 if (scr->horizfactor >= 100) return(TRUE);
8548 scr->horizfactor++;
8549 Dredrawscroll(dia, sc);
8550 Dinvertentry(dia, sc, 1);
8551 Dsethscroll(dia, sc);
8552 return(FALSE);
8553 }
8554
Dleftarrow(INTBIG x,INTBIG y)8555 BOOLEAN Dleftarrow(INTBIG x, INTBIG y)
8556 {
8557 INTBIG sc;
8558 DSCROLL *scr;
8559 UINTBIG thisdiatime;
8560 TDIALOG *dia;
8561
8562 dia = gra_trackingdialog;
8563
8564 /* limit the speed of the button */
8565 thisdiatime = ticktime();
8566 if (thisdiatime - dia->lastdiatime < MINSCROLLTICKS) return(FALSE);
8567 dia->lastdiatime = thisdiatime;
8568 scr = &dia->scroll[sc=dia->curscroll];
8569 if (scr->horizfactor <= 0) return(TRUE);
8570 scr->horizfactor--;
8571 Dredrawscroll(dia, sc);
8572 Dinvertentry(dia, sc, 1);
8573 Dsethscroll(dia, sc);
8574 return(FALSE);
8575 }
8576
Drightpage(INTBIG x,INTBIG y)8577 BOOLEAN Drightpage(INTBIG x, INTBIG y)
8578 {
8579 INTBIG sc;
8580 DSCROLL *scr;
8581 UINTBIG thisdiatime;
8582 TDIALOG *dia;
8583
8584 dia = gra_trackingdialog;
8585
8586 /* limit the speed of the button */
8587 thisdiatime = ticktime();
8588 if (thisdiatime - dia->lastdiatime < MINPAGETICKS) return(FALSE);
8589 dia->lastdiatime = thisdiatime;
8590 scr = &dia->scroll[sc=dia->curscroll];
8591 if (x <= scr->hthumbpos+THUMBSIZE/2 || x > scr->userrect.right-16) return(TRUE);
8592 if (scr->horizfactor >= 100) return(TRUE);
8593 scr->horizfactor += 10;
8594 if (scr->horizfactor >= 100) scr->horizfactor = 100;
8595 Dredrawscroll(dia, sc);
8596 Dinvertentry(dia, sc, 1);
8597 Dsethscroll(dia, sc);
8598 return(FALSE);
8599 }
8600
Dleftpage(INTBIG x,INTBIG y)8601 BOOLEAN Dleftpage(INTBIG x, INTBIG y)
8602 {
8603 INTBIG sc;
8604 DSCROLL *scr;
8605 UINTBIG thisdiatime;
8606 TDIALOG *dia;
8607
8608 dia = gra_trackingdialog;
8609
8610 /* limit the speed of the button */
8611 thisdiatime = ticktime();
8612 if (thisdiatime - dia->lastdiatime < MINPAGETICKS) return(FALSE);
8613 dia->lastdiatime = thisdiatime;
8614
8615 scr = &dia->scroll[sc=dia->curscroll];
8616 if (x >= scr->hthumbpos-THUMBSIZE/2 || x < scr->userrect.left+16) return(TRUE);
8617 if (scr->horizfactor <= 0) return(1);
8618 scr->horizfactor -= 10;
8619 if (scr->horizfactor <= 0) scr->horizfactor = 0;
8620 Dredrawscroll(dia, sc);
8621 Dinvertentry(dia, sc, 1);
8622 Dsethscroll(dia, sc);
8623 return(FALSE);
8624 }
8625
Dhscroll(INTBIG x,INTBIG y)8626 BOOLEAN Dhscroll(INTBIG x, INTBIG y)
8627 {
8628 INTBIG l, sc;
8629 DSCROLL *scr;
8630 TDIALOG *dia;
8631
8632 dia = gra_trackingdialog;
8633 scr = &dia->scroll[sc=dia->curscroll];
8634 l = scr->hthumbpos;
8635 scr->hthumbpos = x + dia->offset;
8636 if (scr->hthumbpos < scr->userrect.left+16+THUMBSIZE/2)
8637 scr->hthumbpos = scr->userrect.left+16+THUMBSIZE/2;
8638 if (scr->hthumbpos > scr->userrect.right-16-THUMBSIZE/2)
8639 scr->hthumbpos = scr->userrect.right-16-THUMBSIZE/2;
8640 if (scr->hthumbpos == l) return(FALSE);
8641 dia->rect.left = l - THUMBSIZE/2;
8642 dia->rect.right = l + THUMBSIZE/2;
8643 Dinvertrectframe(dia, &dia->rect);
8644 dia->rect.left = scr->hthumbpos - THUMBSIZE/2;
8645 dia->rect.right = scr->hthumbpos + THUMBSIZE/2;
8646 Dinvertrectframe(dia, &dia->rect);
8647 return(FALSE);
8648 }
8649
Dredrawscroll(TDIALOG * dia,INTBIG sc)8650 void Dredrawscroll(TDIALOG *dia, INTBIG sc)
8651 {
8652 RECTAREA r;
8653 INTBIG i;
8654 DSCROLL *scr;
8655
8656 scr = &dia->scroll[sc];
8657 r = scr->userrect;
8658 r.left++; r.right--;
8659 r.top++; r.bottom--;
8660 Dintdrawrect(dia, &r, 255, 255, 255);
8661 for(i=scr->firstline; i<scr->scrolllistlen; i++)
8662 {
8663 if (i-scr->firstline >= scr->linesinfolder) break;
8664 Ddrawmsg(dia, sc, scr->scrolllist[i], i-scr->firstline);
8665 }
8666 }
8667
8668 /*
8669 * Routine to set the vertical scroll bar
8670 */
Dsetvscroll(TDIALOG * dia,INTBIG sc)8671 void Dsetvscroll(TDIALOG *dia, INTBIG sc)
8672 {
8673 RECTAREA r;
8674 INTBIG f;
8675 DSCROLL *scr;
8676
8677 /* first redraw the border */
8678 Ddrawvertslider(dia , sc);
8679
8680 /* get the area of the slider without arrows */
8681 scr = &dia->scroll[sc];
8682 r = scr->userrect;
8683 r.top += 16;
8684 r.bottom -= 16;
8685 r.left = r.right;
8686 r.right += 13;
8687
8688 /* if there is nothing to scroll, clear this area */
8689 if (scr->scrolllistlen <= scr->linesinfolder)
8690 {
8691 Dintdrawrect(dia, &r, 255, 255, 255);
8692 return;
8693 }
8694
8695 /* gray the scroll area */
8696 Dgrayrect(dia, &r);
8697
8698 /* compute position of vertical thumb area */
8699 f = scr->firstline; f *= r.bottom - r.top-THUMBSIZE;
8700 f /= scr->scrolllistlen - scr->linesinfolder;
8701 scr->vthumbpos = r.top + THUMBSIZE/2 + f;
8702 if (scr->vthumbpos > r.bottom-THUMBSIZE/2) scr->vthumbpos = r.bottom-THUMBSIZE/2;
8703
8704 /* draw the thumb */
8705 r.top = scr->vthumbpos - THUMBSIZE/2;
8706 r.bottom = scr->vthumbpos + THUMBSIZE/2;
8707 Dintdrawrect(dia, &r, 255, 255, 255);
8708 Ddrawrectframe(dia, &r, 1, 0);
8709 }
8710
8711 /*
8712 * Routine to see if the vertical scroll in this area is tied to another and to change it.
8713 */
Dsyncvscroll(TDIALOG * dia,INTBIG item)8714 void Dsyncvscroll(TDIALOG *dia, INTBIG item)
8715 {
8716 INTBIG value, i;
8717 DSCROLL *scr;
8718
8719 scr = &dia->scroll[dia->curscroll];
8720 value = scr->firstline;
8721 for(i=0; i<dia->numlocks; i++)
8722 {
8723 if (dia->lock1[i] == item)
8724 {
8725 Dsetscroll(dia, dia->lock2[i], value);
8726 if (dia->lock3[i] >= 0)
8727 Dsetscroll(dia, dia->lock3[i], value);
8728 break;
8729 }
8730 if (dia->lock2[i] == item)
8731 {
8732 Dsetscroll(dia, dia->lock1[i], value);
8733 if (dia->lock3[i] >= 0)
8734 Dsetscroll(dia, dia->lock3[i], value);
8735 break;
8736 }
8737 if (dia->lock3[i] == item)
8738 {
8739 Dsetscroll(dia, dia->lock1[i], value);
8740 Dsetscroll(dia, dia->lock2[i], value);
8741 break;
8742 }
8743 }
8744 }
8745
8746 /*
8747 * Routine to set the first line of the scroll list in item "item" to "value"
8748 */
Dsetscroll(TDIALOG * dia,INTBIG item,INTBIG value)8749 void Dsetscroll(TDIALOG *dia, INTBIG item, INTBIG value)
8750 {
8751 REGISTER INTBIG sc;
8752 DSCROLL *scr;
8753
8754 for(sc=0; sc<dia->scrollcount; sc++) if (dia->scroll[sc].scrollitem == item) break;
8755 if (sc >= dia->scrollcount) return;
8756 scr = &dia->scroll[sc];
8757 scr->firstline = value;
8758 Dredrawscroll(dia, sc);
8759 Dinvertentry(dia, sc, 1);
8760 Dsetvscroll(dia, sc);
8761 }
8762
8763 /*
8764 * Routine to set the horizontal scroll bar
8765 */
Dsethscroll(TDIALOG * dia,INTBIG sc)8766 void Dsethscroll(TDIALOG *dia, INTBIG sc)
8767 {
8768 RECTAREA r;
8769 INTBIG f;
8770 DSCROLL *scr;
8771
8772 /* get the area of the slider without arrows */
8773 scr = &dia->scroll[sc];
8774 r = scr->userrect;
8775 r.left += 16;
8776 r.right -= 16;
8777 r.top = r.bottom;
8778 r.bottom += 13;
8779
8780 /* gray the scroll area */
8781 Dgrayrect(dia, &r);
8782
8783 /* compute position of vertical thumb area */
8784 f = scr->horizfactor; f *= (INTBIG)(r.right-r.left-THUMBSIZE); f /= 100;
8785 scr->hthumbpos = r.left + THUMBSIZE/2 + f;
8786 if (scr->hthumbpos > r.right-THUMBSIZE/2) scr->hthumbpos = r.right-THUMBSIZE/2;
8787
8788 /* draw the thumb */
8789 r.left = scr->hthumbpos - THUMBSIZE/2;
8790 r.right = scr->hthumbpos + THUMBSIZE/2;
8791 Dintdrawrect(dia, &r, 255, 255, 255);
8792 Ddrawrectframe(dia, &r, 1, 0);
8793 }
8794
Dinvertentry(TDIALOG * dia,INTBIG sc,INTBIG on)8795 void Dinvertentry(TDIALOG *dia, INTBIG sc, INTBIG on)
8796 {
8797 RECTAREA r;
8798 REGISTER INTBIG which;
8799 DSCROLL *scr;
8800
8801 scr = &dia->scroll[sc];
8802 if (scr->whichlow < 0) return;
8803 for(which = scr->whichlow; which <= scr->whichhigh; which++)
8804 {
8805 if (which-scr->firstline >= 0 && which-scr->firstline < scr->linesinfolder)
8806 {
8807 r.left = scr->userrect.left+1;
8808 r.right = scr->userrect.right-1;
8809 r.top = scr->userrect.top + scr->lineheight*(which-scr->firstline)+1;
8810 r.bottom = r.top + scr->lineheight;
8811 if (r.bottom >= scr->userrect.bottom) r.bottom = scr->userrect.bottom-1;
8812 Dinvertrect(dia, &r);
8813 }
8814 }
8815 }
8816
8817 /*
8818 * routine to determine which item falls under the coordinates (x, y)
8819 */
Dwhichitem(TDIALOG * dia,INTBIG x,INTBIG y)8820 INTBIG Dwhichitem(TDIALOG *dia, INTBIG x, INTBIG y)
8821 {
8822 INTBIG i;
8823 RECTAREA r;
8824
8825 for(i=0; i<dia->dlgresaddr->items; i++)
8826 {
8827 r = dia->dlgresaddr->list[i].r;
8828 if (x >= r.left && x <= r.right && y >= r.top && y <= r.bottom) return(i+1);
8829 }
8830 return(0);
8831 }
8832
Dinsertstr(TDIALOG * dia,CHAR * insmsg)8833 void Dinsertstr(TDIALOG *dia, CHAR *insmsg)
8834 {
8835 INTBIG i, j, newcurspos;
8836 CHAR *oldmsg, *newmsg, *pt;
8837
8838 if (dia->curitem < 0) return;
8839 Dhighlight(dia, 0);
8840 oldmsg = (CHAR *)dia->dlgresaddr->list[dia->curitem].data;
8841
8842 /* allocate space for the new message and fill it */
8843 newmsg = (CHAR *)((estrlen(oldmsg)+estrlen(insmsg)+dia->editend-dia->editstart+1) * SIZEOFCHAR,
8844 el_tempcluster);
8845 if (newmsg == 0) return;
8846 j = 0;
8847 for(i=0; i<dia->editstart; i++) newmsg[j++] = oldmsg[i];
8848 for(i=0; insmsg[i] != 0; i++) newmsg[j++] = insmsg[i];
8849 newcurspos = j;
8850 for(i=dia->editend; oldmsg[i] != 0; i++) newmsg[j++] = oldmsg[i];
8851 newmsg[j] = 0;
8852 dia->editstart = dia->editend = newcurspos;
8853
8854 /* replace the message */
8855 efree((CHAR *)dia->dlgresaddr->list[dia->curitem].data);
8856 dia->dlgresaddr->list[dia->curitem].data = (INTBIG)newmsg;
8857
8858 /* make sure the cursor is visible */
8859 dia->firstch = Dneweditbase(dia);
8860 if (dia->opaqueitem == dia->curitem)
8861 {
8862 (void)allocstring(&oldmsg, newmsg, el_tempcluster);
8863 for(pt = oldmsg; *pt != 0; pt++)
8864 *pt = '\245'; /* bullet */
8865 Dstufftext(dia, oldmsg, &dia->dlgresaddr->list[dia->curitem].r);
8866 efree(oldmsg);
8867 } else
8868 {
8869 Dstufftext(dia, newmsg, &dia->dlgresaddr->list[dia->curitem].r);
8870 }
8871
8872 /* set new highlighting */
8873 Dhighlight(dia, 1);
8874 }
8875
Dneweditbase(TDIALOG * dia)8876 INTBIG Dneweditbase(TDIALOG *dia)
8877 {
8878 INTBIG wid, prevpos, basepos, y, firstoff, len, newfirst;
8879 CHAR *newmsg, *msg;
8880 RECTAREA r;
8881
8882 newfirst = dia->firstch;
8883 newmsg = (CHAR *)dia->dlgresaddr->list[dia->curitem].data;
8884 r = dia->dlgresaddr->list[dia->curitem].r;
8885 if (r.bottom-r.top < dia->lineheight*2)
8886 {
8887 /* if there is only 1 line in the edit field, shift horizontally */
8888 if (dia->editend < newfirst)
8889 {
8890 newfirst = dia->editend-1;
8891 if (newfirst < 0) newfirst = 0;
8892 }
8893 while (dia->editend > newfirst)
8894 {
8895 wid = Dgettextsize(dia, &newmsg[newfirst], dia->editend-newfirst);
8896 if (wid <= r.right-r.left-2) break;
8897 newfirst++;
8898 }
8899 } else
8900 {
8901 /* multiple lines in the edit field, shift vertically */
8902 while (dia->editend < newfirst)
8903 {
8904 msg = newmsg;
8905 prevpos = 0;
8906 basepos = 0;
8907 while (*msg != 0)
8908 {
8909 for(len = estrlen(msg); len>0; len--)
8910 {
8911 wid = Dgettextsize(dia, msg, len);
8912 if (wid < r.right-r.left-2) break;
8913 }
8914 if (len == 0) break;
8915 basepos += len;
8916 if (basepos == newfirst) break;
8917 prevpos += len;
8918 msg += len;
8919 }
8920 newfirst = prevpos;
8921 }
8922 if (dia->editend > newfirst)
8923 {
8924 y = r.top + dia->lineheight;
8925 msg = &newmsg[newfirst];
8926 firstoff = 0;
8927 basepos = 0;
8928 while (*msg != 0)
8929 {
8930 for(len = estrlen(msg); len>0; len--)
8931 {
8932 wid = Dgettextsize(dia, msg, len);
8933 if (wid < r.right-r.left-2) break;
8934 }
8935 if (len == 0) break;
8936 if (dia->editend <= newfirst + basepos + len) break;
8937 if (firstoff == 0) firstoff = len;
8938 msg += len;
8939 basepos += len;
8940 y += dia->lineheight;
8941 if (y > r.bottom) { newfirst += firstoff; break; }
8942 }
8943 }
8944 }
8945 return(newfirst);
8946 }
8947
Dhighlight(TDIALOG * dia,INTBIG on)8948 void Dhighlight(TDIALOG *dia, INTBIG on)
8949 {
8950 INTBIG i, sx, ex, sline, eline, line, dummy, es, ee;
8951 CHAR *msg;
8952 RECTAREA r, itemrect;
8953
8954 if (dia->curitem < 0) return;
8955 itemrect = dia->dlgresaddr->list[dia->curitem].r;
8956 msg = (CHAR *)dia->dlgresaddr->list[dia->curitem].data;
8957 es = dia->editstart; ee = dia->editend;
8958 if (es > ee) { i = es; es = ee; ee = i; }
8959 Dtextlocation(dia, msg, es, &itemrect, &sx, &sline);
8960 Dtextlocation(dia, msg, ee, &itemrect, &ex, &eline);
8961 for(i=sline; i<=eline; i++)
8962 {
8963 r.top = itemrect.top + i * dia->lineheight;
8964 if (r.top >= itemrect.bottom) break;
8965 r.bottom = r.top + dia->lineheight;
8966 if (r.bottom > itemrect.bottom) r.bottom = itemrect.bottom;
8967
8968 r.left = itemrect.left;
8969 if (i == sline)
8970 {
8971 Dtextlocation(dia, msg, es+1, &itemrect, &dummy, &line);
8972 if (line != sline && sline != eline) continue;
8973 r.left += sx;
8974 }
8975 r.right = itemrect.right;
8976 if (i == eline)
8977 {
8978 if (ex == 0 && sline != eline) continue;
8979 r.right = itemrect.left + ex + 1;
8980 }
8981
8982 Dinvertrect(dia, &r);
8983 }
8984 }
8985
8986 /*
8987 * routine to determine where the cursor is in the edit item "r" given character
8988 * "len" of "msg". The horizontal offset is placed in "wid" and the line number
8989 * in "line".
8990 */
Dtextlocation(TDIALOG * dia,CHAR * msg,INTBIG position,RECTAREA * r,INTBIG * x,INTBIG * line)8991 void Dtextlocation(TDIALOG *dia, CHAR *msg, INTBIG position, RECTAREA *r, INTBIG *x, INTBIG *line)
8992 {
8993 INTBIG basepos, len, wid;
8994 /* if beyond the end, any hit is the end */
8995 *line = *x = 0;
8996 if (dia->firstch >= estrlen(msg)) return;
8997
8998 /* set initial message and offset in corner of edit box */
8999 msg = &msg[dia->firstch];
9000 basepos = dia->firstch;
9001 while (*msg != 0)
9002 {
9003 for(len = estrlen(msg); len>0; len--)
9004 {
9005 wid = Dgettextsize(dia, msg, len);
9006 if (wid < r->right-r->left-2) break;
9007 }
9008 if (len <= 0) { *x = 0; break; }
9009
9010 if (position - basepos <= len)
9011 {
9012 *x = Dgettextsize(dia, msg, position - basepos);
9013 break;
9014 }
9015 msg += len;
9016 basepos += len;
9017 (*line)++;
9018 }
9019 }
9020
Dgeteditpos(TDIALOG * dia,RECTAREA * r,INTBIG x,INTBIG y,CHAR * msg)9021 INTBIG Dgeteditpos(TDIALOG *dia, RECTAREA *r, INTBIG x, INTBIG y, CHAR *msg)
9022 {
9023 INTBIG pos, i, basepos, lastpos, len, wid;
9024
9025 /* if beyond the end, any hit is the end */
9026 if (dia->firstch > estrlen(msg)) return(estrlen(msg));
9027
9028 /* set initial message and offset in corner of edit box */
9029 msg = &msg[dia->firstch];
9030 basepos = dia->firstch;
9031 while (*msg != 0)
9032 {
9033 for(len = estrlen(msg); len>0; len--)
9034 {
9035 wid = Dgettextsize(dia, msg, len);
9036 if (wid < r->right-r->left-2) break;
9037 }
9038 if (len <= 0) break;
9039
9040 if (y > r->top && y <= r->top+dia->lineheight)
9041 {
9042 lastpos = 0;
9043 for(i=0; i<len; i++)
9044 {
9045 pos = Dgettextsize(dia, msg, i+1);
9046 if (r->left+(lastpos+pos)/2 > x) break;
9047 lastpos = pos;
9048 }
9049 return(basepos+i);
9050 }
9051
9052 msg += len;
9053 basepos += len;
9054 y -= dia->lineheight;
9055 }
9056 return(basepos);
9057 }
9058
Ddoneedit(TDIALOG * dia)9059 void Ddoneedit(TDIALOG *dia)
9060 {
9061 INTBIG was;
9062
9063 if (dia->curitem < 0) return;
9064 Dhighlight(dia, 0);
9065 was = dia->curitem;
9066 dia->curitem = -1;
9067 if (dia->firstch == 0) return;
9068 dia->firstch = 0;
9069 Dstufftext(dia, (CHAR *)dia->dlgresaddr->list[was-1].data, &dia->dlgresaddr->list[was].r);
9070 }
9071
Ddrawitem(TDIALOG * dia,INTBIG type,RECTAREA * r,CHAR * msg,INTBIG dim)9072 void Ddrawitem(TDIALOG *dia, INTBIG type, RECTAREA *r, CHAR *msg, INTBIG dim)
9073 {
9074 INTBIG j, save, itemtype;
9075 POPUPDATA *pd;
9076 RECTAREA myrect;
9077 INTBIG xv[3], yv[3];
9078
9079 itemtype = type & ITEMTYPE;
9080 if (itemtype == POPUP)
9081 {
9082 /* popup menu item */
9083 pd = (POPUPDATA *)msg;
9084 if (pd->count <= 0) return;
9085 Dstuffmessage(dia, pd->namelist[pd->current], r, dim);
9086 Dinsetrect(r, -1);
9087 Ddrawrectframe(dia, r, 1, 0);
9088 Ddrawline(dia, r->left+3, r->bottom, r->right, r->bottom);
9089 Ddrawline(dia, r->right, r->top+3, r->right, r->bottom);
9090 Dinsetrect(r, 1);
9091 xv[0] = r->right - 18; yv[0] = r->top + 4;
9092 xv[1] = r->right - 12; yv[1] = r->top + 10;
9093 xv[2] = r->right - 6; yv[2] = r->top + 4;
9094 save = r->left; r->left = r->right - 19;
9095 Dintdrawrect(dia, r, 255, 255, 255);
9096 r->left = save;
9097 Ddrawpolygon(dia, xv, yv, 3, 1);
9098 } else if (itemtype == BUTTON || itemtype == DEFBUTTON)
9099 {
9100 /* button */
9101 j = Dgettextsize(dia, msg, estrlen(msg));
9102 Ddrawroundrectframe(dia, r, 12, dim);
9103 Ddrawtext(dia, msg, estrlen(msg), (r->left+r->right-j)/2,
9104 (r->top+r->bottom+dia->lineheight)/2, dim);
9105 } else if (itemtype == CHECK)
9106 {
9107 /* check box */
9108 myrect = *r;
9109 myrect.right = myrect.left + 12;
9110 myrect.top = (myrect.top + myrect.bottom) / 2 - 6;
9111 myrect.bottom = myrect.top + 12;
9112 Ddrawrectframe(dia, &myrect, 1, dim);
9113 Ddrawtext(dia, msg, estrlen(msg), myrect.right+4, r->top+dia->lineheight, dim);
9114 } else if (itemtype == RADIO)
9115 {
9116 /* radio button */
9117 myrect = *r;
9118 myrect.right = myrect.left + 12;
9119 myrect.top = (myrect.top + myrect.bottom) / 2 - 6;
9120 myrect.bottom = myrect.top + 12;
9121 Ddrawcircle(dia, &myrect, dim);
9122 Ddrawtext(dia, msg, estrlen(msg), myrect.right+4, myrect.top+dia->lineheight-2, dim);
9123 } else if (itemtype == MESSAGE)
9124 {
9125 /* message */
9126 Dstuffmessage(dia, msg, r, dim);
9127 } else if (itemtype == EDITTEXT)
9128 {
9129 /* edit text */
9130 if (dim == 0) Dstufftext(dia, msg, r);
9131 Deditbox(dia, r, 1, dim);
9132 } else if (itemtype == SCROLL || itemtype == SCROLLMULTI)
9133 {
9134 /* scrollable list */
9135 Ddrawrectframe(dia, r, 1, dim);
9136 } else if (itemtype == ICON)
9137 {
9138 /* 32x32 icon */
9139 Dputicon(dia, r->left, r->top, (UCHAR1 *)msg);
9140 } else if (itemtype == DIVIDELINE)
9141 {
9142 /* dividing line */
9143 DiaDrawRect(dia, 0, r, 0, 0, 0);
9144 }
9145 }
9146
Ddrawpopupentries(TDIALOG * dia)9147 void Ddrawpopupentries(TDIALOG *dia)
9148 {
9149 INTBIG i, y;
9150 INTBIG xv[3], yv[3];
9151
9152 Dintdrawrect(dia, &dia->rect, 255, 255, 255);
9153 Ddrawrectframe(dia, &dia->rect, 1, 0);
9154 for(i=dia->sta; i<dia->cnt; i++)
9155 {
9156 if (i == dia->sta && dia->sta != 0)
9157 {
9158 y = dia->rect.top+(i-dia->sta+1)*dia->lineheight+1;
9159 xv[0] = dia->rect.left + 18; yv[0] = y - 4;
9160 xv[1] = dia->rect.left + 12; yv[1] = y - 10;
9161 xv[2] = dia->rect.left + 6; yv[2] = y - 4;
9162 Ddrawpolygon(dia, xv, yv, 3, 1);
9163 continue;
9164 }
9165 if (i == dia->cnt-1 && dia->cnt != dia->pd->count)
9166 {
9167 y = dia->rect.top+(i-dia->sta+1)*dia->lineheight+1;
9168 xv[0] = dia->rect.left + 18; yv[0] = y - 10;
9169 xv[1] = dia->rect.left + 12; yv[1] = y - 4;
9170 xv[2] = dia->rect.left + 6; yv[2] = y - 10;
9171 Ddrawpolygon(dia, xv, yv, 3, 1);
9172 continue;
9173 }
9174 Ddrawtext(dia, dia->pd->namelist[i], estrlen(dia->pd->namelist[i]), dia->rect.left+1,
9175 dia->rect.top+(i-dia->sta+1)*dia->lineheight+1, 0);
9176 }
9177 }
9178
Dstufftext(TDIALOG * dia,CHAR * msg,RECTAREA * r)9179 void Dstufftext(TDIALOG *dia, CHAR *msg, RECTAREA *r)
9180 {
9181 INTBIG len, wid, vpos;
9182
9183 Dintdrawrect(dia, r, 255, 255, 255);
9184
9185 /* display the message in multiple lines */
9186 vpos = r->top+dia->lineheight;
9187 if (dia->firstch > estrlen(msg)) return;
9188 msg = &msg[dia->firstch];
9189 while (*msg != 0)
9190 {
9191 for(len = estrlen(msg); len>0; len--)
9192 {
9193 wid = Dgettextsize(dia, msg, len);
9194 if (wid < r->right-r->left-2) break;
9195 }
9196 if (len <= 0) break;
9197 Ddrawtext(dia, msg, len, r->left+1, vpos, 0);
9198 msg += len;
9199 vpos += dia->lineheight;
9200 if (vpos > r->bottom) break;
9201 }
9202 }
9203
Dstuffmessage(TDIALOG * dia,CHAR * msg,RECTAREA * r,INTBIG dim)9204 void Dstuffmessage(TDIALOG *dia, CHAR *msg, RECTAREA *r, INTBIG dim)
9205 {
9206 INTBIG len, wid, truelen, vpos, mostch, i;
9207 CHAR *pt;
9208 REGISTER void *infstr;
9209
9210 for(pt = msg; *pt != 0; pt++) if (estrncmp(pt, x_("(tm)"), 4) == 0)
9211 {
9212 (void)estrcpy(pt, x_("\252")); /* "tm" character */
9213 (void)estrcpy(&pt[1], &pt[4]);
9214 break;
9215 }
9216 Dintdrawrect(dia, r, 255, 255, 255);
9217
9218 /* see how much fits */
9219 truelen = estrlen(msg);
9220 for(len = truelen; len > 0; len--)
9221 {
9222 wid = Dgettextsize(dia, msg, len);
9223 if (wid <= r->right-r->left-2) break;
9224 }
9225 if (len <= 0) return;
9226
9227 /* if it all fits or must fit (because there is just 1 line), draw it */
9228 vpos = r->top+dia->lineheight;
9229 if (len == truelen || dia->lineheight*2 > r->bottom - r->top)
9230 {
9231 if (len != truelen)
9232 {
9233 /* single line doesn't fit: put ellipsis at end */
9234 infstr = initinfstr();
9235 for(i=0; i<len-3; i++) addtoinfstr(infstr, msg[i]);
9236 addstringtoinfstr(infstr, x_("..."));
9237 msg = returninfstr(infstr);
9238 }
9239 Ddrawtext(dia, msg, len, r->left+1, vpos, dim);
9240 return;
9241 }
9242
9243 /* write the message in multiple lines */
9244 while (truelen > 0)
9245 {
9246 mostch = 0;
9247 for(len = truelen; len > 0; len--)
9248 {
9249 wid = Dgettextsize(dia, msg, len);
9250 if (wid > r->right-r->left-2) continue;
9251 if (mostch == 0) mostch = len;
9252 if (msg[len] == 0 || msg[len] == ' ') break;
9253 }
9254 if (len <= 0) len = mostch;
9255 Ddrawtext(dia, msg, len, r->left+1, vpos, dim);
9256 if (msg[len] == ' ') len++;
9257 msg += len;
9258 truelen -= len;
9259 vpos += dia->lineheight;
9260 if (vpos > r->bottom) break;
9261 }
9262 }
9263
Deditbox(TDIALOG * dia,RECTAREA * r,INTBIG draw,INTBIG dim)9264 void Deditbox(TDIALOG *dia, RECTAREA *r, INTBIG draw, INTBIG dim)
9265 {
9266 Dinsetrect(r, -3);
9267 Ddrawrectframe(dia, r, draw, dim);
9268 Dinsetrect(r, 3);
9269 }
9270
9271 /*
9272 * routine to draw line "msg" in position "which" of scroll area "sc"
9273 */
Ddrawmsg(TDIALOG * dia,INTBIG sc,CHAR * msg,INTBIG which)9274 void Ddrawmsg(TDIALOG *dia, INTBIG sc, CHAR *msg, INTBIG which)
9275 {
9276 INTBIG wid, len, firstch, offset;
9277 INTBIG skip;
9278 DSCROLL *scr;
9279
9280 Dsettextsmall(dia, sc);
9281 scr = &dia->scroll[sc];
9282 firstch = offset = 0;
9283 if (scr->horizfactor != 0)
9284 {
9285 skip = scr->userrect.right - scr->userrect.left - 6;
9286 skip *= (INTBIG)scr->horizfactor; skip /= 10;
9287 wid = Dgettextsize(dia, msg, estrlen(msg));
9288 if (skip >= wid) return;
9289 for(firstch = 0; firstch < estrlen(msg); firstch++)
9290 {
9291 wid = Dgettextsize(dia, msg, firstch);
9292 if (wid >= skip) break;
9293 }
9294 offset = wid - skip;
9295 }
9296
9297 for(len = estrlen(&msg[firstch]); len>0; len--)
9298 {
9299 wid = Dgettextsize(dia, &msg[firstch], len);
9300 if (wid+offset < scr->userrect.right-scr->userrect.left-6) break;
9301 }
9302 if (len <= 0) return;
9303 Ddrawtext(dia, &msg[firstch], len, scr->userrect.left+2+offset,
9304 scr->userrect.top + scr->lineheight*(which+1), 0);
9305 Dsettextsmall(dia, -1);
9306 }
9307
Dinsetrect(RECTAREA * r,INTBIG amt)9308 void Dinsetrect(RECTAREA *r, INTBIG amt)
9309 {
9310 r->left += amt; r->right -= amt;
9311 r->top += amt; r->bottom -= amt;
9312 }
9313
Ddrawvertslider(TDIALOG * dia,INTBIG sc)9314 void Ddrawvertslider(TDIALOG *dia, INTBIG sc)
9315 {
9316 RECTAREA r;
9317 DSCROLL *scr;
9318
9319 scr = &dia->scroll[sc];
9320 r = scr->userrect;
9321 r.left = r.right-1; r.right += 14;
9322 Ddrawrectframe(dia, &r, 1, 0);
9323 Ddrawline(dia, r.left, r.top+15, r.right-1, r.top+15);
9324 Ddrawarrow(dia, sc, UPARROW, 0);
9325 Ddrawline(dia, r.left, r.bottom-16, r.right-1, r.bottom-16);
9326 Ddrawarrow(dia, sc, DOWNARROW, 0);
9327 }
9328
Ddrawhorizslider(TDIALOG * dia,INTBIG sc)9329 void Ddrawhorizslider(TDIALOG *dia, INTBIG sc)
9330 {
9331 RECTAREA r;
9332 DSCROLL *scr;
9333
9334 scr = &dia->scroll[sc];
9335 r = scr->userrect;
9336 r.top = r.bottom-1; r.bottom += 14;
9337 Ddrawrectframe(dia, &r, 1, 0);
9338 Ddrawline(dia, r.left+15, r.top, r.left+15, r.bottom-1);
9339 Ddrawarrow(dia, sc, LEFTARROW, 0);
9340 Ddrawline(dia, r.right-16, r.top, r.right-16, r.bottom-1);
9341 Ddrawarrow(dia, sc, RIGHTARROW, 0);
9342 Dsethscroll(dia, sc);
9343 }
9344
9345 #define ARROWLEN 7
Ddrawarrow(TDIALOG * dia,INTBIG sc,INTBIG which,INTBIG filled)9346 void Ddrawarrow(TDIALOG *dia, INTBIG sc, INTBIG which, INTBIG filled)
9347 {
9348 INTBIG i, left, top, bottom, right;
9349 INTBIG xv[ARROWLEN], yv[ARROWLEN];
9350 DSCROLL *scr;
9351 static INTBIG arrowx[] = {4, 10, 10, 13, 7, 1, 4};
9352 static INTBIG arrowy[] = {12, 12, 8, 8, 2, 8, 8};
9353
9354 scr = &dia->scroll[sc];
9355 top = scr->userrect.top;
9356 bottom = scr->userrect.bottom-1;
9357 right = scr->userrect.right-1;
9358 left = scr->userrect.left;
9359 for(i=0; i<ARROWLEN; i++)
9360 {
9361 switch (which)
9362 {
9363 case UPARROW:
9364 xv[i] = right+arrowx[i];
9365 yv[i] = top+arrowy[i];
9366 break;
9367 case DOWNARROW:
9368 xv[i] = right+arrowx[i];
9369 yv[i] = bottom-arrowy[i];
9370 break;
9371 case LEFTARROW:
9372 xv[i] = left+arrowy[i];
9373 yv[i] = bottom+arrowx[i];
9374 break;
9375 case RIGHTARROW:
9376 xv[i] = right-arrowy[i];
9377 yv[i] = bottom+arrowx[i];
9378 break;
9379 }
9380 }
9381 Ddrawpolygon(dia, xv, yv, ARROWLEN, filled);
9382 }
9383
DTextCopy(TDIALOG * dia)9384 void DTextCopy(TDIALOG *dia)
9385 {
9386 CHAR *msg;
9387 INTBIG i;
9388 REGISTER void *infstr;
9389
9390 if (dia->curitem < 0) return;
9391
9392 /* copy selected text to the scrap */
9393 msg = (CHAR *)dia->dlgresaddr->list[dia->curitem].data;
9394 infstr = initinfstr();
9395 for(i=dia->editstart; i < dia->editend; i++)
9396 addtoinfstr(infstr, msg[i]);
9397 setcutbuffer(returninfstr(infstr));
9398 }
DTextCut(TDIALOG * dia)9399 void DTextCut(TDIALOG *dia)
9400 {
9401 CHAR *msg;
9402 INTBIG i, len, newcaret;
9403 REGISTER void *infstr;
9404
9405 if (dia->curitem < 0) return;
9406
9407 /* copy selected text to the scrap */
9408 msg = (CHAR *)dia->dlgresaddr->list[dia->curitem].data;
9409 len = estrlen(msg);
9410 infstr = initinfstr();
9411 for(i=dia->editstart; i < dia->editend; i++)
9412 addtoinfstr(infstr, msg[i]);
9413 setcutbuffer(returninfstr(infstr));
9414
9415 /* remove selected text */
9416 newcaret = dia->editstart;
9417 infstr = initinfstr();
9418 for(i=0; i<dia->editstart; i++)
9419 addtoinfstr(infstr, msg[i]);
9420 for(i=dia->editend; i<len; i++)
9421 addtoinfstr(infstr, msg[i]);
9422 DiaSetText(dia, dia->curitem+1, returninfstr(infstr));
9423 Dhighlight(dia, 0);
9424 dia->editstart = dia->editend = newcaret;
9425 Dhighlight(dia, 1);
9426 }
9427
DTextPaste(TDIALOG * dia)9428 CHAR DTextPaste(TDIALOG *dia)
9429 {
9430 CHAR *msg, *oldmsg;
9431 INTBIG i, len, newcaret;
9432 REGISTER void *infstr;
9433
9434 if (dia->curitem < 0) return(0);
9435 oldmsg = (CHAR *)dia->dlgresaddr->list[dia->curitem].data;
9436 len = estrlen(oldmsg);
9437 msg = getcutbuffer();
9438 newcaret = dia->editstart + estrlen(msg);
9439 infstr = initinfstr();
9440 for(i=0; i<dia->editstart; i++)
9441 addtoinfstr(infstr, oldmsg[i]);
9442 addstringtoinfstr(infstr, msg);
9443 for(i=dia->editend; i<len; i++)
9444 addtoinfstr(infstr, oldmsg[i]);
9445 DiaSetText(dia, dia->curitem+1, returninfstr(infstr));
9446 Dhighlight(dia, 0);
9447 dia->editstart = dia->editend = newcaret;
9448 Dhighlight(dia, 1);
9449 return(0);
9450 }
9451
Dredrawdialogwindow(TDIALOG * dia)9452 void Dredrawdialogwindow(TDIALOG *dia)
9453 {
9454 INTBIG i, itemtype, dim, pureitemtype;
9455 CHAR *line;
9456 RECTAREA r;
9457 USERTYPE routine;
9458
9459 Dclear(dia);
9460
9461 /* do not handle the first macintosh update event */
9462 if (dia->firstupdate != 0)
9463 {
9464 dia->firstupdate = 0;
9465 return;
9466 }
9467
9468 /* redraw the window frame */
9469 Dsettextsmall(dia, -1);
9470
9471 for(i=0; i<dia->dlgresaddr->items; i++)
9472 {
9473 /* draw the item */
9474 itemtype = dia->dlgresaddr->list[i].type;
9475 pureitemtype = itemtype & ITEMTYPE;
9476 r = dia->dlgresaddr->list[i].r;
9477 if (pureitemtype == USERDRAWN)
9478 {
9479 routine = (USERTYPE)dia->dlgresaddr->list[i].data;
9480 if (routine != 0) (*routine)(&r, dia);
9481 continue;
9482 }
9483 if (pureitemtype == MESSAGE || pureitemtype == EDITTEXT || pureitemtype == POPUP ||
9484 pureitemtype == BUTTON || pureitemtype == DEFBUTTON || pureitemtype == ICON)
9485 {
9486 line = (CHAR *)dia->dlgresaddr->list[i].data;
9487 } else if (pureitemtype == CHECK || pureitemtype == RADIO)
9488 {
9489 line = &((CHAR *)dia->dlgresaddr->list[i].data)[1];
9490 } else line = dia->dlgresaddr->list[i].msg;
9491 if ((itemtype&INACTIVE) != 0) dim = 1; else dim = 0;
9492 Ddrawitem(dia, itemtype, &r, line, dim);
9493
9494 /* handle set controls */
9495 if (pureitemtype == CHECK && ((CHAR *)dia->dlgresaddr->list[i].data)[0] != 0)
9496 {
9497 r.right = r.left + 12;
9498 r.top = (r.top + r.bottom) / 2 - 6;
9499 r.bottom = r.top + 12;
9500 Ddrawline(dia, r.left, r.top, r.right-1, r.bottom-1);
9501 Ddrawline(dia, r.left, r.bottom-1, r.right-1, r.top);
9502 }
9503 if (pureitemtype == RADIO && ((CHAR *)dia->dlgresaddr->list[i].data)[0] != 0)
9504 {
9505 r.right = r.left + 12;
9506 r.top = (r.top + r.bottom) / 2 - 6;
9507 r.bottom = r.top + 12;
9508 Dinsetrect(&r, 3);
9509 Ddrawdisc(dia, &r);
9510 }
9511
9512 /* highlight the default button */
9513 if (i == dia->defaultbutton-1 &&
9514 (itemtype == BUTTON || itemtype == DEFBUTTON)) Dhighlightrect(dia, &r);
9515 }
9516
9517 /* turn on anything being edited */
9518 if (dia->curitem >= 0) Dhighlight(dia, 1);
9519 for(i=0; i<dia->scrollcount; i++)
9520 {
9521 Dredrawscroll(dia, i);
9522 Dinvertentry(dia, i, 1); /* restores previous inverted entry */
9523 Dsetvscroll(dia, i);
9524 if ((dia->scroll[i].flags&SCHORIZBAR) != 0)
9525 {
9526 Ddrawhorizslider(dia, i);
9527 Dsethscroll(dia, i);
9528 }
9529 }
9530 }
9531
9532 /****************************** DIALOG PRIMITIVE GRAPHICS ******************************/
9533
9534 /*
9535 * routine to prepare a dialog in location "r", draggable if "movable" is nonzero
9536 */
Dnewdialogwindow(TDIALOG * dia,RECTAREA * r,CHAR * movable,BOOLEAN modeless)9537 void Dnewdialogwindow(TDIALOG *dia, RECTAREA *r, CHAR *movable, BOOLEAN modeless)
9538 {
9539 FontInfo fi;
9540 WindowPtr frontmost, wBehind;
9541 INTBIG type;
9542 Str255 line;
9543
9544 setdefaultcursortype(NORMALCURSOR);
9545
9546 if (movable != 0)
9547 {
9548 estrcpy((CHAR *)&line[1], movable);
9549 line[0] = estrlen((CHAR *)&line[1]);
9550 type = noGrowDocProc;
9551 } else
9552 {
9553 line[0] = 0;
9554 type = dBoxProc;
9555 }
9556
9557 gra_frontnonfloatingwindow(&frontmost);
9558 if (frontmost != 0) gra_activatewindow(frontmost, FALSE);
9559
9560 if (modeless)
9561 {
9562 wBehind = gra_lastfloatingwindow();
9563 if (wBehind == 0) wBehind = (WindowPtr)-1;
9564 } else wBehind = (WindowPtr)-1;
9565
9566 dia->theDialog = (GrafPtr)NewCWindow(0L, (Rect *)r, line, 0, type, wBehind, 0, 0L);
9567 if (dia->theDialog == 0) return;
9568
9569 ShowHide(dia->theDialog, 1);
9570 if (modeless)
9571 {
9572 gra_frontnonfloatingwindow(&frontmost);
9573 gra_activatewindow((WindowRef)dia->theDialog, FALSE);
9574 gra_activatewindow(frontmost, TRUE);
9575 } else
9576 {
9577 gra_activatewindow(dia->theDialog, TRUE);
9578 }
9579
9580 SetPort(dia->theDialog);
9581
9582 /* setup for small scroll text */
9583 TextFont(DSFONT);
9584 TextSize(10);
9585 GetFontInfo(&fi);
9586 dia->slineheight = fi.ascent + fi.descent + fi.leading;
9587 dia->slineoffset = fi.descent;
9588
9589 /* setup for all other text */
9590 TextFont(DFONT);
9591 TextSize(12);
9592 GetFontInfo(&fi);
9593 dia->lineheight = fi.ascent + fi.descent + fi.leading;
9594 dia->lineoffset = fi.descent;
9595 dia->curlineoffset = dia->lineoffset;
9596 }
9597
9598 /*
9599 * routine to terminate the current dialog
9600 */
Ddonedialogwindow(TDIALOG * dia)9601 void Ddonedialogwindow(TDIALOG *dia)
9602 {
9603 Rect r;
9604 INTBIG wid, hei;
9605
9606 if (dia->dlgresaddr->movable != 0)
9607 {
9608 r = (*((WindowPeek)dia->theDialog)->strucRgn)->rgnBBox;
9609 #if 1
9610 wid = dia->dlgresaddr->windowRect.right - dia->dlgresaddr->windowRect.left;
9611 hei = dia->dlgresaddr->windowRect.bottom - dia->dlgresaddr->windowRect.top;
9612 dia->dlgresaddr->windowRect.left = r.left+gra_winoffleft;
9613 dia->dlgresaddr->windowRect.right = dia->dlgresaddr->windowRect.left+wid;
9614 dia->dlgresaddr->windowRect.top = r.top+gra_winofftop;
9615 dia->dlgresaddr->windowRect.bottom = dia->dlgresaddr->windowRect.top+hei;
9616 #else
9617 dia->dlgresaddr->windowRect.left = r.left+gra_winoffleft;
9618 dia->dlgresaddr->windowRect.right = r.right+gra_winoffright;
9619 dia->dlgresaddr->windowRect.top = r.top+gra_winofftop;
9620 dia->dlgresaddr->windowRect.bottom = r.bottom+gra_winoffbottom;
9621 #endif
9622 }
9623 gra_disposeoswindow(dia->theDialog);
9624 }
9625
9626 /*
9627 * routine to erase the dialog window
9628 */
Dclear(TDIALOG * dia)9629 void Dclear(TDIALOG *dia)
9630 {
9631 gra_selectoswindow(dia->theDialog);
9632 SetPort(dia->theDialog);
9633 }
9634
9635 /*
9636 * routine to force the dialog window to be current (on window systems
9637 * where this is relevant)
9638 */
Dforcedialog(TDIALOG * dia)9639 void Dforcedialog(TDIALOG *dia)
9640 {
9641 gra_selectoswindow(dia->theDialog);
9642 SetPort(dia->theDialog);
9643 }
9644
9645 /*
9646 * routine to wait for the next action from the dialog window. Returns:
9647 * -1 Nothing happened
9648 * 0 Key typed, character in "chr"/"special"
9649 * 1 Mouse button pushed, coordinates in (x,y), modifiers in "chr"
9650 * 2 Mouse button released, coordinates in (x,y)
9651 * 4 Mouse motion while button down, coordinates in (x,y)
9652 * 5 Double-click of mouse button, coordinates in (x,y), modifiers in "chr"
9653 */
Dwaitforaction(TDIALOG * dia,INTBIG * x,INTBIG * y,INTBIG * chr,INTBIG * special,UINTBIG * time,BOOLEAN * shifted)9654 INTBIG Dwaitforaction(TDIALOG *dia, INTBIG *x, INTBIG *y, INTBIG *chr, INTBIG *special, UINTBIG *time, BOOLEAN *shifted)
9655 {
9656 INTBIG sx, sy, but;
9657
9658 gra_handlingdialog = dia;
9659 if (ttydataready())
9660 {
9661 *chr = getnxtchar(special);
9662 *time = ticktime();
9663 *shifted = FALSE;
9664 gra_handlingdialog = NOTDIALOG;
9665 return(0);
9666 }
9667
9668 /* get button */
9669 waitforbutton(&sx, &sy, &but);
9670 gra_handlingdialog = NOTDIALOG;
9671 *x = sx; *y = sy;
9672 if (but < 0) return(-1);
9673 *time = ticktime();
9674 *shifted = shiftbutton(but);
9675 if (doublebutton(but)) return(5);
9676 return(1);
9677 }
9678
9679 /*
9680 * routine to track mouse movements while the button remains down, calling
9681 * the routine "eachdown" for each advance. The routine is given the
9682 * mouse coordinates as parameters. The initial mouse position is (fx,fy).
9683 */
Dtrackcursor(TDIALOG * dia,INTBIG fx,INTBIG fy,BOOLEAN (* eachdown)(INTBIG,INTBIG))9684 void Dtrackcursor(TDIALOG *dia, INTBIG fx, INTBIG fy, BOOLEAN (*eachdown)(INTBIG, INTBIG))
9685 {
9686 gra_trackingdialog = dia;
9687 trackcursor(FALSE, us_nullup, us_nullvoid, eachdown, us_nullchar, us_nullvoid, TRACKNORMAL);
9688 }
9689
9690 /*
9691 * routine to move the rectangle "sr" to "dr"
9692 */
Dshiftbits(TDIALOG * dia,RECTAREA * sr,RECTAREA * dr)9693 void Dshiftbits(TDIALOG *dia, RECTAREA *sr, RECTAREA *dr)
9694 {
9695 SetPort(dia->theDialog);
9696 CopyBits(&dia->theDialog->portBits, &dia->theDialog->portBits,
9697 (Rect *)sr, (Rect *)dr, srcCopy, 0);
9698 }
9699
9700 /*
9701 * routine to handle popup menu "pd" in rectangle "r". Returns negative if
9702 * the function is not possible. Returns the entry in "pd" that is selected
9703 * (returns pd->current if no change is made).
9704 */
Dhandlepopup(TDIALOG * dia,RECTAREA * r,POPUPDATA * pd)9705 INTBIG Dhandlepopup(TDIALOG *dia, RECTAREA *r, POPUPDATA *pd)
9706 {
9707 INTBIG ret, i, j;
9708 CHAR *itemname;
9709 Str255 name;
9710 MenuHandle menu;
9711 Point p;
9712
9713 SetPort(dia->theDialog);
9714 p.h = r->left; p.v = r->top;
9715 LocalToGlobal(&p);
9716 menu = NewMenu(2048, x_("\p"));
9717 for(i=0; i<pd->count; i++)
9718 {
9719 itemname = pd->namelist[i];
9720 for(j=0; itemname[j] != 0; j++)
9721 {
9722 if (itemname[j] == '(') name[j+1] = '{'; else
9723 if (itemname[j] == ')') name[j+1] = '}'; else
9724 name[j+1] = itemname[j];
9725 }
9726 name[0] = j;
9727 AppendMenu(menu, name);
9728 }
9729 InsertMenu(menu, -1);
9730 ret = PopUpMenuSelect(menu, p.v, p.h, pd->current+1);
9731 DeleteMenu(2048);
9732 DisposeMenu(menu);
9733 if (HiWord(ret) == 0) return(pd->current);
9734 return(LoWord(ret) - 1);
9735 }
9736
9737 /*
9738 * routine to draw the 32x32 bitmap in "data" at (x,y)
9739 */
Dputicon(TDIALOG * dia,INTBIG x,INTBIG y,UCHAR1 * data)9740 void Dputicon(TDIALOG *dia, INTBIG x, INTBIG y, UCHAR1 *data)
9741 {
9742 BitMap b;
9743
9744 b.baseAddr = (CHAR1 *)data;
9745 b.rowBytes = 4;
9746 b.bounds.left = x; b.bounds.top = y;
9747 b.bounds.right = x+32; b.bounds.bottom = y+32;
9748 CopyBits(&b, &dia->theDialog->portBits, &b.bounds, &b.bounds, srcCopy, 0L);
9749 }
9750
9751 /*
9752 * routine to draw a line from (xf,yf) to (xt,yt) in the dialog
9753 */
Ddrawline(TDIALOG * dia,INTBIG xf,INTBIG yf,INTBIG xt,INTBIG yt)9754 void Ddrawline(TDIALOG *dia, INTBIG xf, INTBIG yf, INTBIG xt, INTBIG yt)
9755 {
9756 SetPort(dia->theDialog);
9757 MoveTo(xf, yf);
9758 LineTo(xt, yt);
9759 }
9760
9761 /*
9762 * routine to draw a filled rectangle at "rect" in the dialog with color (r,g,b).
9763 */
Dintdrawrect(TDIALOG * dia,RECTAREA * rect,INTBIG r,INTBIG g,INTBIG b)9764 void Dintdrawrect(TDIALOG *dia, RECTAREA *rect, INTBIG r, INTBIG g, INTBIG b)
9765 {
9766 RGBColor color, oldcolor;
9767
9768 SetPort(dia->theDialog);
9769 color.red = r << 8;
9770 color.green = g << 8;
9771 color.blue = b << 8;
9772 GetForeColor(&oldcolor);
9773 RGBForeColor(&color);
9774 FillRect((Rect *)rect, &qd.black);
9775 RGBForeColor(&oldcolor);
9776 }
9777
9778 /*
9779 * routine to draw a gray rectangle at "r" in the dialog
9780 */
Dgrayrect(TDIALOG * dia,RECTAREA * r)9781 void Dgrayrect(TDIALOG *dia, RECTAREA *r)
9782 {
9783 SetPort(dia->theDialog);
9784 FillRect((Rect *)r, &qd.ltGray);
9785 }
9786
9787 /*
9788 * routines to invert a rectangle at "r" in the dialog
9789 */
Dinvertrect(TDIALOG * dia,RECTAREA * r)9790 void Dinvertrect(TDIALOG *dia, RECTAREA *r)
9791 {
9792 SetPort(dia->theDialog);
9793 InvertRect((Rect *)r);
9794 }
9795
9796 /*
9797 * routine to invert a rounded rectangle at "r" in the dialog
9798 */
Dinvertroundrect(TDIALOG * dia,RECTAREA * r)9799 void Dinvertroundrect(TDIALOG *dia, RECTAREA *r)
9800 {
9801 SetPort(dia->theDialog);
9802 InvertRoundRect((Rect *)r, 10, 10);
9803 }
9804
9805 /*
9806 * routine to draw the outline of rectangle "r" in the dialog. Erases if "on" is zero
9807 */
Ddrawrectframe(TDIALOG * dia,RECTAREA * r,INTBIG on,INTBIG dim)9808 void Ddrawrectframe(TDIALOG *dia, RECTAREA *r, INTBIG on, INTBIG dim)
9809 {
9810 SetPort(dia->theDialog);
9811 if (on == 0) PenMode(patBic);
9812 FrameRect((Rect *)r);
9813 PenMode(patCopy);
9814 if (dim != 0)
9815 {
9816 PenMode(patBic);
9817 PenPat(&qd.gray);
9818 PaintRect((Rect *)r);
9819 PenMode(patCopy);
9820 PenPat(&qd.black);
9821 }
9822 }
9823 /*
9824 * routine to highlight the outline of rectangle "r" in the dialog
9825 */
Dhighlightrect(TDIALOG * dia,RECTAREA * r)9826 void Dhighlightrect(TDIALOG *dia, RECTAREA *r)
9827 {
9828 Dinsetrect(r, -4);
9829 SetPort(dia->theDialog);
9830 PenSize(3, 3);
9831 FrameRoundRect((Rect *)r, 16, 16);
9832 PenSize(1, 1);
9833 }
9834
9835 /*
9836 * routine to draw the outline of rounded rectangle "r" in the dialog
9837 */
Ddrawroundrectframe(TDIALOG * dia,RECTAREA * r,INTBIG arc,INTBIG dim)9838 void Ddrawroundrectframe(TDIALOG *dia, RECTAREA *r, INTBIG arc, INTBIG dim)
9839 {
9840 SetPort(dia->theDialog);
9841 FrameRoundRect((Rect *)r, arc, arc);
9842 if (dim != 0)
9843 {
9844 PenMode(patBic);
9845 PenPat(&qd.gray);
9846 PaintRect((Rect *)r);
9847 PenMode(patCopy);
9848 PenPat(&qd.black);
9849 }
9850 }
9851
9852 /*
9853 * routine to invert the outline of rectangle "r" in the dialog
9854 */
Dinvertrectframe(TDIALOG * dia,RECTAREA * r)9855 void Dinvertrectframe(TDIALOG *dia, RECTAREA *r)
9856 {
9857 SetPort(dia->theDialog);
9858 PenMode(patXor);
9859 FrameRect((Rect *)r);
9860 PenMode(patCopy);
9861 }
9862
9863 /*
9864 * routine to draw the polygon in "count" points (xv,yv) and fill it if "filled" is nonzero
9865 */
Ddrawpolygon(TDIALOG * dia,INTBIG * xv,INTBIG * yv,INTBIG count,INTBIG filled)9866 void Ddrawpolygon(TDIALOG *dia, INTBIG *xv, INTBIG *yv, INTBIG count, INTBIG filled)
9867 {
9868 PolyHandle ph;
9869 INTBIG i, l;
9870
9871 SetPort(dia->theDialog);
9872 ph = OpenPoly();
9873 for(i=0; i<count; i++)
9874 {
9875 if (i == 0) l = count-1; else l = i-1;
9876 MoveTo(xv[l], yv[l]);
9877 LineTo(xv[i], yv[i]);
9878 }
9879 ClosePoly();
9880 if (filled != 0) FillPoly(ph, &qd.black); else
9881 {
9882 FillPoly(ph, &qd.white);
9883 FramePoly(ph);
9884 }
9885 KillPoly(ph);
9886 }
9887
9888 /*
9889 * routine to draw a circle outline in rectangle "r" in the dialog
9890 */
Ddrawcircle(TDIALOG * dia,RECTAREA * r,INTBIG dim)9891 void Ddrawcircle(TDIALOG *dia, RECTAREA *r, INTBIG dim)
9892 {
9893 SetPort(dia->theDialog);
9894 FrameOval((Rect *)r);
9895 if (dim != 0)
9896 {
9897 PenMode(patBic);
9898 PenPat(&qd.gray);
9899 PaintRect((Rect *)r);
9900 PenMode(patCopy);
9901 PenPat(&qd.black);
9902 }
9903 }
9904
9905 /*
9906 * routine to draw a filled circle in rectangle "r" in the dialog
9907 */
Ddrawdisc(TDIALOG * dia,RECTAREA * r)9908 void Ddrawdisc(TDIALOG *dia, RECTAREA *r)
9909 {
9910 SetPort(dia->theDialog);
9911 FillOval((Rect *)r, &qd.black);
9912 }
9913
9914 /*
9915 * routine to determine the width of the "len" characters at "msg"
9916 */
Dgettextsize(TDIALOG * dia,CHAR * msg,INTBIG len)9917 INTBIG Dgettextsize(TDIALOG *dia, CHAR *msg, INTBIG len)
9918 {
9919 INTBIG wid;
9920
9921 if (len == 0) return(0);
9922 SetPort(dia->theDialog);
9923 wid = TextWidth(msg, 0, len);
9924 return(wid);
9925 }
9926
9927 /*
9928 * Routine to set the current text size to the large or small scroll text.
9929 */
Dsettextsmall(TDIALOG * dia,INTBIG sc)9930 void Dsettextsmall(TDIALOG *dia, INTBIG sc)
9931 {
9932 INTBIG smallf;
9933 DSCROLL *scr;
9934
9935 if (sc < 0) smallf = 0; else
9936 {
9937 scr = &dia->scroll[sc];
9938 smallf = scr->flags & SCSMALLFONT;
9939 }
9940 if (smallf != 0)
9941 {
9942 dia->curlineoffset = scr->lineoffset;
9943 TextFont(DSFONT);
9944 TextSize(10);
9945 } else
9946 {
9947 dia->curlineoffset = dia->lineoffset;
9948 TextFont(DFONT);
9949 TextSize(12);
9950 }
9951 }
9952
9953 /*
9954 * routine to draw "len" characters of "msg" at (x,y)
9955 */
Ddrawtext(TDIALOG * dia,CHAR * msg,INTBIG len,INTBIG x,INTBIG y,INTBIG dim)9956 void Ddrawtext(TDIALOG *dia, CHAR *msg, INTBIG len, INTBIG x, INTBIG y, INTBIG dim)
9957 {
9958 Rect r;
9959
9960 SetPort(dia->theDialog);
9961 MoveTo(x, y-dia->curlineoffset-1);
9962 DrawText(msg, 0, len);
9963 if (dim != 0)
9964 {
9965 r.left = x; r.right = x + TextWidth(msg, 0, len);
9966 r.bottom = y; r.top = y - dia->lineheight;
9967 PenPat(&qd.gray);
9968 PenMode(patBic);
9969 PaintRect(&r);
9970 PenMode(patCopy);
9971 PenPat(&qd.black);
9972 }
9973 }
9974
gra_makepstring(CHAR * string)9975 CHAR *gra_makepstring(CHAR *string)
9976 {
9977 static CHAR pstring[256];
9978 REGISTER INTBIG len;
9979
9980 estrncpy(&pstring[1], string, 255);
9981 len = estrlen(string);
9982 if (len > 255) len = 255;
9983 pstring[0] = len;
9984 return(pstring);
9985 }
9986
9987 /*
9988 * Helper routine for "DiaLoadTextDialog" that makes strings go in ascending order.
9989 */
gra_stringposascending(const void * e1,const void * e2)9990 int gra_stringposascending(const void *e1, const void *e2)
9991 {
9992 REGISTER CHAR *c1, *c2;
9993
9994 c1 = *((CHAR **)e1);
9995 c2 = *((CHAR **)e2);
9996 return(namesame(&c1[gra_dialogstringpos], &c2[gra_dialogstringpos]));
9997 }
9998