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(&currentFrontWindow);
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 				&copyrect, &copyrect, 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 				&copyrect, &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