1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: graphpccode.cpp
6 * Interface for Win32 (Win9x/NT/2K/XP) 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 #include "graphpcstdafx.h"
33 #include "graphpc.h"
34 #include "graphpcdoc.h"
35 #include "graphpcview.h"
36 #include "graphpcmainframe.h"
37 #include "graphpcchildframe.h"
38 #include "graphpcmsgview.h"
39 #include "graphpcdialog.h"
40 #include "graphpcdialoglistbox.h"
41
42 #include "global.h"
43 #include "database.h"
44 #include "egraphics.h"
45 #include "usr.h"
46 #include "usrtrack.h"
47 #include "eio.h"
48 #include "edialogs.h"
49 #if LANGTCL
50 # include "dblang.h"
51 #endif
52
53 /* #define USEDIRECTSOUND 1 */ /* uncomment to use direct-sound for playing sounds */
54
55 #include <io.h>
56 #include <signal.h>
57 #include <sys/stat.h>
58 #include <direct.h>
59 #include <sys/timeb.h>
60 #include <sys/utime.h>
61 #include <afxmt.h>
62 #include <MMSystem.h> /* need link with "winmm.lib" */
63
64 #ifdef _UNICODE
65 # define estat _wstat
66 # define estatstr _stat
67 # define eaccess _waccess
68 # define emkdir _wmkdir
69 # define egetcwd _wgetcwd
70 # define ecreat _wcreat
71 # define efullpath _wfullpath
72 #else
73 # define estat stat
74 # define estatstr stat
75 # define eaccess access
76 # define emkdir mkdir
77 # define egetcwd getcwd
78 # define ecreat creat
79 # define efullpath _fullpath
80 #endif
81
82 /****** windows and control ******/
83 extern CElectricApp gra_app; /* this application */
84 static WINDOWFRAME *gra_cureditwindowframe; /* the current window frame */
85 static WINDOWFRAME *gra_palettewindowframe = NOWINDOWFRAME; /* window frame with palette */
86 static INTBIG gra_windownumberindex = 0; /* counter for window and dialog indices */
87 static INTBIG gra_newwindowoffset = 0; /* offset of the next window (stagger them) */
88 static CHAR *gra_initialdirectory; /* location where Electric started */
89 static BOOLEAN gra_creatingwindow = FALSE;/* TRUE if creating a window */
90 static BOOLEAN gra_noflush = FALSE; /* TRUE to supress display flushing */
91
92 /****** the messages window ******/
93 #define MAXTYPEDLINE 256 /* max chars on input line */
94
95 CChildFrame *gra_messageswindow; /* the messages window */
96 static CRichEditCtrl *gra_editCtrl; /* the rich-edit control for messages text */
97 static BOOLEAN gra_messagescurrent; /* true if messages window is current */
98 static INTBIG gra_messagesleft; /* left bound of messages window screen */
99 static INTBIG gra_messagesright; /* right bound of messages window screen */
100 static INTBIG gra_messagestop; /* top bound of messages window screen */
101 static INTBIG gra_messagesbottom; /* bottom bound of messages window screen */
102
103 /****** for text drawing ******/
104 static CDC *gra_texthdc; /* device context for text buffer */
105 static HBITMAP gra_textbitmap; /* bitmap for text buffer */
106 static BITMAPINFO *gra_textbitmapinfo; /* bitmap information structure */
107 static UCHAR1 *gra_textdatabuffer; /* data in text buffer */
108 static UCHAR1 **gra_textrowstart; /* row starts for text buffer */
109 static INTBIG gra_textbufwid; /* width of text buffer */
110 static INTBIG gra_textbufhei; /* height of text buffer */
111 static BOOLEAN gra_textbufinited = FALSE; /* true if text buffer is initialized */
112
113 /****** for offscreen copying at a larger scale ******/
114 static BOOLEAN gra_biggeroffbufinited = FALSE; /* true if bigger offscreen buffer is initialized */
115 static INTBIG gra_biggeroffbufwid; /* width of bigger offscreen buffer */
116 static INTBIG gra_biggeroffbufhei; /* height of bigger offscreen buffer */
117 static UCHAR1 **gra_biggeroffrowstart; /* row starts for bigger offscreen buffer */
118 static BITMAPINFO *gra_biggeroffbitmapinfo; /* bitmap information structure */
119 static HBITMAP gra_biggeroffbitmap; /* bitmap for bigger offscreen buffer */
120 static UCHAR1 *gra_biggeroffdatabuffer; /* data in bigger offscreen buffer */
121 static CDC *gra_biggeroffhdc; /* device context for bigger offscreen buffer */
122
123 /****** the status bar ******/
124 #define MAXSTATUSLINES 1
125
126 static STATUSFIELD *gra_statusfields[100];
127 static CHAR *gra_statusfieldtext[100];
128 static INTBIG gra_indicatorcount = 0;
129 static UINT gra_indicators[] = {ID_INDICATOR_ELECTRIC01, ID_INDICATOR_ELECTRIC02,
130 ID_INDICATOR_ELECTRIC03, ID_INDICATOR_ELECTRIC04, ID_INDICATOR_ELECTRIC05,
131 ID_INDICATOR_ELECTRIC06, ID_INDICATOR_ELECTRIC07, ID_INDICATOR_ELECTRIC08,
132 ID_INDICATOR_ELECTRIC09, ID_INDICATOR_ELECTRIC10, ID_INDICATOR_ELECTRIC11,
133 ID_INDICATOR_ELECTRIC12, ID_INDICATOR_ELECTRIC13, ID_INDICATOR_ELECTRIC14,
134 ID_INDICATOR_ELECTRIC15, ID_INDICATOR_ELECTRIC16, ID_INDICATOR_ELECTRIC17};
135
136 /****** the dialogs ******/
137 #define PROGRESSOFFSET 100
138 #define MAXSCROLLMULTISELECT 1000
139 #define MAXLOCKS 3 /* maximum locked pairs of scroll lists */
140 #ifndef SPI_GETSNAPTODEFBUTTON
141 # define SPI_GETSNAPTODEFBUTTON 95 /* why isn't this defined in system headers? */
142 #endif
143
144 #define NOTDIALOG ((TDIALOG *)-1)
145
146 typedef struct Itdialog
147 {
148 CElectricDialog *window;
149 DIALOG *itemdesc;
150 INTBIG windindex;
151 INTBIG defaultbutton;
152 POINT firstpoint;
153 INTBIG numlocks, lock1[MAXLOCKS], lock2[MAXLOCKS], lock3[MAXLOCKS];
154 INTBIG redrawitem;
155 INTBIG useritemdoubleclick;
156 INTBIG usertextsize;
157 void (*redrawroutine)(RECTAREA*, void*);
158 INTBIG dialoghit;
159 struct Itdialog *nexttdialog;
160 void (*diaeachdown)(INTBIG x, INTBIG y);
161 void (*modelessitemhit)(void *dia, INTBIG item);
162 } TDIALOG;
163
164 static TDIALOG *gra_firstactivedialog = NOTDIALOG;
165 static CBrush *gra_dialogoffbrush = 0;
166 static CBrush *gra_dialogbkgrbrush = 0;
167 static TDIALOG *gra_trackingdialog = 0;
168
169 /****** events ******/
170 #define CHARREAD 0377 /* character that was read */
171 #define ISKEYSTROKE 0400 /* set if key typed */
172 #define ISBUTTON 01000 /* set if button pushed (or released) */
173 #define BUTTONUP 02000 /* set if button was released */
174 #define SHIFTISDOWN 04000 /* set if shift key was held down */
175 #define ALTISDOWN 010000 /* set if alt key was held down */
176 #define CONTROLISDOWN 020000 /* set if control key was held down */
177 #define DOUBLECLICK 040000 /* set if this is second click */
178 #define MOTION 0100000 /* set if mouse motion detected */
179 #define WINDOWSIZE 0200000 /* set if window grown */
180 #define WINDOWMOVE 0400000 /* set if window moved */
181 #define MENUEVENT 01000000 /* set if menu entry selected (values in cursor) */
182 #define FILEREPLY 02000000 /* set if file selected in standard file dialog */
183 #define DIAITEMCLICK 04000000 /* set if item clicked in dialog */
184 #define DIASCROLLSEL 010000000 /* set if scroll item selected in dialog */
185 #define DIAEDITTEXT 020000000 /* set if edit text changed in dialog */
186 #define DIAPOPUPSEL 040000000 /* set if popup item selected in dialog */
187 #define DIASETCONTROL 0100000000 /* set if control changed in dialog */
188 #define DIAUSERMOUSE 0200000000 /* set if mouse moved in user area of dialog */
189 #define DIAENDDIALOG 0400000000 /* set when dialog terminates */
190 #define WHICHBUTTON 07000000000 /* which button was pushed */
191 #define ISLEFT 0 /* the left button */
192 #define ISMIDDLE 01000000000 /* the middle button */
193 #define ISRIGHT 02000000000 /* the right button */
194 #define ISWHLFWD 03000000000 /* forward on the mouse wheel */
195 #define ISWHLBKW 04000000000 /* backward on the mouse wheel */
196 #define POPUPSELECT 010000000000 /* popup selection made */
197 #define NOEVENT -1 /* set if nothing happened */
198
199 #define FLUSHTICKS 120
200
201 struct /* only used to communicate mouse coordinates for dialog logging */
202 {
203 INTBIG x;
204 INTBIG y;
205 } gra_action;
206
207 #define EVENTQUEUESIZE 100
208
209 typedef struct
210 {
211 INTBIG cursorx, cursory; /* current position of mouse */
212 INTBIG inputstate; /* current state of device input */
213 INTBIG special; /* current "special" code for keyboard */
214 UINTBIG eventtime; /* time this event happened */
215 } MYEVENTQUEUE;
216
217 static MYEVENTQUEUE gra_eventqueue[EVENTQUEUESIZE];
218 static MYEVENTQUEUE *gra_eventqueuehead; /* points to next event in queue */
219 static MYEVENTQUEUE *gra_eventqueuetail; /* points to first free event in queue */
220 static UINTBIG gra_eventtime; /* time last event happened */
221 static void *gra_eventqueuemutex = 0; /* mutex for event queue */
222 static INTBIG gra_inputstate; /* current state of device input */
223 static INTBIG gra_inputspecial; /* current "special" keyboard value */
224 static INTBIG gra_cursorx, gra_cursory; /* current position of mouse */
225 static INTBIG gra_logrecordcount = 0; /* count for session flushing */
226 static INTBIG gra_lastloggedaction = NOEVENT;
227 static INTBIG gra_lastloggedx, gra_lastloggedy;
228 static INTBIG gra_lastloggedindex;
229 static UINTBIG gra_logbasetime; /* base of time for log output */
230 static UINTBIG gra_lastplaybacktime = 0;
231 static CHAR *gra_logfile, *gra_logfilesave;
232
233
234 /****** pulldown menus ******/
235 #define IDR_MENU 3000 /* base ID for menus */
236
237 static CMenu *gra_hMenu; /* System Menu */
238 CMenu **gra_pulldownmenus; /* list of Windows pulldown menus */
239 static CHAR **gra_pulldowns; /* list of Electric pulldown menu names */
240 INTBIG gra_pulldownmenucount; /* number of pulldown menus */
241 static int gra_menures[] = {ID_ELECTRIC_MENU01, ID_ELECTRIC_MENU02,
242 ID_ELECTRIC_MENU03, ID_ELECTRIC_MENU04, ID_ELECTRIC_MENU05, ID_ELECTRIC_MENU06,
243 ID_ELECTRIC_MENU07, ID_ELECTRIC_MENU08, ID_ELECTRIC_MENU09, ID_ELECTRIC_MENU10,
244 ID_ELECTRIC_MENU11, ID_ELECTRIC_MENU12, ID_ELECTRIC_MENU13, ID_ELECTRIC_MENU14,
245 ID_ELECTRIC_MENU15, ID_ELECTRIC_MENU16, ID_ELECTRIC_MENU17, ID_ELECTRIC_MENU18,
246 ID_ELECTRIC_MENU19, ID_ELECTRIC_MENU20, ID_ELECTRIC_MENU21, ID_ELECTRIC_MENU22,
247 ID_ELECTRIC_MENU23, ID_ELECTRIC_MENU24, ID_ELECTRIC_MENU25, ID_ELECTRIC_MENU26,
248 ID_ELECTRIC_MENU27, ID_ELECTRIC_MENU28, ID_ELECTRIC_MENU29};
249
250 /****** mouse buttons ******/
251 #define BUTTONS 45 /* cannot exceed NUMBUTS in "usr.h" */
252 #define REALBUTS 5 /* actual number of buttons */
253
254 struct
255 {
256 CHAR *name; /* button name */
257 INTBIG unique; /* number of letters that make it unique */
258 } gra_buttonname[BUTTONS] =
259 {
260 {x_("LEFT"), 1}, {x_("MIDDLE"), 1}, {x_("RIGHT"), 1}, {x_("FORWARD"), 1},{x_("BACKWARD"), 1}, /* 0: unshifted */
261 {x_("SLEFT"),2}, {x_("SMIDDLE"), 2}, {x_("SRIGHT"), 2}, {x_("SFORWARD"), 2},{x_("SBACKWARD"), 2}, /* 5: shift held down */
262 {x_("CLEFT"),2}, {x_("CMIDDLE"), 2}, {x_("CRIGHT"), 2}, {x_("CFORWARD"), 2},{x_("CBACKWARD"), 2}, /* 10: control held down */
263 {x_("ALEFT"),2}, {x_("AMIDDLE"), 2}, {x_("ARIGHT"), 2}, {x_("AFORWARD"), 2},{x_("ABACKWARD"), 2}, /* 15: alt held down */
264 {x_("SCLEFT"),3}, {x_("SCMIDDLE"),3}, {x_("SCRIGHT"),3}, {x_("SCFORWARD"), 3},{x_("SCBACKWARD"), 3}, /* 20: control/shift held down */
265 {x_("SALEFT"),3}, {x_("SAMIDDLE"),3}, {x_("SARIGHT"),3}, {x_("SAFORWARD"), 3},{x_("SABACKWARD"), 3}, /* 25: shift/alt held down */
266 {x_("CALEFT"),3}, {x_("CAMIDDLE"),3}, {x_("CARIGHT"),3}, {x_("CAFORWARD"), 3},{x_("CABACKWARD"), 3}, /* 30: control/alt held down */
267 {x_("SCALEFT"),4},{x_("SCAMIDDLE"),4},{x_("SCARIGHT"),4},{x_("SCAFORWARD"),4},{x_("SCABACKWARD"),4}, /* 35: shift/control/alt held down */
268 {x_("DLEFT"),2}, {x_("DMIDDLE"), 2}, {x_("DRIGHT"), 2}, {x_("DFORWARD"), 2},{x_("DBACKWARD"), 2} /* 40: double-click */
269 };
270
271 /****** cursors ******/
272 static HCURSOR gra_normalCurs; /* the default cursor */
273 static HCURSOR gra_wantttyCurs; /* a "use the TTY" cursor */
274 static HCURSOR gra_penCurs; /* a "draw with pen" cursor */
275 static HCURSOR gra_menuCurs; /* a menu selection cursor */
276 static HCURSOR gra_handCurs; /* a hand dragging cursor */
277 static HCURSOR gra_techCurs; /* a technology edit cursor */
278 static HCURSOR gra_ibeamCurs; /* a text edit cursor */
279 static HCURSOR gra_waitCurs; /* an hourglass cursor */
280 static HCURSOR gra_lrCurs; /* a left/right pointing cursor */
281 static HCURSOR gra_udCurs; /* an up/down pointing cursor */
282
283 #ifdef WINSAVEDBOX
284
285 /****** rectangle saving ******/
286 #define NOSAVEDBOX ((SAVEDBOX *)-1)
287
288 typedef struct Isavedbox
289 {
290 HBITMAP hBox;
291 BITMAPINFO *bminfo;
292 CDC *hMemDC;
293 UCHAR1 *data;
294 UCHAR1 **rowstart;
295 WINDOWPART *win;
296 INTBIG lx, hx, ly, hy;
297 struct Isavedbox *nextsavedbox;
298 } SAVEDBOX;
299
300 static SAVEDBOX *gra_firstsavedbox = NOSAVEDBOX;
301 #endif
302
303 /****** fonts ******/
304 #define MAXCACHEDFONTS 200
305 #define FONTHASHSIZE 211 /* must be prime */
306
307 typedef struct
308 {
309 CFont *font;
310 INTBIG face;
311 INTBIG italic;
312 INTBIG bold;
313 INTBIG underline;
314 INTBIG size;
315 } FONTHASH;
316
317 static FONTHASH gra_fonthash[FONTHASHSIZE];
318 static CFont *gra_fontcache[MAXCACHEDFONTS];
319 static INTBIG gra_numfaces = 0;
320 static CHAR **gra_facelist;
321 static INTBIG gra_textrotation = 0;
322 static BOOLEAN gra_texttoosmall = FALSE;
323
324 /****** miscellaneous ******/
325 #define PALETTEWIDTH 136 /* width of palette */
326 #define MAXPATHLEN 256 /* max chars in file path */
327 #define SBARWIDTH 15 /* width of scroll bars */
328 #define MAXLOCALSTRING 256 /* size of "gra_localstring" */
329
330 static INTBIG gra_screenleft, /* left bound of any editor window screen */
331 gra_screenright, /* right bound of any editor window screen */
332 gra_screentop, /* top bound of any editor window screen */
333 gra_screenbottom; /* bottom bound of any editor window screen */
334 static CHAR gra_localstring[MAXLOCALSTRING]; /* local string */
335 static void *gra_fileliststringarray = 0;
336 static time_t gra_timebasesec;
337 static INTBIG gra_timebasems;
338 static UINTBIG gra_timeoffset = 0; /* offset to system time */
339
340 /****** prototypes for internal routines ******/
341 static void gra_addeventtoqueue(INTBIG state, INTBIG special, INTBIG x, INTBIG y);
342 static BOOLEAN gra_addfiletolist(CHAR *file);
343 static BOOLEAN gra_buildoffscreenbuffer(WINDOWFRAME *wf, INTBIG wid, INTBIG hei, CDC **hdc,
344 HBITMAP *bitmap, BITMAPINFO **bminfo, UCHAR1 **databuffer, UCHAR1 ***rowstart);
345 static BOOLEAN gra_buildwindow(WINDOWFRAME*, BOOLEAN, RECTAREA*);
346 static void gra_copyhighlightedtoclipboard(void);
347 static CFont *gra_createtextfont(INTBIG, CHAR*, INTBIG, INTBIG, INTBIG);
348 static BOOLEAN gra_diaeachdownhandler(INTBIG x, INTBIG y);
349 static INTBIG gra_dodialogisinsideuserdrawn(TDIALOG *dia, int x, int y);
350 static int APIENTRY gra_enumfaces(LPLOGFONT lpLogFont, LPTEXTMETRIC lpTEXTMETRICs, DWORD fFontType, LPVOID lpData);
351 static void gra_floatpalette(void);
352 static void gra_freewindowframe(WINDOWFRAME *wf);
353 static BOOLEAN gra_getbiggeroffscreenbuffer(WINDOWFRAME *wf, INTBIG wid, INTBIG hei);
354 static void gra_getdevices(void);
355 static INTBIG gra_getdialogitem(TDIALOG *dia, int x, int y);
356 static RECT *gra_geteditorwindowlocation(void);
357 static TDIALOG *gra_getdialogfromindex(INTBIG index);
358 static WINDOWFRAME *gra_getframefromindex(INTBIG index);
359 static CFont *gra_gettextfont(WINDOWPART*, TECHNOLOGY*, UINTBIG*);
360 static HWND gra_getwindow(WINDOWPART *win);
361 static BOOLEAN gra_initdialog(DIALOG *dialog, TDIALOG *dia, BOOLEAN modeless);
362 static void gra_initfilelist(void);
363 static BOOLEAN gra_loggetnextaction(CHAR *message);
364 static BOOLEAN gra_logreadline(CHAR *string, INTBIG limit);
365 static void gra_logwriteaction(INTBIG inputstate, INTBIG special, INTBIG cursorx, INTBIG cursory, void *extradata);
366 static void gra_logwritecomment(CHAR *comment);
367 static INTBIG gra_makebutton(INTBIG);
368 static BOOLEAN gra_makeeditwindow(WINDOWFRAME*);
369 static HICON gra_makeicon(INTBIG data);
370 static BOOLEAN gra_makemessageswindow(void);
371 static CMenu *gra_makepdmenu(POPUPMENU *);
372 static BOOLEAN gra_messagesnotvisible(void);
373 static INTBIG gra_nativepopuptif(POPUPMENU **menu, BOOLEAN header, INTBIG left, INTBIG top);
374 static void gra_nextevent(void);
375 static INTBIG gra_pulldownindex(POPUPMENU *);
376 static void gra_redrawdisplay(WINDOWFRAME*);
377 static void gra_redrawstatusindicators(void);
378 static void gra_reloadmap(void);
379 static BOOLEAN gra_remakeeditwindow(WINDOWFRAME*);
380 static void gra_removewindowextent(RECT *r, CWnd *wnd);
381 static void gra_setdefaultcursor(void);
382 static INTBIG gra_setregistry(HKEY key, CHAR *subkey, CHAR *value, CHAR *newstring);
383 static void gra_tomessagesbottom(void);
384 #if LANGTCL
385 INTBIG gra_initializetcl(void);
386 #endif
387
388 #ifdef USEDIRECTSOUND
389 # include <dsound.h> /* need link with "dsound.lib" */
390 typedef struct
391 {
392 IDirectSound *gpds;
393 IDirectSoundBuffer *secondarybuffer;
394 } SOUND;
395 static void gra_playsound(SOUND *sound);
396 static SOUND *gra_initsound(CHAR *filename);
397 extern "C" { extern HINSTANCE g_hDSoundLib; }
398 typedef HRESULT (WINAPI *PFN_DSCREATE)(LPGUID lpguid, LPDIRECTSOUND *ppDS, IUnknown FAR *pUnkOuter);
399 static PFN_DSCREATE gra_DSCreate;
400 #endif
401
402 /****** prototypes for externally called routines ******/
403 void gra_activateframe(CChildFrame *frame, BOOL bActivate);
404 void gra_buttonaction(int state, UINT nFlags, CPoint point, CWnd *frm);
405 int gra_closeframe(CChildFrame *frame);
406 int gra_closeworld(void);
407 void gra_diaredrawitem(CElectricDialog*);
408 int gra_dodialoglistkey(CElectricDialog *diawin, UINT nKey, CListBox* pListBox, UINT nIndex);
409 void gra_dodialogtextchange(CElectricDialog *diawin, int nID);
410 INTBIG gra_getregistry(HKEY key, CHAR *subkey, CHAR *value, CHAR *result);
411 void gra_itemclicked(CElectricDialog *diawin, int nID);
412 void gra_itemdoubleclicked(CElectricDialog *diawin, int nID);
413 void gra_itemvscrolled(void *vdia, int nID);
414 void gra_keyaction(UINT nChar, INTBIG special, UINT nRepCnt);
415 void gra_mouseaction(UINT nFlags, CPoint point, CWnd *frm);
416 void gra_mousewheelaction(UINT nFlags, short zDelta, CPoint point, CWnd *frm);
417 void gra_movedwindow(CChildFrame *frame, int x, int y);
418 void gra_nativemenudoone(INTBIG low, INTBIG high);
419 void gra_onint(void);
420 void gra_repaint(CChildFrame *frame, CPaintDC *dc);
421 void gra_resize(CChildFrame *frame, int cx, int cy);
422 void gra_resizemain(int cx, int cy);
423 int gra_setpropercursor(CWnd *wnd, int x, int y);
424 void gra_setrect(WINDOWFRAME*, INTBIG, INTBIG, INTBIG, INTBIG);
425 void gra_timerticked(void);
426
427 /******************** INITIALIZATION ********************/
428
429 /*
430 * routines to establish the default display
431 */
graphicsoptions(CHAR * name,INTBIG * argc,CHAR1 ** argv)432 void graphicsoptions(CHAR *name, INTBIG *argc, CHAR1 **argv)
433 {
434 us_erasech = BACKSPACEKEY;
435 us_killch = 025;
436 }
437
438 /*
439 * routine to initialize the display device
440 */
initgraphics(BOOLEAN messages)441 BOOLEAN initgraphics(BOOLEAN messages)
442 {
443 CHAR username[256];
444 UINTBIG size;
445 INTBIG i;
446 REGISTER void *infstr;
447
448 gra_inputstate = NOEVENT;
449 gra_pulldownmenucount = 0; /* number of pulldown menus */
450 gra_hMenu = 0;
451
452 /* setup globals that describe location of windows */
453 gra_getdevices();
454
455 /* remember the initial directory and the log file locations */
456 (void)allocstring(&gra_initialdirectory, currentdirectory(), db_cluster);
457 size = 256;
458 GetUserName(username, &size);
459 infstr = initinfstr();
460 addstringtoinfstr(infstr, gra_initialdirectory);
461 addstringtoinfstr(infstr, x_("electric_"));
462 addstringtoinfstr(infstr, username);
463 addstringtoinfstr(infstr, x_(".log"));
464 (void)allocstring(&gra_logfile, returninfstr(infstr), db_cluster);
465 infstr = initinfstr();
466 addstringtoinfstr(infstr, gra_initialdirectory);
467 addstringtoinfstr(infstr, x_("electriclast_"));
468 addstringtoinfstr(infstr, username);
469 addstringtoinfstr(infstr, x_(".log"));
470 (void)allocstring(&gra_logfilesave, returninfstr(infstr), db_cluster);
471
472 /* create the scrolling messages window */
473 if (!messages) gra_messageswindow = 0; else
474 {
475 if (gra_makemessageswindow()) error(_("Cannot create messages window"));
476 }
477
478 /* get cursors */
479 gra_normalCurs = gra_app.LoadStandardCursor(IDC_ARROW);
480 gra_waitCurs = gra_app.LoadStandardCursor(IDC_WAIT);
481 gra_ibeamCurs = gra_app.LoadStandardCursor(IDC_IBEAM);
482 gra_wantttyCurs = gra_app.LoadCursor(IDC_CURSORTTY);
483 if (gra_wantttyCurs == 0) gra_wantttyCurs = gra_normalCurs;
484 gra_penCurs = gra_app.LoadCursor(IDC_CURSORPEN);
485 if (gra_penCurs == 0) gra_penCurs = gra_normalCurs;
486 gra_handCurs = gra_app.LoadCursor(IDC_CURSORHAND);
487 if (gra_handCurs == 0) gra_handCurs = gra_normalCurs;
488 gra_menuCurs = gra_app.LoadCursor(IDC_CURSORMENU);
489 if (gra_menuCurs == 0) gra_menuCurs = gra_normalCurs;
490 gra_techCurs = gra_app.LoadCursor(IDC_CURSORTECH);
491 if (gra_techCurs == 0) gra_techCurs = gra_normalCurs;
492 gra_lrCurs = gra_app.LoadStandardCursor(IDC_SIZEWE);
493 if (gra_lrCurs == 0) gra_lrCurs = gra_normalCurs;
494 gra_udCurs = gra_app.LoadStandardCursor(IDC_SIZENS);
495 if (gra_udCurs == 0) gra_udCurs = gra_normalCurs;
496
497 /* initialize the cursor */
498 SetCursor(0);
499 us_normalcursor = NORMALCURSOR;
500 us_cursorstate = us_normalcursor;
501
502 /* initialize font cache */
503 for(i=0; i<MAXCACHEDFONTS; i++) gra_fontcache[i] = 0;
504 for(i=0; i<FONTHASHSIZE; i++) gra_fonthash[i].font = 0;
505
506 gra_eventqueuehead = gra_eventqueuetail = gra_eventqueue;
507 el_firstwindowframe = el_curwindowframe = NOWINDOWFRAME;
508 gra_cureditwindowframe = NOWINDOWFRAME;
509
510 /* get mutex */
511 (void)ensurevalidmutex(&gra_eventqueuemutex, TRUE);
512
513 return(FALSE);
514 }
515
gra_makemessageswindow(void)516 BOOLEAN gra_makemessageswindow(void)
517 {
518 RECT rmsg;
519 CCreateContext context;
520
521 /* create a context to tell this window to be an EditView */
522 context.m_pNewViewClass = RUNTIME_CLASS(CElectricMsgView);
523 context.m_pCurrentDoc = NULL;
524 context.m_pNewDocTemplate = NULL;
525 context.m_pLastView = NULL;
526 context.m_pCurrentFrame = NULL;
527
528 /* set messages window location */
529 rmsg.left = gra_messagesleft;
530 rmsg.right = gra_messagesright;
531 rmsg.top = gra_messagestop;
532 rmsg.bottom = gra_messagesbottom;
533
534 /* create the window */
535 gra_messageswindow = new CChildFrame();
536 gra_messageswindow->Create(NULL, _("Electric Messages"),
537 WS_CHILD|WS_OVERLAPPEDWINDOW|WS_VISIBLE, rmsg, NULL, &context);
538 gra_messageswindow->InitialUpdateFrame(NULL, TRUE);
539 CRichEditView *msgView = (CRichEditView *)gra_messageswindow->GetActiveView();
540 gra_editCtrl = &msgView->GetRichEditCtrl();
541
542 gra_messagescurrent = FALSE;
543 return(FALSE);
544 }
545
546 /*
547 * Routine to examine the display devices available and to setup globals that describe
548 * the editing windows and messages window extents. On exit, the globals "gra_screenleft",
549 * "gra_screenright", "gra_screentop", and "gra_screenbottom" will describe the area
550 * for the editing windows and the variables "gra_messagesleft", "gra_messagesright",
551 * "gra_messagestop", and "gra_messagesbottom" will describe the messages window.
552 */
gra_getdevices(void)553 void gra_getdevices(void)
554 {
555 RECT rDesktop;
556
557 /* obtain the current device */
558 gra_app.m_pMainWnd->GetClientRect(&rDesktop);
559 rDesktop.bottom -= 22; /* status bar height? */
560
561 gra_screenleft = 0;
562 gra_screenright = rDesktop.right-rDesktop.left;
563 gra_screentop = 0;
564 gra_screenbottom = rDesktop.bottom-rDesktop.top;
565
566 gra_messagesleft = gra_screenleft + PALETTEWIDTH;
567 gra_messagesright = gra_screenright - PALETTEWIDTH;
568 gra_messagestop = gra_screentop - 2 + (gra_screenbottom-gra_screentop) * 4 / 5;
569 gra_messagesbottom = gra_screenbottom;
570 }
571
572 /******************** TERMINATION ********************/
573
termgraphics(void)574 void termgraphics(void)
575 {
576 REGISTER WINDOWFRAME *wf;
577 REGISTER INTBIG i;
578
579 gra_termgraph();
580
581 while (el_firstwindowframe != NOWINDOWFRAME)
582 {
583 wf = el_firstwindowframe;
584 el_firstwindowframe = el_firstwindowframe->nextwindowframe;
585 delete (CChildFrame *)wf->wndframe;
586 gra_freewindowframe(wf);
587 }
588 if (gra_messageswindow != 0)
589 delete gra_messageswindow;
590
591 if (gra_textbufinited)
592 {
593 efree((CHAR *)gra_textrowstart);
594 efree((CHAR *)gra_textbitmapinfo);
595 DeleteObject(gra_textbitmap);
596 delete gra_texthdc;
597 }
598
599 if (gra_biggeroffbufinited)
600 {
601 efree((CHAR *)gra_biggeroffrowstart);
602 efree((CHAR *)gra_biggeroffbitmapinfo);
603 DeleteObject(gra_biggeroffbitmap);
604 delete gra_biggeroffhdc;
605 }
606
607 if (gra_pulldownmenucount != 0)
608 {
609 efree((CHAR *)gra_pulldownmenus);
610 for(i=0; i<gra_pulldownmenucount; i++) efree(gra_pulldowns[i]);
611 efree((CHAR *)gra_pulldowns);
612 }
613
614 if (gra_fileliststringarray != 0)
615 killstringarray(gra_fileliststringarray);
616 efree((CHAR *)gra_initialdirectory);
617 efree((CHAR *)gra_logfile);
618 efree((CHAR *)gra_logfilesave);
619
620 /* free cached fonts */
621 for(i=0; i<MAXCACHEDFONTS; i++)
622 {
623 if (gra_fontcache[i] != 0) delete gra_fontcache[i];
624 gra_fontcache[i] = 0;
625 }
626 for(i=0; i<FONTHASHSIZE; i++)
627 {
628 if (gra_fonthash[i].font != 0) delete gra_fonthash[i].font;
629 gra_fonthash[i].font = 0;
630 }
631 for(i=0; i<gra_numfaces; i++) efree((CHAR *)gra_facelist[i]);
632 if (gra_numfaces > 0) efree((CHAR *)gra_facelist);
633 }
634
exitprogram(void)635 void exitprogram(void)
636 {
637 exit(0);
638 }
639
640 /******************** WINDOW CONTROL ********************/
641
newwindowframe(BOOLEAN floating,RECTAREA * r)642 WINDOWFRAME *newwindowframe(BOOLEAN floating, RECTAREA *r)
643 {
644 WINDOWFRAME *wf, *oldlisthead;
645
646 /* allocate one */
647 wf = (WINDOWFRAME *)emalloc((sizeof (WINDOWFRAME)), us_tool->cluster);
648 if (wf == 0) return(NOWINDOWFRAME);
649 wf->numvar = 0;
650 wf->rowstart = 0;
651 wf->windindex = gra_windownumberindex++;
652
653 /* insert window-frame in linked list */
654 oldlisthead = el_firstwindowframe;
655 wf->nextwindowframe = el_firstwindowframe;
656 el_firstwindowframe = wf;
657 el_curwindowframe = wf;
658 if (floating) gra_palettewindowframe = wf; else
659 gra_cureditwindowframe = wf;
660
661 /* load an editor window into this frame */
662 wf->pColorPalette = 0;
663 if (gra_buildwindow(wf, floating, r))
664 {
665 efree((CHAR *)wf);
666 el_firstwindowframe = oldlisthead;
667 return(NOWINDOWFRAME);
668 }
669 return(wf);
670 }
671
killwindowframe(WINDOWFRAME * owf)672 void killwindowframe(WINDOWFRAME *owf)
673 {
674 WINDOWFRAME *wf, *lastwf;
675
676 /* kill the actual window */
677 ((CChildFrame *)owf->wndframe)->DestroyWindow();
678
679 /* find this frame in the list */
680 lastwf = NOWINDOWFRAME;
681 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
682 {
683 if (wf == owf) break;
684 lastwf = wf;
685 }
686 if (wf == NOWINDOWFRAME) return;
687 if (lastwf == NOWINDOWFRAME) el_firstwindowframe = owf->nextwindowframe; else
688 lastwf->nextwindowframe = owf->nextwindowframe;
689 if (el_curwindowframe == owf) el_curwindowframe = NOWINDOWFRAME;
690 if (gra_cureditwindowframe == owf) gra_cureditwindowframe = NOWINDOWFRAME;
691
692 gra_freewindowframe(owf);
693 }
694
gra_freewindowframe(WINDOWFRAME * wf)695 void gra_freewindowframe(WINDOWFRAME *wf)
696 {
697 if (wf->rowstart != 0)
698 {
699 efree((CHAR *)wf->rowstart);
700 efree((CHAR *)wf->bminfo);
701 DeleteObject(wf->hBitmap);
702 delete ((CDC *)wf->hDCOff);
703 efree((CHAR *)wf->pColorPalette);
704 }
705 efree((CHAR *)wf);
706 }
707
getwindowframe(BOOLEAN canfloat)708 WINDOWFRAME *getwindowframe(BOOLEAN canfloat)
709 {
710 if (el_curwindowframe != NOWINDOWFRAME)
711 {
712 if (canfloat || !el_curwindowframe->floating)
713 return(el_curwindowframe);
714 }
715 if (gra_cureditwindowframe != NOWINDOWFRAME)
716 return(gra_cureditwindowframe);
717 return(NOWINDOWFRAME);
718 }
719
720 /*
721 * routine to return size of window frame "wf" in "wid" and "hei"
722 */
getwindowframesize(WINDOWFRAME * wf,INTBIG * wid,INTBIG * hei)723 void getwindowframesize(WINDOWFRAME *wf, INTBIG *wid, INTBIG *hei)
724 {
725 *wid = wf->swid;
726 *hei = wf->shei;
727 }
728
729 /*
730 * Routine to get the extent of the messages window.
731 */
getmessagesframeinfo(INTBIG * top,INTBIG * left,INTBIG * bottom,INTBIG * right)732 void getmessagesframeinfo(INTBIG *top, INTBIG *left, INTBIG *bottom, INTBIG *right)
733 {
734 RECT fr;
735 CWnd *parent;
736
737 parent = gra_messageswindow->GetParent();
738 gra_messageswindow->GetWindowRect(&fr);
739 parent->ScreenToClient(&fr);
740 *top = fr.top;
741 *left = fr.left;
742 *bottom = fr.bottom;
743 *right = fr.right;
744 }
745
746 /*
747 * Routine to set the size and position of the messages window.
748 */
setmessagesframeinfo(INTBIG top,INTBIG left,INTBIG bottom,INTBIG right)749 void setmessagesframeinfo(INTBIG top, INTBIG left, INTBIG bottom, INTBIG right)
750 {
751 (void)gra_messageswindow->SetWindowPos(0, left, top, right-left, bottom-top,
752 SWP_NOZORDER);
753 }
754
sizewindowframe(WINDOWFRAME * wf,INTBIG wid,INTBIG hei)755 void sizewindowframe(WINDOWFRAME *wf, INTBIG wid, INTBIG hei)
756 {
757 RECT fr, cr;
758 int framewid, framehei;
759 WINDOWPLACEMENT wp;
760
761 /* if window frame already this size, stop now */
762 if (wid == wf->swid && hei == wf->shei) return;
763
764 /* resize window if needed */
765 ((CChildFrame *)wf->wndframe)->GetClientRect(&cr);
766 if (wid != cr.right-cr.left || hei != cr.bottom-cr.top)
767 {
768 ((CChildFrame *)wf->wndframe)->GetWindowPlacement(&wp);
769 fr = wp.rcNormalPosition;
770
771 framewid = (fr.right - fr.left) - (cr.right - cr.left);
772 framehei = (fr.bottom - fr.top) - (cr.bottom - cr.top);
773
774 /* determine new window size */
775 wid += framewid;
776 hei += framehei;
777
778 /* resize the window */
779 if (((CChildFrame *)wf->wndframe)->SetWindowPos(0, 0, 0, wid, hei, SWP_NOMOVE|SWP_NOZORDER) == 0)
780 {
781 /* failed to resize window */
782 return;
783 }
784 }
785
786 /* rebuild the offscreen windows */
787 if (gra_remakeeditwindow(wf))
788 {
789 // fr.left += 1; fr.right -= 2; fr.bottom -= 2;
790 // SetWindowPos(wf->realwindow, NULL, 0, 0, fr.right-fr.left, fr.bottom-fr.top, SWP_NOZORDER | SWP_NOMOVE);
791 return;
792 }
793 gra_reloadmap();
794 }
795
movewindowframe(WINDOWFRAME * wf,INTBIG left,INTBIG top)796 void movewindowframe(WINDOWFRAME *wf, INTBIG left, INTBIG top)
797 {
798 RECT fr;
799 WINDOWPLACEMENT wp;
800
801 ((CChildFrame *)wf->wndframe)->GetWindowPlacement(&wp);
802 fr = wp.rcNormalPosition;
803
804 /* determine new window location */
805 if (left == fr.left && top == fr.top) return;
806 ((CChildFrame *)wf->wndframe)->SetWindowPos(0, left, top, 0, 0, SWP_NOSIZE|SWP_NOZORDER);
807 }
808
809 /*
810 * Routine to close the messages window if it is in front. Returns true if the
811 * window was closed.
812 */
closefrontmostmessages(void)813 BOOLEAN closefrontmostmessages(void)
814 {
815 if (gra_messagescurrent && gra_messageswindow != 0)
816 {
817 gra_messageswindow->DestroyWindow();
818 gra_messagescurrent = FALSE;
819 gra_messageswindow = 0;
820 return(TRUE);
821 }
822 return(FALSE);
823 }
824
825 /*
826 * Routine to bring window "win" to the front.
827 */
bringwindowtofront(WINDOWFRAME * fwf)828 void bringwindowtofront(WINDOWFRAME *fwf)
829 {
830 REGISTER WINDOWFRAME *wf;
831
832 /* validate the window frame */
833 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
834 if (wf == fwf) break;
835 if (wf == NOWINDOWFRAME)
836 {
837 ttyputmsg(x_("Warning: attempt to manipulate deleted window"));
838 return;
839 }
840
841 /* bring it to the top */
842 ((CChildFrame *)fwf->wndframe)->BringWindowToTop();
843 }
844
845 /*
846 * Routine to organize the windows according to "how" (0: tile horizontally,
847 * 1: tile vertically, 2: cascade).
848 */
adjustwindowframe(INTBIG how)849 void adjustwindowframe(INTBIG how)
850 {
851 RECT r;
852 REGISTER INTBIG children, ret;
853 REGISTER WINDOWFRAME *wf;
854 HWND *kids;
855 CWnd *parent, *compmenu;
856
857 /* figure out how many windows need to be rearranged */
858 children = 0;
859 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
860 if (!wf->floating) children++;
861 if (children <= 0) return;
862
863 /* make a list of windows to rearrange */
864 kids = (HWND *)emalloc(children * (sizeof (HWND)), el_tempcluster);
865 if (kids == 0) return;
866 children = 0;
867 compmenu = NULL;
868 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
869 {
870 if (!wf->floating)
871 {
872 kids[children++] = wf->realwindow;
873 parent = ((CChildFrame *)wf->wndframe)->GetParent();
874 } else
875 {
876 compmenu = (CChildFrame *)wf->wndframe;
877 }
878 }
879
880 /* determine area for windows */
881 parent->GetClientRect(&r);
882 if (compmenu != NULL)
883 {
884 /* remove component menu from area of tiling */
885 gra_removewindowextent(&r, compmenu);
886 }
887 if (gra_messageswindow != 0)
888 {
889 /* remove messages menu from area of tiling */
890 gra_removewindowextent(&r, gra_messageswindow);
891 }
892
893 /* rearrange the windows */
894 switch (how)
895 {
896 case 0: /* tile horizontally */
897 ret = TileWindows(parent->m_hWnd, MDITILE_HORIZONTAL, &r, children, kids);
898 break;
899 case 1: /* tile vertically */
900 ret = TileWindows(parent->m_hWnd, MDITILE_VERTICAL, &r, children, kids);
901 break;
902 case 2: /* cascade */
903 ret = CascadeWindows(parent->m_hWnd, 0, &r, children, kids);
904 break;
905 }
906 if (ret == 0)
907 {
908 ret = GetLastError();
909 ttyputerr(_("Window rearrangement failed (error %ld)"), ret);
910 }
911 efree((CHAR *)kids);
912 }
913
914 /*
915 * Helper routine to remove the location of window "wnd" from the rectangle "r".
916 */
gra_removewindowextent(RECT * r,CWnd * wnd)917 void gra_removewindowextent(RECT *r, CWnd *wnd)
918 {
919 RECT er;
920 CWnd *parent;
921
922 parent = wnd->GetParent();
923 wnd->GetWindowRect(&er);
924 parent->ScreenToClient(&er);
925 if (er.right-er.left > er.bottom-er.top)
926 {
927 /* horizontal occluding window */
928 if (er.bottom - r->top < r->bottom - er.top)
929 {
930 /* occluding window on top */
931 r->top = er.bottom;
932 } else
933 {
934 /* occluding window on bottom */
935 r->bottom = er.top;
936 }
937 } else
938 {
939 /* vertical occluding window */
940 if (er.right - r->left < r->right - er.left)
941 {
942 /* occluding window on left */
943 r->left = er.right;
944 } else
945 {
946 /* occluding window on right */
947 r->right = er.left;
948 }
949 }
950 }
951
952 /*
953 * routine to return the important pieces of information in placing the floating
954 * palette with the fixed menu. The maximum screen size is placed in "wid" and
955 * "hei", and the amount of space that is being left for this palette on the
956 * side of the screen is placed in "palettewidth".
957 */
getpaletteparameters(INTBIG * wid,INTBIG * hei,INTBIG * palettewidth)958 void getpaletteparameters(INTBIG *wid, INTBIG *hei, INTBIG *palettewidth)
959 {
960 RECT r;
961 CMainFrame *wnd;
962
963 wnd = (CMainFrame *)AfxGetMainWnd();
964 wnd->GetClientRect(&r);
965 *hei = r.bottom - r.top - 50;
966 *wid = r.right - r.left;
967 *palettewidth = PALETTEWIDTH;
968 }
969
970 /*
971 * Routine called when the component menu has moved to a different location
972 * on the screen (left/right/top/bottom). Resets local state of the position.
973 */
resetpaletteparameters(void)974 void resetpaletteparameters(void)
975 {
976 }
977
gra_geteditorwindowlocation(void)978 RECT *gra_geteditorwindowlocation(void)
979 {
980 static RECT redit;
981
982 redit.top = gra_newwindowoffset + gra_screentop;
983 redit.bottom = redit.top + (gra_screenbottom-gra_screentop) * 4 / 5 - 1;
984 redit.left = gra_newwindowoffset + gra_screenleft + PALETTEWIDTH;
985 redit.right = redit.left + (gra_screenright-gra_screenleft-PALETTEWIDTH) * 4 / 5;
986
987 /* is the editing window visible on this display? */
988 if ((redit.bottom > gra_screenbottom) || (redit.right > gra_screenright))
989 {
990 gra_newwindowoffset = 0;
991 redit.top = gra_screentop;
992 redit.bottom = redit.top + (gra_screenbottom-gra_screentop) * 3 / 5;
993 redit.left = gra_screenleft + PALETTEWIDTH;
994 redit.right = redit.left + (gra_screenright-gra_screenleft-PALETTEWIDTH) * 4 / 5;
995 }
996 gra_newwindowoffset += 30;
997 return(&redit);
998 }
999
1000 /*
1001 * routine to build a new window frame
1002 */
gra_buildwindow(WINDOWFRAME * wf,BOOLEAN floating,RECTAREA * r)1003 BOOLEAN gra_buildwindow(WINDOWFRAME *wf, BOOLEAN floating, RECTAREA *r)
1004 {
1005 RECT redit;
1006 REGISTER INTBIG i;
1007 REGISTER VARIABLE *varred, *vargreen, *varblue;
1008 CChildFrame *tempFrame;
1009
1010 wf->floating = floating;
1011 wf->wndframe = 0;
1012 if (r != 0)
1013 {
1014 redit.left = r->left; redit.right = r->right;
1015 redit.top = r->top; redit.bottom = r->bottom;
1016 }
1017 if (!floating)
1018 {
1019 /* get editor window location */
1020 if (r == 0) redit = *gra_geteditorwindowlocation();
1021
1022 /* create the editing window */
1023 tempFrame = new CChildFrame();
1024 tempFrame->Create(NULL, x_("Electric"),
1025 WS_CHILD|WS_OVERLAPPEDWINDOW|WS_VISIBLE, redit, NULL, NULL);
1026 wf->wndframe = tempFrame;
1027 wf->realwindow = tempFrame->m_hWnd;
1028 } else
1029 {
1030 /* default palette window location */
1031 if (r == 0)
1032 {
1033 redit.top = gra_screentop + 2;
1034 redit.bottom = (gra_screentop+gra_screenbottom)/2;
1035 redit.left = gra_screenleft + 1;
1036 redit.right = redit.left + PALETTEWIDTH/2;
1037 }
1038
1039 /* create the floating window */
1040 gra_creatingwindow = TRUE;
1041 tempFrame = new CChildFrame();
1042 tempFrame->m_wndFloating = 1;
1043 tempFrame->Create(NULL, x_("Components"),
1044 WS_CHILD|WS_VISIBLE|WS_CAPTION, redit, NULL, NULL);
1045 gra_creatingwindow = FALSE;
1046 wf->wndframe = tempFrame;
1047 wf->realwindow = tempFrame->m_hWnd;
1048 }
1049 if (wf->realwindow == 0) return(TRUE);
1050
1051 wf->hDC = (CDC *)((CChildFrame *)wf->wndframe)->GetDC();
1052 ((CChildFrame *)wf->wndframe)->ReleaseDC((CDC *)wf->hDC);
1053 ((CChildFrame *)wf->wndframe)->ShowWindow(SW_SHOW);
1054 wf->hPalette = 0;
1055
1056 /* load any map the first time to establish the map segment length */
1057 el_maplength = 256;
1058
1059 /* create a color palette for the buffer */
1060 varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
1061 vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
1062 varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
1063 if (varred != NOVARIABLE && vargreen != NOVARIABLE && varblue != NOVARIABLE)
1064 {
1065 wf->pColorPalette = (LOGPALETTE *)emalloc(256 * (sizeof (PALETTEENTRY)) + 2 * (sizeof (WORD)),
1066 db_cluster);
1067 if (wf->pColorPalette == 0) return(TRUE);
1068 wf->pColorPalette->palVersion = 0x300;
1069 wf->pColorPalette->palNumEntries = 256;
1070 for(i=0; i<256; i++)
1071 {
1072 wf->pColorPalette->palPalEntry[i].peRed = (UCHAR1)((INTBIG *)varred->addr)[i];
1073 wf->pColorPalette->palPalEntry[i].peGreen = (UCHAR1)((INTBIG *)vargreen->addr)[i];
1074 wf->pColorPalette->palPalEntry[i].peBlue = (UCHAR1)((INTBIG *)varblue->addr)[i];
1075 wf->pColorPalette->palPalEntry[i].peFlags = 0;
1076 }
1077 wf->pColorPalette->palPalEntry[255].peRed = (UCHAR1)(255-((INTBIG *)varred->addr)[255]);
1078 wf->pColorPalette->palPalEntry[255].peGreen = (UCHAR1)(255-((INTBIG *)vargreen->addr)[255]);
1079 wf->pColorPalette->palPalEntry[255].peBlue = (UCHAR1)(255-((INTBIG *)varblue->addr)[255]);
1080 wf->hPalette = (CPalette *)new CPalette();
1081 ((CPalette *)wf->hPalette)->CreatePalette(wf->pColorPalette);
1082 }
1083
1084 /* build the offscreen buffer for the window */
1085 if (gra_makeeditwindow(wf))
1086 {
1087 /* DestroyWindow(wf->realwindow); */
1088 return(TRUE);
1089 }
1090
1091 return(FALSE);
1092 }
1093
1094 /*
1095 * Routine to redraw editing window "wf" due to a drag or grow
1096 */
gra_redrawdisplay(WINDOWFRAME * wf)1097 void gra_redrawdisplay(WINDOWFRAME *wf)
1098 {
1099 us_beginchanges();
1100 us_drawmenu(-1, wf);
1101 us_endchanges(NOWINDOWPART);
1102 us_state |= HIGHLIGHTSET;
1103 us_showallhighlight();
1104 }
1105
1106 /*
1107 * Routine to allocate the offscreen buffer that corresponds with the window
1108 * "wf->realwindow". The buffer is 8-bits deep and is stored in "wf->window".
1109 * Returns true if memory cannot be allocated.
1110 */
gra_makeeditwindow(WINDOWFRAME * wf)1111 BOOLEAN gra_makeeditwindow(WINDOWFRAME *wf)
1112 {
1113 RECT r;
1114
1115 /* get information about the window that was just created */
1116 ((CChildFrame *)wf->wndframe)->GetClientRect(&r);
1117
1118 /* set frame characteristics */
1119 wf->swid = r.right - r.left;
1120 wf->shei = r.bottom - r.top;
1121 wf->revy = wf->shei - 1;
1122 wf->offscreendirty = FALSE;
1123
1124 /* allocate the main offscreen buffer */
1125 if (gra_buildoffscreenbuffer(wf, wf->swid, wf->shei, (CDC **)&wf->hDCOff, &wf->hBitmap,
1126 &wf->bminfo, &wf->data, &wf->rowstart)) return(TRUE);
1127
1128 /* attach the color palette to drawing window section */
1129 if (wf->hPalette != 0)
1130 {
1131 (void)((CDC *)wf->hDCOff)->SelectPalette((CPalette *)wf->hPalette, TRUE);
1132 (void)((CDC *)wf->hDCOff)->RealizePalette();
1133 }
1134
1135 return(FALSE);
1136 }
1137
1138 /*
1139 * Routine to build an offscreen buffer that is "wid" by "hei" and based on window frame "wf".
1140 * The device context is placed in "hdc", the bitmap in "bitmap", the actual offscreen memory in
1141 * "databuffer" and the row start array in "rowstart". Returns true on error.
1142 */
gra_buildoffscreenbuffer(WINDOWFRAME * wf,INTBIG wid,INTBIG hei,CDC ** hdc,HBITMAP * bitmap,BITMAPINFO ** bmiInfo,UCHAR1 ** databuffer,UCHAR1 *** rowstart)1143 BOOLEAN gra_buildoffscreenbuffer(WINDOWFRAME *wf, INTBIG wid, INTBIG hei, CDC **hdc,
1144 HBITMAP *bitmap, BITMAPINFO **bmiInfo, UCHAR1 **databuffer, UCHAR1 ***rowstart)
1145 {
1146 BITMAPINFOHEADER bmiHeader;
1147 REGISTER VARIABLE *varred, *vargreen, *varblue;
1148 RGBQUAD bmiColors[256];
1149 REGISTER INTBIG i, j;
1150 REGISTER BOOLEAN retval;
1151 REGISTER INTBIG size;
1152 REGISTER UCHAR1 *ptr;
1153
1154 /* make the info structure */
1155 *bmiInfo = (BITMAPINFO *)emalloc(sizeof(bmiHeader) + sizeof(bmiColors), db_cluster);
1156 if (*bmiInfo == 0) return(TRUE);
1157
1158 /* grab the device context */
1159 wf->hDC = (CDC *)((CChildFrame *)wf->wndframe)->GetDC();
1160
1161 /* setup the header block */
1162 bmiHeader.biSize = (DWORD)sizeof(bmiHeader);
1163 bmiHeader.biWidth = (LONG)wid;
1164 bmiHeader.biHeight = (LONG)-hei;
1165 bmiHeader.biPlanes = 1;
1166 bmiHeader.biBitCount = 8;
1167 bmiHeader.biCompression = (DWORD)BI_RGB;
1168 bmiHeader.biSizeImage = 0;
1169 bmiHeader.biXPelsPerMeter = 0;
1170 bmiHeader.biYPelsPerMeter = 0;
1171 bmiHeader.biClrUsed = 256;
1172 bmiHeader.biClrImportant = 0;
1173
1174 /* get color map information */
1175 varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
1176 vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
1177 varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
1178 if (varred != NOVARIABLE && vargreen != NOVARIABLE && varblue != NOVARIABLE)
1179 {
1180 for(i=0; i<255; i++)
1181 {
1182 bmiColors[i].rgbRed = (UCHAR1)((INTBIG *)varred->addr)[i];
1183 bmiColors[i].rgbGreen = (UCHAR1)((INTBIG *)vargreen->addr)[i];
1184 bmiColors[i].rgbBlue = (UCHAR1)((INTBIG *)varblue->addr)[i];
1185 bmiColors[i].rgbReserved = 0;
1186 }
1187 bmiColors[255].rgbRed = (UCHAR1)(255-((INTBIG *)varred->addr)[255]);
1188 bmiColors[255].rgbGreen = (UCHAR1)(255-((INTBIG *)vargreen->addr)[255]);
1189 bmiColors[255].rgbBlue = (UCHAR1)(255-((INTBIG *)varblue->addr)[255]);
1190 }
1191
1192 /* create a device context for this offscreen buffer */
1193 retval = TRUE;
1194 *hdc = new CDC();
1195 BOOL result = (*hdc)->CreateCompatibleDC((CDC *)wf->hDC);
1196 if (result)
1197 {
1198 /* prepare structure describing offscreen buffer */
1199 ptr = (UCHAR1 *)*bmiInfo;
1200 memcpy(ptr, &bmiHeader, sizeof(bmiHeader));
1201 ptr += sizeof(bmiHeader);
1202 memcpy(ptr, &bmiColors, sizeof(bmiColors));
1203
1204 /* allocate offscreen buffer */
1205 *bitmap = CreateDIBSection((*hdc)->m_hDC, *bmiInfo, DIB_RGB_COLORS, (void **)databuffer, NULL, 0);
1206 if (*bitmap != 0)
1207 {
1208 (*hdc)->SelectObject(CBitmap::FromHandle(*bitmap));
1209
1210 /* setup row pointers to offscreen buffer */
1211 *rowstart = (UCHAR1 **)emalloc(hei * (sizeof (UCHAR1 *)), db_cluster);
1212 if (*rowstart == 0) return(TRUE);
1213 size = (wid+3)/4*4;
1214 for(j=0; j<hei; j++) (*rowstart)[j] = (*databuffer) + (size * j);
1215 retval = FALSE;
1216 }
1217 }
1218
1219 /* release the device context */
1220 ((CChildFrame *)wf->wndframe)->ReleaseDC((CDC *)wf->hDC);
1221 return(retval);
1222 }
1223
1224 /*
1225 * Routine to rebuild the offscreen buffer when its size or depth has changed.
1226 * Returns true if the window cannot be rebuilt.
1227 */
gra_remakeeditwindow(WINDOWFRAME * wf)1228 BOOLEAN gra_remakeeditwindow(WINDOWFRAME *wf)
1229 {
1230 /* free memory associated with the frame */
1231 if (wf->rowstart != 0)
1232 {
1233 efree((CHAR *)wf->rowstart);
1234 efree((CHAR *)wf->bminfo);
1235 DeleteObject(wf->hBitmap);
1236 delete (CDC *)wf->hDCOff;
1237 }
1238 wf->rowstart = 0;
1239
1240 return(gra_makeeditwindow(wf));
1241 }
1242
1243 /******************** MISCELLANEOUS EXTERNAL ROUTINES ********************/
1244
1245 /*
1246 * return true if the capabilities in "want" are present
1247 */
graphicshas(INTBIG want)1248 BOOLEAN graphicshas(INTBIG want)
1249 {
1250 /* only 1 status area, shared by each frame */
1251 if ((want&CANSTATUSPERFRAME) != 0) return(FALSE);
1252
1253 /* cannot run subprocesses */
1254 if ((want&CANRUNPROCESS) != 0) return(FALSE);
1255
1256 return(TRUE);
1257 }
1258
1259 /*
1260 * Routine to make sound "sound". If sounds are turned off, no
1261 * sound is made (unless "force" is TRUE)
1262 */
ttybeep(INTBIG sound,BOOLEAN force)1263 void ttybeep(INTBIG sound, BOOLEAN force)
1264 {
1265 void *infstr;
1266 #ifdef USEDIRECTSOUND
1267 static BOOLEAN clicksoundinited = FALSE;
1268 static SOUND *clicksound = 0;
1269 #endif
1270
1271 if ((us_tool->toolstate & TERMBEEP) != 0 || force)
1272 {
1273 switch (sound)
1274 {
1275 case SOUNDBEEP:
1276 MessageBeep(MB_ICONASTERISK);
1277 break;
1278 case SOUNDCLICK:
1279 if ((us_useroptions&NOEXTRASOUND) != 0) break;
1280 #ifdef USEDIRECTSOUND
1281 /* this crashed on some Windows 2000 systems (a laptop) */
1282 /* try "waveOutOpen()" and others... */
1283 if (!clicksoundinited)
1284 {
1285 infstr = initinfstr();
1286 formatinfstr(infstr, x_("%sclick.wav"), el_libdir);
1287 clicksound = gra_initsound(returninfstr(infstr));
1288 clicksoundinited = TRUE;
1289 }
1290 if (clicksound != 0)
1291 gra_playsound(clicksound);
1292 #else
1293 infstr = initinfstr();
1294 formatinfstr(infstr, x_("%sclick.wav"), el_libdir);
1295 PlaySound(returninfstr(infstr), 0, SND_FILENAME);
1296 #endif
1297 break;
1298 }
1299 }
1300 }
1301
1302 #ifdef USEDIRECTSOUND
1303
1304 /*
1305 * Routine to create a SOUND object for the WAVE file "filename". Returns zero on error.
1306 */
gra_initsound(CHAR * filename)1307 SOUND *gra_initsound(CHAR *filename)
1308 {
1309 UINTBIG i, buffersize, len1, len2;
1310 UCHAR1 *data, *ptr1 = NULL, *ptr2 = NULL;
1311 SOUND *sound;
1312 CMainFrame *frame;
1313 WORD extrabytes;
1314 DSBUFFERDESC sbuf;
1315 IDirectSoundBuffer *primarybuffer;
1316 WAVEFORMATEX *waveinfo;
1317 HMMIO mmio;
1318 MMIOINFO mmioinfo;
1319 MMCKINFO mmiobufheader, mmiobuf;
1320 PCMWAVEFORMAT formatchunk;
1321
1322 /* make the object */
1323 sound = (SOUND *)emalloc(sizeof (SOUND), us_tool->cluster);
1324 if (sound == 0) return(0);
1325 sound->gpds = 0;
1326 sound->secondarybuffer = 0;
1327
1328 gra_DSCreate = (PFN_DSCREATE)GetProcAddress(g_hDSoundLib, x_("DirectSoundCreate"));
1329 if (gra_DSCreate == NULL)
1330 {
1331 return(0);
1332 }
1333
1334 /* open the direct sound system */
1335 if (DirectSoundCreate(NULL, &sound->gpds, NULL) != DS_OK) return(0);
1336 frame = (CMainFrame *)AfxGetMainWnd();
1337 if (sound->gpds->SetCooperativeLevel(frame->m_hWnd, DSSCL_PRIORITY) != DS_OK) return(0);
1338
1339 /* make a primary sound buffer */
1340 ZeroMemory(&sbuf, sizeof(DSBUFFERDESC));
1341 sbuf.dwSize = sizeof (DSBUFFERDESC);
1342 sbuf.dwFlags = DSBCAPS_PRIMARYBUFFER;
1343 if (sound->gpds->CreateSoundBuffer(&sbuf, &primarybuffer, NULL) != DS_OK) return(0);
1344
1345 /* get the wave file */
1346 mmio = mmioOpen(filename, NULL, MMIO_ALLOCBUF|MMIO_READ);
1347 if (mmio == NULL) return(0);
1348 if (mmioDescend(mmio, &mmiobufheader, NULL, 0) != 0) return(0);
1349 if (mmiobufheader.ckid != FOURCC_RIFF ||
1350 mmiobufheader.fccType != mmioFOURCC('W', 'A', 'V', 'E')) return(0);
1351
1352 /* find the format chunk of the wave file */
1353 mmiobuf.ckid = mmioFOURCC('f', 'm', 't', ' ');
1354 if (mmioDescend(mmio, &mmiobuf, &mmiobufheader, MMIO_FINDCHUNK) != 0) return(0);
1355 if (mmiobuf.cksize < sizeof(PCMWAVEFORMAT)) return(0);
1356 if (mmioRead(mmio, (UCHAR1 *)&formatchunk, sizeof(formatchunk)) != sizeof(formatchunk))
1357 return(0);
1358
1359 /* allocate the waveformat structure */
1360 extrabytes = 0;
1361 if (formatchunk.wf.wFormatTag != WAVE_FORMAT_PCM)
1362 {
1363 if (mmioRead(mmio, (UCHAR1 *)&extrabytes, sizeof(extrabytes)) != sizeof(extrabytes))
1364 return(0);
1365 }
1366 waveinfo = (WAVEFORMATEX *)emalloc(sizeof(WAVEFORMATEX)+extrabytes, db_cluster);
1367 if (waveinfo == 0) return(0);
1368
1369 /* load the waveformat structure */
1370 memcpy(waveinfo, &formatchunk, sizeof(formatchunk));
1371 waveinfo->cbSize = extrabytes;
1372 if (extrabytes != 0)
1373 {
1374 if (mmioRead(mmio, (UCHAR1 *)(((UCHAR1 *)&waveinfo->cbSize)+sizeof(extrabytes)),
1375 extrabytes) != extrabytes) return(0);
1376 }
1377
1378 /* exit the format chunk of the wave file */
1379 if (mmioAscend(mmio, &mmiobuf, 0) != 0) return(0);
1380
1381 /* find the data chunk of the wave file */
1382 (void)mmioSeek(mmio, mmiobufheader.dwDataOffset + sizeof(FOURCC), SEEK_SET);
1383 mmiobuf.ckid = mmioFOURCC('d', 'a', 't', 'a');
1384 if (mmioDescend(mmio, &mmiobuf, &mmiobufheader, MMIO_FINDCHUNK) != 0) return(0);
1385
1386 /* allocate space for the data */
1387 data = (UCHAR1 *)emalloc(mmiobuf.cksize, db_cluster);
1388 if (data == 0) return(0);
1389
1390 /* get the data from the wave file */
1391 if (mmioGetInfo(mmio, &mmioinfo, 0) != 0) return(0);
1392 buffersize = mmiobuf.cksize;
1393 if (buffersize > mmiobuf.cksize) buffersize = mmiobuf.cksize;
1394 mmiobuf.cksize -= buffersize;
1395
1396 /* copy the data */
1397 for (i = 0; i < buffersize; i++)
1398 {
1399 if (mmioinfo.pchNext == mmioinfo.pchEndRead)
1400 {
1401 if (mmioAdvance(mmio, &mmioinfo, MMIO_READ) != 0) return(0);
1402 if (mmioinfo.pchNext == mmioinfo.pchEndRead) return(0);
1403 }
1404 data[i] = *mmioinfo.pchNext++;
1405 }
1406
1407 /* clean up the wave file */
1408 if (mmioSetInfo(mmio, &mmioinfo, 0) != 0) return(0);
1409 mmioClose(mmio, 0);
1410
1411 /* create a sound buffer */
1412 ZeroMemory(&sbuf, sizeof(DSBUFFERDESC));
1413 sbuf.dwSize = sizeof (DSBUFFERDESC);
1414 sbuf.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_STATIC;
1415 sbuf.dwBufferBytes = buffersize;
1416 sbuf.lpwfxFormat = waveinfo;
1417 if (sound->gpds->CreateSoundBuffer(&sbuf, &sound->secondarybuffer, NULL) != 0) return(0);
1418
1419 /* load the data into the buffer */
1420 if (sound->secondarybuffer->Lock(0, buffersize, (void **)&ptr1, &len1,
1421 (void **)&ptr2, &len2, 0L) != 0) return(0);
1422 CopyMemory(ptr1, data, buffersize);
1423 if (sound->secondarybuffer->Unlock(ptr1, buffersize, ptr2, 0) != 0) return(0);
1424 return(sound);
1425 }
1426
1427 /*
1428 * Routine to play sound "sound" and only return when it is finished playing.
1429 */
gra_playsound(SOUND * sound)1430 void gra_playsound(SOUND *sound)
1431 {
1432 UINTBIG status;
1433
1434 if (sound->secondarybuffer == 0) return;
1435
1436 /* play the sound */
1437 sound->secondarybuffer->SetCurrentPosition(0);
1438 if (sound->secondarybuffer->Play(0, 0, 0) != DS_OK) return;
1439
1440 /* query the sound */
1441 for(;;)
1442 {
1443 if (sound->secondarybuffer->GetStatus(&status) != DS_OK) return;
1444 if ((status&DSBSTATUS_PLAYING) == 0) break;
1445 }
1446 }
1447 #endif
1448
1449 extern "C" {
1450 DIALOGITEM db_severeerrordialogitems[] =
1451 {
1452 /* 1 */ {0, {80,8,104,72}, BUTTON, N_("Exit")},
1453 /* 2 */ {0, {80,96,104,160}, BUTTON, N_("Save")},
1454 /* 3 */ {0, {80,184,104,256}, BUTTON, N_("Continue")},
1455 /* 4 */ {0, {8,8,72,256}, MESSAGE, x_("")}
1456 };
1457 DIALOG db_severeerrordialog = {{50,75,163,341}, N_("Fatal Error"), 0, 4, db_severeerrordialogitems, 0, 0};
1458 };
1459
1460 #define DSER_EXIT 1 /* Exit (button) */
1461 #define DSER_SAVE 2 /* Save (button) */
1462 #define DSER_CONTINUE 3 /* Continue (button) */
1463 #define DSER_ERRMSG 4 /* Error message (stat text) */
1464
error(CHAR * s,...)1465 void error(CHAR *s, ...)
1466 {
1467 va_list ap;
1468 CHAR line[500];
1469 REGISTER INTBIG itemHit, *curstate;
1470 REGISTER INTBIG retval;
1471 REGISTER LIBRARY *lib;
1472 REGISTER void *dia;
1473
1474 /* disable any session logging */
1475 if (us_logplay != NULL)
1476 {
1477 xclose(us_logplay);
1478 us_logplay = NULL;
1479 }
1480
1481 /* build the error message */
1482 var_start(ap, s);
1483 evsnprintf(line, 500, s, ap);
1484 va_end(ap);
1485
1486 /* display the severe error dialog box */
1487 dia = DiaInitDialog(&db_severeerrordialog);
1488 if (dia) return;
1489
1490 /* load the message */
1491 DiaSetText(dia, DSER_ERRMSG, line);
1492
1493 /* loop until done */
1494 for(;;)
1495 {
1496 itemHit = DiaNextHit(dia);
1497 if (itemHit == DSER_EXIT) exitprogram();
1498 if (itemHit == DSER_SAVE)
1499 {
1500 /* save libraries: make sure that backups are kept */
1501 curstate = io_getstatebits();
1502 if ((curstate[0]&BINOUTBACKUP) == BINOUTNOBACK)
1503 {
1504 curstate[0] |= BINOUTONEBACK;
1505 io_setstatebits(curstate);
1506 }
1507
1508 /* save each modified library */
1509 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1510 {
1511 if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
1512 if ((lib->userbits&(LIBCHANGEDMAJOR|LIBCHANGEDMINOR)) == 0) continue;
1513
1514 /* save the library in binary format */
1515 makeoptionstemporary(lib);
1516 retval = asktool(io_tool, x_("write"), (INTBIG)lib, (INTBIG)x_("binary"));
1517 restoreoptionstate(lib);
1518 if (retval != 0) return;
1519 }
1520 }
1521 if (itemHit == DSER_CONTINUE) break;
1522 }
1523 DiaDoneDialog(dia);
1524 }
1525
1526 /*
1527 * Routine to get the environment variable "name" and return its value.
1528 */
egetenv(CHAR * name)1529 CHAR *egetenv(CHAR *name)
1530 {
1531 return(0);
1532 }
1533
1534 /*
1535 * Routine to get the current language that Electric speaks.
1536 */
elanguage(void)1537 CHAR *elanguage(void)
1538 {
1539 #ifdef INTERNATIONAL
1540 return(x_("fr"));
1541 #else
1542 return(x_("en"));
1543 #endif
1544 }
1545
1546 /*
1547 * Routine to fork a new process. Returns the child process number if this is the
1548 * parent thread. Returns 0 if this is the child thread.
1549 * Returns 1 if forking is not possible (process 1 is INIT on UNIX and can't possibly
1550 * be assigned to a normal process).
1551 */
efork(void)1552 INTBIG efork(void)
1553 {
1554 return(1);
1555 }
1556
1557 /*
1558 * Routine to run the string "command" in a shell.
1559 * Returns nonzero if the command cannot be run.
1560 */
esystem(CHAR * command)1561 INTBIG esystem(CHAR *command)
1562 {
1563 return(1);
1564 }
1565
1566 /*
1567 * Routine to execute the program "program" with the arguments "args"
1568 */
eexec(CHAR * program,CHAR * args[])1569 void eexec(CHAR *program, CHAR *args[])
1570 {
1571 }
1572
1573 /*
1574 * routine to send signal "signal" to process "process".
1575 */
ekill(INTBIG process)1576 INTBIG ekill(INTBIG process)
1577 {
1578 return(1);
1579 }
1580
1581 /*
1582 * routine to wait for the completion of child process "process"
1583 */
ewait(INTBIG process)1584 void ewait(INTBIG process)
1585 {
1586 }
1587
1588 /*
1589 * Routine to return the number of processors on this machine.
1590 */
enumprocessors(void)1591 INTBIG enumprocessors(void)
1592 {
1593 SYSTEM_INFO si;
1594
1595 GetSystemInfo(&si);
1596 return(si.dwNumberOfProcessors);
1597 }
1598
1599 #define MFCTHREADS 1 /* comment out to use WIN32 versions */
1600
1601 #define MUTEXCLASS CSemaphore
1602 //#define MUTEXCLASS CCriticalSection
1603 //#define MUTEXCLASS CSingleLock
1604
1605 /*
1606 * Routine to create a new thread that calls "function" with "argument".
1607 */
enewthread(void * (* function)(void *),void * argument)1608 void enewthread(void* (*function)(void*), void *argument)
1609 {
1610 #ifdef MFCTHREADS
1611 CWinThread *thread = AfxBeginThread((AFX_THREADPROC)function, argument);
1612 #else
1613 UINTBIG threadid;
1614
1615 if (CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)function, argument, 0, &threadid) == 0)
1616 {
1617 /* function failed */
1618 ttyputmsg(x_("Failed to create a thread"));
1619 }
1620 #endif
1621 }
1622
1623 /*
1624 * Routine that creates a mutual-exclusion object and returns it.
1625 */
emakemutex(void)1626 void *emakemutex(void)
1627 {
1628 #ifdef MFCTHREADS
1629 MUTEXCLASS *mutex;
1630
1631 mutex = new MUTEXCLASS();
1632 mutex->Unlock();
1633 return((void *)mutex);
1634 #else
1635 HANDLE mutex;
1636 static INTBIG mutexindex = 1;
1637 CHAR mutexname[50];
1638
1639 esnprintf(mutexname, 50, x_("mutex%ld"), mutexindex++);
1640 mutex = ::CreateMutex(NULL, FALSE, mutexname);
1641 return((void *)mutex);
1642 #endif
1643 }
1644
1645 /*
1646 * Routine that locks mutual-exclusion object "vmutex". If the object is already
1647 * locked, the routine blocks until it is unlocked.
1648 */
emutexlock(void * vmutex)1649 void emutexlock(void *vmutex)
1650 {
1651 #ifdef MFCTHREADS
1652 MUTEXCLASS *mutex;
1653
1654 mutex = (MUTEXCLASS *)vmutex;
1655 mutex->Lock();
1656 #else
1657 HANDLE mutex;
1658 int result;
1659
1660 mutex = (HANDLE)vmutex;
1661 result = WaitForSingleObject(mutex, INFINITE);
1662 if (result != WAIT_OBJECT_0)
1663 ttyputerr(x_("Wait on mutex %ld returned %ld"), mutex, result);
1664 #endif
1665 }
1666
1667 /*
1668 * Routine that unlocks mutual-exclusion object "vmutex".
1669 */
emutexunlock(void * vmutex)1670 void emutexunlock(void *vmutex)
1671 {
1672 #ifdef MFCTHREADS
1673 MUTEXCLASS *mutex;
1674
1675 mutex = (MUTEXCLASS *)vmutex;
1676 mutex->Unlock();
1677 #else
1678 HANDLE mutex;
1679
1680 mutex = (HANDLE)vmutex;
1681 ReleaseMutex(mutex);
1682 #endif
1683 }
1684
1685 /*
1686 * Routine to determine the list of printers and return it.
1687 * The list terminates with a zero.
1688 */
eprinterlist(void)1689 CHAR **eprinterlist(void)
1690 {
1691 static CHAR *lplist[1];
1692
1693 lplist[0] = 0;
1694 return(lplist);
1695 }
1696
1697 /*
1698 * Routine to establish the library directories from the environment.
1699 * The registry entry for this is stored in:
1700 * HKEY_LOCAL_MACHINE\Software\Static Free Software\Electric\ELECTRIC_LIBDIR
1701 * If this directory is valid (i.e. has the file "cadrc" in it) then it is
1702 * used. If the directory is not valid, the registry entry is removed.
1703 */
setupenvironment(void)1704 void setupenvironment(void)
1705 {
1706 CHAR tmp[256], subkey[256], value[256], elibname[256], testfile[256], applocation[256];
1707 REGISTER INTBIG doupdate;
1708 FILE *io;
1709
1710 /* default library location */
1711 (void)allocstring(&el_libdir, LIBDIR, db_cluster);
1712
1713 /* see if the registry has an overriding library directory path */
1714 estrcpy(subkey, x_("Software\\Static Free Software\\Electric"));
1715 estrcpy(value, x_("ELECTRIC_LIBDIR"));
1716 if (gra_getregistry(HKEY_LOCAL_MACHINE, subkey, value, tmp) == 0)
1717 {
1718 if (tmp[0] != 0)
1719 {
1720 estrcpy(testfile, tmp);
1721 estrcat(testfile, x_("cadrc"));
1722 io = efopen(testfile, x_("r"));
1723 if (io != 0)
1724 {
1725 /* valid "cadrc" file in directory, use it */
1726 fclose(io);
1727 (void)reallocstring(&el_libdir, tmp, db_cluster);
1728 } else
1729 {
1730 /* key points to bogus directory: delete it */
1731 (void)gra_setregistry(HKEY_LOCAL_MACHINE, subkey, value, x_(""));
1732 }
1733 }
1734 }
1735
1736 /*
1737 * linking an extension to an application is described in the article:
1738 * "Fusing Your Applications to the System Through the Windows95 Shell"
1739 */
1740
1741 /* see if the ".elib" extension is defined */
1742 estrcpy(subkey, x_(".elib"));
1743 if (gra_getregistry(HKEY_CLASSES_ROOT, subkey, x_(""), elibname) == 0)
1744 {
1745 /* determine location of application */
1746 GetModuleFileName(0, applocation, 256);
1747
1748 /* see what the registry thinks is the application location */
1749 doupdate = 1;
1750 esnprintf(subkey, 256, x_("%s\\shell\\open\\command\\"), elibname);
1751 if (gra_getregistry(HKEY_CLASSES_ROOT, subkey, x_(""), tmp) == 0)
1752 {
1753 if (estrcmp(applocation, tmp) == 0) doupdate = 0;
1754 }
1755
1756 /* if the application location must be updated, do it now */
1757 if (doupdate != 0)
1758 {
1759 if (gra_setregistry(HKEY_CLASSES_ROOT, subkey, x_(""), applocation) != 0)
1760 ttyputerr(_("Error setting key"));
1761 }
1762 }
1763
1764 /* set the machine name */
1765 nextchangequiet();
1766 (void)setval((INTBIG)us_tool, VTOOL, x_("USER_machine"),
1767 (INTBIG)x_("Windows"), VSTRING|VDONTSAVE);
1768 }
1769
1770 /*
1771 * Routine to change the global "el_libdir" as well as the registry.
1772 */
setlibdir(CHAR * libdir)1773 void setlibdir(CHAR *libdir)
1774 {
1775 CHAR *pp, tmp[256], subkey[256], value[256];
1776 BOOLEAN doupdate;
1777 REGISTER void *infstr;
1778
1779 /* make sure UNIX '/' isn't in use */
1780 for(pp = libdir; *pp != 0; pp++)
1781 if (*pp == '/') *pp = DIRSEP;
1782
1783 infstr = initinfstr();
1784 libdir = efullpath(tmp, libdir, 256);
1785 addstringtoinfstr(infstr, libdir);
1786 if (libdir[estrlen(libdir)-1] != DIRSEP) addtoinfstr(infstr, DIRSEP);
1787 (void)reallocstring(&el_libdir, returninfstr(infstr), db_cluster);
1788
1789 /* see what the current registry key says */
1790 doupdate = TRUE;
1791 estrcpy(subkey, x_("Software\\Static Free Software\\Electric"));
1792 estrcpy(value, x_("ELECTRIC_LIBDIR"));
1793 if (gra_getregistry(HKEY_LOCAL_MACHINE, subkey, value, tmp) == 0)
1794 {
1795 /* if the current registry entry is correct, do not update */
1796 if (estrcmp(el_libdir, tmp) == 0) doupdate = FALSE;
1797 }
1798
1799 /* if the key must be updated, do it now */
1800 if (doupdate)
1801 {
1802 if (gra_setregistry(HKEY_LOCAL_MACHINE, subkey, value, el_libdir) != 0)
1803 ttyputerr(_("Error setting key"));
1804 }
1805 }
1806
1807 /*
1808 * Routine to querry key "key", subkey "subkey", value "value" of the registry and
1809 * return the value found in "result". Returns zero if successful, nonzero if the value
1810 * was not found in the registry.
1811 */
gra_getregistry(HKEY key,CHAR * subkey,CHAR * value,CHAR * result)1812 INTBIG gra_getregistry(HKEY key, CHAR *subkey, CHAR *value, CHAR *result)
1813 {
1814 HKEY hKey;
1815 DWORD size;
1816 INTBIG retval, err;
1817
1818 if (RegOpenKeyEx(key, subkey, 0, KEY_READ, &hKey) != ERROR_SUCCESS) return(1);
1819 size = 256;
1820 err = RegQueryValueEx(hKey, value, NULL, NULL, (UCHAR1 *)result, &size);
1821 if (err == ERROR_SUCCESS) retval = 0; else
1822 retval = 1;
1823 RegCloseKey(hKey);
1824 return(retval);
1825 }
1826
1827 /*
1828 * Routine to set key "key", subkey "subkey", value "value" of the registry to
1829 * the string in "newstring". Returns zero if successful, nonzero if the registry
1830 * was not changed.
1831 */
gra_setregistry(HKEY key,CHAR * subkey,CHAR * value,CHAR * newstring)1832 INTBIG gra_setregistry(HKEY key, CHAR *subkey, CHAR *value, CHAR *newstring)
1833 {
1834 HKEY hKey;
1835 INTBIG err;
1836
1837 if (RegCreateKey(key, subkey, &hKey) != ERROR_SUCCESS) return(1);
1838 err = RegSetValueEx(hKey, value, 0, REG_SZ, (UCHAR1 *)newstring,
1839 estrlen(newstring)*SIZEOFCHAR);
1840 RegCloseKey(hKey);
1841 if (err != 0) return(1);
1842 return(0);
1843 }
1844
1845 /*
1846 * Routine to force the module to return with some event so that the user interface will
1847 * relinquish control and let a slice happen.
1848 */
forceslice(void)1849 void forceslice(void)
1850 {
1851 }
1852
1853 /******************** MESSAGES WINDOW ROUTINES ********************/
1854
1855 /*
1856 * Routine to put the string "s" into the messages window.
1857 * Pops up the messages window if "important" is true.
1858 */
putmessagesstring(CHAR * s,BOOLEAN important)1859 void putmessagesstring(CHAR *s, BOOLEAN important)
1860 {
1861 REGISTER INTBIG line, pos1, pos2;
1862
1863 /* ensure window exists, is noniconic, and is on top */
1864 if (important)
1865 {
1866 if (gra_messageswindow == 0)
1867 (void)gra_makemessageswindow();
1868 if (gra_messageswindow->IsIconic())
1869 gra_messageswindow->ShowWindow(SW_RESTORE);
1870 if (gra_messagesnotvisible())
1871 gra_messageswindow->BringWindowToTop();
1872 }
1873
1874 /* get next line and load it up */
1875 if (gra_messageswindow == 0) return;
1876
1877 /* if messages buffer is running out of space, clear from the top */
1878 line = gra_editCtrl->GetLineCount();
1879 pos1 = gra_editCtrl->LineIndex(line-1);
1880 pos2 = gra_editCtrl->GetLimitText();
1881 if (pos2-pos1 < 2000)
1882 {
1883 gra_editCtrl->SetSel(0, 2000);
1884 gra_editCtrl->ReplaceSel(x_("..."));
1885 }
1886
1887 gra_tomessagesbottom();
1888 gra_editCtrl->ReplaceSel(s);
1889 gra_editCtrl->ReplaceSel(x_("\r\n"));
1890 }
1891
gra_tomessagesbottom(void)1892 void gra_tomessagesbottom(void)
1893 {
1894 int pos;
1895
1896 pos = gra_editCtrl->GetLimitText();
1897 gra_editCtrl->SetSel(pos, pos);
1898 }
1899
1900 /*
1901 * Routine to return the name of the key that ends a session from the messages window.
1902 */
getmessageseofkey(void)1903 CHAR *getmessageseofkey(void)
1904 {
1905 return(_("ESC"));
1906 }
1907
1908 /*
1909 * Routine to get a string from the scrolling messages window. Returns zero if end-of-file
1910 * (^D) is typed.
1911 */
getmessagesstring(CHAR * prompt)1912 CHAR *getmessagesstring(CHAR *prompt)
1913 {
1914 long line, pos, startpos, startposonline, charcount, pos2, i;
1915 CHAR cTmpCh, *pt, ch[2];
1916 static CHAR typedline[MAXTYPEDLINE];
1917
1918 /* ensure window exists, is noniconic, and is on top */
1919 if (gra_messageswindow == 0)
1920 (void)gra_makemessageswindow();
1921 if (gra_messageswindow->IsIconic())
1922 gra_messageswindow->ShowWindow(SW_RESTORE);
1923 if (gra_messagesnotvisible())
1924 gra_messageswindow->BringWindowToTop();
1925 flushscreen();
1926
1927 /* advance to next line and allocate maximum number of characters */
1928 gra_messageswindow->ActivateFrame();
1929 gra_tomessagesbottom();
1930 gra_editCtrl->ReplaceSel(prompt);
1931 gra_editCtrl->GetSel(startpos, pos2);
1932 line = gra_editCtrl->GetLineCount() - 1;
1933 startposonline = estrlen(prompt);
1934 for(;;)
1935 {
1936 /* continue to force the messages window up */
1937 if (gra_messageswindow == 0)
1938 (void)gra_makemessageswindow();
1939 if (gra_messageswindow->IsIconic())
1940 gra_messageswindow->ShowWindow(SW_RESTORE);
1941
1942 gra_nextevent();
1943 if (gra_inputstate == NOEVENT) continue;
1944 if ((gra_inputstate&ISKEYSTROKE) != 0 && gra_inputspecial == 0)
1945 {
1946 cTmpCh = (CHAR)(gra_inputstate & CHARREAD);
1947 if (cTmpCh == CTRLDKEY || cTmpCh == ESCKEY)
1948 {
1949 /* ESC (eof) */
1950 gra_editCtrl->GetSel(pos, pos2);
1951 if (startpos == pos)
1952 {
1953 gra_editCtrl->ReplaceSel(x_("\r\n"));
1954 gra_inputstate = NOEVENT;
1955 return(NULL);
1956 }
1957 cTmpCh = 0x0D;
1958 }
1959 if (cTmpCh == BACKSPACEKEY)
1960 {
1961 /* backspace */
1962 gra_editCtrl->GetSel(pos, pos2);
1963 if (pos <= startpos) continue;
1964 gra_editCtrl->SetSel(pos-1, pos);
1965 ch[0] = 0;
1966 gra_editCtrl->ReplaceSel(ch);
1967 continue;
1968 }
1969 if (cTmpCh == 0x0A || cTmpCh == 0x0D)
1970 {
1971 /* end of line */
1972 charcount = gra_editCtrl->GetLine(line, typedline, MAXTYPEDLINE);
1973 typedline[charcount] = 0;
1974 for(i=startposonline; typedline[i] != 0; i++)
1975 if (typedline[i] == '\r' || typedline[i] == '\n')
1976 {
1977 typedline[i] = 0;
1978 break;
1979 }
1980 pt = &typedline[startposonline];
1981 gra_inputstate = NOEVENT;
1982 return(pt);
1983 }
1984 gra_tomessagesbottom();
1985 ch[0] = cTmpCh; ch[1] = 0;
1986 gra_editCtrl->ReplaceSel(ch);
1987 }
1988 gra_inputstate = NOEVENT;
1989 }
1990 }
1991
1992 /*
1993 * routine to select fonts in the messages window
1994 */
setmessagesfont(void)1995 void setmessagesfont(void)
1996 {
1997 CFont *fnt;
1998 CFontDialog dlg;
1999 LOGFONT lf;
2000
2001 if (dlg.DoModal() == IDOK)
2002 {
2003 /* Retrieve the dialog data */
2004 dlg.GetCurrentFont(&lf);
2005 fnt = new CFont();
2006 fnt->CreateFontIndirect(&lf);
2007 gra_editCtrl->SetFont(fnt);
2008 }
2009 }
2010
2011 /*
2012 * routine to cut text from the messages window if it is current. Returns true
2013 * if sucessful.
2014 */
cutfrommessages(void)2015 BOOLEAN cutfrommessages(void)
2016 {
2017 if (gra_messageswindow != 0)
2018 {
2019 if (!gra_messageswindow->IsIconic())
2020 {
2021 CMDIFrameWnd *parent = gra_messageswindow->GetMDIFrame();
2022 CWnd *wnd = parent->MDIGetActive();
2023 if (gra_messageswindow == wnd)
2024 {
2025 /* do the cut */
2026 gra_editCtrl->Cut();
2027 return(TRUE);
2028 }
2029 }
2030 }
2031 if (el_curwindowpart == NOWINDOWPART) return(FALSE);
2032 if ((el_curwindowpart->state&WINDOWTYPE) == DISPWINDOW)
2033 gra_copyhighlightedtoclipboard();
2034 return(FALSE);
2035 }
2036
2037 /*
2038 * routine to copy text from the messages window if it is current. Returns true
2039 * if sucessful.
2040 */
copyfrommessages(void)2041 BOOLEAN copyfrommessages(void)
2042 {
2043 if (gra_messageswindow != 0)
2044 {
2045 if (!gra_messageswindow->IsIconic())
2046 {
2047 CMDIFrameWnd *parent = gra_messageswindow->GetMDIFrame();
2048 CWnd *wnd = parent->MDIGetActive();
2049 if (gra_messageswindow == wnd)
2050 {
2051 /* do the copy */
2052 gra_editCtrl->Copy();
2053 return(TRUE);
2054 }
2055 }
2056 }
2057 if (el_curwindowpart == NOWINDOWPART) return(FALSE);
2058 if ((el_curwindowpart->state&WINDOWTYPE) == DISPWINDOW)
2059 gra_copyhighlightedtoclipboard();
2060 return(FALSE);
2061 }
2062
2063 /*
2064 * Routine to build the bigger offscreen buffer for copying at higher resolution.
2065 */
gra_getbiggeroffscreenbuffer(WINDOWFRAME * wf,INTBIG wid,INTBIG hei)2066 BOOLEAN gra_getbiggeroffscreenbuffer(WINDOWFRAME *wf, INTBIG wid, INTBIG hei)
2067 {
2068 /* see if text buffer needs to be (re)initialized */
2069 if (gra_biggeroffbufinited)
2070 {
2071 if (wid > gra_biggeroffbufwid || hei > gra_biggeroffbufhei)
2072 {
2073 efree((CHAR *)gra_biggeroffrowstart);
2074 efree((CHAR *)gra_biggeroffbitmapinfo);
2075 DeleteObject(gra_biggeroffbitmap);
2076 delete gra_biggeroffhdc;
2077 gra_biggeroffbufinited = FALSE;
2078 }
2079 }
2080
2081 /* allocate text buffer if needed */
2082 if (!gra_biggeroffbufinited)
2083 {
2084 if (gra_buildoffscreenbuffer(wf, wid, hei, &gra_biggeroffhdc, &gra_biggeroffbitmap,
2085 &gra_biggeroffbitmapinfo, &gra_biggeroffdatabuffer, &gra_biggeroffrowstart)) return(TRUE);
2086
2087 /* remember information about text buffer */
2088 gra_biggeroffbufwid = wid; gra_biggeroffbufhei = hei;
2089 gra_biggeroffbufinited = TRUE;
2090 }
2091 return(FALSE);
2092 }
2093
2094 /*
2095 * routine to copy the highlighted graphics to the clipboard.
2096 */
gra_copyhighlightedtoclipboard(void)2097 void gra_copyhighlightedtoclipboard(void)
2098 {
2099 REGISTER INTBIG wid, hei, *dest, x, y, r, g, b, index, hsize, dsize, rowbytes,
2100 *redmap, *greenmap, *bluemap, savewid, savehei, bigwid, bighei, resfactor;
2101 INTBIG lx, hx, ly, hy;
2102 REGISTER UCHAR1 *source, **saverowstart, *savedata;
2103 REGISTER UCHAR1 *data, *store;
2104 REGISTER WINDOWFRAME *wf;
2105 REGISTER VARIABLE *varred, *vargreen, *varblue, *var;
2106 HGLOBAL h;
2107 BITMAPINFOHEADER *bmiHeader;
2108 BITMAPINFO *savebmiinfo;
2109 HBITMAP savebitmap;
2110 BOOLEAN savedirty;
2111 CDC *saveoff;
2112
2113 /* determine the size of the area to copy */
2114 if (us_getareabounds(&lx, &hx, &ly, &hy) == NONODEPROTO) return;
2115
2116 /* get the copy resolution scale factor */
2117 var = getval((INTBIG)io_tool, VTOOL, VINTEGER, x_("IO_print_resolution_scale"));
2118 if (var == NOVARIABLE) resfactor = 1; else
2119 resfactor = var->addr;
2120
2121 /* make the window bigger */
2122 wf = el_curwindowpart->frame;
2123 bigwid = wf->swid * resfactor;
2124 bighei = wf->shei * resfactor;
2125 if (gra_getbiggeroffscreenbuffer(wf, bigwid, bighei)) return;
2126 saveoff = (CDC *)wf->hDCOff; wf->hDCOff = (void *)gra_biggeroffhdc;
2127 savebitmap = wf->hBitmap; wf->hBitmap = gra_biggeroffbitmap;
2128 savebmiinfo = wf->bminfo; wf->bminfo = gra_biggeroffbitmapinfo;
2129 savedata = wf->data; wf->data = gra_biggeroffdatabuffer;
2130 saverowstart = wf->rowstart; wf->rowstart = gra_biggeroffrowstart;
2131 savewid = wf->swid; wf->swid = bigwid;
2132 savehei = wf->shei; wf->shei = bighei;
2133 savedirty = wf->offscreendirty; wf->offscreendirty = FALSE;
2134 wf->revy = wf->shei - 1;
2135 if (wf->hPalette != 0)
2136 {
2137 (void)((CDC *)wf->hDCOff)->SelectPalette((CPalette *)wf->hPalette, TRUE);
2138 (void)((CDC *)wf->hDCOff)->RealizePalette();
2139 }
2140 el_curwindowpart->uselx *= resfactor;
2141 el_curwindowpart->usehx *= resfactor;
2142 el_curwindowpart->usely *= resfactor;
2143 el_curwindowpart->usehy *= resfactor;
2144 computewindowscale(el_curwindowpart);
2145
2146 /* redraw the window in the larger buffer */
2147 gra_noflush = TRUE;
2148 us_redisplaynow(el_curwindowpart, TRUE);
2149 us_endchanges(NOWINDOWPART);
2150 gra_noflush = FALSE;
2151
2152 /* determine the size of the part to copy */
2153 (void)us_makescreen(&lx, &ly, &hx, &hy, el_curwindowpart);
2154
2155 /* restore the normal state of the window */
2156 wf->hDCOff = saveoff;
2157 wf->hBitmap = savebitmap;
2158 wf->bminfo = savebmiinfo;
2159 wf->data = savedata;
2160 wf->rowstart = saverowstart;
2161 wf->swid = savewid;
2162 wf->shei = savehei;
2163 wf->revy = wf->shei - 1;
2164 wf->offscreendirty = savedirty;
2165 if (wf->hPalette != 0)
2166 {
2167 (void)((CDC *)wf->hDCOff)->SelectPalette((CPalette *)wf->hPalette, TRUE);
2168 (void)((CDC *)wf->hDCOff)->RealizePalette();
2169 }
2170 el_curwindowpart->uselx /= resfactor;
2171 el_curwindowpart->usehx /= resfactor;
2172 el_curwindowpart->usely /= resfactor;
2173 el_curwindowpart->usehy /= resfactor;
2174 computewindowscale(el_curwindowpart);
2175
2176 /* get information about the area to be copied */
2177 wid = hx - lx + 1;
2178 hei = hy - ly + 1;
2179 rowbytes = wid*4;
2180 dsize = rowbytes * hei;
2181
2182 /* get colormap information */
2183 varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
2184 vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
2185 varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
2186 if (varred == NOVARIABLE || vargreen == NOVARIABLE || varblue == NOVARIABLE) return;
2187 redmap = (INTBIG *)varred->addr;
2188 greenmap = (INTBIG *)vargreen->addr;
2189 bluemap = (INTBIG *)varblue->addr;
2190
2191 hsize = sizeof (BITMAPINFOHEADER);
2192 hsize += 12; /* why is this needed? */
2193 h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE|GMEM_ZEROINIT, hsize + dsize);
2194 if (h == 0) return;
2195 store = *((UCHAR1 **)h);
2196 bmiHeader = (BITMAPINFOHEADER *)store;
2197 bmiHeader->biSize = (DWORD)sizeof(BITMAPINFOHEADER);
2198 bmiHeader->biWidth = wid;
2199 bmiHeader->biHeight = hei;
2200 bmiHeader->biPlanes = 1;
2201 bmiHeader->biBitCount = 32;
2202 bmiHeader->biCompression = (DWORD)BI_RGB;
2203 data = &store[hsize];
2204
2205 /* load the image data */
2206 for(y=0; y<hei; y++)
2207 {
2208 dest = (INTBIG *)(&data[y * rowbytes]);
2209 source = &gra_biggeroffrowstart[bighei-1-(y+ly)][lx];
2210 for(x=0; x<wid; x++)
2211 {
2212 index = ((*source++) & ~HIGHLIT) & 0xFF;
2213 r = redmap[index];
2214 g = greenmap[index];
2215 b = bluemap[index];
2216 *dest++ = b | (g << 8) | (r << 16);
2217 }
2218 }
2219
2220 /* put the image into the clipboard */
2221 if (OpenClipboard(0) != 0)
2222 {
2223 EmptyClipboard();
2224 SetClipboardData(CF_DIB, h);
2225 CloseClipboard();
2226 }
2227 }
2228
2229 /*
2230 * routine to paste text to the messages window if it is current. Returns true
2231 * if sucessful.
2232 */
pastetomessages(void)2233 BOOLEAN pastetomessages(void)
2234 {
2235 if (gra_messageswindow == 0) return(FALSE);
2236 if (gra_messageswindow->IsIconic()) return(FALSE);
2237 CMDIFrameWnd *parent = gra_messageswindow->GetMDIFrame();
2238 CWnd *wnd = parent->MDIGetActive();
2239 if (gra_messageswindow != wnd) return(FALSE);
2240
2241 /* do the copy */
2242 gra_editCtrl->Paste();
2243 return(TRUE);
2244 }
2245
2246 /*
2247 * routine to get the contents of the system cut buffer
2248 */
getcutbuffer(void)2249 CHAR *getcutbuffer(void)
2250 {
2251 CHAR *ptr;
2252 REGISTER void *infstr;
2253
2254 if (OpenClipboard(NULL) == 0) return(x_(""));
2255 ptr = (CHAR *)GetClipboardData(CF_TEXT);
2256 infstr = initinfstr();
2257 if (ptr != 0)
2258 addstringtoinfstr(infstr, ptr);
2259 CloseClipboard();
2260 return(returninfstr(infstr));
2261 }
2262
2263 /*
2264 * routine to set the contents of the system cut buffer to "msg"
2265 */
setcutbuffer(CHAR * msg)2266 void setcutbuffer(CHAR *msg)
2267 {
2268 HGLOBAL hnd;
2269
2270 if (OpenClipboard(NULL) == 0) return;
2271
2272 /* Remove the current Clipboard contents */
2273 if (EmptyClipboard() == 0)
2274 {
2275 CloseClipboard();
2276 return;
2277 }
2278
2279 hnd = GlobalAlloc(GHND, estrlen(msg)+SIZEOFCHAR);
2280 estrcpy(*((CHAR **)hnd), msg);
2281 (void)SetClipboardData(CF_TEXT, hnd);
2282
2283 CloseClipboard();
2284 }
2285
2286 /*
2287 * Routine to return true if the messages window is obscured by
2288 * an editor window. Should ignore edit windows below this!!!
2289 */
gra_messagesnotvisible(void)2290 BOOLEAN gra_messagesnotvisible(void)
2291 {
2292 RECT mr, r;
2293 CWnd *wnd;
2294 WINDOWFRAME *wf;
2295
2296 gra_messageswindow->GetWindowRect(&mr);
2297 mr.top += 2; mr.bottom -= 2;
2298 mr.left += 2; mr.right -= 2;
2299
2300 /* look for "previous" windows that may obscure this one */
2301 wnd = gra_messageswindow;
2302 for(;;)
2303 {
2304 wnd = wnd->GetNextWindow(GW_HWNDPREV);
2305 if (wnd == 0) break;
2306
2307 /* ignore palette */
2308 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
2309 if ((CChildFrame *)wf->wndframe == wnd) break;
2310 if (wf != NOWINDOWFRAME && wf->floating) continue;
2311 wnd->GetWindowRect(&r);
2312 if (r.left < mr.right && r.right > mr.left &&
2313 r.top < mr.bottom && r.bottom > mr.top) return(TRUE);
2314 }
2315 return(FALSE);
2316 }
2317
2318 /*
2319 * Routine to clear all text from the messages window.
2320 */
clearmessageswindow(void)2321 void clearmessageswindow(void)
2322 {
2323 CHAR ch[1];
2324 int pos;
2325
2326 if (gra_messageswindow == 0) return;
2327 pos = gra_editCtrl->GetLimitText();
2328 gra_editCtrl->SetSel(0, pos);
2329 ch[0] = 0;
2330 gra_editCtrl->ReplaceSel(ch);
2331 }
2332
2333 /******************** STATUS BAR ROUTINES ********************/
2334
2335 /*
2336 * Routine to return the number of status lines on the display.
2337 */
ttynumstatuslines(void)2338 INTBIG ttynumstatuslines(void)
2339 {
2340 return(MAXSTATUSLINES);
2341 }
2342
2343 /*
2344 * Routine to free status field object "sf".
2345 */
ttyfreestatusfield(STATUSFIELD * sf)2346 void ttyfreestatusfield(STATUSFIELD *sf)
2347 {
2348 INTBIG i, j;
2349
2350 for(i=0; i<gra_indicatorcount; i++)
2351 {
2352 if (gra_statusfields[i] != sf) continue;
2353
2354 /* remove the field */
2355 efree(gra_statusfieldtext[i]);
2356 for(j=i+1; j<gra_indicatorcount; j++)
2357 {
2358 gra_statusfields[j-1] = gra_statusfields[j];
2359 gra_statusfieldtext[j-1] = gra_statusfieldtext[j];
2360 }
2361 gra_indicatorcount--;
2362 gra_redrawstatusindicators();
2363 break;
2364 }
2365
2366 efree(sf->label);
2367 efree((CHAR *)sf);
2368 }
2369
2370 /*
2371 * Routine to display "message" in the status "field" of window "wf" (uses all windows
2372 * if "wf" is zero). If "cancrop" is false, field cannot be cropped and should be
2373 * replaced with "*" if there isn't room.
2374 */
ttysetstatusfield(WINDOWFRAME * wf,STATUSFIELD * field,CHAR * message,BOOLEAN cancrop)2375 void ttysetstatusfield(WINDOWFRAME *wf, STATUSFIELD *field, CHAR *message, BOOLEAN cancrop)
2376 {
2377 INTBIG len, i, j, pos, newpos;
2378 CMainFrame *wnd;
2379
2380 /* figure out which indicator this is */
2381 if (field == 0) return;
2382
2383 /* construct the status line */
2384 len = estrlen(field->label);
2385 if (len + estrlen(message) >= MAXLOCALSTRING)
2386 {
2387 estrcpy(gra_localstring, field->label);
2388 i = MAXLOCALSTRING - len - 1;
2389 estrncat(gra_localstring, message, i);
2390 gra_localstring[MAXLOCALSTRING-1] = 0;
2391 } else
2392 {
2393 esnprintf(gra_localstring, 256, x_("%s%s"), field->label, message);
2394 }
2395 len = estrlen(gra_localstring);
2396 while (len > 0 && gra_localstring[len-1] == ' ') gra_localstring[--len] = 0;
2397
2398 /* if this is a title bar setting, do it now */
2399 if (field->line == 0)
2400 {
2401 if (wf == NOWINDOWFRAME) return;
2402 if (*gra_localstring == 0) estrcpy(gra_localstring, _("*** NO CELL ***"));
2403 ((CChildFrame *)wf->wndframe)->SetWindowText(gra_localstring);
2404 return;
2405 }
2406
2407 /* ignore null fields */
2408 if (*field->label == 0) return;
2409
2410 /* see if this indicator is in the list */
2411 wnd = (CMainFrame *)AfxGetMainWnd();
2412 for(i=0; i<gra_indicatorcount; i++)
2413 {
2414 if (gra_statusfields[i]->line != field->line ||
2415 gra_statusfields[i]->startper != field->startper ||
2416 gra_statusfields[i]->endper != field->endper) continue;
2417
2418 /* load the string */
2419 (void)reallocstring(&gra_statusfieldtext[i], gra_localstring, db_cluster);
2420 wnd->m_wndStatusBar.SetPaneText(i+1, gra_localstring);
2421 return;
2422 }
2423
2424 /* code cannot be called by multiple procesors: uses globals */
2425 NOT_REENTRANT;
2426
2427 /* not found: find where this field fits in the order */
2428 newpos = (field->line-1) * 100 + field->startper;
2429 for(i=0; i<gra_indicatorcount; i++)
2430 {
2431 pos = (gra_statusfields[i]->line-1) * 100 + gra_statusfields[i]->startper;
2432 if (newpos < pos) break;
2433 }
2434 for(j=gra_indicatorcount; j>i; j--)
2435 {
2436 gra_statusfieldtext[j] = gra_statusfieldtext[j-1];
2437 gra_statusfields[j] = gra_statusfields[j-1];
2438 }
2439 gra_statusfields[i] = field;
2440 (void)allocstring(&gra_statusfieldtext[i], gra_localstring, db_cluster);
2441 gra_indicatorcount++;
2442
2443 /* reload all indicators */
2444 gra_redrawstatusindicators();
2445 }
2446
gra_redrawstatusindicators(void)2447 void gra_redrawstatusindicators(void)
2448 {
2449 INTBIG i, wid, screenwid, totalwid;
2450 RECT r;
2451 CMainFrame *wnd;
2452
2453 wnd = (CMainFrame *)AfxGetMainWnd();
2454 wnd->GetClientRect(&r);
2455 screenwid = r.right - r.left - gra_indicatorcount * 5;
2456 wnd->m_wndStatusBar.SetIndicators(gra_indicators, gra_indicatorcount+1);
2457 totalwid = 0;
2458 for(i=0; i<gra_indicatorcount; i++)
2459 totalwid += gra_statusfields[i]->endper - gra_statusfields[i]->startper;
2460 for(i=0; i<=gra_indicatorcount; i++)
2461 {
2462 if (i == 0)
2463 {
2464 wnd->m_wndStatusBar.SetPaneInfo(i, gra_indicators[i], SBPS_NOBORDERS, 0);
2465 wnd->m_wndStatusBar.SetPaneText(i, x_(""));
2466 } else
2467 {
2468 wid = gra_statusfields[i-1]->endper - gra_statusfields[i-1]->startper;
2469 wid = wid * screenwid / totalwid;
2470 wnd->m_wndStatusBar.SetPaneInfo(i, gra_indicators[i], SBPS_NORMAL, wid);
2471 wnd->m_wndStatusBar.SetPaneText(i, gra_statusfieldtext[i-1]);
2472 }
2473 }
2474 }
2475
2476 /******************** GRAPHICS CONTROL ROUTINES ********************/
2477
flushscreen(void)2478 void flushscreen(void)
2479 {
2480 WINDOWFRAME *wf;
2481
2482 if (gra_noflush) return;
2483 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
2484 {
2485 if (wf->wndframe == 0) continue;
2486
2487 /* if screen has not changed, stop now */
2488 if (!wf->offscreendirty) continue;
2489 wf->offscreendirty = FALSE;
2490
2491 /* refresh screen */
2492 wf->hDC = (CDC *)((CChildFrame *)wf->wndframe)->GetDC();
2493 ((CDC *)wf->hDC)->BitBlt(wf->copyleft, wf->copytop, wf->copyright-wf->copyleft,
2494 wf->copybottom-wf->copytop, (CDC *)wf->hDCOff, wf->copyleft, wf->copytop, SRCCOPY);
2495 ((CChildFrame *)wf->wndframe)->ReleaseDC((CDC *)wf->hDC);
2496 }
2497 }
2498
2499 /*
2500 * Routine to accumulate the rectangle of change to the offscreen PixMap
2501 */
gra_setrect(WINDOWFRAME * wf,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy)2502 void gra_setrect(WINDOWFRAME *wf, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy)
2503 {
2504 static INTBIG checktimefreq = 0;
2505
2506 if (wf->offscreendirty)
2507 {
2508 if (lx < wf->copyleft) wf->copyleft = lx;
2509 if (hx > wf->copyright) wf->copyright = hx;
2510 if (ly < wf->copytop) wf->copytop = ly;
2511 if (hy > wf->copybottom) wf->copybottom = hy;
2512 } else
2513 {
2514 wf->copyleft = lx;
2515 wf->copyright = hx;
2516 wf->copytop = ly;
2517 wf->copybottom = hy;
2518 wf->offscreendirty = TRUE;
2519 wf->starttime = ticktime();
2520 }
2521
2522 /* flush the screen every two seconds */
2523 checktimefreq++;
2524 if (checktimefreq > 10000)
2525 {
2526 checktimefreq = 0;
2527 if (ticktime() - wf->starttime > FLUSHTICKS) flushscreen();
2528 }
2529 }
2530
gra_reloadmap(void)2531 void gra_reloadmap(void)
2532 {
2533 REGISTER VARIABLE *varred, *vargreen, *varblue;
2534
2535 varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
2536 vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
2537 varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
2538 if (varred == NOVARIABLE || vargreen == NOVARIABLE || varblue == NOVARIABLE) return;
2539 colormapload((INTBIG *)varred->addr, (INTBIG *)vargreen->addr, (INTBIG *)varblue->addr, 0, 255);
2540 }
2541
colormapload(INTBIG * red,INTBIG * green,INTBIG * blue,INTBIG low,INTBIG high)2542 void colormapload(INTBIG *red, INTBIG *green, INTBIG *blue, INTBIG low, INTBIG high)
2543 {
2544 INTBIG i;
2545 INTBIG forecolor, backcolor;
2546 REGISTER WINDOWFRAME *wf;
2547 RGBQUAD bmiColors[256];
2548
2549 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
2550 {
2551 /* do not touch the color map when in B&W mode */
2552 if (wf->pColorPalette == 0) continue;
2553
2554 i = GetDIBColorTable(((CDC *)wf->hDCOff)->m_hDC, 0, 256, bmiColors);
2555 for(i=low; i<=high; i++)
2556 {
2557 bmiColors[i].rgbRed = (UCHAR1)red[i-low];
2558 bmiColors[i].rgbGreen = (UCHAR1)green[i-low];
2559 bmiColors[i].rgbBlue = (UCHAR1)blue[i-low];
2560 bmiColors[i].rgbReserved = 0;
2561 if (i == 255)
2562 {
2563 bmiColors[i].rgbRed = (UCHAR1)(255-red[i-low]);
2564 bmiColors[i].rgbGreen = (UCHAR1)(255-green[i-low]);
2565 bmiColors[i].rgbBlue = (UCHAR1)(255-blue[i-low]);
2566 }
2567
2568 wf->pColorPalette->palPalEntry[i].peRed = bmiColors[i].rgbRed;
2569 wf->pColorPalette->palPalEntry[i].peGreen = bmiColors[i].rgbGreen;
2570 wf->pColorPalette->palPalEntry[i].peBlue = bmiColors[i].rgbBlue;
2571 wf->pColorPalette->palPalEntry[i].peFlags = 0;
2572 }
2573 i = SetDIBColorTable(((CDC *)wf->hDCOff)->m_hDC, 0, 256, bmiColors);
2574
2575 if (wf->hPalette != 0)
2576 delete (CPalette *)wf->hPalette;
2577
2578 wf->hPalette = (CPalette *)new CPalette();
2579 ((CPalette *)wf->hPalette)->CreatePalette(wf->pColorPalette);
2580
2581 /* graphics window */
2582 ((CDC *)wf->hDCOff)->SelectPalette((CPalette *)wf->hPalette, TRUE);
2583 ((CDC *)wf->hDCOff)->RealizePalette();
2584 gra_setrect(wf, 0, wf->swid-1, 0, wf->shei-1);
2585 }
2586
2587 /* change the messages window to conform */
2588 if (low == 0 && high == 255 && gra_messageswindow != 0)
2589 {
2590 forecolor = (blue[CELLTXT] << 16) | (green[CELLTXT] << 8) | red[CELLTXT];
2591 backcolor = (blue[0] << 16) | (green[0] << 8) | red[0];
2592 CElectricMsgView *msgView = (CElectricMsgView *)gra_messageswindow;
2593 msgView->SetColors((COLORREF)forecolor, (COLORREF)backcolor);
2594 }
2595 }
2596
2597 /*
2598 * helper routine to set the cursor shape to "state"
2599 */
setdefaultcursortype(INTBIG state)2600 void setdefaultcursortype(INTBIG state)
2601 {
2602 if (us_cursorstate == state) return;
2603
2604 switch (state)
2605 {
2606 case NORMALCURSOR: SetCursor(gra_normalCurs); break;
2607 case WANTTTYCURSOR: SetCursor(gra_wantttyCurs); break;
2608 case PENCURSOR: SetCursor(gra_penCurs); break;
2609 case NULLCURSOR: SetCursor(gra_normalCurs); break;
2610 case MENUCURSOR: SetCursor(gra_menuCurs); break;
2611 case HANDCURSOR: SetCursor(gra_handCurs); break;
2612 case TECHCURSOR: SetCursor(gra_techCurs); break;
2613 case IBEAMCURSOR: SetCursor(gra_ibeamCurs); break;
2614 case WAITCURSOR: SetCursor(gra_waitCurs); break;
2615 case LRCURSOR: SetCursor(gra_lrCurs); break;
2616 case UDCURSOR: SetCursor(gra_udCurs); break;
2617 }
2618 ShowCursor(TRUE);
2619 us_cursorstate = state;
2620 }
2621
2622 /*
2623 * Routine to change the default cursor (to indicate modes).
2624 */
setnormalcursor(INTBIG curs)2625 void setnormalcursor(INTBIG curs)
2626 {
2627 us_normalcursor = curs;
2628 setdefaultcursortype(us_normalcursor);
2629 }
2630
2631 /******************** GRAPHICS LINES ********************/
2632
screendrawline(WINDOWPART * win,INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2,GRAPHICS * desc,INTBIG texture)2633 void screendrawline(WINDOWPART *win, INTBIG x1, INTBIG y1, INTBIG x2, INTBIG y2, GRAPHICS *desc, INTBIG texture)
2634 {
2635 gra_drawline(win, x1, y1, x2, y2, desc, texture);
2636 }
2637
screeninvertline(WINDOWPART * win,INTBIG x1,INTBIG y1,INTBIG x2,INTBIG y2)2638 void screeninvertline(WINDOWPART *win, INTBIG x1, INTBIG y1, INTBIG x2, INTBIG y2)
2639 {
2640 gra_invertline(win, x1, y1, x2, y2);
2641 }
2642
2643 /******************** GRAPHICS POLYGONS ********************/
2644
screendrawpolygon(WINDOWPART * win,INTBIG * x,INTBIG * y,INTBIG count,GRAPHICS * desc)2645 void screendrawpolygon(WINDOWPART *win, INTBIG *x, INTBIG *y, INTBIG count, GRAPHICS *desc)
2646 {
2647 gra_drawpolygon(win, x, y, count, desc);
2648 }
2649
2650 /******************** GRAPHICS BOXES ********************/
2651
screendrawbox(WINDOWPART * win,INTBIG lowx,INTBIG highx,INTBIG lowy,INTBIG highy,GRAPHICS * desc)2652 void screendrawbox(WINDOWPART *win, INTBIG lowx, INTBIG highx, INTBIG lowy, INTBIG highy, GRAPHICS *desc)
2653 {
2654 gra_drawbox(win, lowx, highx, lowy, highy, desc);
2655 }
2656
2657 /*
2658 * routine to invert the bits in the box from (lowx, lowy) to (highx, highy)
2659 */
screeninvertbox(WINDOWPART * win,INTBIG lowx,INTBIG highx,INTBIG lowy,INTBIG highy)2660 void screeninvertbox(WINDOWPART *win, INTBIG lowx, INTBIG highx, INTBIG lowy, INTBIG highy)
2661 {
2662 gra_invertbox(win, lowx, highx, lowy, highy);
2663 }
2664
2665 /*
2666 * routine to move bits on the display starting with the area at
2667 * (sx,sy) and ending at (dx,dy). The size of the area to be
2668 * moved is "wid" by "hei".
2669 */
screenmovebox(WINDOWPART * win,INTBIG sx,INTBIG sy,INTBIG wid,INTBIG hei,INTBIG dx,INTBIG dy)2670 void screenmovebox(WINDOWPART *win, INTBIG sx, INTBIG sy, INTBIG wid, INTBIG hei, INTBIG dx, INTBIG dy)
2671 {
2672 #ifdef WINSAVEDBOX
2673 REGISTER INTBIG totop, tobottom, toleft, toright, fromleft, fromtop;
2674 REGISTER WINDOWFRAME *wf;
2675
2676 wf = win->frame;
2677
2678 /* setup source rectangle */
2679 fromleft = sx;
2680 fromtop = wf->revy + 1 - sy - hei;
2681
2682 /* setup destination rectangle */
2683 toleft = dx;
2684 toright = toleft + wid;
2685 totop = wf->revy + 1 - dy - hei;
2686 tobottom = totop + hei;
2687
2688 ((CDC *)wf->hDCOff)->BitBlt(toleft, totop, wid, hei, (CDC *)wf->hDCOff,
2689 fromleft, fromtop, SRCCOPY);
2690
2691 gra_setrect(wf, toleft, toright, totop, tobottom);
2692 #else
2693 gra_movebox(win, sx, sy, wid, hei, dx, dy);
2694 #endif
2695 }
2696
2697 /*
2698 * routine to save the contents of the box from "lx" to "hx" in X and from
2699 * "ly" to "hy" in Y. A code is returned that identifies this box for
2700 * overwriting and restoring. The routine returns -1 if there is a error.
2701 */
screensavebox(WINDOWPART * win,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy)2702 INTBIG screensavebox(WINDOWPART *win, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy)
2703 {
2704 #ifdef WINSAVEDBOX
2705 SAVEDBOX *box;
2706 REGISTER INTBIG xsize, ysize;
2707 REGISTER INTBIG i, x, y;
2708 REGISTER WINDOWFRAME *wf;
2709 REGISTER UCHAR1 *source, *dest;
2710
2711 wf = win->frame;
2712 i = ly;
2713 ly = wf->revy-hy;
2714 hy = wf->revy-i;
2715 xsize = hx-lx+1;
2716 ysize = hy-ly+1;
2717 box = (SAVEDBOX *)emalloc((sizeof (SAVEDBOX)), us_tool->cluster);
2718 if (box == 0) return(-1);
2719
2720 if (gra_buildoffscreenbuffer(wf, xsize, ysize, &box->hMemDC,
2721 &box->hBox, &box->bminfo, &box->data, &box->rowstart)) return(-1);
2722
2723 box->win = win;
2724 box->nextsavedbox = gra_firstsavedbox;
2725 gra_firstsavedbox = box;
2726 box->lx = lx; box->hx = hx;
2727 box->ly = ly; box->hy = hy;
2728
2729 /* move the bits */
2730 for(y=0; y<ysize; y++)
2731 {
2732 source = &wf->rowstart[ly+y][lx];
2733 dest = box->rowstart[y];
2734 for(x=0; x<xsize; x++) *dest++ = *source++;
2735 }
2736
2737 return((INTBIG)box);
2738 #else
2739 return(gra_savebox(win, lx, hx, ly, hy));
2740 #endif
2741 }
2742
2743 /*
2744 * routine to shift the saved box "code" so that it is restored in a different location,
2745 * offset by (dx,dy)
2746 */
screenmovesavedbox(INTBIG code,INTBIG dx,INTBIG dy)2747 void screenmovesavedbox(INTBIG code, INTBIG dx, INTBIG dy)
2748 {
2749 #ifdef WINSAVEDBOX
2750 REGISTER SAVEDBOX *box;
2751
2752 if (code == -1) return;
2753 box = (SAVEDBOX *)code;
2754 box->lx += dx; box->hx += dx;
2755 box->ly -= dy; box->hy -= dy;
2756 #else
2757 gra_movesavedbox(code, dx, dy);
2758 #endif
2759 }
2760
2761 /*
2762 * routine to restore saved box "code" to the screen. "destroy" is:
2763 * 0 restore box, do not free memory
2764 * 1 restore box, free memory
2765 * -1 free memory
2766 */
screenrestorebox(INTBIG code,INTBIG destroy)2767 void screenrestorebox(INTBIG code, INTBIG destroy)
2768 {
2769 #ifdef WINSAVEDBOX
2770 REGISTER SAVEDBOX *box, *lbox, *tbox;
2771 REGISTER INTBIG x, y, xsize, ysize;
2772 REGISTER UCHAR1 *source, *dest;
2773 REGISTER WINDOWFRAME *wf;
2774
2775 /* get the box */
2776 if (code == -1) return;
2777 box = (SAVEDBOX *)code;
2778
2779 /* move the bits */
2780 if (destroy >= 0)
2781 {
2782 wf = box->win->frame;
2783 xsize = box->hx - box->lx + 1;
2784 ysize = box->hy - box->ly + 1;
2785 for(y=0; y<ysize; y++)
2786 {
2787 dest = &wf->rowstart[box->ly+y][box->lx];
2788 source = box->rowstart[y];
2789 for(x=0; x<xsize; x++) *dest++ = *source++;
2790 }
2791 efree((CHAR *)box->rowstart);
2792 efree((CHAR *)box->bminfo);
2793 DeleteObject(box->hBox);
2794 delete box->hMemDC;
2795 gra_setrect(wf, box->lx, box->hx+1, box->ly, box->hy+1);
2796 }
2797
2798 /* destroy this box's memory if requested */
2799 if (destroy != 0)
2800 {
2801 lbox = NOSAVEDBOX;
2802 for(tbox = gra_firstsavedbox; tbox != NOSAVEDBOX; tbox = tbox->nextsavedbox)
2803 {
2804 if (tbox == box)
2805 break;
2806 lbox = tbox;
2807 }
2808 if (lbox == NOSAVEDBOX)
2809 gra_firstsavedbox = box->nextsavedbox;
2810 else
2811 lbox->nextsavedbox = box->nextsavedbox;
2812 efree((CHAR *)box);
2813 }
2814 #else
2815 (void)gra_restorebox(code, destroy);
2816 #endif
2817 }
2818
2819 /******************** GRAPHICS TEXT ********************/
2820
2821 /*
2822 * Routine to find face with name "facename" and to return
2823 * its index in list of used fonts. If font was not used before,
2824 * then it is appended to list of used fonts.
2825 * If font "facename" is not available on the system, -1 is returned.
2826 */
screenfindface(CHAR * facename)2827 INTBIG screenfindface(CHAR *facename)
2828 {
2829 INTBIG i;
2830
2831 for (i = 0; i < gra_numfaces; i++)
2832 if (namesame(facename, gra_facelist[i]) == 0) return(i);
2833 return(-1);
2834 }
2835
2836 /*
2837 * Routine to return the number of typefaces used (when "all" is FALSE)
2838 * or available on the system (when "all" is TRUE)
2839 * and to return their names in the array "list".
2840 * "screenfindface
2841 */
screengetfacelist(CHAR *** list,BOOLEAN all)2842 INTBIG screengetfacelist(CHAR ***list, BOOLEAN all)
2843 {
2844 CDC *curdc;
2845 CChildFrame *child;
2846 REGISTER INTBIG i;
2847
2848 if (gra_numfaces == 0)
2849 {
2850 if (el_curwindowframe != NOWINDOWFRAME)
2851 child = (CChildFrame *)el_curwindowframe->wndframe; else
2852 child = gra_messageswindow;
2853 curdc = (CDC *)child->GetDC();
2854 EnumFonts(curdc->m_hDC, NULL, (FONTENUMPROC)gra_enumfaces, (LPARAM)NULL);
2855 if (gra_numfaces > VTMAXFACE)
2856 {
2857 ttyputerr(_("Warning: found %ld fonts, but can only keep track of %d"), gra_numfaces,
2858 VTMAXFACE);
2859 for(i=VTMAXFACE; i<gra_numfaces; i++)
2860 {
2861 efree((CHAR *)gra_facelist[i]);
2862 gra_facelist[i] = 0;
2863 }
2864 gra_numfaces = VTMAXFACE;
2865 }
2866 esort(&gra_facelist[1], gra_numfaces-1, sizeof (CHAR *), sort_stringascending);
2867 }
2868 *list = gra_facelist;
2869 return(gra_numfaces);
2870 }
2871
2872 /*
2873 * Routine to return the default typeface used on the screen.
2874 */
screengetdefaultfacename(void)2875 CHAR *screengetdefaultfacename(void)
2876 {
2877 return(x_("Arial"));
2878 }
2879
2880 /*
2881 * Callback routine to get the number of fonts
2882 */
gra_enumfaces(LPLOGFONT lpLogFont,LPTEXTMETRIC lpTEXTMETRICs,DWORD fFontType,LPVOID lpData)2883 int APIENTRY gra_enumfaces(LPLOGFONT lpLogFont, LPTEXTMETRIC lpTEXTMETRICs, DWORD fFontType, LPVOID lpData)
2884 {
2885 INTBIG newcellotal, i;
2886 CHAR **newfacelist;
2887
2888 if (gra_numfaces == 0) newcellotal = 2; else
2889 newcellotal = gra_numfaces + 1;
2890 newfacelist = (CHAR **)emalloc(newcellotal * (sizeof (CHAR *)), us_tool->cluster);
2891 if (newfacelist == 0) return(0);
2892 for(i=0; i<gra_numfaces; i++)
2893 newfacelist[i] = gra_facelist[i];
2894 for(i=gra_numfaces; i<newcellotal; i++)
2895 newfacelist[i] = 0;
2896 if (gra_numfaces > 0) efree((CHAR *)gra_facelist);
2897 gra_facelist = newfacelist;
2898 if (gra_numfaces == 0)
2899 (void)allocstring(&gra_facelist[gra_numfaces++], _("DEFAULT FACE"), us_tool->cluster);
2900 if (gra_facelist[gra_numfaces] != 0) efree((CHAR *)gra_facelist[gra_numfaces]);
2901 (void)allocstring(&gra_facelist[gra_numfaces++], lpLogFont->lfFaceName, us_tool->cluster);
2902 return(1);
2903 }
2904
screensettextinfo(WINDOWPART * win,TECHNOLOGY * tech,UINTBIG * descript)2905 void screensettextinfo(WINDOWPART *win, TECHNOLOGY *tech, UINTBIG *descript)
2906 {
2907 REGISTER WINDOWFRAME *wf;
2908
2909 wf = win->frame;
2910 wf->hFont = 0;
2911 wf->hFont = gra_gettextfont(win, tech, descript);
2912 if (wf->hFont == 0) return;
2913 ((CDC *)wf->hDCOff)->SelectObject((CFont *)wf->hFont);
2914 }
2915
gra_gettextfont(WINDOWPART * win,TECHNOLOGY * tech,UINTBIG * descript)2916 CFont *gra_gettextfont(WINDOWPART *win, TECHNOLOGY *tech, UINTBIG *descript)
2917 {
2918 static CFont *txteditor = 0, *txtmenu = 0;
2919 CFont *theFont;
2920 REGISTER INTBIG font, size, italic, bold, underline, face, i;
2921 REGISTER UINTBIG hash;
2922 REGISTER CHAR *facename, **list;
2923
2924 gra_texttoosmall = FALSE;
2925 font = TDGETSIZE(descript);
2926 if (font == TXTEDITOR)
2927 {
2928 if (txteditor == 0) txteditor = gra_createtextfont(12, x_("Lucida Console"), 0, 0, 0);
2929 return(txteditor);
2930 }
2931 if (font == TXTMENU)
2932 {
2933 if (txtmenu == 0) txtmenu = gra_createtextfont(13, x_("MS Sans Serif"), 0, 0, 0);
2934 return(txtmenu);
2935 }
2936 size = truefontsize(font, win, tech);
2937 if (size < 1)
2938 {
2939 gra_texttoosmall = TRUE;
2940 return(0);
2941 }
2942 if (size < MINIMUMTEXTSIZE) size = MINIMUMTEXTSIZE;
2943
2944 face = TDGETFACE(descript);
2945 italic = TDGETITALIC(descript);
2946 bold = TDGETBOLD(descript);
2947 underline = TDGETUNDERLINE(descript);
2948 gra_textrotation = TDGETROTATION(descript);
2949 if (face == 0 && italic == 0 && bold == 0 && underline == 0)
2950 {
2951 if (size >= MAXCACHEDFONTS) size = MAXCACHEDFONTS-1;
2952 if (gra_fontcache[size] == 0)
2953 gra_fontcache[size] = gra_createtextfont(size, x_("Arial"), 0, 0, 0);
2954 return(gra_fontcache[size]);
2955 } else
2956 {
2957 hash = size + 3*italic + 5*bold + 7*underline + 11*face;
2958 hash %= FONTHASHSIZE;
2959 for(i=0; i<FONTHASHSIZE; i++)
2960 {
2961 if (gra_fonthash[hash].font == 0) break;
2962 if (gra_fonthash[hash].face == face && gra_fonthash[hash].size == size &&
2963 gra_fonthash[hash].italic == italic && gra_fonthash[hash].bold == bold &&
2964 gra_fonthash[hash].underline == underline)
2965 return(gra_fonthash[hash].font);
2966 hash++;
2967 if (hash >= FONTHASHSIZE) hash = 0;
2968 }
2969 facename = x_("Arial");
2970 if (face > 0)
2971 {
2972 if (gra_numfaces == 0) (void)screengetfacelist(&list, FALSE);
2973 if (face < gra_numfaces)
2974 facename = gra_facelist[face];
2975 }
2976 theFont = gra_createtextfont(size, facename, italic, bold, underline);
2977 if (gra_fonthash[hash].font == 0)
2978 {
2979 gra_fonthash[hash].font = theFont;
2980 gra_fonthash[hash].face = face;
2981 gra_fonthash[hash].size = size;
2982 gra_fonthash[hash].italic = italic;
2983 gra_fonthash[hash].bold = bold;
2984 gra_fonthash[hash].underline = underline;
2985 }
2986 return(theFont);
2987 }
2988 }
2989
gra_createtextfont(INTBIG fontSize,CHAR * face,INTBIG italic,INTBIG bold,INTBIG underline)2990 CFont *gra_createtextfont(INTBIG fontSize, CHAR *face, INTBIG italic, INTBIG bold,
2991 INTBIG underline)
2992 {
2993 LOGFONT lf;
2994 CFont *hf;
2995
2996 lf.lfHeight = -fontSize;
2997 estrcpy(lf.lfFaceName, face);
2998 lf.lfWidth = 0;
2999 lf.lfEscapement = 0;
3000 lf.lfOrientation = 0;
3001 if (bold != 0) lf.lfWeight = FW_BOLD; else
3002 lf.lfWeight = FW_NORMAL;
3003 if (italic != 0) lf.lfItalic = 1; else
3004 lf.lfItalic = 0;
3005 if (underline != 0) lf.lfUnderline = 1; else
3006 lf.lfUnderline = 0;
3007 lf.lfStrikeOut = 0;
3008 lf.lfCharSet = DEFAULT_CHARSET;
3009 lf.lfOutPrecision = OUT_STROKE_PRECIS;
3010 lf.lfClipPrecision = CLIP_STROKE_PRECIS;
3011 lf.lfQuality = DEFAULT_QUALITY;
3012 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
3013
3014 hf = new CFont();
3015 hf->CreateFontIndirect(&lf);
3016 return(hf);
3017 }
3018
screengettextsize(WINDOWPART * win,CHAR * str,INTBIG * x,INTBIG * y)3019 void screengettextsize(WINDOWPART *win, CHAR *str, INTBIG *x, INTBIG *y)
3020 {
3021 INTBIG len;
3022 CSize textSize;
3023 REGISTER WINDOWFRAME *wf;
3024
3025 if (gra_texttoosmall)
3026 {
3027 *x = *y = 0;
3028 return;
3029 }
3030 wf = win->frame;
3031 len = estrlen(str);
3032 textSize = ((CDC *)wf->hDCOff)->GetTextExtent(str, len);
3033 switch (gra_textrotation)
3034 {
3035 case 0: /* normal */
3036 *x = textSize.cx;
3037 *y = textSize.cy+1;
3038 break;
3039 case 1: /* 90 degrees counterclockwise */
3040 *x = -textSize.cy+1;
3041 *y = textSize.cx;
3042 break;
3043 case 2: /* 180 degrees */
3044 *x = -textSize.cx;
3045 *y = -textSize.cy+1;
3046 break;
3047 case 3: /* 90 degrees clockwise */
3048 *x = textSize.cy+1;
3049 *y = -textSize.cx;
3050 break;
3051 }
3052 }
3053
screendrawtext(WINDOWPART * win,INTBIG atx,INTBIG aty,CHAR * s,GRAPHICS * desc)3054 void screendrawtext(WINDOWPART *win, INTBIG atx, INTBIG aty, CHAR *s, GRAPHICS *desc)
3055 {
3056 if (gra_texttoosmall) return;
3057 gra_drawtext(win, atx, aty, gra_textrotation, s, desc);
3058 }
3059
3060 /*
3061 * Routine to convert the string "msg" (to be drawn into window "win") into an
3062 * array of pixels. The size of the array is returned in "wid" and "hei", and
3063 * the pixels are returned in an array of character vectors "rowstart".
3064 * The routine returns true if the operation cannot be done.
3065 */
gettextbits(WINDOWPART * win,CHAR * msg,INTBIG * wid,INTBIG * hei,UCHAR1 *** rowstart)3066 BOOLEAN gettextbits(WINDOWPART *win, CHAR *msg, INTBIG *wid, INTBIG *hei, UCHAR1 ***rowstart)
3067 {
3068 REGISTER INTBIG i, len, j;
3069 CSize textSize;
3070 REGISTER WINDOWFRAME *wf;
3071 REGISTER UCHAR1 *ptr;
3072
3073 /* copy the string and correct it */
3074 len = estrlen(msg);
3075 if (len == 0 || gra_texttoosmall)
3076 {
3077 *wid = *hei = 0;
3078 return(FALSE);
3079 }
3080 /* determine size of string */
3081 wf = win->frame;
3082 textSize = ((CDC *)wf->hDCOff)->GetTextExtent(msg, len);
3083 *wid = textSize.cx;
3084 *hei = textSize.cy;
3085
3086 /* see if text buffer needs to be (re)initialized */
3087 if (gra_textbufinited)
3088 {
3089 if (*wid > gra_textbufwid || *hei > gra_textbufhei)
3090 {
3091 efree((CHAR *)gra_textrowstart);
3092 efree((CHAR *)gra_textbitmapinfo);
3093 DeleteObject(gra_textbitmap);
3094 delete gra_texthdc;
3095 gra_textbufinited = FALSE;
3096 }
3097 }
3098
3099 /* allocate text buffer if needed */
3100 if (!gra_textbufinited)
3101 {
3102 if (gra_buildoffscreenbuffer(wf, *wid, *hei, &gra_texthdc, &gra_textbitmap,
3103 &gra_textbitmapinfo, &gra_textdatabuffer, &gra_textrowstart)) return(TRUE);
3104 gra_texthdc->SetTextColor(PALETTEINDEX(1));
3105 gra_texthdc->SetROP2(R2_COPYPEN);
3106 gra_texthdc->SetBkMode(TRANSPARENT);
3107 gra_texthdc->SetTextAlign(TA_TOP<<8);
3108
3109 /* remember information about text buffer */
3110 gra_textbufwid = *wid; gra_textbufhei = *hei;
3111 gra_textbufinited = TRUE;
3112 }
3113
3114 /* clear the text buffer */
3115 for(i=0; i < *hei; i++)
3116 {
3117 ptr = gra_textrowstart[i];
3118 for(j=0; j < *wid; j++) *ptr++ = 0;
3119 }
3120
3121 /* write to the text buffer */
3122 gra_texthdc->SelectObject((CFont *)wf->hFont);
3123 gra_texthdc->TextOut(0, 0, msg, len);
3124
3125 *rowstart = gra_textrowstart;
3126 return(FALSE);
3127 }
3128
3129 /******************** CIRCLE DRAWING ********************/
3130
screendrawcircle(WINDOWPART * win,INTBIG atx,INTBIG aty,INTBIG radius,GRAPHICS * desc)3131 void screendrawcircle(WINDOWPART *win, INTBIG atx, INTBIG aty, INTBIG radius, GRAPHICS *desc)
3132 {
3133 gra_drawcircle(win, atx, aty, radius, desc);
3134 }
3135
screendrawthickcircle(WINDOWPART * win,INTBIG atx,INTBIG aty,INTBIG radius,GRAPHICS * desc)3136 void screendrawthickcircle(WINDOWPART *win, INTBIG atx, INTBIG aty, INTBIG radius,
3137 GRAPHICS *desc)
3138 {
3139 gra_drawthickcircle(win, atx, aty, radius, desc);
3140 }
3141
3142 /******************** FILLED CIRCLE DRAWING ********************/
3143
3144 /*
3145 * routine to draw a filled-in circle of radius "radius"
3146 */
screendrawdisc(WINDOWPART * win,INTBIG atx,INTBIG aty,INTBIG radius,GRAPHICS * desc)3147 void screendrawdisc(WINDOWPART *win, INTBIG atx, INTBIG aty, INTBIG radius, GRAPHICS *desc)
3148 {
3149 gra_drawdisc(win, atx, aty, radius, desc);
3150 }
3151
3152 /******************** ARC DRAWING ********************/
3153
3154 /*
3155 * draws a thin arc centered at (centerx, centery), clockwise,
3156 * passing by (x1,y1) and (x2,y2)
3157 */
screendrawcirclearc(WINDOWPART * win,INTBIG centerx,INTBIG centery,INTBIG p1_x,INTBIG p1_y,INTBIG p2_x,INTBIG p2_y,GRAPHICS * desc)3158 void screendrawcirclearc(WINDOWPART *win, INTBIG centerx, INTBIG centery, INTBIG p1_x, INTBIG p1_y,
3159 INTBIG p2_x, INTBIG p2_y, GRAPHICS *desc)
3160 {
3161 gra_drawcirclearc(win, centerx, centery, p1_x, p1_y, p2_x, p2_y, FALSE, desc);
3162 }
3163
3164 /*
3165 * draws a thick arc centered at (centerx, centery), clockwise,
3166 * passing by (x1,y1) and (x2,y2)
3167 */
screendrawthickcirclearc(WINDOWPART * win,INTBIG centerx,INTBIG centery,INTBIG p1_x,INTBIG p1_y,INTBIG p2_x,INTBIG p2_y,GRAPHICS * desc)3168 void screendrawthickcirclearc(WINDOWPART *win, INTBIG centerx, INTBIG centery, INTBIG p1_x, INTBIG p1_y,
3169 INTBIG p2_x, INTBIG p2_y, GRAPHICS *desc)
3170 {
3171 gra_drawcirclearc(win, centerx, centery, p1_x, p1_y, p2_x, p2_y, TRUE, desc);
3172 }
3173
3174 /******************** GRID CONTROL ********************/
3175
3176 /*
3177 * grid drawing routine
3178 */
screendrawgrid(WINDOWPART * win,POLYGON * obj)3179 void screendrawgrid(WINDOWPART *win, POLYGON *obj)
3180 {
3181 gra_drawgrid(win, obj);
3182 }
3183
3184 /******************** MOUSE CONTROL ********************/
3185
3186 /*
3187 * routine to return the number of buttons on the mouse
3188 */
buttoncount(void)3189 INTBIG buttoncount(void)
3190 {
3191 return(mini(BUTTONS, NUMBUTS));
3192 }
3193
3194 /*
3195 * routine to tell whether button "but" is a double-click
3196 */
doublebutton(INTBIG b)3197 BOOLEAN doublebutton(INTBIG b)
3198 {
3199 if (b >= BUTTONS - REALBUTS) return(TRUE);
3200 return(FALSE);
3201 }
3202
3203 /*
3204 * routine to tell whether button "but" is a context button (right)
3205 */
contextbutton(INTBIG b)3206 BOOLEAN contextbutton(INTBIG b)
3207 {
3208 if ((b%5) == 2) return(TRUE);
3209 return(FALSE);
3210 }
3211
3212 /*
3213 * routine to tell whether button "but" has the "shift" key held
3214 */
shiftbutton(INTBIG b)3215 BOOLEAN shiftbutton(INTBIG b)
3216 {
3217 b = b / REALBUTS;
3218
3219 /* this "switch" statement is taken from the array "gra_buttonname" */
3220 switch (b)
3221 {
3222 case 0: return(FALSE); /* no shift keys */
3223 case 1: return(TRUE); /* shift */
3224 case 2: return(FALSE); /* control */
3225 case 3: return(FALSE); /* alt */
3226 case 4: return(TRUE); /* shift-control */
3227 case 5: return(TRUE); /* shift-alt */
3228 case 6: return(FALSE); /* control-alt */
3229 case 7: return(TRUE); /* shift-control-alt */
3230 case 8: return(FALSE); /* double-click */
3231 }
3232 return(FALSE);
3233 }
3234
3235 /*
3236 * routine to tell whether button "but" is a "mouse wheel" button
3237 */
wheelbutton(INTBIG b)3238 BOOLEAN wheelbutton(INTBIG b)
3239 {
3240 b = b % REALBUTS;
3241 if (b == 3 || b == 4) return(TRUE);
3242 return(FALSE);
3243 }
3244
3245 /*
3246 * routine to return the name of button "b" (from 0 to "buttoncount()").
3247 * The number of letters unique to the button is placed in "important".
3248 */
buttonname(INTBIG b,INTBIG * important)3249 CHAR *buttonname(INTBIG b, INTBIG *important)
3250 {
3251 *important = gra_buttonname[b].unique;
3252 return(gra_buttonname[b].name);
3253 }
3254
3255 /*
3256 * routine to convert from "state" (the typical input parameter)
3257 * to button numbers (the table "gra_buttonname")
3258 */
gra_makebutton(INTBIG state)3259 INTBIG gra_makebutton(INTBIG state)
3260 {
3261 REGISTER INTBIG base;
3262
3263 switch (state&WHICHBUTTON)
3264 {
3265 case ISLEFT: base = 0; break;
3266 case ISMIDDLE: base = 1; break;
3267 case ISRIGHT: base = 2; break;
3268 case ISWHLFWD: base = 3; break;
3269 case ISWHLBKW: base = 4; break;
3270 }
3271
3272 if ((state&DOUBLECLICK) != 0) return(base+REALBUTS*8);
3273 switch (state & (SHIFTISDOWN|CONTROLISDOWN|ALTISDOWN))
3274 {
3275 case SHIFTISDOWN : return(base+REALBUTS*1);
3276 case CONTROLISDOWN : return(base+REALBUTS*2);
3277 case ALTISDOWN: return(base+REALBUTS*3);
3278 case SHIFTISDOWN|CONTROLISDOWN : return(base+REALBUTS*4);
3279 case SHIFTISDOWN| ALTISDOWN: return(base+REALBUTS*5);
3280 case CONTROLISDOWN|ALTISDOWN: return(base+REALBUTS*6);
3281 case SHIFTISDOWN|CONTROLISDOWN|ALTISDOWN: return(base+REALBUTS*7);
3282 }
3283 return(base);
3284 }
3285
3286 /*
3287 * routine to wait for a button push and return its index (0 based) in "*but".
3288 * The coordinates of the cursor are placed in "*x" and "*y". If there is no
3289 * button push, the value of "*but" is negative.
3290 */
waitforbutton(INTBIG * x,INTBIG * y,INTBIG * but)3291 void waitforbutton(INTBIG *x, INTBIG *y, INTBIG *but)
3292 {
3293 if (gra_inputstate != NOEVENT && (gra_inputstate&(ISBUTTON|BUTTONUP)) == ISBUTTON)
3294 {
3295 *but = gra_makebutton(gra_inputstate);
3296 *x = gra_cursorx;
3297 *y = gra_cursory;
3298 gra_inputstate = NOEVENT;
3299 if (us_cursorstate != IBEAMCURSOR) setdefaultcursortype(us_normalcursor);
3300 return;
3301 }
3302 gra_nextevent();
3303 if (gra_inputstate != NOEVENT && (gra_inputstate&(ISBUTTON|BUTTONUP)) == ISBUTTON)
3304 {
3305 *but = gra_makebutton(gra_inputstate);
3306 *x = gra_cursorx;
3307 *y = gra_cursory;
3308 gra_inputstate = NOEVENT;
3309 if (us_cursorstate != IBEAMCURSOR) setdefaultcursortype(us_normalcursor);
3310 return;
3311 }
3312 *but = -1;
3313 }
3314
3315 /*
3316 * routine to do modal loop, calling "charhandler" for each typed key and "buttonhandler"
3317 * for each pushed button. The "charhandler" routine is called with the character value
3318 * that was typed. The "buttonhandler" routine is called with coordinates of cursor.
3319 * The "charhandler" and "buttonhandler" returns true to abort loop.
3320 * The value of "cursor" determines cursor appearance.
3321 */
modalloop(BOOLEAN (* charhandler)(INTSML chr,INTBIG special),BOOLEAN (* buttonhandler)(INTBIG x,INTBIG y,INTBIG but),INTBIG cursor)3322 void modalloop(BOOLEAN (*charhandler)(INTSML chr, INTBIG special),
3323 BOOLEAN (*buttonhandler)(INTBIG x, INTBIG y, INTBIG but), INTBIG cursor)
3324 {
3325 INTBIG oldnormalcursor, special, x, y, but;
3326 INTSML chr;
3327
3328 /* set cursor */
3329 oldnormalcursor = us_normalcursor;
3330 setnormalcursor(cursor);
3331
3332 for (;;)
3333 {
3334 if (ttydataready())
3335 {
3336 chr = getnxtchar(&special);
3337 if ((*charhandler)(chr, special)) break;
3338 } else
3339 {
3340 waitforbutton(&x, &y, &but);
3341 if (but >= 0 && buttonhandler != 0)
3342 if ((*buttonhandler)(x, y, but)) break;
3343 }
3344 }
3345
3346 /* restore cursor */
3347 setnormalcursor(oldnormalcursor);
3348 }
3349
3350 /*
3351 * routine to track the cursor until a button is released, calling "whileup" for
3352 * each co-ordinate when the mouse moves before the first button push, calling
3353 * "whendown" once when the button goes down, calling "eachdown" for each
3354 * co-ordinate when the mouse moves after the button is pushed, calling
3355 * "eachchar" for each key that is typed at any time, and calling "done" once
3356 * when done. The "whendown" and "done" routines are called with no parameters;
3357 * "whileup" and "eachdown" are called with the X and Y coordinates of the
3358 * cursor; and "eachchar" is called with the X, Y, and character value that was
3359 * typed. The "whileup", "eachdown", and "eachchar" routines return nonzero to
3360 * abort tracking.
3361 * If "waitforpush" is true then the routine will wait for a button to
3362 * actually be pushed before tracking (otherwise it will begin tracking
3363 * immediately). The value of "purpose" determines what the cursor will look
3364 * like during dragging: 0 for normal (the standard cursor), 1 for drawing (a pen),
3365 * 2 for dragging (a hand), 3 for popup menu selection (a horizontal arrow), 4 for
3366 * hierarchical popup menu selection (arrow, stays at end).
3367 */
trackcursor(BOOLEAN waitforpush,BOOLEAN (* whileup)(INTBIG,INTBIG),void (* whendown)(void),BOOLEAN (* eachdown)(INTBIG,INTBIG),BOOLEAN (* eachchar)(INTBIG,INTBIG,INTSML),void (* done)(void),INTBIG purpose)3368 void trackcursor(BOOLEAN waitforpush, BOOLEAN (*whileup)(INTBIG, INTBIG),
3369 void (*whendown)(void), BOOLEAN (*eachdown)(INTBIG, INTBIG),
3370 BOOLEAN (*eachchar)(INTBIG, INTBIG, INTSML), void (*done)(void), INTBIG purpose)
3371 {
3372 REGISTER BOOLEAN keepon;
3373 INTBIG action, oldcursor;
3374
3375 /* change the cursor to an appropriate icon */
3376 oldcursor = us_normalcursor;
3377 switch (purpose)
3378 {
3379 case TRACKDRAWING:
3380 setnormalcursor(PENCURSOR);
3381 break;
3382 case TRACKDRAGGING:
3383 setnormalcursor(HANDCURSOR);
3384 break;
3385 case TRACKSELECTING:
3386 case TRACKHSELECTING:
3387 setnormalcursor(MENUCURSOR);
3388 break;
3389 }
3390
3391 /* now wait for a button to go down, if requested */
3392 keepon = FALSE;
3393 if (waitforpush)
3394 {
3395 while (!keepon)
3396 {
3397 gra_nextevent();
3398 if (gra_inputstate == NOEVENT) continue;
3399 action = gra_inputstate;
3400 gra_inputstate = NOEVENT;
3401
3402 /* if button just went down, stop this loop */
3403 if ((action&ISBUTTON) != 0 && (action&BUTTONUP) == 0) break;
3404 if ((action&MOTION) != 0)
3405 {
3406 keepon = (*whileup)(gra_cursorx, gra_cursory);
3407 } else if ((action&ISKEYSTROKE) != 0 && gra_inputspecial == 0)
3408 {
3409 keepon = (*eachchar)(gra_cursorx, gra_cursory, (INTSML)(action&CHARREAD));
3410 }
3411 if (el_pleasestop != 0) keepon = TRUE;
3412 }
3413 }
3414
3415 /* button is now down, real tracking begins */
3416 if (!keepon)
3417 {
3418 (*whendown)();
3419 keepon = (*eachdown)(gra_cursorx, gra_cursory);
3420 }
3421
3422 /* now track while the button is down */
3423 while (!keepon)
3424 {
3425 gra_nextevent();
3426 us_endchanges(NOWINDOWPART);
3427
3428 /* for each motion, report the coordinates */
3429 if (gra_inputstate == NOEVENT) continue;
3430 action = gra_inputstate;
3431 gra_inputstate = NOEVENT;
3432 if ((action&ISBUTTON) != 0 && (action&BUTTONUP) != 0) break;
3433 if ((action&MOTION) != 0)
3434 {
3435 keepon = (*eachdown)(gra_cursorx, gra_cursory);
3436 } else if ((action&ISKEYSTROKE) != 0 && gra_inputspecial == 0)
3437 {
3438 keepon = (*eachchar)(gra_cursorx, gra_cursory, (INTSML)(action&CHARREAD));
3439 }
3440 if (el_pleasestop != 0) keepon = TRUE;
3441 }
3442
3443 /* inform the user that all is done */
3444 (*done)();
3445
3446 /* restore the state of the world */
3447 setnormalcursor(oldcursor);
3448 }
3449
3450 /*
3451 * routine to read the current co-ordinates of the tablet and return them
3452 * in "*x" and "*y".
3453 */
readtablet(INTBIG * x,INTBIG * y)3454 void readtablet(INTBIG *x, INTBIG *y)
3455 {
3456 *x = gra_cursorx;
3457 *y = gra_cursory;
3458 }
3459
3460 /*
3461 * routine to turn off the cursor tracking if it is on
3462 */
stoptablet(void)3463 void stoptablet(void)
3464 {
3465 if (us_cursorstate != IBEAMCURSOR)
3466 setdefaultcursortype(us_normalcursor);
3467 }
3468
3469 /******************** KEYBOARD CONTROL ********************/
3470
3471 /*
3472 * routine to get the next character from the keyboard
3473 */
getnxtchar(INTBIG * special)3474 INTSML getnxtchar(INTBIG *special)
3475 {
3476 REGISTER INTSML i;
3477
3478 if (gra_inputstate != NOEVENT && (gra_inputstate&ISKEYSTROKE) != 0)
3479 {
3480 i = (INTSML)(gra_inputstate & CHARREAD);
3481 *special = gra_inputspecial;
3482 gra_inputstate = NOEVENT;
3483 return(i);
3484 }
3485 if (us_cursorstate != IBEAMCURSOR)
3486 setdefaultcursortype(WANTTTYCURSOR);
3487 for(;;)
3488 {
3489 gra_nextevent();
3490 if (gra_inputstate != NOEVENT && (gra_inputstate&ISKEYSTROKE) != 0)
3491 break;
3492 }
3493 i = (INTSML)(gra_inputstate & CHARREAD);
3494 *special = gra_inputspecial;
3495 gra_inputstate = NOEVENT;
3496 if (us_cursorstate != IBEAMCURSOR)
3497 setdefaultcursortype(us_normalcursor);
3498 return(i);
3499 }
3500
checkforinterrupt(void)3501 void checkforinterrupt(void)
3502 {
3503 MSG msg;
3504
3505 while ( ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
3506 {
3507 if (!gra_app.PumpMessage())
3508 {
3509 ::PostQuitMessage(0);
3510 break;
3511 }
3512 }
3513 setdefaultcursortype(WAITCURSOR);
3514 }
3515
3516 /*
3517 * Routine to return which "bucky bits" are held down (shift, control, etc.)
3518 */
getbuckybits(void)3519 INTBIG getbuckybits(void)
3520 {
3521 REGISTER INTBIG bits;
3522
3523 bits = 0;
3524 if ((GetKeyState(VK_CONTROL)&0x8000) != 0) bits |= CONTROLDOWN|ACCELERATORDOWN;
3525 if ((GetKeyState(VK_SHIFT)&0x8000) != 0) bits |= SHIFTDOWN;
3526 if ((GetKeyState(VK_MENU)&0x8000) != 0) bits |= OPTALTMETDOWN;
3527 return(bits);
3528 }
3529
3530 /*
3531 * routine to tell whether data is waiting at the terminal. Returns true
3532 * if data is ready.
3533 */
ttydataready(void)3534 BOOLEAN ttydataready(void)
3535 {
3536 /* see if something is already pending */
3537 if (gra_inputstate != NOEVENT)
3538 {
3539 if ((gra_inputstate&ISKEYSTROKE) != 0) return(TRUE);
3540 }
3541
3542 /* wait for something and analyze it */
3543 gra_nextevent();
3544 if (gra_inputstate != NOEVENT && (gra_inputstate&ISKEYSTROKE) != 0) return(TRUE);
3545 return(FALSE);
3546 }
3547
3548 /****************************** FILES ******************************/
3549
3550 /*
3551 * Routine to prompt for multiple files of type "filetype", giving the
3552 * message "msg". Returns a string that contains all of the file names,
3553 * separated by the NONFILECH (a character that cannot be in a file name).
3554 */
3555 #define MAXMULTIFILECHARS 4000
multifileselectin(CHAR * msg,INTBIG filetype)3556 CHAR *multifileselectin(CHAR *msg, INTBIG filetype)
3557 {
3558 CHAR fs[MAXMULTIFILECHARS], prompt[256], *extension, *winfilter, *shortname,
3559 *longname, *pt;
3560 CFileDialog *fileDlg;
3561 REGISTER INTBIG which;
3562 REGISTER INTBIG ret;
3563 INTBIG mactype;
3564 BOOLEAN binary;
3565 REGISTER void *infstr;
3566
3567 /* build filter string */
3568 describefiletype(filetype, &extension, &winfilter, &mactype, &binary, &shortname, &longname);
3569 estrcpy(fs, longname);
3570 estrcat(fs, x_(" ("));
3571 estrcat(fs, winfilter);
3572 estrcat(fs, x_(")|"));
3573 estrcat(fs, winfilter);
3574 estrcat(fs, _("|All Files (*.*)|*.*||"));
3575
3576 fileDlg = new CFileDialog(TRUE, NULL, NULL, NULL, fs, NULL);
3577 if (fileDlg == NULL) return(0);
3578 fs[0] = 0;
3579 fileDlg->m_ofn.lpstrFile = fs;
3580 fileDlg->m_ofn.nMaxFile = MAXMULTIFILECHARS;
3581 fileDlg->m_ofn.Flags |= OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT |
3582 OFN_EXPLORER;
3583 esnprintf(prompt, 256, _("%s Selection"), msg);
3584 fileDlg->m_ofn.lpstrTitle = prompt;
3585 pt = 0;
3586 ret = fileDlg->DoModal();
3587 if (ret == IDOK)
3588 {
3589 pt = fs;
3590 infstr = initinfstr();
3591 which = 0;
3592 while (*pt != 0)
3593 {
3594 if (which == 0)
3595 {
3596 estrcpy(gra_localstring, pt);
3597 } else
3598 {
3599 if (which > 1) addtoinfstr(infstr, NONFILECH);
3600 addstringtoinfstr(infstr, gra_localstring);
3601 addtoinfstr(infstr, DIRSEP);
3602 addstringtoinfstr(infstr, pt);
3603 }
3604 which++;
3605 while (*pt != 0) pt++;
3606 pt++;
3607 }
3608 if (which == 1) addstringtoinfstr(infstr, gra_localstring);
3609 pt = returninfstr(infstr);
3610 }
3611 delete fileDlg;
3612 return(pt);
3613 }
3614
3615 /*
3616 * Routine to display a standard file prompt dialog and return the selected file.
3617 * The prompt message is in "msg" and the kind of file is in "filetype". The default
3618 * output file name is in "defofile" (only used if "filetype" is negative).
3619 */
fileselect(CHAR * msg,INTBIG filetype,CHAR * defofile)3620 CHAR *fileselect(CHAR *msg, INTBIG filetype, CHAR *defofile)
3621 {
3622 REGISTER INTBIG i;
3623 CHAR ofile[256], fs[256], prompt[256], *extension, *winfilter, *shortname,
3624 *longname;
3625 CFileDialog *fileDlg;
3626 INTBIG mactype;
3627 BOOLEAN binary;
3628
3629 /* build filter string */
3630 describefiletype(filetype, &extension, &winfilter, &mactype, &binary, &shortname, &longname);
3631 estrcpy(fs, longname);
3632 estrcat(fs, x_(" ("));
3633 estrcat(fs, winfilter);
3634 estrcat(fs, x_(")|"));
3635 estrcat(fs, winfilter);
3636 estrcat(fs, x_("|"));
3637 estrcat(fs, _("All Files"));
3638 estrcat(fs, x_(" (*.*)|*.*||"));
3639
3640 if (us_logplay != NULL)
3641 {
3642 if (gra_loggetnextaction(gra_localstring)) return(0);
3643 if (gra_inputstate != FILEREPLY) gra_localstring[0] = 0;
3644 } else
3645 {
3646 gra_localstring[0] = 0;
3647 if ((filetype & FILETYPEWRITE) == 0)
3648 {
3649 /* open file dialog */
3650 fileDlg = new CFileDialog(TRUE, NULL, NULL, NULL, fs, NULL);
3651 if (fileDlg == NULL) gra_localstring[0] = 0; else
3652 {
3653 fileDlg->m_ofn.Flags |= OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
3654 esnprintf(prompt, 256, _("%s Selection"), msg);
3655 fileDlg->m_ofn.lpstrTitle = prompt;
3656 if (fileDlg->DoModal() == IDOK)
3657 estrcpy(gra_localstring, fileDlg->GetPathName());
3658 delete fileDlg;
3659 }
3660 } else
3661 {
3662 /* save file dialog */
3663 for(i = estrlen(defofile)-1; i > 0; i--)
3664 if (defofile[i] == ':' || defofile[i] == '/' || defofile[i] == '\\') break;
3665 if (i > 0) i++;
3666 (void)estrcpy(ofile, &defofile[i]);
3667 fileDlg = new CFileDialog(FALSE, extension, ofile, NULL, fs, NULL);
3668 if (fileDlg != NULL)
3669 {
3670 fileDlg->m_ofn.Flags |= OFN_OVERWRITEPROMPT;
3671 esnprintf(prompt, 256, _("%s Creation"), msg);
3672 fileDlg->m_ofn.lpstrTitle = prompt;
3673 if (fileDlg->DoModal() == IDOK)
3674 estrcpy(gra_localstring, fileDlg->GetPathName());
3675 delete fileDlg;
3676 }
3677 }
3678 }
3679
3680 /* log this result */
3681 gra_logwriteaction(FILEREPLY, 0, 0, 0, gra_localstring);
3682
3683 if (gra_localstring[0] == 0) return((CHAR *)NULL); else
3684 return(gra_localstring);
3685 }
3686
3687 /*
3688 * Helper routine to initialize the list of files in a directory.
3689 */
gra_initfilelist(void)3690 void gra_initfilelist(void)
3691 {
3692 if (gra_fileliststringarray == 0)
3693 {
3694 gra_fileliststringarray = newstringarray(db_cluster);
3695 if (gra_fileliststringarray == 0) return;
3696 }
3697 clearstrings(gra_fileliststringarray);
3698 }
3699
3700 /*
3701 * Helper routine to add "file" to the list of files in a directory.
3702 * Returns true on error.
3703 */
gra_addfiletolist(CHAR * file)3704 BOOLEAN gra_addfiletolist(CHAR *file)
3705 {
3706 addtostringarray(gra_fileliststringarray, file);
3707 return(FALSE);
3708 }
3709
3710 /*
3711 * Routine to search for all of the files/directories in directory "directory" and
3712 * return them in the array of strings "filelist". Returns the number of files found.
3713 */
filesindirectory(CHAR * directory,CHAR *** filelist)3714 INTBIG filesindirectory(CHAR *directory, CHAR ***filelist)
3715 {
3716 HANDLE handle;
3717 WIN32_FIND_DATA data;
3718 BOOL found;
3719 CHAR *dir;
3720 INTBIG len;
3721 REGISTER void *infstr;
3722
3723 /* search for all files in directory */
3724 infstr = initinfstr();
3725 addstringtoinfstr(infstr, directory);
3726 addstringtoinfstr(infstr, x_("*.*"));
3727 dir = returninfstr(infstr);
3728
3729 handle = FindFirstFile(dir, &data);
3730 if (handle == INVALID_HANDLE_VALUE) return(0);
3731
3732 gra_initfilelist();
3733 for (found = 1; found; found = FindNextFile(handle, &data))
3734 {
3735 if (gra_addfiletolist(data.cFileName)) return(0);
3736 }
3737 FindClose(handle);
3738
3739 *filelist = getstringarray(gra_fileliststringarray, &len);
3740 return(len);
3741 }
3742
3743 /* routine to convert a path name with "~" to a real path */
truepath(CHAR * line)3744 CHAR *truepath(CHAR *line)
3745 {
3746 /* only have tilde parsing on UNIX */
3747 return(line);
3748 }
3749
3750 /*
3751 * Routine to return the full path to file "file".
3752 */
fullfilename(CHAR * file)3753 CHAR *fullfilename(CHAR *file)
3754 {
3755 static CHAR fullfile[MAXPATHLEN];
3756
3757 /* is this a hack? Full path defined when it starts with "LETTER:" */
3758 if (isalpha(file[0]) != 0 && file[1] == ':') return(file);
3759
3760 /* full path also defined by "\\" at the start */
3761 if (file[0] == '\\' && file[1] == '\\') return(file);
3762
3763 /* build the proper path */
3764 estrcpy(fullfile, currentdirectory());
3765 estrcat(fullfile, file);
3766 return(fullfile);
3767 }
3768
3769 /*
3770 * routine to rename file "file" to "newfile"
3771 * returns nonzero on error
3772 */
erename(CHAR * file,CHAR * newfile)3773 INTBIG erename(CHAR *file, CHAR *newfile)
3774 {
3775 #ifdef _UNICODE
3776 return(_wrename(file, newfile));
3777 #else
3778 return(rename(file, newfile));
3779 #endif
3780 }
3781
3782 /*
3783 * routine to delete file "file"
3784 */
eunlink(CHAR * file)3785 INTBIG eunlink(CHAR *file)
3786 {
3787 #ifdef _UNICODE
3788 return(_wunlink(file));
3789 #else
3790 return(_unlink(file));
3791 #endif
3792 }
3793
3794 /*
3795 * Routine to return information about the file or directory "name":
3796 * 0: does not exist
3797 * 1: is a file
3798 * 2: is a directory
3799 * 3: is a locked file (read-only)
3800 */
fileexistence(CHAR * name)3801 INTBIG fileexistence(CHAR *name)
3802 {
3803 struct estatstr buf;
3804
3805 if (estat(name, &buf) < 0) return(0);
3806 if ((buf.st_mode & S_IFMT) == S_IFDIR) return(2);
3807
3808 /* a file: see if it is writable */
3809 if (eaccess(name, 2) == 0) return(1);
3810 return(3);
3811 }
3812
3813 /*
3814 * Routine to create a directory.
3815 * Returns true on error.
3816 */
createdirectory(CHAR * dirname)3817 BOOLEAN createdirectory(CHAR *dirname)
3818 {
3819 if (emkdir(dirname) == 0) return(FALSE);
3820 return(TRUE);
3821 }
3822
3823 /*
3824 * Routine to return the current directory name
3825 */
currentdirectory(void)3826 CHAR *currentdirectory(void)
3827 {
3828 static CHAR line[MAXPATHLEN+1];
3829 REGISTER INTBIG len;
3830
3831 egetcwd(line, MAXPATHLEN);
3832 len = estrlen(line);
3833 if (line[len-1] != DIRSEP)
3834 {
3835 line[len++] = DIRSEP;
3836 line[len] = 0;
3837 }
3838 return(line);
3839 }
3840
3841 /*
3842 * Routine to return the home directory (returns 0 if it doesn't exist)
3843 */
hashomedir(void)3844 CHAR *hashomedir(void)
3845 {
3846 return(0);
3847 }
3848
3849 /*
3850 * Routine to return the path to the "options" library.
3851 */
optionsfilepath(void)3852 CHAR *optionsfilepath(void)
3853 {
3854 CHAR username[256];
3855 UINTBIG size;
3856 REGISTER void *infstr;
3857
3858 infstr = initinfstr();
3859 addstringtoinfstr(infstr, el_libdir);
3860 addstringtoinfstr(infstr, x_("electricoptions_"));
3861 size = 256;
3862 GetUserName(username, &size);
3863 addstringtoinfstr(infstr, username);
3864 addstringtoinfstr(infstr, x_(".elib"));
3865 return(returninfstr(infstr));
3866 }
3867
3868 /*
3869 * Routine to obtain the modification date on file "filename".
3870 */
filedate(CHAR * filename)3871 time_t filedate(CHAR *filename)
3872 {
3873 struct estatstr buf;
3874 time_t thetime;
3875
3876 estat(filename, &buf);
3877 thetime = buf.st_mtime;
3878 thetime -= machinetimeoffset();
3879 return(thetime);
3880 }
3881
3882 /*
3883 * Routine to lock a resource called "lockfilename" by creating such a file
3884 * if it doesn't exist. Returns true if successful, false if unable to
3885 * lock the file.
3886 */
lockfile(CHAR * lockfilename)3887 BOOLEAN lockfile(CHAR *lockfilename)
3888 {
3889 int fd;
3890
3891 fd = ecreat(lockfilename, 0);
3892 if (fd == -1) return(FALSE);
3893 if (close(fd) == -1) return(FALSE);
3894 return(TRUE);
3895 }
3896
3897 /*
3898 * Routine to unlock a resource called "lockfilename" by deleting such a file.
3899 */
unlockfile(CHAR * lockfilename)3900 void unlockfile(CHAR *lockfilename)
3901 {
3902 INTBIG attrs;
3903 attrs = GetFileAttributes(lockfilename);
3904 if ((attrs & FILE_ATTRIBUTE_READONLY) != 0)
3905 {
3906 if (SetFileAttributes(lockfilename, attrs & ~FILE_ATTRIBUTE_READONLY) == 0)
3907 {
3908 ttyputerr(_("Error removing readonly bit on %s (error %ld)"),
3909 lockfilename, GetLastError());
3910 }
3911 }
3912
3913 if (DeleteFile(lockfilename) == 0)
3914 ttyputerr(_("Error unlocking %s (error %ld)"), lockfilename, GetLastError());
3915 }
3916
3917 /*
3918 * Routine to show file "filename" in a browser window.
3919 * Returns true if the operation cannot be done.
3920 */
browsefile(CHAR * filename)3921 BOOLEAN browsefile(CHAR *filename)
3922 {
3923 CMainFrame *wnd;
3924 INTBIG err;
3925
3926 wnd = (CMainFrame *)AfxGetMainWnd();
3927 err = (INTBIG)ShellExecute(wnd->m_hWnd, x_("open"), filename, x_(""),
3928 x_("C:\\Temp\\"), SW_SHOWNORMAL);
3929 if (err > 32) return(FALSE);
3930 ttyputmsg(_("Could not browse %s (error %ld)"), filename, err);
3931 return(TRUE);
3932 }
3933
3934 /****************************** CHANNELS ******************************/
3935
3936 /*
3937 * routine to create a pipe connection between the channels in "channels"
3938 */
epipe(int channels[2])3939 INTBIG epipe(int channels[2])
3940 {
3941 return(0);
3942 }
3943
3944 /*
3945 * Routine to set channel "channel" into an appropriate mode for single-character
3946 * interaction (i.e. break mode).
3947 */
setinteractivemode(int channel)3948 void setinteractivemode(int channel)
3949 {
3950 }
3951
3952 /*
3953 * Routine to replace channel "channel" with a pointer to file "file".
3954 * Returns a pointer to the original channel.
3955 */
channelreplacewithfile(int channel,CHAR * file)3956 INTBIG channelreplacewithfile(int channel, CHAR *file)
3957 {
3958 return(0);
3959 }
3960
3961 /*
3962 * Routine to replace channel "channel" with new channel "newchannel".
3963 * Returns a pointer to the original channel.
3964 */
channelreplacewithchannel(int channel,int newchannel)3965 INTBIG channelreplacewithchannel(int channel, int newchannel)
3966 {
3967 return(0);
3968 }
3969
3970 /*
3971 * Routine to restore channel "channel" to the pointer that was returned
3972 * by "channelreplacewithfile" or "channelreplacewithchannel" (and is in "saved").
3973 */
channelrestore(int channel,INTBIG saved)3974 void channelrestore(int channel, INTBIG saved)
3975 {
3976 }
3977
3978 /*
3979 * Routine to read "count" bytes from channel "channel" into "addr".
3980 * Returns the number of bytes read.
3981 */
eread(int channel,UCHAR1 * addr,INTBIG count)3982 INTBIG eread(int channel, UCHAR1 *addr, INTBIG count)
3983 {
3984 return(0);
3985 }
3986
3987 /*
3988 * Routine to write "count" bytes to channel "channel" from "addr".
3989 * Returns the number of bytes written.
3990 */
ewrite(int channel,UCHAR1 * addr,INTBIG count)3991 INTBIG ewrite(int channel, UCHAR1 *addr, INTBIG count)
3992 {
3993 return(0);
3994 }
3995
3996 /*
3997 * routine to close a channel in "channel"
3998 */
eclose(int channel)3999 INTBIG eclose(int channel)
4000 {
4001 return(0);
4002 }
4003
4004 /*************************** TIME ROUTINES ***************************/
4005
machinetimeoffset(void)4006 time_t machinetimeoffset(void)
4007 {
4008 return(0);
4009 }
4010
4011 /* returns the time at which the current event occurred */
eventtime(void)4012 UINTBIG eventtime(void)
4013 {
4014 return(gra_eventtime);
4015 }
4016
4017 /* returns the current time in 60ths of a second */
ticktime(void)4018 UINTBIG ticktime(void)
4019 {
4020 UINTBIG msTime;
4021
4022 /* convert milliseconds to ticks */
4023 msTime = GetTickCount();
4024 return(msTime*6/100 + gra_timeoffset);
4025 }
4026
4027 /* returns the double-click interval in 60ths of a second */
doubleclicktime(void)4028 INTBIG doubleclicktime(void)
4029 {
4030 INTBIG dct;
4031
4032 dct = GetDoubleClickTime();
4033 dct = dct * 60 / 1000;
4034 return(dct);
4035 }
4036
4037 /*
4038 * Routine to wait "ticks" sixtieths of a second and then return.
4039 */
gotosleep(INTBIG ticks)4040 void gotosleep(INTBIG ticks)
4041 {
4042 Sleep(ticks * 100 / 6);
4043 }
4044
4045 /*
4046 * Routine to start counting time.
4047 */
starttimer(void)4048 void starttimer(void)
4049 {
4050 struct timeb timeptr;
4051
4052 /* code cannot be called by multiple procesors: uses globals */
4053 NOT_REENTRANT;
4054
4055 ftime(&timeptr);
4056 gra_timebasesec = timeptr.time;
4057 gra_timebasems = timeptr.millitm;
4058 }
4059
4060 /*
4061 * Routine to stop counting time and return the number of elapsed seconds
4062 * since the last call to "starttimer()".
4063 */
endtimer(void)4064 float endtimer(void)
4065 {
4066 float seconds;
4067 INTBIG milliseconds;
4068 struct timeb timeptr;
4069
4070 ftime(&timeptr);
4071 milliseconds = (timeptr.time - gra_timebasesec) * 1000 + (timeptr.millitm-gra_timebasems);
4072 seconds = ((float)milliseconds) / 1000.0f;
4073 return(seconds);
4074 }
4075
4076 /*************************** EVENT ROUTINES ***************************/
4077
4078 #define INITIALTIMERDELAY 8
4079
4080 INTBIG gra_lasteventstate = 0;
4081 INTBIG gra_lasteventx;
4082 INTBIG gra_lasteventy;
4083 INTBIG gra_lasteventtime;
4084 INTBIG gra_cureventtime = 0;
4085
gra_timerticked(void)4086 void gra_timerticked(void)
4087 {
4088 gra_cureventtime++;
4089 if (gra_cureventtime > gra_lasteventtime+INITIALTIMERDELAY)
4090 {
4091 /* see if the last event was a mouse button going down */
4092 if ((gra_lasteventstate&(ISBUTTON|BUTTONUP)) == ISBUTTON)
4093 {
4094 /* turn it into a null motion */
4095 gra_addeventtoqueue((gra_lasteventstate & ~ISBUTTON) | MOTION, 0,
4096 gra_lasteventx, gra_lasteventy);
4097 gra_lasteventtime -= INITIALTIMERDELAY;
4098 return;
4099 }
4100
4101 /* see if the last event was a motion with button down */
4102 if ((gra_lasteventstate&(MOTION|BUTTONUP)) == MOTION)
4103 {
4104 /* repeat the last event */
4105 gra_addeventtoqueue(gra_lasteventstate, 0, gra_lasteventx, gra_lasteventy);
4106 gra_lasteventtime -= INITIALTIMERDELAY;
4107 return;
4108 }
4109 }
4110 }
4111
gra_addeventtoqueue(INTBIG state,INTBIG special,INTBIG x,INTBIG y)4112 void gra_addeventtoqueue(INTBIG state, INTBIG special, INTBIG x, INTBIG y)
4113 {
4114 MYEVENTQUEUE *next, *prev;
4115
4116 if (db_multiprocessing) emutexlock(gra_eventqueuemutex);
4117
4118 next = gra_eventqueuetail + 1;
4119 if (next >= &gra_eventqueue[EVENTQUEUESIZE])
4120 next = gra_eventqueue;
4121 if (next == gra_eventqueuehead)
4122 {
4123 /* queue is full: see if last event was repeated */
4124 if (gra_eventqueuetail == gra_eventqueue)
4125 prev = &gra_eventqueue[EVENTQUEUESIZE-1]; else
4126 prev = gra_eventqueuetail - 1;
4127 if (prev->inputstate == state)
4128 {
4129 prev->cursorx = x;
4130 prev->cursory = y;
4131 } else
4132 {
4133 MessageBeep(MB_ICONASTERISK);
4134 }
4135 } else
4136 {
4137 gra_lasteventstate = gra_eventqueuetail->inputstate = state;
4138 gra_eventqueuetail->special = special;
4139 gra_lasteventx = gra_eventqueuetail->cursorx = x;
4140 gra_lasteventy = gra_eventqueuetail->cursory = y;
4141 gra_eventqueuetail->eventtime = ticktime();
4142 gra_lasteventtime = gra_cureventtime;
4143 gra_eventqueuetail = next;
4144 }
4145
4146 if (db_multiprocessing) emutexunlock(gra_eventqueuemutex);
4147 }
4148
4149 /*
4150 * Routine to get the next Electric input action and set the global "gra_inputstate"
4151 * accordingly.
4152 */
gra_nextevent(void)4153 void gra_nextevent(void)
4154 {
4155 MSG msg;
4156 REGISTER INTBIG windowindex, i, j, trueItem;
4157 BOOLEAN saveslice;
4158 REGISTER INTBIG x, y;
4159 BOOLEAN verbose;
4160 POPUPMENU *pm;
4161 REGISTER POPUPMENUITEM *mi;
4162 extern BOOLEAN el_inslice;
4163
4164 flushscreen();
4165
4166 /* process events */
4167 while ( ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
4168 {
4169 if (!gra_app.PumpMessage())
4170 {
4171 ::PostQuitMessage(0);
4172 break;
4173 }
4174 }
4175
4176 if (us_logplay != NULL)
4177 {
4178 /* playing back log file: wait for an event */
4179 gra_inputstate = NOEVENT;
4180 static INTBIG lastx = 0, lasty = 0;
4181 while (gra_eventqueuehead != gra_eventqueuetail)
4182 {
4183 gra_inputstate = gra_eventqueuehead->inputstate;
4184 gra_inputspecial = gra_eventqueuehead->special;
4185 gra_cursorx = gra_eventqueuehead->cursorx;
4186 gra_cursory = gra_eventqueuehead->cursory;
4187 us_state &= ~GOTXY;
4188 gra_eventqueuehead++;
4189 if (gra_eventqueuehead >= &gra_eventqueue[EVENTQUEUESIZE])
4190 gra_eventqueuehead = gra_eventqueue;
4191
4192 /* mouse click terminates */
4193 if ((gra_inputstate&ISBUTTON) != 0)
4194 {
4195 ttyputerr(_("Session playback aborted by mouse click"));
4196 xclose(us_logplay);
4197 us_logplay = NULL;
4198 gra_inputstate = NOEVENT;
4199 return;
4200 }
4201
4202 /* stop if this is the last event in the queue */
4203 if (gra_eventqueuehead == gra_eventqueuetail) break;
4204
4205 /* stop if the mouse moved */
4206 if (gra_cursorx != lastx || gra_cursory != lasty) break;
4207
4208 /* stop if this and the next event are not motion */
4209 if ((gra_inputstate&MOTION) == 0) break;
4210 if ((gra_eventqueuehead->inputstate&MOTION) == 0) break;
4211 }
4212 lastx = gra_cursorx; lasty = gra_cursory;
4213
4214 if (gra_inputstate != NOEVENT || gra_firstactivedialog != NOTDIALOG)
4215 {
4216 /* replace this with the logged action */
4217 (void)gra_loggetnextaction(0);
4218 }
4219 } else
4220 {
4221 /* normal interaction: get next event */
4222 gra_inputstate = NOEVENT;
4223 while (gra_eventqueuehead != gra_eventqueuetail)
4224 {
4225 gra_inputstate = gra_eventqueuehead->inputstate;
4226 gra_inputspecial = gra_eventqueuehead->special;
4227 gra_cursorx = gra_eventqueuehead->cursorx;
4228 gra_cursory = gra_eventqueuehead->cursory;
4229 gra_eventtime = gra_eventqueuehead->eventtime;
4230 us_state &= ~GOTXY;
4231 gra_eventqueuehead++;
4232 if (gra_eventqueuehead >= &gra_eventqueue[EVENTQUEUESIZE])
4233 gra_eventqueuehead = gra_eventqueue;
4234
4235 /* stop if this is the last event in the queue */
4236 if (gra_eventqueuehead == gra_eventqueuetail) break;
4237
4238 /* stop if this and the next event are not motion */
4239 if ((gra_inputstate&MOTION) == 0) break;
4240 if ((gra_eventqueuehead->inputstate&MOTION) == 0) break;
4241 }
4242 }
4243
4244 /* record valid events */
4245 if (gra_inputstate != NOEVENT)
4246 {
4247 if (gra_inputstate == WINDOWSIZE || gra_inputstate == WINDOWMOVE)
4248 {
4249 windowindex = gra_cursorx;
4250 x = gra_cursory >> 16;
4251 y = gra_cursory & 0xFFFF;
4252 gra_logwriteaction(gra_inputstate, 0, x, y, (void *)windowindex);
4253 gra_inputstate = NOEVENT;
4254 } else
4255 {
4256 windowindex = -1;
4257 if (el_curwindowframe != NOWINDOWFRAME) windowindex = el_curwindowframe->windindex;
4258 gra_logwriteaction(gra_inputstate, gra_inputspecial, gra_cursorx,
4259 gra_cursory, (void *)windowindex);
4260 }
4261
4262 /* handle menu events */
4263 if (gra_inputstate == MENUEVENT)
4264 {
4265 gra_inputstate = NOEVENT;
4266 i = gra_cursorx;
4267 if (i >= 0 && i < gra_pulldownmenucount)
4268 {
4269 pm = us_getpopupmenu(gra_pulldowns[i]);
4270 for(trueItem=j=0; j < pm->total; j++)
4271 {
4272 mi = &pm->list[j];
4273 if (mi->response->active < 0 && *mi->attribute == 0) continue;
4274 trueItem++;
4275 if (trueItem != gra_cursory) continue;
4276 us_state |= DIDINPUT;
4277 us_state &= ~GOTXY;
4278 setdefaultcursortype(us_normalcursor);
4279
4280 /* special case for "system" commands": don't erase */
4281 us_forceeditchanges();
4282 saveslice = el_inslice;
4283 el_inslice = TRUE;
4284 if ((us_tool->toolstate&ECHOBIND) != 0) verbose = TRUE; else
4285 verbose = FALSE;
4286 us_execute(mi->response, verbose, TRUE, TRUE);
4287 el_inslice = saveslice;
4288 db_setcurrenttool(us_tool);
4289 setactivity(mi->attribute);
4290 break;
4291 }
4292 }
4293 }
4294 }
4295 }
4296
gra_buttonaction(int state,UINT nFlags,CPoint point,CWnd * frm)4297 void gra_buttonaction(int state, UINT nFlags, CPoint point, CWnd *frm)
4298 {
4299 WINDOWFRAME *wf;
4300 INTBIG event, itemtype, x, y, item;
4301 TDIALOG *dia;
4302
4303 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
4304 if ((CChildFrame *)wf->wndframe == frm) break;
4305 if (wf == NOWINDOWFRAME)
4306 {
4307 for(dia = gra_firstactivedialog; dia != NOTDIALOG; dia = dia->nexttdialog)
4308 if (dia->window == frm) break;
4309 if (dia == NOTDIALOG) return;
4310
4311 item = gra_getdialogitem(dia, point.x, point.y);
4312 if (item == 0) return;
4313 itemtype = dia->itemdesc->list[item-1].type;
4314 if ((itemtype&ITEMTYPE) == USERDRAWN || (itemtype&ITEMTYPE) == ICON ||
4315 (dia->modelessitemhit != 0 && gra_trackingdialog == 0))
4316 {
4317 if (state == 0)
4318 {
4319 gra_itemclicked((CElectricDialog *)frm, item-1+ID_DIALOGITEM_0);
4320 return;
4321 }
4322 if (state == 2)
4323 {
4324 gra_itemdoubleclicked((CElectricDialog *)frm, item-1);
4325 return;
4326 }
4327 }
4328 }
4329
4330 /* set appropriate button */
4331 if ((nFlags & MK_LBUTTON) != 0) event = ISBUTTON|ISLEFT;
4332 if ((nFlags & MK_MBUTTON) != 0) event = ISBUTTON|ISMIDDLE;
4333 if ((nFlags & MK_RBUTTON) != 0) event = ISBUTTON|ISRIGHT;
4334
4335 /* add in extras */
4336 if ((nFlags & MK_SHIFT) != 0) event |= SHIFTISDOWN;
4337 if ((nFlags & MK_CONTROL) != 0) event |= CONTROLISDOWN;
4338 if ((GetKeyState(VK_MENU)&0x8000) != 0) event |= ALTISDOWN;
4339 if (state == 2 && (event&(SHIFTISDOWN|CONTROLISDOWN|ALTISDOWN)) == 0)
4340 event |= DOUBLECLICK;
4341 if (state == 1)
4342 event |= BUTTONUP;
4343
4344 x = point.x;
4345 if (wf == NOWINDOWFRAME) y = point.y; else
4346 y = wf->revy - point.y;
4347 us_state |= DIDINPUT;
4348 gra_addeventtoqueue(event, 0, x, y);
4349 }
4350
gra_mouseaction(UINT nFlags,CPoint point,CWnd * frm)4351 void gra_mouseaction(UINT nFlags, CPoint point, CWnd *frm)
4352 {
4353 WINDOWFRAME *wf;
4354 INTBIG event, x, y, inmenu;
4355 REGISTER VARIABLE *var;
4356 CHAR *str;
4357 static BOOLEAN overrodestatus = FALSE;
4358 COMMANDBINDING commandbinding;
4359 TDIALOG *dia;
4360
4361 /* find the appropriate window */
4362 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
4363 if ((CChildFrame *)wf->wndframe == frm) break;
4364 inmenu = 0;
4365 if (wf != NOWINDOWFRAME)
4366 {
4367 /* report the menu if over one */
4368 if ((nFlags & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) == 0 && wf->floating)
4369 {
4370 gra_cursorx = point.x;
4371 gra_cursory = wf->revy - point.y;
4372 us_state &= ~GOTXY;
4373 if (us_menuxsz > 0 && us_menuysz > 0)
4374 {
4375 x = (gra_cursorx-us_menulx) / us_menuxsz;
4376 y = (gra_cursory-us_menuly) / us_menuysz;
4377 if (x >= 0 && y >= 0 && x < us_menux && y < us_menuy)
4378 {
4379 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_menu_key);
4380 if (var != NOVARIABLE)
4381 {
4382 if (us_menupos <= 1) str = ((CHAR **)var->addr)[y * us_menux + x]; else
4383 str = ((CHAR **)var->addr)[x * us_menuy + y];
4384 us_parsebinding(str, &commandbinding);
4385 if (*commandbinding.command != 0)
4386 {
4387 if (commandbinding.nodeglyph != NONODEPROTO)
4388 {
4389 ttysetstatusfield(NOWINDOWFRAME, us_statusarc, describearcproto(us_curarcproto), TRUE);
4390 ttysetstatusfield(NOWINDOWFRAME, us_statusnode, us_describemenunode(&commandbinding), TRUE);
4391 overrodestatus = TRUE;
4392 inmenu = 1;
4393 }
4394 if (commandbinding.arcglyph != NOARCPROTO)
4395 {
4396 ttysetstatusfield(NOWINDOWFRAME, us_statusarc, describearcproto(commandbinding.arcglyph), TRUE);
4397 if (us_curnodeproto == NONODEPROTO) str = x_(""); else
4398 str = describenodeproto(us_curnodeproto);
4399 ttysetstatusfield(NOWINDOWFRAME, us_statusnode, str, TRUE);
4400 overrodestatus = TRUE;
4401 inmenu = 1;
4402 }
4403 }
4404 us_freebindingparse(&commandbinding);
4405 }
4406 }
4407 }
4408 }
4409 }
4410 if (inmenu == 0 && overrodestatus)
4411 {
4412 ttysetstatusfield(NOWINDOWFRAME, us_statusarc, describearcproto(us_curarcproto), TRUE);
4413 if (us_curnodeproto == NONODEPROTO) str = x_(""); else
4414 str = describenodeproto(us_curnodeproto);
4415 ttysetstatusfield(NOWINDOWFRAME, us_statusnode, str, TRUE);
4416 overrodestatus = FALSE;
4417 }
4418
4419 if (gra_inputstate != NOEVENT) return;
4420
4421 if (wf == NOWINDOWFRAME)
4422 {
4423 for(dia = gra_firstactivedialog; dia != NOTDIALOG; dia = dia->nexttdialog)
4424 if (dia->window == frm) break;
4425 if (dia == NOTDIALOG) return;
4426 if (gra_dodialogisinsideuserdrawn(dia, point.x, point.y) == 0) return;
4427 }
4428
4429 x = point.x;
4430 if (wf == NOWINDOWFRAME) y = point.y; else
4431 y = wf->revy - point.y;
4432 event = MOTION;
4433
4434 if ((nFlags & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) == 0)
4435 event |= BUTTONUP;
4436 gra_addeventtoqueue(event, 0, x, y);
4437 }
4438
4439 extern "C" INTBIG sim_window_wavexbar;
4440
gra_setpropercursor(CWnd * frm,int x,int y)4441 int gra_setpropercursor(CWnd *frm, int x, int y)
4442 {
4443 WINDOWFRAME *wf;
4444 INTBIG lx, hx, ly, hy, xfx, xfy;
4445 REGISTER WINDOWPART *w;
4446 REGISTER EDITOR *e;
4447
4448 /* find the appropriate window */
4449 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
4450 if ((CChildFrame *)wf->wndframe == frm) break;
4451 if (wf != NOWINDOWFRAME)
4452 {
4453 /* if the window is known, set the cursor appropriately */
4454 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
4455 {
4456 if (w->frame != wf) continue;
4457 y = wf->revy - y;
4458
4459 /* see if the cursor is over a window partition separator */
4460 us_gettruewindowbounds(w, &lx, &hx, &ly, &hy);
4461 if (x >= lx-1 && x <= lx+1 && y > ly+1 && y < hy-1 &&
4462 us_hasotherwindowpart(lx-10, y, w))
4463 {
4464 setdefaultcursortype(LRCURSOR);
4465 return(1);
4466 } else if (x >= hx-1 && x <= hx+1 && y > ly+1 && y < hy-1 &&
4467 us_hasotherwindowpart(hx+10, y, w))
4468 {
4469 setdefaultcursortype(LRCURSOR);
4470 return(1);
4471 } else if (y >= ly-1 && y <= ly+1 && x > lx+1 && x < hx-1 &&
4472 us_hasotherwindowpart(x, ly-10, w))
4473 {
4474 setdefaultcursortype(UDCURSOR);
4475 return(1);
4476 } else if (y >= hy-1 && y <= hy+1 && x > lx+1 && x < hx-1 &&
4477 us_hasotherwindowpart(x, hy+10, w))
4478 {
4479 setdefaultcursortype(UDCURSOR);
4480 return(1);
4481 }
4482 if (x < w->uselx || x > w->usehx || y < w->usely || y > w->usehy) continue;
4483 if ((w->state&WINDOWTYPE) == WAVEFORMWINDOW)
4484 {
4485 xfx = muldiv(x - w->uselx, w->screenhx - w->screenlx,
4486 w->usehx - w->uselx) + w->screenlx;
4487 xfy = muldiv(y - w->usely, w->screenhy - w->screenly,
4488 w->usehy - w->usely) + w->screenly;
4489 if (abs(xfx - sim_window_wavexbar) < 2 && xfy >= 560)
4490 {
4491 setdefaultcursortype(LRCURSOR);
4492 return(1);
4493 }
4494 }
4495 if ((w->state&WINDOWTYPE) == POPTEXTWINDOW ||
4496 (w->state&WINDOWTYPE) == TEXTWINDOW)
4497 {
4498 e = w->editor;
4499 if ((e->state&EDITORTYPE) == PACEDITOR)
4500 {
4501 if (x <= w->usehx - SBARWIDTH && y >= w->usely + SBARWIDTH && y < e->revy)
4502 {
4503 setdefaultcursortype(IBEAMCURSOR);
4504 return(1);
4505 }
4506 }
4507 }
4508 break;
4509 }
4510 }
4511 setdefaultcursortype(us_normalcursor);
4512 return(0);
4513 }
4514
gra_mousewheelaction(UINT nFlags,short zDelta,CPoint point,CWnd * frm)4515 void gra_mousewheelaction(UINT nFlags, short zDelta, CPoint point, CWnd *frm)
4516 {
4517 WINDOWFRAME *wf;
4518 INTBIG event;
4519 INTBIG x, y;
4520
4521 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
4522 if ((CChildFrame *)wf->wndframe == frm) break;
4523 if (wf == NOWINDOWFRAME) return;
4524
4525 /* set appropriate "button" */
4526 if (zDelta > 0) event = ISBUTTON|ISWHLFWD; else
4527 event = ISBUTTON|ISWHLBKW;
4528
4529 /* add in extras */
4530 if ((nFlags & MK_SHIFT) != 0) event |= SHIFTISDOWN;
4531 if ((nFlags & MK_CONTROL) != 0) event |= CONTROLISDOWN;
4532 if ((GetKeyState(VK_MENU)&0x8000) != 0) event |= ALTISDOWN;
4533
4534 x = point.x;
4535 if (wf == NOWINDOWFRAME) y = point.y; else
4536 y = wf->revy - point.y;
4537 us_state |= DIDINPUT;
4538 gra_addeventtoqueue(event, 0, x, y);
4539 }
4540
gra_keyaction(UINT nChar,INTBIG special,UINT nRepCnt)4541 void gra_keyaction(UINT nChar, INTBIG special, UINT nRepCnt)
4542 {
4543 POINT pt, p2;
4544 CWnd *wnd;
4545 INTBIG event, x, y;
4546
4547 /* determine corner of window */
4548 if (el_curwindowframe == NOWINDOWFRAME) wnd = AfxGetMainWnd(); else
4549 wnd = (CWnd *)el_curwindowframe->wndframe;
4550 p2.x = p2.y = 0;
4551 wnd->MapWindowPoints(0, &p2, 1);
4552
4553 /* determine current cursor coordinates */
4554 GetCursorPos(&pt);
4555 x = pt.x - p2.x;
4556 y = pt.y - p2.y;
4557 if (el_curwindowframe != NOWINDOWFRAME)
4558 y = el_curwindowframe->revy - y;
4559
4560 /* queue the event */
4561 if (nChar == 015) nChar = 012;
4562 event = (nChar & CHARREAD) | ISKEYSTROKE;
4563 us_state |= DIDINPUT;
4564 gra_addeventtoqueue(event, special, x, y);
4565 }
4566
gra_setdefaultcursor(void)4567 void gra_setdefaultcursor(void)
4568 {
4569 int curstate;
4570
4571 curstate = us_cursorstate;
4572 us_cursorstate++;
4573 setdefaultcursortype(curstate);
4574 }
4575
gra_activateframe(CChildFrame * frame,BOOL bActivate)4576 void gra_activateframe(CChildFrame *frame, BOOL bActivate)
4577 {
4578 REGISTER WINDOWFRAME *wf;
4579 REGISTER WINDOWPART *w;
4580
4581 if (!bActivate)
4582 {
4583 if (frame == gra_messageswindow) gra_messagescurrent = FALSE; else
4584 el_curwindowframe = NOWINDOWFRAME;
4585 return;
4586 }
4587
4588 if (frame == gra_messageswindow) gra_messagescurrent = TRUE; else
4589 {
4590 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
4591 if ((CChildFrame *)wf->wndframe == frame) break;
4592 if (wf != NOWINDOWFRAME)
4593 {
4594 el_curwindowframe = wf;
4595 gra_cureditwindowframe = wf;
4596
4597 /* see if the change of window frame invalidates the current window */
4598 if (el_curwindowpart == NOWINDOWPART || el_curwindowpart->frame != wf)
4599 {
4600 /* must choose new window (if not broadcasting) */
4601 if (db_broadcasting == 0)
4602 {
4603 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
4604 {
4605 if (w->frame == wf)
4606 {
4607 (void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key,
4608 (INTBIG)w, VWINDOWPART|VDONTSAVE);
4609 (void)setval((INTBIG)el_curlib, VLIBRARY, x_("curnodeproto"),
4610 (INTBIG)w->curnodeproto, VNODEPROTO);
4611 break;
4612 }
4613 }
4614 }
4615 }
4616 }
4617 }
4618
4619 /* if another windows was activated, make sure the palette is on top */
4620 gra_floatpalette();
4621 }
4622
4623 /*
4624 * Routine to ensure that the floating component menu is on top
4625 */
gra_floatpalette(void)4626 void gra_floatpalette(void)
4627 {
4628 REGISTER WINDOWFRAME *wf;
4629
4630 if (gra_creatingwindow) return;
4631 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
4632 {
4633 if (!wf->floating) continue;
4634 ((CChildFrame *)wf->wndframe)->SetWindowPos(&CWnd::wndTop, 0, 0, 0, 0,
4635 SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
4636 break;
4637 }
4638 }
4639
gra_closeframe(CChildFrame * frame)4640 int gra_closeframe(CChildFrame *frame)
4641 {
4642 WINDOWFRAME *wf;
4643 CHAR *par[2];
4644
4645 if (frame == gra_messageswindow)
4646 {
4647 gra_messagescurrent = FALSE;
4648 gra_messageswindow = 0;
4649 return(1);
4650 }
4651
4652 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
4653 {
4654 if (frame == (CChildFrame *)wf->wndframe) break;
4655 }
4656 if (wf == NOWINDOWFRAME) return(0);
4657
4658 // ((CChildFrame *)wf->wndframe)->SetActiveWindow();
4659 par[0] = x_("delete");
4660 us_window(1, par);
4661 return(0);
4662 }
4663
gra_closeworld(void)4664 int gra_closeworld(void)
4665 {
4666 if (us_preventloss(NOLIBRARY, 0, TRUE)) return(1); /* keep working */
4667 bringdown();
4668 return(0);
4669 }
4670
gra_repaint(CChildFrame * frame,CPaintDC * dc)4671 void gra_repaint(CChildFrame *frame, CPaintDC *dc)
4672 {
4673 WINDOWFRAME *wf;
4674
4675 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
4676 {
4677 if (frame == (CChildFrame *)wf->wndframe)
4678 {
4679 dc->BitBlt(0, 0, wf->swid, wf->shei, (CDC *)wf->hDCOff, 0, 0, SRCCOPY);
4680 break;
4681 }
4682 }
4683 gra_floatpalette();
4684 }
4685
gra_resize(CChildFrame * frame,int cx,int cy)4686 void gra_resize(CChildFrame *frame, int cx, int cy)
4687 {
4688 WINDOWFRAME *wf;
4689 RECT r;
4690 WINDOWPLACEMENT wp;
4691
4692 if (frame->IsIconic()) return;
4693
4694 if (frame == gra_messageswindow)
4695 {
4696 gra_messageswindow->GetWindowPlacement(&wp);
4697 r = wp.rcNormalPosition;
4698 gra_messagesleft = r.left;
4699 gra_messagesright = r.right;
4700 gra_messagestop = r.top;
4701 gra_messagesbottom = r.bottom;
4702 return;
4703 }
4704
4705 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
4706 {
4707 if (frame == (CChildFrame *)wf->wndframe)
4708 {
4709 sizewindowframe(wf, cx, cy);
4710 gra_redrawdisplay(wf);
4711 gra_addeventtoqueue(WINDOWSIZE, 0, wf->windindex, ((cx & 0xFFFF) << 16) | (cy & 0xFFFF));
4712 break;
4713 }
4714 }
4715 gra_floatpalette();
4716 }
4717
gra_movedwindow(CChildFrame * frame,int x,int y)4718 void gra_movedwindow(CChildFrame *frame, int x, int y)
4719 {
4720 RECT fr, cr, r;
4721 int framewid, framehei;
4722 WINDOWPLACEMENT wp;
4723 WINDOWFRAME *wf;
4724
4725 if (frame == gra_messageswindow)
4726 {
4727 gra_messageswindow->GetWindowPlacement(&wp);
4728 r = wp.rcNormalPosition;
4729 gra_messagesleft = r.left;
4730 gra_messagesright = r.right;
4731 gra_messagestop = r.top;
4732 gra_messagesbottom = r.bottom;
4733 return;
4734 }
4735
4736 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
4737 {
4738 if (frame == (CChildFrame *)wf->wndframe)
4739 {
4740 ((CChildFrame *)wf->wndframe)->GetWindowPlacement(&wp);
4741 fr = wp.rcNormalPosition;
4742 ((CChildFrame *)wf->wndframe)->GetClientRect(&cr);
4743 framewid = (fr.right - fr.left) - (cr.right - cr.left);
4744 framehei = (fr.bottom - fr.top) - (cr.bottom - cr.top);
4745 x -= framewid/2; y -= (framehei-framewid/2);
4746 gra_addeventtoqueue(WINDOWMOVE, 0, wf->windindex, ((x & 0xFFFF) << 16) | (y & 0xFFFF));
4747 break;
4748 }
4749 }
4750 gra_floatpalette();
4751 }
4752
gra_resizemain(int cx,int cy)4753 void gra_resizemain(int cx, int cy)
4754 {
4755 WINDOWPLACEMENT wndpl;
4756 CHAR tmp[256], subkey[256], value[256];
4757 CMainFrame *wnd;
4758
4759 gra_redrawstatusindicators();
4760 if (gra_palettewindowframe != NOWINDOWFRAME)
4761 us_drawmenu(-1, gra_palettewindowframe);
4762
4763 /* remember this size in the registry */
4764 wnd = (CMainFrame *)AfxGetMainWnd();
4765 wnd->GetWindowPlacement(&wndpl);
4766 estrcpy(subkey, x_("Software\\Static Free Software\\Electric"));
4767 estrcpy(value, x_("Window_Location"));
4768 esnprintf(tmp, 256, x_("%ld,%ld,%ld,%ld,%d"), wndpl.rcNormalPosition.top, wndpl.rcNormalPosition.left,
4769 wndpl.rcNormalPosition.bottom, wndpl.rcNormalPosition.right, wndpl.showCmd);
4770 (void)gra_setregistry(HKEY_LOCAL_MACHINE, subkey, value, tmp);
4771 }
4772
4773 /* handle interrupts */
gra_onint(void)4774 void gra_onint(void)
4775 {
4776 el_pleasestop = 1;
4777 ttyputerr(_("Interrupted..."));
4778 }
4779
4780 /*************************** SESSION LOGGING ROUTINES ***************************/
4781
4782 extern "C" {
4783 /* Session Playback */
4784 DIALOGITEM gra_sesplaydialogitems[] =
4785 {
4786 /* 1 */ {0, {100,132,124,212}, BUTTON, N_("Yes")},
4787 /* 2 */ {0, {100,8,124,88}, BUTTON, N_("No")},
4788 /* 3 */ {0, {8,8,24,232}, MESSAGE, N_("Electric has found a session log file")},
4789 /* 4 */ {0, {24,8,40,232}, MESSAGE, N_("which may be from a recent crash.")},
4790 /* 5 */ {0, {52,8,68,232}, MESSAGE, N_("Do you wish to replay this session")},
4791 /* 6 */ {0, {68,8,84,232}, MESSAGE, N_("and reconstruct the lost work?")}
4792 };
4793 DIALOG gra_sesplaydialog = {{75,75,208,316}, N_("Replay Log?"), 0, 6, gra_sesplaydialogitems, 0, 0};
4794 };
4795
4796 /* special items for the session playback dialog: */
4797 #define DSPL_YES 1 /* Yes (button) */
4798 #define DSPL_NO 2 /* No (button) */
4799
4800 /*
4801 * routine to create a session logging file
4802 */
logstartrecord(void)4803 void logstartrecord(void)
4804 {
4805 UCHAR1 count;
4806 REGISTER INTBIG itemhit, filestatus;
4807 REGISTER LIBRARY *lib;
4808 REGISTER WINDOWFRAME *wf;
4809 REGISTER WINDOWPART *w;
4810 RECT fr;
4811 WINDOWPLACEMENT wp;
4812 REGISTER VARIABLE *var;
4813 REGISTER void *dia;
4814
4815 /* if there is already a log file, it may be from a previous crash */
4816 filestatus = fileexistence(gra_logfile);
4817 if (filestatus == 1 || filestatus == 3)
4818 {
4819 dia = DiaInitDialog(&gra_sesplaydialog);
4820 for(;;)
4821 {
4822 itemhit = DiaNextHit(dia);
4823 if (itemhit == DSPL_YES || itemhit == DSPL_NO) break;
4824 }
4825 DiaDoneDialog(dia);
4826 if (itemhit == DSPL_YES)
4827 {
4828 if (fileexistence(gra_logfilesave) == 1)
4829 eunlink(gra_logfilesave);
4830 erename(gra_logfile, gra_logfilesave);
4831 (void)logplayback(gra_logfilesave);
4832 }
4833 }
4834
4835 us_logrecord = xcreate(gra_logfile, us_filetypelog, 0, 0);
4836 if (us_logrecord == 0) return;
4837 gra_logbasetime = ticktime();
4838
4839 /* document the header */
4840 xprintf(us_logrecord, x_("; ============= The header:\n"));
4841 xprintf(us_logrecord, x_("; LC n Library count\n"));
4842 xprintf(us_logrecord, x_("; LD name file Library read from disk\n"));
4843 xprintf(us_logrecord, x_("; LM name file Library not read from disk\n"));
4844 xprintf(us_logrecord, x_("; WO n Window offset currently 'n'\n"));
4845 xprintf(us_logrecord, x_("; WT n Window count\n"));
4846 xprintf(us_logrecord, x_("; WC n x y w h Component window, index 'n' at (x,y), size (wXh)\n"));
4847 xprintf(us_logrecord, x_("; WE n x y w h Edit window, index 'n' at (x,y), size (wXh)\n"));
4848 xprintf(us_logrecord, x_("; WP n Window has 'n' partitions\n"));
4849 xprintf(us_logrecord, x_("; WB lx hx ly hy slx shx sly shy state cell loc Window partition (background)\n"));
4850 xprintf(us_logrecord, x_("; WF lx hx ly hy slx shx sly shy state cell loc Window partition (foreground)\n"));
4851 xprintf(us_logrecord, x_("; CI n Current window index\n"));
4852 xprintf(us_logrecord, x_("; CT tech Current technology\n"));
4853
4854 /* log current libraries */
4855 count = 0;
4856 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
4857 if ((lib->userbits&HIDDENLIBRARY) == 0) count++;
4858 xprintf(us_logrecord, x_("LC %d\n"), count);
4859 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
4860 {
4861 if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
4862 if ((lib->userbits&READFROMDISK) != 0)
4863 {
4864 xprintf(us_logrecord, x_("LD %s %s\n"), lib->libname, lib->libfile);
4865 } else
4866 {
4867 xprintf(us_logrecord, x_("LM %s %s\n"), lib->libname, lib->libfile);
4868 }
4869 }
4870
4871 /* log current windows */
4872 xprintf(us_logrecord, x_("WO %ld\n"), gra_newwindowoffset);
4873 count = 0;
4874 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe) count++;
4875 xprintf(us_logrecord, x_("WT %d\n"), count);
4876 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
4877 {
4878 ((CChildFrame *)wf->wndframe)->GetWindowPlacement(&wp);
4879 fr = wp.rcNormalPosition;
4880 if (wf->floating != 0)
4881 {
4882 xprintf(us_logrecord, x_("WC %ld %ld %ld %ld %ld\n"), wf->windindex, fr.left, fr.top,
4883 fr.right-fr.left, fr.bottom-fr.top);
4884 } else
4885 {
4886 xprintf(us_logrecord, x_("WE %ld %ld %ld %ld %ld\n"), wf->windindex, fr.left, fr.top,
4887 fr.right-fr.left, fr.bottom-fr.top);
4888 }
4889
4890 count = 0;
4891 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
4892 if (w->frame == wf) count++;
4893 xprintf(us_logrecord, x_("WP %d\n"), count);
4894 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
4895 {
4896 if (w->frame != wf) continue;
4897 if (w == el_curwindowpart)
4898 {
4899 xprintf(us_logrecord, x_("WF %ld %ld %ld %ld %ld %ld %ld %ld %ld %s %s\n"),
4900 w->uselx, w->usehx, w->usely, w->usehy, w->screenlx, w->screenhx,
4901 w->screenly, w->screenhy, w->state, describenodeproto(w->curnodeproto),
4902 w->location);
4903 } else
4904 {
4905 xprintf(us_logrecord, x_("WB %ld %ld %ld %ld %ld %ld %ld %ld %ld %s %s\n"),
4906 w->uselx, w->usehx, w->usely, w->usehy, w->screenlx, w->screenhx,
4907 w->screenly, w->screenhy, w->state, describenodeproto(w->curnodeproto),
4908 w->location);
4909 }
4910 }
4911 }
4912 xprintf(us_logrecord, x_("CI %ld\n"), gra_windownumberindex);
4913
4914 /* log current technology (macros store this in %H) */
4915 var = getval((INTBIG)us_tool, VTOOL, VSTRING, x_("USER_local_caph"));
4916 if (var != NOVARIABLE)
4917 {
4918 /* technology name found in local variable */
4919 xprintf(us_logrecord, x_("CT %s\n"), (CHAR *)var->addr);
4920 } else
4921 {
4922 /* just write the current technology name */
4923 xprintf(us_logrecord, x_("CT %s\n"), el_curtech->techname);
4924 }
4925
4926 /* document the body */
4927 xprintf(us_logrecord, x_("; ============= The body:\n"));
4928 xprintf(us_logrecord, x_("; KT k x y s w t Key 'k' typed at (x,y), special 's', window 'w', time 't'\n"));
4929 xprintf(us_logrecord, x_("; BP n x y s w t Button 'n' pressed at (x,y), special 's', window 'w', time 't'\n"));
4930 xprintf(us_logrecord, x_("; BD n x y s w t Button 'n' double-clicked at (x,y), special 's', window 'w', time 't'\n"));
4931 xprintf(us_logrecord, x_("; BR n x y s w t Button 'n' released at (x,y), special 's', window 'w', time 't'\n"));
4932 xprintf(us_logrecord, x_("; MP x y s w Motion with button pressed at (x,y), special 's', window 'w'\n"));
4933 xprintf(us_logrecord, x_("; MR x y s w Motion with button released at (x,y), special 's', window 'w'\n"));
4934 xprintf(us_logrecord, x_("; ME m i t Invoked menu 'm', item 'i', time 't'\n"));
4935 xprintf(us_logrecord, x_("; WS w x y t Window 'w' grows to (xXy), time 't'\n"));
4936 xprintf(us_logrecord, x_("; WM w x y t Window 'w' moves to (x,y), time 't'\n"));
4937 xprintf(us_logrecord, x_("; FS path File selected is 'path'\n"));
4938 xprintf(us_logrecord, x_("; PM v t Popup menu selected 'v', time 't'\n"));
4939 xprintf(us_logrecord, x_("; DI w i Item 'i' of dialog 'w' selected\n"));
4940 xprintf(us_logrecord, x_("; DS w i c vals Dialog 'w' scroll item 'i' selects 'c' lines in 'vals'\n"));
4941 xprintf(us_logrecord, x_("; DE w i hc s Dialog 'w' edit item 'i' hit character 'hc', text now 's'\n"));
4942 xprintf(us_logrecord, x_("; DP w i e Dialog 'w' popup item 'i' set to entry 'e'\n"));
4943 xprintf(us_logrecord, x_("; DC w i v Dialog 'w' item 'i' set to value 'v'\n"));
4944 xprintf(us_logrecord, x_("; DM w x y Dialog 'w' coordinates at (x,y)\n"));
4945 xprintf(us_logrecord, x_("; DD w Dialog 'w' done\n"));
4946 }
4947
4948 /*
4949 * routine to begin playback of session logging file "file". The routine
4950 * returns true if there is an error.
4951 */
logplayback(CHAR * file)4952 BOOLEAN logplayback(CHAR *file)
4953 {
4954 CHAR *filename, tempstring[300], *pt, *start;
4955 UCHAR1 count, wcount, i, j, cur, fromdisk;
4956 BOOLEAN floating;
4957 REGISTER WINDOWFRAME *wf;
4958 RECTAREA r;
4959 REGISTER FILE *saveio;
4960 REGISTER WINDOWPART *w, *nextw;
4961 REGISTER INTBIG wid, hei, uselx, usehx, usely, usehy, sindex;
4962 REGISTER INTBIG screenlx, screenhx, screenly, screenhy, state;
4963 REGISTER LIBRARY *lib, *firstlib;
4964
4965 us_logplay = xopen(file, us_filetypelog, x_(""), &filename);
4966 if (us_logplay == NULL) return(TRUE);
4967 ttyputmsg(_("Playing log file..."));
4968 ttyputmsg(_(" Move mouse continuously to advance playback"));
4969 ttyputmsg(_(" Click mouse to abort playback"));
4970 gra_lastplaybacktime = 0;
4971
4972 /* get current libraries */
4973 (void)gra_logreadline(tempstring, 300);
4974 if (estrncmp(tempstring, x_("LC"), 2) != 0)
4975 {
4976 ttyputerr(_("Log file is corrupt (error %d)"), 1);
4977 return(TRUE);
4978 }
4979 count = eatoi(&tempstring[3]);
4980 firstlib = NOLIBRARY;
4981 for(i=0; i<count; i++)
4982 {
4983 (void)gra_logreadline(tempstring, 300);
4984 if (estrncmp(tempstring, x_("LD"), 2) == 0)
4985 {
4986 fromdisk = 1;
4987 } else if (estrncmp(tempstring, x_("LM"), 2) == 0)
4988 {
4989 fromdisk = 0;
4990 } else
4991 {
4992 ttyputerr(_("Log file is corrupt (error %d)"), 2);
4993 return(TRUE);
4994 }
4995 start = &tempstring[3];
4996 for(pt = start; *pt != 0; pt++) if (*pt == ' ') break;
4997 if (*pt == 0)
4998 {
4999 ttyputerr(_("Log file is corrupt (error %d)"), 3);
5000 return(TRUE);
5001 }
5002 *pt++ = 0;
5003 lib = getlibrary(start);
5004 if (lib == NOLIBRARY)
5005 {
5006 /* read library file "gra_localstring" */
5007 lib = newlibrary(start, pt);
5008 if (lib == NOLIBRARY) continue;
5009 if (fromdisk != 0)
5010 {
5011 saveio = us_logplay;
5012 us_logplay = 0;
5013 (void)asktool(io_tool, x_("read"), (INTBIG)lib, (INTBIG)x_("binary"), 0);
5014 us_logplay = saveio;
5015 }
5016 }
5017 if (firstlib == NOLIBRARY) firstlib = lib;
5018 }
5019 selectlibrary(firstlib, TRUE);
5020
5021 /* delete all existing windows */
5022 for(w = el_topwindowpart; w != NOWINDOWPART; w = nextw)
5023 {
5024 nextw = w->nextwindowpart;
5025 db_retractwindowpart(w);
5026 }
5027 el_curwindowpart = NOWINDOWPART;
5028
5029 /* get current windows */
5030 (void)gra_logreadline(tempstring, 300);
5031 if (estrncmp(tempstring, x_("WO"), 2) != 0)
5032 {
5033 ttyputerr(_("Log file is corrupt (error %d)"), 4);
5034 return(TRUE);
5035 }
5036 gra_newwindowoffset = eatoi(&tempstring[3]);
5037
5038 (void)gra_logreadline(tempstring, 300);
5039 if (estrncmp(tempstring, x_("WT"), 2) != 0)
5040 {
5041 ttyputerr(_("Log file is corrupt (error %d)"), 5);
5042 return(TRUE);
5043 }
5044 count = eatoi(&tempstring[3]);
5045
5046 for(i=0; i<count; i++)
5047 {
5048 (void)gra_logreadline(tempstring, 300);
5049 if (estrncmp(tempstring, x_("WC"), 2) == 0)
5050 {
5051 floating = 1;
5052 } else if (estrncmp(tempstring, x_("WE"), 2) == 0)
5053 {
5054 floating = 0;
5055 } else
5056 {
5057 ttyputerr(_("Log file is corrupt (error %d)"), 6);
5058 return(TRUE);
5059 }
5060 pt = &tempstring[3];
5061 sindex = eatoi(getkeyword(&pt, x_(" ")));
5062 r.left = eatoi(getkeyword(&pt, x_(" ")));
5063 r.top = eatoi(getkeyword(&pt, x_(" ")));
5064 wid = eatoi(getkeyword(&pt, x_(" ")));
5065 hei = eatoi(getkeyword(&pt, x_(" ")));
5066 r.right = r.left + (INTSML)wid;
5067 r.bottom = r.top + (INTSML)hei;
5068 if (floating)
5069 {
5070 /* get the floating window frame */
5071 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
5072 if (wf->floating) break;
5073 if (wf == NOWINDOWFRAME) wf = newwindowframe(TRUE, &r);
5074 } else
5075 {
5076 /* create a new window frame */
5077 wf = newwindowframe(FALSE, &r);
5078 }
5079 wf->windindex = sindex;
5080
5081 (void)gra_logreadline(tempstring, 300);
5082 if (estrncmp(tempstring, x_("WP"), 2) != 0)
5083 {
5084 ttyputerr(_("Log file is corrupt (error %d)"), 7);
5085 return(TRUE);
5086 }
5087 wcount = eatoi(&tempstring[3]);
5088 for(j=0; j<wcount; j++)
5089 {
5090 (void)gra_logreadline(tempstring, 300);
5091 if (estrncmp(tempstring, x_("WB"), 2) == 0)
5092 {
5093 cur = 0;
5094 } else if (estrncmp(tempstring, x_("WF"), 2) == 0)
5095 {
5096 cur = 1;
5097 } else
5098 {
5099 ttyputerr(_("Log file is corrupt (error %d)"), 8);
5100 return(TRUE);
5101 }
5102 pt = &tempstring[3];
5103 uselx = eatoi(getkeyword(&pt, x_(" ")));
5104 usehx = eatoi(getkeyword(&pt, x_(" ")));
5105 usely = eatoi(getkeyword(&pt, x_(" ")));
5106 usehy = eatoi(getkeyword(&pt, x_(" ")));
5107 screenlx = eatoi(getkeyword(&pt, x_(" ")));
5108 screenhx = eatoi(getkeyword(&pt, x_(" ")));
5109 screenly = eatoi(getkeyword(&pt, x_(" ")));
5110 screenhy = eatoi(getkeyword(&pt, x_(" ")));
5111 state = eatoi(getkeyword(&pt, x_(" ")));
5112 start = getkeyword(&pt, x_(" "));
5113 while (*pt != 0 && *pt != ' ') pt++;
5114 if (*pt == ' ') pt++;
5115
5116 w = newwindowpart(pt, NOWINDOWPART);
5117 w->buttonhandler = DEFAULTBUTTONHANDLER;
5118 w->charhandler = DEFAULTCHARHANDLER;
5119 w->changehandler = DEFAULTCHANGEHANDLER;
5120 w->termhandler = DEFAULTTERMHANDLER;
5121 w->redisphandler = DEFAULTREDISPHANDLER;
5122 w->uselx = uselx; w->usehx = usehx;
5123 w->usely = usely; w->usehy = usehy;
5124 w->screenlx = screenlx; w->screenhx = screenhx;
5125 w->screenly = screenly; w->screenhy = screenhy;
5126 computewindowscale(w);
5127 w->state = state;
5128 w->curnodeproto = getnodeproto(start);
5129 w->frame = wf;
5130 if (cur != 0) el_curwindowpart = w;
5131 us_redisplay(w);
5132 }
5133 }
5134 (void)gra_logreadline(tempstring, 300);
5135 if (estrncmp(tempstring, x_("CI"), 2) != 0)
5136 {
5137 ttyputerr(_("Log file is corrupt (error %d)"), 9);
5138 return(TRUE);
5139 }
5140 gra_windownumberindex = eatoi(&tempstring[3]);
5141
5142 /* switch to proper technology */
5143 (void)gra_logreadline(tempstring, 300);
5144 if (estrncmp(tempstring, x_("CT"), 2) != 0)
5145 {
5146 ttyputerr(_("Log file is corrupt (error %d)"), 10);
5147 return(TRUE);
5148 }
5149 us_ensurepropertechnology(NONODEPROTO, &tempstring[3], TRUE);
5150
5151 return(FALSE);
5152 }
5153
5154 /*
5155 * routine to terminate session logging
5156 */
logfinishrecord(void)5157 void logfinishrecord(void)
5158 {
5159 if (us_logrecord != NULL)
5160 {
5161 xclose(us_logrecord);
5162 if (fileexistence(gra_logfilesave) == 1)
5163 eunlink(gra_logfilesave);
5164 erename(gra_logfile, gra_logfilesave);
5165 }
5166 us_logrecord = NULL;
5167 }
5168
5169 /*
5170 * Routine to log an event (if logging) of type "inputstate".
5171 * The event has parameters (cursorx,cursory) and "extradata", depending on "inputstate":
5172 * WINDOWSIZE: window "extradata" is now "cursorx" x "cursory"
5173 * WINDOWMOVE: window "extradata" is now at (cursorx, cursory)
5174 * MENUEVENT: selected menu "cursorx", item "cursory"
5175 * FILEREPLY: file selected by standard-file dialog is in "extradata"
5176 * POPUPSELECT: popup menu returned "cursorx"
5177 * DIAITEMCLICK: dialog "special" item "cursorx" clicked
5178 * DIASCROLLSEL: dialog "special" scroll item "cursorx" set to "cursory" entries in "extradata"
5179 * DIAEDITTEXT: dialog "special" edit item "cursorx" changed to "extradata"
5180 * DIAPOPUPSEL: dialog "special" popup item "cursorx" set to entry "cursory"
5181 * DIASETCONTROL: dialog "special" control item "cursorx" changed to "cursory"
5182 * DIAENDDIALOG: dialog "special" terminated
5183 * all others: cursor in (cursorx,cursory) and window index in "extradata"
5184 */
gra_logwriteaction(INTBIG inputstate,INTBIG special,INTBIG cursorx,INTBIG cursory,void * extradata)5185 void gra_logwriteaction(INTBIG inputstate, INTBIG special, INTBIG cursorx, INTBIG cursory,
5186 void *extradata)
5187 {
5188 REGISTER CHAR *filename;
5189 REGISTER INTBIG i, j, trueItem;
5190 REGISTER POPUPMENU *pm;
5191 REGISTER POPUPMENUITEM *mi;
5192
5193 if (us_logrecord == NULL) return;
5194
5195 /* ignore redundant cursor motion */
5196 if (inputstate == MOTION || inputstate == (MOTION|BUTTONUP))
5197 {
5198 i = (INTBIG)extradata;
5199 if (inputstate == gra_lastloggedaction && cursorx == gra_lastloggedx &&
5200 cursory == gra_lastloggedy && i == gra_lastloggedindex)
5201 return;
5202 }
5203 gra_lastloggedaction = inputstate;
5204 gra_lastloggedx = cursorx;
5205 gra_lastloggedy = cursory;
5206 gra_lastloggedindex = (INTBIG)extradata;
5207
5208 if ((inputstate&MOTION) != 0)
5209 {
5210 if ((inputstate&BUTTONUP) != 0)
5211 {
5212 xprintf(us_logrecord, x_("MR %ld %ld %ld %ld\n"),
5213 cursorx, cursory, special, extradata);
5214 } else
5215 {
5216 xprintf(us_logrecord, x_("MP %ld %ld %ld %ld\n"),
5217 cursorx, cursory, special, extradata);
5218 }
5219 } else if ((inputstate&ISKEYSTROKE) != 0)
5220 {
5221 xprintf(us_logrecord, x_("KT '%s' %ld %ld %ld %ld\n"),
5222 us_describeboundkey((INTSML)(inputstate&CHARREAD), special, 1),
5223 cursorx, cursory, extradata, ticktime()-gra_logbasetime);
5224 } else if ((inputstate&ISBUTTON) != 0)
5225 {
5226 if ((inputstate&BUTTONUP) != 0)
5227 {
5228 xprintf(us_logrecord, x_("BR %ld %ld %ld %ld %ld %ld\n"),
5229 inputstate&(WHICHBUTTON|SHIFTISDOWN|ALTISDOWN|CONTROLISDOWN),
5230 cursorx, cursory, special, extradata, ticktime()-gra_logbasetime);
5231 } else
5232 {
5233 if ((inputstate&DOUBLECLICK) != 0)
5234 {
5235 xprintf(us_logrecord, x_("BD %ld %ld %ld %ld %ld %ld\n"),
5236 inputstate&(WHICHBUTTON|SHIFTISDOWN|ALTISDOWN|CONTROLISDOWN),
5237 cursorx, cursory, special, extradata, ticktime()-gra_logbasetime);
5238 } else
5239 {
5240 xprintf(us_logrecord, x_("BP %ld %ld %ld %ld %ld %ld\n"),
5241 inputstate&(WHICHBUTTON|SHIFTISDOWN|ALTISDOWN|CONTROLISDOWN),
5242 cursorx, cursory, special, extradata, ticktime()-gra_logbasetime);
5243 }
5244 }
5245 } else if (inputstate == MENUEVENT)
5246 {
5247 xprintf(us_logrecord, x_("ME %ld %ld %ld"), cursorx, cursory,
5248 ticktime()-gra_logbasetime);
5249 if (cursorx >= 0 && cursorx < gra_pulldownmenucount)
5250 {
5251 pm = us_getpopupmenu(gra_pulldowns[cursorx]);
5252 for(trueItem=j=0; j < pm->total; j++)
5253 {
5254 mi = &pm->list[j];
5255 if (mi->response->active < 0 && *mi->attribute == 0) continue;
5256 trueItem++;
5257 if (trueItem == cursory) break;
5258 }
5259 if (j < pm->total)
5260 xprintf(us_logrecord, x_(" ; command=%s"),
5261 us_stripampersand(mi->attribute));
5262 }
5263 xprintf(us_logrecord, x_("\n"));
5264 } else if (inputstate == FILEREPLY)
5265 {
5266 filename = (CHAR *)extradata;
5267 xprintf(us_logrecord, x_("FS %s\n"), filename);
5268 } else if (inputstate == POPUPSELECT)
5269 {
5270 xprintf(us_logrecord, x_("PM %ld %ld\n"), cursorx, ticktime()-gra_logbasetime);
5271 } else if (inputstate == DIAEDITTEXT)
5272 {
5273 filename = (CHAR *)extradata;
5274 xprintf(us_logrecord, x_("DE %ld %ld %s\n"), special, cursorx, filename);
5275 } else if (inputstate == DIASCROLLSEL)
5276 {
5277 xprintf(us_logrecord, x_("DS %ld %ld %ld"), special, cursorx, cursory);
5278 for(i=0; i<cursory; i++) xprintf(us_logrecord, x_(" %ld"), ((INTBIG *)extradata)[i]);
5279 xprintf(us_logrecord, x_("\n"));
5280 } else if (inputstate == DIAPOPUPSEL)
5281 {
5282 xprintf(us_logrecord, x_("DP %ld %ld %ld\n"), special, cursorx, cursory);
5283 } else if (inputstate == DIASETCONTROL)
5284 {
5285 xprintf(us_logrecord, x_("DC %ld %ld %ld\n"), special, cursorx, cursory);
5286 } else if (inputstate == DIAITEMCLICK)
5287 {
5288 xprintf(us_logrecord, x_("DI %ld %ld\n"), special, cursorx);
5289 } else if (inputstate == DIAUSERMOUSE)
5290 {
5291 xprintf(us_logrecord, x_("DM %ld %ld %ld\n"), special, cursorx, cursory);
5292 } else if (inputstate == DIAENDDIALOG)
5293 {
5294 xprintf(us_logrecord, x_("DD %ld\n"), special);
5295 } else if (inputstate == WINDOWMOVE)
5296 {
5297 xprintf(us_logrecord, x_("WM %ld %ld %ld %ld\n"), extradata,
5298 cursorx, cursory, ticktime()-gra_logbasetime);
5299 } else if (inputstate == WINDOWSIZE)
5300 {
5301 xprintf(us_logrecord, x_("WS %ld %ld %ld %ld\n"), extradata,
5302 cursorx, cursory, ticktime()-gra_logbasetime);
5303 } else
5304 {
5305 ttyputmsg(x_("Unknown event being logged: %ld"), inputstate);
5306 }
5307
5308 /* flush the log file every so often */
5309 gra_logrecordcount++;
5310 if (gra_logrecordcount >= us_logflushfreq)
5311 {
5312 gra_logrecordcount = 0;
5313 xflushbuf(us_logrecord);
5314 }
5315 }
5316
gra_logwritecomment(CHAR * comment)5317 void gra_logwritecomment(CHAR *comment)
5318 {
5319 if (us_logrecord == 0) return;
5320 xprintf(us_logrecord, x_("; %s\n"), comment);
5321 }
5322
gra_loggetnextaction(CHAR * message)5323 BOOLEAN gra_loggetnextaction(CHAR *message)
5324 {
5325 REGISTER BOOLEAN eof;
5326 CHAR tempstring[300], *pt, *start;
5327 REGISTER TDIALOG *dia;
5328 REGISTER WINDOWFRAME *wf;
5329 INTSML boundkey;
5330 INTBIG sellist[MAXSCROLLMULTISELECT], i, x, y, item, count;
5331 UINTBIG nowtime;
5332
5333 eof = gra_logreadline(tempstring, 300);
5334 if (stopping(STOPREASONPLAYBACK)) eof = TRUE;
5335 if (eof)
5336 {
5337 /* stop playback */
5338 ttyputmsg(_("End of session playback file"));
5339 xclose(us_logplay);
5340 us_logplay = NULL;
5341 return(TRUE);
5342 }
5343
5344 /* load the event structure */
5345 if (estrncmp(tempstring, x_("WS"), 2) == 0)
5346 {
5347 gra_inputstate = NOEVENT;
5348 pt = &tempstring[3];
5349 x = eatoi(getkeyword(&pt, x_(" ")));
5350 y = eatoi(getkeyword(&pt, x_(" ")));
5351 wf = gra_getframefromindex(eatoi(getkeyword(&pt, x_(" "))));
5352 nowtime = eatoi(getkeyword(&pt, x_(" ")));
5353 gra_timeoffset += nowtime - gra_lastplaybacktime;
5354 gra_lastplaybacktime = nowtime;
5355 if (wf != NOWINDOWFRAME)
5356 sizewindowframe(wf, x, y);
5357 return(FALSE);
5358 }
5359 if (estrncmp(tempstring, x_("WM"), 2) == 0)
5360 {
5361 gra_inputstate = NOEVENT;
5362 pt = &tempstring[3];
5363 x = eatoi(getkeyword(&pt, x_(" ")));
5364 y = eatoi(getkeyword(&pt, x_(" ")));
5365 wf = gra_getframefromindex(eatoi(getkeyword(&pt, x_(" "))));
5366 nowtime = eatoi(getkeyword(&pt, x_(" ")));
5367 gra_timeoffset += nowtime - gra_lastplaybacktime;
5368 gra_lastplaybacktime = nowtime;
5369 if (wf != NOWINDOWFRAME)
5370 movewindowframe(wf, x, y);
5371 return(FALSE);
5372 }
5373 if (estrncmp(tempstring, x_("DI"), 2) == 0)
5374 {
5375 gra_inputstate = NOEVENT;
5376 pt = &tempstring[3];
5377 dia = gra_getdialogfromindex(eatoi(getkeyword(&pt, x_(" "))));
5378 if (dia == NOTDIALOG) return(FALSE);
5379 item = eatoi(getkeyword(&pt, x_(" ")));
5380 if (dia->modelessitemhit == 0)
5381 {
5382 /* current modal dialog */
5383 dia->dialoghit = item;
5384 } else
5385 {
5386 /* a modeless dialog */
5387 (*dia->modelessitemhit)(dia, item);
5388 }
5389 return(FALSE);
5390 }
5391 if (estrncmp(tempstring, x_("DS"), 2) == 0)
5392 {
5393 gra_inputstate = NOEVENT;
5394 pt = &tempstring[3];
5395 dia = gra_getdialogfromindex(eatoi(getkeyword(&pt, x_(" "))));
5396 if (dia == NOTDIALOG) return(FALSE);
5397 item = eatoi(getkeyword(&pt, x_(" ")));
5398 count = eatoi(getkeyword(&pt, x_(" ")));
5399 for(i=0; i<count; i++) sellist[i] = eatoi(getkeyword(&pt, x_(" ")));
5400 if (count == 1)
5401 {
5402 DiaSelectLine(dia, item, sellist[0]);
5403 } else
5404 {
5405 DiaSelectLines(dia, item, count, sellist);
5406 }
5407 return(FALSE);
5408 }
5409 if (estrncmp(tempstring, x_("DP"), 2) == 0)
5410 {
5411 gra_inputstate = NOEVENT;
5412 pt = &tempstring[3];
5413 dia = gra_getdialogfromindex(eatoi(getkeyword(&pt, x_(" "))));
5414 if (dia == NOTDIALOG) return(FALSE);
5415 item = eatoi(getkeyword(&pt, x_(" ")));
5416 i = eatoi(getkeyword(&pt, x_(" ")));
5417 DiaSetPopupEntry(dia, item, i);
5418 return(FALSE);
5419 }
5420 if (estrncmp(tempstring, x_("DC"), 2) == 0)
5421 {
5422 gra_inputstate = NOEVENT;
5423 pt = &tempstring[3];
5424 dia = gra_getdialogfromindex(eatoi(getkeyword(&pt, x_(" "))));
5425 if (dia == NOTDIALOG) return(FALSE);
5426 item = eatoi(getkeyword(&pt, x_(" ")));
5427 i = eatoi(getkeyword(&pt, x_(" ")));
5428 DiaSetControl(dia, item, i);
5429 return(FALSE);
5430 }
5431 if (estrncmp(tempstring, x_("DE"), 2) == 0)
5432 {
5433 gra_inputstate = NOEVENT;
5434 pt = &tempstring[3];
5435 dia = gra_getdialogfromindex(eatoi(getkeyword(&pt, x_(" "))));
5436 if (dia == NOTDIALOG) return(FALSE);
5437 item = eatoi(getkeyword(&pt, x_(" ")));
5438 while (*pt != 0 && *pt != ' ') pt++;
5439 if (*pt == ' ') pt++;
5440 DiaSetText(dia, item, pt);
5441 if (dia->modelessitemhit == 0)
5442 {
5443 /* current modal dialog */
5444 dia->dialoghit = item;
5445 } else
5446 {
5447 /* a modeless dialog */
5448 (*dia->modelessitemhit)(dia, item);
5449 }
5450 return(FALSE);
5451 }
5452 if (estrncmp(tempstring, x_("DM"), 2) == 0)
5453 {
5454 gra_inputstate = DIAUSERMOUSE;
5455 pt = &tempstring[3];
5456 dia = gra_getdialogfromindex(eatoi(getkeyword(&pt, x_(" "))));
5457 if (dia == NOTDIALOG) return(FALSE);
5458 gra_action.x = eatoi(getkeyword(&pt, x_(" ")));
5459 gra_action.y = eatoi(getkeyword(&pt, x_(" ")));
5460 return(FALSE);
5461 }
5462 if (estrncmp(tempstring, x_("DD"), 2) == 0)
5463 {
5464 pt = &tempstring[3];
5465 dia = gra_getdialogfromindex(eatoi(getkeyword(&pt, x_(" "))));
5466 gra_inputstate = DIAENDDIALOG;
5467 return(FALSE);
5468 }
5469 if (estrncmp(tempstring, x_("ME"), 2) == 0)
5470 {
5471 gra_inputstate = MENUEVENT;
5472 pt = &tempstring[3];
5473 gra_cursorx = eatoi(getkeyword(&pt, x_(" ")));
5474 gra_cursory = eatoi(getkeyword(&pt, x_(" ")));
5475 nowtime = eatoi(getkeyword(&pt, x_(" ")));
5476 gra_timeoffset += nowtime - gra_lastplaybacktime;
5477 gra_lastplaybacktime = nowtime;
5478 return(FALSE);
5479 }
5480 if (estrncmp(tempstring, x_("FS"), 2) == 0)
5481 {
5482 gra_inputstate = FILEREPLY;
5483 pt = &tempstring[3];
5484 if (message != 0) estrcpy(message, pt);
5485 return(FALSE);
5486 }
5487 if (estrncmp(tempstring, x_("PM"), 2) == 0)
5488 {
5489 gra_inputstate = POPUPSELECT;
5490 pt = &tempstring[3];
5491 gra_cursorx = eatoi(getkeyword(&pt, x_(" ")));
5492 nowtime = eatoi(getkeyword(&pt, x_(" ")));
5493 gra_timeoffset += nowtime - gra_lastplaybacktime;
5494 gra_lastplaybacktime = nowtime;
5495 return(FALSE);
5496 }
5497
5498 if (estrncmp(tempstring, x_("MR"), 2) == 0 || estrncmp(tempstring, x_("MP"), 2) == 0)
5499 {
5500 pt = &tempstring[3];
5501 gra_inputstate = MOTION;
5502 gra_cursorx = eatoi(getkeyword(&pt, x_(" ")));
5503 gra_cursory = eatoi(getkeyword(&pt, x_(" ")));
5504 gra_inputspecial = eatoi(getkeyword(&pt, x_(" ")));
5505 i = eatoi(getkeyword(&pt, x_(" ")));
5506 if (tempstring[1] == 'R') gra_inputstate |= BUTTONUP;
5507 } else if (estrncmp(tempstring, x_("KT"), 2) == 0)
5508 {
5509 start = &tempstring[4];
5510 for(i = estrlen(start)-1; i>0; i--)
5511 if (start[i] == '\'') break;
5512 if (i <= 0) return(FALSE);
5513 start[i] = 0;
5514 pt = &start[i+2];
5515 (void)us_getboundkey(start, &boundkey, &gra_inputspecial);
5516 gra_inputstate = ISKEYSTROKE | (boundkey & CHARREAD);
5517 gra_cursorx = eatoi(getkeyword(&pt, x_(" ")));
5518 gra_cursory = eatoi(getkeyword(&pt, x_(" ")));
5519 i = eatoi(getkeyword(&pt, x_(" ")));
5520 nowtime = eatoi(getkeyword(&pt, x_(" ")));
5521 gra_timeoffset += nowtime - gra_lastplaybacktime;
5522 gra_lastplaybacktime = nowtime;
5523 } else if (tempstring[0] == 'B')
5524 {
5525 pt = &tempstring[3];
5526 gra_inputstate = ISBUTTON | eatoi(getkeyword(&pt, x_(" ")));
5527 gra_cursorx = eatoi(getkeyword(&pt, x_(" ")));
5528 gra_cursory = eatoi(getkeyword(&pt, x_(" ")));
5529 gra_inputspecial = eatoi(getkeyword(&pt, x_(" ")));
5530 i = eatoi(getkeyword(&pt, x_(" ")));
5531 if (tempstring[1] == 'D') gra_inputstate |= DOUBLECLICK;
5532 if (tempstring[1] == 'R') gra_inputstate |= BUTTONUP;
5533 nowtime = eatoi(getkeyword(&pt, x_(" ")));
5534 gra_timeoffset += nowtime - gra_lastplaybacktime;
5535 gra_lastplaybacktime = nowtime;
5536 }
5537 wf = gra_getframefromindex(i);
5538 if (wf != NOWINDOWFRAME && wf != el_curwindowframe)
5539 ((CChildFrame *)wf->wndframe)->ActivateFrame();
5540 us_state &= ~GOTXY;
5541 return(FALSE);
5542 }
5543
gra_logreadline(CHAR * string,INTBIG limit)5544 BOOLEAN gra_logreadline(CHAR *string, INTBIG limit)
5545 {
5546 for(;;)
5547 {
5548 if (xfgets(string, limit, us_logplay) != 0) return(TRUE);
5549 if (string[0] != ';') break;
5550 }
5551 return(FALSE);
5552 }
5553
gra_getframefromindex(INTBIG index)5554 WINDOWFRAME *gra_getframefromindex(INTBIG index)
5555 {
5556 REGISTER WINDOWFRAME *wf;
5557
5558 for(wf = el_firstwindowframe; wf != NOWINDOWFRAME; wf = wf->nextwindowframe)
5559 if (wf->windindex == index) return(wf);
5560 return(NOWINDOWFRAME);
5561 }
5562
gra_getdialogfromindex(INTBIG index)5563 TDIALOG *gra_getdialogfromindex(INTBIG index)
5564 {
5565 REGISTER TDIALOG *dia;
5566
5567 for(dia = gra_firstactivedialog; dia != NOTDIALOG; dia = dia->nexttdialog)
5568 if (dia->windindex == index) return(dia);
5569 return(NOTDIALOG);
5570 }
5571
5572 /****************************** MENUS ******************************/
5573
getacceleratorstrings(CHAR ** acceleratorstring,CHAR ** acceleratorprefix)5574 void getacceleratorstrings(CHAR **acceleratorstring, CHAR **acceleratorprefix)
5575 {
5576 *acceleratorstring = _("Ctrl");
5577 *acceleratorprefix = _("Ctrl-");
5578 }
5579
getinterruptkey(void)5580 CHAR *getinterruptkey(void)
5581 {
5582 return(_("Windows-C"));
5583 }
5584
nativepopupmenu(POPUPMENU ** menu,BOOLEAN header,INTBIG left,INTBIG top)5585 INTBIG nativepopupmenu(POPUPMENU **menu, BOOLEAN header, INTBIG left, INTBIG top)
5586 {
5587 INTBIG retval;
5588
5589 retval = gra_nativepopuptif(menu, header, left, top);
5590 gra_logwriteaction(POPUPSELECT, 0, retval, 0, 0);
5591 return(retval);
5592 }
5593
gra_nativepopuptif(POPUPMENU ** menu,BOOLEAN header,INTBIG left,INTBIG top)5594 INTBIG gra_nativepopuptif(POPUPMENU **menu, BOOLEAN header, INTBIG left, INTBIG top)
5595 {
5596 CMainFrame *wnd;
5597 INTBIG j, k, pindex, submenus;
5598 REGISTER POPUPMENUITEM *mi, *submi;
5599 REGISTER POPUPMENU *themenu, **subpmlist;
5600 REGISTER USERCOM *uc;
5601 HMENU popmenu, subpopmenu, *submenulist;
5602 POINT p, p2;
5603 UINT flags;
5604
5605 while (us_logplay != NULL)
5606 {
5607 if (gra_loggetnextaction(0)) break;
5608 j = gra_inputstate;
5609 gra_inputstate = NOEVENT;
5610 if (j == POPUPSELECT) return(gra_cursorx);
5611 }
5612
5613 themenu = *menu;
5614 wnd = (CMainFrame *)AfxGetMainWnd();
5615 flags = TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON;
5616 if (left < 0 || top < 0)
5617 {
5618 p2.x = p2.y = 0;
5619 wnd->MapWindowPoints(0, &p2, 1);
5620 GetCursorPos(&p);
5621 left = p.x - p2.x;
5622 top = p.y - p2.y;
5623 flags |= TPM_CENTERALIGN|TPM_VCENTERALIGN;
5624 } else
5625 {
5626 if (el_curwindowpart != NOWINDOWPART)
5627 top = el_curwindowpart->frame->revy - top;
5628 flags |= TPM_LEFTALIGN;
5629 }
5630 popmenu = CreatePopupMenu();
5631 if (popmenu == 0) return(-1);
5632 if (header)
5633 {
5634 if (AppendMenu(popmenu, MF_STRING, 0, themenu->header) == 0) return(-1);
5635 if (AppendMenu(popmenu, MF_SEPARATOR, 0, 0) == 0) return(-1);
5636 }
5637
5638 /* count the number of submenus */
5639 submenus = 0;
5640 for(j=0; j < themenu->total; j++)
5641 {
5642 mi = &themenu->list[j];
5643 if (*mi->attribute != 0 && mi->response != NOUSERCOM &&
5644 mi->response->menu != NOPOPUPMENU) submenus++;
5645 }
5646 if (submenus > 0)
5647 {
5648 submenulist = (HMENU *)emalloc(submenus * (sizeof (HMENU)), us_tool->cluster);
5649 if (submenulist == 0) return(-1);
5650 subpmlist = (POPUPMENU **)emalloc(submenus * (sizeof (POPUPMENU *)), us_tool->cluster);
5651 if (subpmlist == 0) return(-1);
5652 }
5653
5654 /* load the menus */
5655 submenus = 0;
5656 for(j=0; j < themenu->total; j++)
5657 {
5658 mi = &themenu->list[j];
5659 mi->changed = FALSE;
5660 if (*mi->attribute == 0)
5661 {
5662 if (AppendMenu(popmenu, MF_SEPARATOR, 0, 0) == 0) return(-1);
5663 } else
5664 {
5665 uc = mi->response;
5666 if (uc != NOUSERCOM && uc->menu != NOPOPUPMENU)
5667 {
5668 subpopmenu = CreatePopupMenu();
5669 if (subpopmenu == 0) return(-1);
5670 submenulist[submenus] = subpopmenu;
5671 subpmlist[submenus] = uc->menu;
5672 submenus++;
5673
5674 for(k=0; k < uc->menu->total; k++)
5675 {
5676 submi = &uc->menu->list[k];
5677 if (*submi->attribute == 0)
5678 {
5679 if (AppendMenu(subpopmenu, MF_SEPARATOR, 0, 0) == 0) return(-1);
5680 } else
5681 {
5682 if (AppendMenu(subpopmenu, MF_STRING, (submenus << 16) | (k+1), submi->attribute) == 0) return(-1);
5683 }
5684 }
5685 if (InsertMenu(popmenu, j+2, MF_POPUP | MF_BYPOSITION,
5686 (DWORD)subpopmenu, mi->attribute) == 0)
5687 return(0);
5688 } else
5689 {
5690 if (AppendMenu(popmenu, MF_STRING, j+1, mi->attribute) == 0) return(-1);
5691 }
5692 }
5693 }
5694 pindex = TrackPopupMenu(popmenu, flags, left, top, 0, wnd->m_hWnd, 0) - 1;
5695 if (pindex < 0) return(-1);
5696 j = pindex >> 16;
5697 if (j != 0) *menu = subpmlist[j-1];
5698 DestroyMenu(popmenu);
5699 for(j=0; j<submenus; j++)
5700 DestroyMenu(submenulist[j]);
5701 if (submenus > 0)
5702 {
5703 efree((CHAR *)submenulist);
5704 efree((CHAR *)subpmlist);
5705 }
5706 return(pindex & 0xFFFF);
5707 }
5708
5709 /*
5710 * routine to handle the menu
5711 */
gra_nativemenudoone(INTBIG item,INTBIG menuindex)5712 void gra_nativemenudoone(INTBIG item, INTBIG menuindex)
5713 {
5714 gra_addeventtoqueue(MENUEVENT, 0, menuindex, item);
5715 }
5716
5717 /*
5718 * Routine to establish the "count" pulldown menu names in "par" as the pulldown menu bar
5719 */
nativemenuload(INTBIG count,CHAR * par[])5720 void nativemenuload(INTBIG count, CHAR *par[])
5721 {
5722 REGISTER INTBIG i, menuindex;
5723 REGISTER POPUPMENU *pm;
5724 POPUPMENU *pulls[25];
5725
5726 if (gra_hMenu == 0)
5727 {
5728 gra_hMenu = new CMenu();
5729 gra_hMenu->CreateMenu();
5730 }
5731
5732 for(i=0; i<count; i++)
5733 {
5734 pm = us_getpopupmenu(par[i]);
5735 if (pm == NOPOPUPMENU) continue;
5736 pulls[i] = pm;
5737
5738 menuindex = gra_pulldownindex(pm);
5739 if (menuindex < 0) continue;
5740 if (gra_hMenu->InsertMenu(menuindex, MF_ENABLED | MF_POPUP | MF_BYPOSITION,
5741 (DWORD)gra_pulldownmenus[menuindex]->m_hMenu, pm->header) == 0)
5742 {
5743 ttyputerr(_("Item %s can't be inserted in menu bar"), par[i]);
5744 return;
5745 }
5746 }
5747 CWnd* parent = AfxGetMainWnd();
5748 CMenu* lastMenu = parent->GetMenu();
5749 if (parent->SetMenu(gra_hMenu) == 0)
5750 {
5751 ttyputerr(_("SetMenu failed"));
5752 return;
5753 }
5754 gra_hMenu->Detach();
5755 parent->DrawMenuBar();
5756 }
5757
5758 /*
5759 * Routine to create a pulldown menu from popup menu "pm". Returns an index to
5760 * the table of pulldown menus (-1 on error).
5761 */
gra_pulldownindex(POPUPMENU * pm)5762 INTBIG gra_pulldownindex(POPUPMENU *pm)
5763 {
5764 REGISTER INTBIG i, pindex;
5765 CMenu **newpulldownmenus;
5766 CHAR **newpulldowns;
5767
5768 for(i=0; i<gra_pulldownmenucount; i++)
5769 if (namesame(gra_pulldowns[i], pm->name) == 0) return(i);
5770
5771 /* allocate new space with one more */
5772 newpulldownmenus = (CMenu **)emalloc((gra_pulldownmenucount+1) *
5773 (sizeof (CMenu *)), us_tool->cluster);
5774 if (newpulldownmenus == 0) return(-1);
5775 newpulldowns = (CHAR **)emalloc((gra_pulldownmenucount+1) *
5776 (sizeof (CHAR *)), us_tool->cluster);
5777 if (newpulldowns == 0) return(-1);
5778
5779 /* copy former arrays then delete them */
5780 for(i=0; i<gra_pulldownmenucount; i++)
5781 {
5782 newpulldownmenus[i] = gra_pulldownmenus[i];
5783 newpulldowns[i] = gra_pulldowns[i];
5784 }
5785 if (gra_pulldownmenucount != 0)
5786 {
5787 efree((CHAR *)gra_pulldownmenus);
5788 efree((CHAR *)gra_pulldowns);
5789 }
5790
5791 gra_pulldownmenus = newpulldownmenus;
5792 gra_pulldowns = newpulldowns;
5793
5794 pindex = gra_pulldownmenucount++;
5795 (void)allocstring(&gra_pulldowns[pindex], pm->name, us_tool->cluster);
5796 gra_pulldownmenus[pindex] = gra_makepdmenu(pm);
5797 if (gra_pulldownmenus[pindex] == 0) return(-1);
5798 return(pindex);
5799 }
5800
gra_makepdmenu(POPUPMENU * pm)5801 CMenu *gra_makepdmenu(POPUPMENU *pm)
5802 {
5803 CMenu *hPrevMenu, *hMenu;
5804 REGISTER USERCOM *uc;
5805 REGISTER POPUPMENUITEM *mi;
5806 REGISTER INTBIG j, submenuindex, len, idIndex;
5807 INTSML key;
5808 INTBIG special;
5809 REGISTER INTBIG flags;
5810 REGISTER CHAR *pt;
5811 CHAR myline[100];
5812
5813 hMenu = new CMenu();
5814 if (hMenu->CreatePopupMenu() == 0) return(0);
5815
5816 idIndex = 0;
5817 for(j=0; j < pm->total; j++)
5818 {
5819 mi = &pm->list[j];
5820 uc = mi->response;
5821 if (uc->active < 0)
5822 {
5823 if (*mi->attribute == 0)
5824 {
5825 if (hMenu->AppendMenu(MF_SEPARATOR) == 0) return(0);
5826 } else
5827 {
5828 if (hMenu->AppendMenu(MF_STRING | MF_DISABLED, gra_menures[idIndex++], mi->attribute) == 0) return(0);
5829 }
5830 continue;
5831 }
5832
5833 if (uc->menu != NOPOPUPMENU)
5834 {
5835 hPrevMenu = hMenu;
5836 idIndex++;
5837 submenuindex = gra_pulldownindex(uc->menu);
5838 if (hPrevMenu->InsertMenu(-1, MF_POPUP | MF_BYPOSITION,
5839 (DWORD)gra_pulldownmenus[submenuindex]->m_hMenu, mi->attribute) == 0)
5840 return(0);
5841 continue;
5842 }
5843 flags = 0;
5844 if (mi->attribute[0] == '>')
5845 {
5846 flags = MF_CHECKED;
5847 estrcpy(myline, &mi->attribute[1]);
5848 } else
5849 {
5850 estrcpy(myline, mi->attribute);
5851 }
5852 len = estrlen(myline);
5853 if (myline[len-1] == '<') myline[len-1] = 0;
5854 for(pt = myline; *pt != 0; pt++) if (*pt == '/' || *pt == '\\') break;
5855 if (*pt != 0)
5856 {
5857 (void)us_getboundkey(pt, &key, &special);
5858 esnprintf(pt, 50, x_("\t%s"), us_describeboundkey(key, special, 1));
5859 }
5860 if (hMenu->AppendMenu(MF_STRING|flags, gra_menures[idIndex++], myline) == 0) return(0);
5861 }
5862 return(hMenu);
5863 }
5864
5865 /* routine to redraw entry "pindex" of popupmenu "pm" because it changed */
nativemenurename(POPUPMENU * pm,INTBIG pindex)5866 void nativemenurename(POPUPMENU *pm, INTBIG pindex)
5867 {
5868 INTBIG i, j, k, len, key, idIndex;
5869 REGISTER INTBIG flags;
5870 CHAR line[100], *pt, slash;
5871 USERCOM *uc;
5872 REGISTER POPUPMENUITEM *mi;
5873
5874 /* find this pulldown menu */
5875 for(i=0; i<gra_pulldownmenucount; i++)
5876 if (namesame(gra_pulldowns[i], pm->name) == 0) break;
5877 if (i >= gra_pulldownmenucount) return;
5878
5879 /* make sure the menu didn't change size */
5880 j = (INTBIG)gra_pulldownmenus[i]->GetMenuItemCount();
5881 if (pm->total != j)
5882 {
5883 if (pm->total > j)
5884 {
5885 /* must add new entries */
5886 for(k=j; k<pm->total; k++)
5887 gra_pulldownmenus[i]->AppendMenu(MF_STRING, gra_menures[k], x_("X"));
5888 } else
5889 {
5890 /* must delete extra entries */
5891 for(k=pm->total; k<j; k++)
5892 gra_pulldownmenus[i]->RemoveMenu(pm->total, MF_BYPOSITION);
5893 }
5894 }
5895
5896 idIndex = 0;
5897 for(j=0; j < pm->total; j++)
5898 {
5899 mi = &pm->list[j];
5900 uc = mi->response;
5901 if (j == pindex) break;
5902 if (uc->active < 0 && *mi->attribute == 0) continue;
5903 idIndex++;
5904 }
5905 if (uc->active < 0)
5906 {
5907 if (*pm->list[pindex].attribute == 0)
5908 {
5909 gra_pulldownmenus[i]->ModifyMenu(pindex, MF_BYPOSITION|MF_SEPARATOR);
5910 return;
5911 } else
5912 {
5913 gra_pulldownmenus[i]->EnableMenuItem(pindex, MF_BYPOSITION|MF_GRAYED);
5914 }
5915 } else
5916 {
5917 gra_pulldownmenus[i]->EnableMenuItem(pindex, MF_BYPOSITION|MF_ENABLED);
5918 }
5919
5920 /* copy and examine the menu string */
5921 flags = 0;
5922 if (pm->list[pindex].attribute[0] == '>')
5923 {
5924 flags = MF_CHECKED;
5925 (void)estrcpy(line, &pm->list[pindex].attribute[1]);
5926 } else
5927 {
5928 (void)estrcpy(line, pm->list[pindex].attribute);
5929 }
5930 len = estrlen(line);
5931 if (line[len-1] == '<') line[len-1] = 0;
5932
5933 /* handle single-key equivalents */
5934 for(pt = line; *pt != 0; pt++) if (*pt == '/' || *pt == '\\') break;
5935 if (*pt != 0)
5936 {
5937 slash = *pt;
5938 *pt++ = 0;
5939 len = estrlen(line);
5940 if (*pt != 0)
5941 {
5942 if (estrlen(pt) > 1)
5943 {
5944 esnprintf(&line[len], 50, x_("\t%s"), pt);
5945 } else
5946 {
5947 key = *pt & 0xFF;
5948 if (slash == '/')
5949 {
5950 esnprintf(&line[len], 50, x_("\tCtrl-%c"), key);
5951 } else
5952 {
5953 esnprintf(&line[len], 50, x_("\t%c"), key);
5954 }
5955 }
5956 }
5957 }
5958 gra_pulldownmenus[i]->ModifyMenu(pindex, MF_BYPOSITION|MF_STRING|flags, gra_menures[idIndex], line);
5959 }
5960
5961 /****************************** DIALOGS ******************************/
5962
5963 /*
5964 * Routine to initialize a dialog described by "dialog".
5965 * Returns the address of the dialog object (0 if dialog cannot be initialized).
5966 */
DiaInitDialog(DIALOG * dialog)5967 void *DiaInitDialog(DIALOG *dialog)
5968 {
5969 TDIALOG *dia;
5970
5971 dia = (TDIALOG *)emalloc(sizeof (TDIALOG), db_cluster);
5972 if (dia == 0) return(0);
5973 if (gra_initdialog(dialog, dia, FALSE)) return(0);
5974 return(dia);
5975 }
5976
5977 /*
5978 * Routine to initialize dialog "dialog" in modeless style, calling
5979 * "itemhit" for each hit.
5980 */
DiaInitDialogModeless(DIALOG * dialog,void (* itemhit)(void * dia,INTBIG item))5981 void *DiaInitDialogModeless(DIALOG *dialog, void (*itemhit)(void *dia, INTBIG item))
5982 {
5983 TDIALOG *dia;
5984
5985 dia = (TDIALOG *)emalloc(sizeof (TDIALOG), db_cluster);
5986 if (dia == 0) return(0);
5987 if (gra_initdialog(dialog, dia, TRUE)) return(0);
5988 dia->modelessitemhit = itemhit;
5989 return(dia);
5990 }
5991
5992 /* Internal routine to initialize dialog structure "dialog" into "dia" */
gra_initdialog(DIALOG * dialog,TDIALOG * dia,BOOLEAN modeless)5993 BOOLEAN gra_initdialog(DIALOG *dialog, TDIALOG *dia, BOOLEAN modeless)
5994 {
5995 DLGTEMPLATE *dtheader;
5996 WORD *dtmenu, *dtclass, *dttitle;
5997 int headerlength, menulength, classlength, titlelength, itemslength,
5998 *itemlengths, i, j, len, itemtype, style, itemclass, totallen,
5999 dialogdbnx, dialogdbny, dialogdbux, dialogdbuy;
6000 INTBIG dbu, dbuL, dbuH;
6001 DLGITEMTEMPLATE **dtitems;
6002 RECT r;
6003 UCHAR1 *descblock, *pt;
6004 CHAR *title, *msg;
6005 WORD output[100];
6006 wchar_t *woutput;
6007 CProgressCtrl *prog;
6008 CListBoxEx *list;
6009 CStatic *stat;
6010 CWnd *wnd;
6011 CSize textSize;
6012 REGISTER void *infstr;
6013 HFONT hf;
6014
6015 /* add this to the list of active dialogs */
6016 dia->nexttdialog = gra_firstactivedialog;
6017 gra_firstactivedialog = dia;
6018
6019 /* be sure the dialog is translated */
6020 DiaTranslate(dialog);
6021
6022 /*
6023 * for small fonts, dbuH = 16, dbuL = 8,
6024 * for large fonts, dbuH = 20, dbuL = 10
6025 */
6026 dbu = GetDialogBaseUnits();
6027 dbuL = dbu & 0xFFFF;
6028 dbuH = (dbu >> 16) & 0xFFFF;
6029 dialogdbnx = 2 * (46-dbuL)-1; dialogdbux = 14 * dbuL;
6030 dialogdbny = 131 * 8; dialogdbuy = 105 * dbuH;
6031
6032 dia->window = new CElectricDialog();
6033 dia->itemdesc = dialog;
6034 dia->windindex = gra_windownumberindex++;
6035 dia->numlocks = 0;
6036 dia->modelessitemhit = 0;
6037 dia->redrawroutine = 0;
6038
6039 /* compute size of some items to automatically scale them */
6040 #ifdef INTERNATIONAL
6041 CDC *dc;
6042 CFont *cf;
6043 hf = (HFONT)GetStockObject(SYSTEM_FONT);
6044 cf = CFont::FromHandle(hf);
6045 dc = AfxGetApp()->m_pMainWnd->GetDC();
6046 dc->SelectObject(cf);
6047 for(i=0; i<dialog->items; i++)
6048 {
6049 itemtype = dialog->list[i].type & ITEMTYPE;
6050 switch (itemtype)
6051 {
6052 case DEFBUTTON:
6053 case BUTTON:
6054 case CHECK:
6055 case RADIO:
6056 case MESSAGE:
6057 int offset, amt;
6058 if (itemtype == BUTTON || itemtype == DEFBUTTON) offset = 8; else
6059 if (itemtype == CHECK || itemtype == RADIO) offset = 16; else
6060 offset = 0;
6061 pt = dialog->list[i].msg;
6062 textSize = dc->GetTextExtent(pt, estrlen(pt));
6063 j = textSize.cx * dialogdbnx / dialogdbux;
6064 amt = (j + offset) - (dialog->list[i].r.right - dialog->list[i].r.left);
6065 if (amt > 0)
6066 {
6067 for(j=0; j<dialog->items; j++)
6068 {
6069 if (j == i) continue;
6070 if (dialog->list[j].r.left >= dialog->list[i].r.right &&
6071 dialog->list[j].r.left < dialog->list[i].r.right+amt)
6072 {
6073 dialog->list[j].r.left += amt;
6074 dialog->list[j].r.right += amt;
6075 }
6076 }
6077 dialog->list[i].r.right += amt;
6078 }
6079 break;
6080 }
6081 }
6082 for(i=0; i<dialog->items; i++)
6083 {
6084 j = dialog->list[i].r.right + 5;
6085 if (j < dialog->windowRect.right - dialog->windowRect.left) continue;
6086 dialog->windowRect.right = dialog->windowRect.left + j;
6087 }
6088 AfxGetApp()->m_pMainWnd->ReleaseDC(dc);
6089 #endif
6090
6091 /* determine item lengths */
6092 itemlengths = (int *)emalloc(dialog->items * (sizeof (int)), us_tool->cluster);
6093 if (itemlengths == 0) return(TRUE);
6094 dtitems = (DLGITEMTEMPLATE **)emalloc(dialog->items * (sizeof (DLGITEMTEMPLATE *)), us_tool->cluster);
6095 if (dtitems == 0) return(TRUE);
6096 itemslength = 0;
6097 for(i=0; i<dialog->items; i++)
6098 {
6099 itemlengths[i] = (sizeof DLGITEMTEMPLATE) + 3 * (sizeof (WORD));
6100 itemtype = dialog->list[i].type;
6101 switch (itemtype&ITEMTYPE)
6102 {
6103 case BUTTON:
6104 case DEFBUTTON:
6105 case CHECK:
6106 case RADIO:
6107 case EDITTEXT:
6108 case MESSAGE:
6109 itemlengths[i] += (estrlen(dialog->list[i].msg) + 1) * (sizeof (WORD));
6110 break;
6111 default:
6112 itemlengths[i] += 1 * (sizeof (WORD));
6113 break;
6114 }
6115 itemlengths[i] = (itemlengths[i] + 3) & ~3;
6116 itemslength += itemlengths[i];
6117 }
6118
6119 /* allocate space for entire dialog template */
6120 headerlength = sizeof (DLGTEMPLATE);
6121 menulength = sizeof (WORD);
6122 classlength = sizeof (WORD);
6123 if (dialog->movable != 0) title = dialog->movable; else
6124 title = x_("");
6125 titlelength = (estrlen(title) + 1) * (sizeof (WORD));
6126 i = headerlength + menulength + classlength + titlelength;
6127 totallen = (i + 3) & ~3;
6128 descblock = (UCHAR1 *)emalloc(totallen + itemslength, us_tool->cluster);
6129 if (descblock == 0) return(TRUE);
6130 pt = descblock;
6131 dtheader = (DLGTEMPLATE *)pt; pt += headerlength;
6132 dtmenu = (WORD *)pt; pt += menulength;
6133 dtclass = (WORD *)pt; pt += classlength;
6134 dttitle = (WORD *)pt; pt += titlelength;
6135 for(i=0; i<dialog->items; i++)
6136 {
6137 pt = (UCHAR1 *)(((DWORD)pt + 3) & ~3);
6138 dtitems[i] = (DLGITEMTEMPLATE *)pt;
6139 pt += itemlengths[i];
6140 }
6141
6142 /* load dialog template header */
6143 dtheader->style = WS_VISIBLE | WS_DLGFRAME | WS_POPUP /* | DS_ABSALIGN */;
6144 if (dialog->movable != 0) dtheader->style |= WS_CAPTION | DS_MODALFRAME;
6145 dtheader->dwExtendedStyle = WS_EX_CONTROLPARENT;
6146 dtheader->cdit = (unsigned short)dialog->items;
6147 dtheader->x = dialog->windowRect.left;
6148 dtheader->y = dialog->windowRect.top;
6149 dtheader->cx = (dialog->windowRect.right - dialog->windowRect.left) * dialogdbnx / dialogdbux;
6150 dtheader->cy = (dialog->windowRect.bottom - dialog->windowRect.top) * dialogdbny / dialogdbuy;
6151
6152 /* no menu or class in this dialog */
6153 dtmenu[0] = 0;
6154 dtclass[0] = 0;
6155
6156 /* load the dialog title */
6157 woutput = (wchar_t *)output;
6158 #ifdef _UNICODE
6159 len = estrlen(title);
6160 for(j=0; j<len; j++) *dttitle++ = title[j];
6161 #else
6162 len = MultiByteToWideChar(CP_ACP, 0, title, estrlen(title), woutput, 100);
6163 for(j=0; j<len; j++) *dttitle++ = output[j];
6164 #endif
6165 *dttitle++ = 0;
6166
6167 /* find the default button */
6168 dia->defaultbutton = 1;
6169 for(i=0; i<dialog->items; i++)
6170 {
6171 itemtype = dialog->list[i].type;
6172 if ((itemtype&ITEMTYPE) == DEFBUTTON) dia->defaultbutton = i+1;
6173 }
6174
6175 /* load the items */
6176 for(i=0; i<dialog->items; i++)
6177 {
6178 dtitems[i]->x = dialog->list[i].r.left * dialogdbnx / dialogdbux;
6179 dtitems[i]->y = dialog->list[i].r.top * dialogdbny / dialogdbuy;
6180 dtitems[i]->cx = (dialog->list[i].r.right - dialog->list[i].r.left) * dialogdbnx / dialogdbux;
6181 dtitems[i]->cy = (dialog->list[i].r.bottom - dialog->list[i].r.top) * dialogdbny / dialogdbuy;
6182 dtitems[i]->dwExtendedStyle = 0;
6183 dtitems[i]->id = i+ID_DIALOGITEM_0;
6184 itemtype = dialog->list[i].type;
6185 switch (itemtype&ITEMTYPE)
6186 {
6187 case BUTTON:
6188 case DEFBUTTON:
6189 itemclass = 0x80;
6190 style = WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON | WS_TABSTOP;
6191 if (i+1 == dia->defaultbutton) style |= BS_DEFPUSHBUTTON;
6192 break;
6193 case CHECK:
6194 itemclass = 0x80;
6195 style = WS_VISIBLE | WS_CHILD | BS_CHECKBOX | WS_TABSTOP;
6196 break;
6197 case RADIO:
6198 itemclass = 0x80;
6199 style = WS_VISIBLE | WS_CHILD | BS_RADIOBUTTON | WS_TABSTOP;
6200 break;
6201 case EDITTEXT:
6202 itemclass = 0x81;
6203 style = WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | WS_TABSTOP;
6204 if (dtitems[i]->cy > 10) style |= ES_MULTILINE;
6205 dtitems[i]->y--;
6206 dtitems[i]->cy += 2;
6207 break;
6208 case MESSAGE:
6209 itemclass = 0x82;
6210 style = WS_CHILD | WS_VISIBLE | SS_LEFT;
6211 if ((itemtype&INACTIVE) == 0) style |= SS_NOTIFY;
6212 dtitems[i]->y--;
6213 dtitems[i]->cy += 2;
6214 break;
6215 case PROGRESS:
6216 case SCROLL:
6217 case SCROLLMULTI:
6218 /* dummy: create it for real later */
6219 itemclass = 0x82;
6220 style = WS_CHILD;
6221 dtitems[i]->id += PROGRESSOFFSET;
6222 break;
6223 case USERDRAWN:
6224 itemclass = 0x82;
6225 style = WS_CHILD | WS_VISIBLE;
6226 dtitems[i]->x += 1000;
6227 dtitems[i]->y += 1000;
6228 break;
6229 case POPUP:
6230 itemclass = 0x85;
6231 dtitems[i]->cy *= 8;
6232 dtitems[i]->y -= 2;
6233 style = WS_CHILD | WS_VISIBLE | WS_VSCROLL | CBS_DROPDOWNLIST | WS_TABSTOP;
6234 break;
6235 case ICON:
6236 itemclass = 0x82;
6237 style = WS_CHILD | WS_VISIBLE;
6238 dtitems[i]->x += 1000;
6239 dtitems[i]->y += 1000;
6240 if ((itemtype&INACTIVE) == 0) style |= SS_NOTIFY;
6241 break;
6242 default:
6243 itemclass = 0x82;
6244 style = WS_CHILD | SS_LEFT;
6245 break;
6246 }
6247 dtitems[i]->style = style;
6248 pt = ((UCHAR1 *)dtitems[i]) + (sizeof (DLGITEMTEMPLATE));
6249 dtclass = (WORD *)pt;
6250 *dtclass++ = 0xFFFF;
6251 *dtclass++ = itemclass;
6252 switch (itemtype&ITEMTYPE)
6253 {
6254 case BUTTON:
6255 case DEFBUTTON:
6256 case CHECK:
6257 case RADIO:
6258 case EDITTEXT:
6259 case MESSAGE:
6260 msg = dialog->list[i].msg;
6261 woutput = (wchar_t *)output;
6262 #ifdef _UNICODE
6263 len = estrlen(msg);
6264 for(j=0; j<len; j++) *dtclass++ = msg[j];
6265 #else
6266 len = MultiByteToWideChar(CP_ACP, 0, msg, estrlen(msg), woutput, 100);
6267 for(j=0; j<len; j++) *dtclass++ = output[j];
6268 #endif
6269 *dtclass++ = 0;
6270 break;
6271 default:
6272 *dtclass++ = 0;
6273 break;
6274 }
6275 *dtclass++ = 0;
6276 }
6277
6278 /* create the dialog */
6279 if (dia->window->CreateIndirect(dtheader) == 0)
6280 {
6281 return(TRUE);
6282 }
6283
6284 /* finish initialization */
6285 wnd = 0;
6286 for(i=0; i<dialog->items; i++)
6287 {
6288 itemtype = dialog->list[i].type;
6289 switch (itemtype&ITEMTYPE)
6290 {
6291 case EDITTEXT:
6292 if (wnd == 0)
6293 wnd = dia->window->GetDlgItem(i+ID_DIALOGITEM_0);
6294 (void)allocstring((CHAR **)&dialog->list[i].data, dialog->list[i].msg, el_tempcluster);
6295 break;
6296 case PROGRESS:
6297 stat = (CStatic *)dia->window->GetDlgItem(i+ID_DIALOGITEM_0+PROGRESSOFFSET);
6298 stat->GetWindowRect(&r);
6299 dia->window->ScreenToClient(&r);
6300 prog = new CProgressCtrl();
6301 prog->Create(WS_CHILD | WS_VISIBLE, r, dia->window, i+ID_DIALOGITEM_0);
6302 prog->ModifyStyleEx(0, WS_EX_CLIENTEDGE); /* makes it look 3D */
6303 break;
6304 case SCROLL:
6305 case SCROLLMULTI:
6306 r.left = dialog->list[i].r.left;
6307 r.top = dialog->list[i].r.top;
6308 r.right = dialog->list[i].r.right;
6309 r.bottom = dialog->list[i].r.bottom;
6310 style = WS_BORDER | WS_CHILD | WS_VISIBLE | LBS_USETABSTOPS |
6311 WS_VSCROLL | WS_HSCROLL | LBS_WANTKEYBOARDINPUT | LBS_SORT | WS_TABSTOP;
6312 if ((itemtype&ITEMTYPE) == SCROLLMULTI)
6313 style |= LBS_EXTENDEDSEL;
6314 if ((itemtype&INACTIVE) == 0) style |= LBS_NOTIFY;
6315 list = new CListBoxEx();
6316 list->vdia = dia;
6317 list->Create(style, r, dia->window, i+ID_DIALOGITEM_0);
6318 list->ModifyStyleEx(0, WS_EX_CLIENTEDGE); /* makes it look 3D */
6319 hf = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
6320 list->SetFont(CFont::FromHandle(hf));
6321 list->SetTabStops(1);
6322 break;
6323 case ICON:
6324 dialog->list[i].data = (INTBIG)dialog->list[i].msg;
6325 break;
6326 }
6327 }
6328 if (wnd == 0)
6329 wnd = dia->window->GetDlgItem(dia->defaultbutton-1+ID_DIALOGITEM_0);
6330 dia->window->GotoDlgCtrl(wnd);
6331 dia->window->SetDefID(dia->defaultbutton-1+ID_DIALOGITEM_0);
6332
6333 /* determine location of dialog in screen coordinates */
6334 dia->window->GetWindowRect(&r);
6335
6336 /*
6337 * For some reason, the dialog doesn't always appear where we want it.
6338 * Probably because it is forced to be placed relative to the previous dialog,
6339 * rather than at an absolute location, as we want.
6340 *
6341 * The hack is to move the dialog after creating it. This causes a side-effect
6342 * when the mouse is set to "snap to cursor": the snapping happens too soon and
6343 * the cursor is in the wrong place. So we must move the cursor too.
6344 */
6345 if (r.left != dtheader->x || r.top != dtheader->y)
6346 {
6347 BOOL res;
6348 INTBIG dx, dy;
6349 POINT cp;
6350
6351 dia->window->SetWindowPos(0, dtheader->x, dtheader->y, 0, 0,
6352 SWP_NOZORDER|SWP_NOSIZE);
6353 dx = dtheader->x - r.left;
6354 dy = dtheader->y - r.top;
6355 dia->window->GetWindowRect(&r);
6356
6357 /* see if mouse is set to "snap to cursor" */
6358 SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0, &res, 0);
6359 if (res)
6360 {
6361 /* mouse snapping on: adjust position */
6362 GetCursorPos(&cp);
6363 SetCursorPos(cp.x + dx, cp.y + dy);
6364 }
6365 }
6366
6367 dia->firstpoint.x = r.left;
6368 dia->firstpoint.y = r.top;
6369
6370 dia->useritemdoubleclick = 0;
6371 dia->usertextsize = 8;
6372
6373 efree((CHAR *)itemlengths);
6374 efree((CHAR *)dtitems);
6375 efree((CHAR *)descblock);
6376
6377 if (*title == 0) title = _("UNTITLED");
6378 infstr = initinfstr();
6379 formatinfstr(infstr, _("Start dialog %s"), title);
6380 gra_logwritecomment(returninfstr(infstr));
6381 dia->dialoghit = -1;
6382 return(FALSE);
6383 }
6384
6385 /*
6386 * Routine to handle actions and return the next item hit.
6387 */
DiaNextHit(void * vdia)6388 INTBIG DiaNextHit(void *vdia)
6389 {
6390 INTBIG item;
6391 TDIALOG *dia;
6392
6393 dia = (TDIALOG *)vdia;
6394 for(;;)
6395 {
6396 flushscreen();
6397 gra_nextevent();
6398 if (dia->dialoghit != -1)
6399 {
6400 item = dia->dialoghit;
6401 dia->dialoghit = -1;
6402 return(item);
6403 }
6404 }
6405 }
6406
DiaDoneDialog(void * vdia)6407 void DiaDoneDialog(void *vdia)
6408 {
6409 REGISTER INTBIG dx, dy, i, itemtype;
6410 RECT rect;
6411 TDIALOG *dia, *ldia, *odia;
6412
6413 dia = (TDIALOG *)vdia;
6414
6415 /* remove this from the list of active dialogs */
6416 ldia = NOTDIALOG;
6417 for(odia = gra_firstactivedialog; odia != NOTDIALOG; odia = odia->nexttdialog)
6418 {
6419 if (odia == dia) break;
6420 ldia = odia;
6421 }
6422 if (odia != NOTDIALOG)
6423 {
6424 if (ldia == NOTDIALOG) gra_firstactivedialog = dia->nexttdialog; else
6425 ldia->nexttdialog = dia->nexttdialog;
6426 }
6427
6428 /* if playing back, search for end-dialog marker */
6429 while (us_logplay != NULL)
6430 {
6431 if (gra_loggetnextaction(0)) break;
6432 if (gra_inputstate == DIAENDDIALOG) break;
6433 gra_inputstate = NOEVENT;
6434 }
6435 gra_inputstate = NOEVENT;
6436 gra_logwriteaction(DIAENDDIALOG, dia->windindex, 0, 0, 0);
6437
6438 /* free memory used by edit text fields */
6439 for(i=0; i<dia->itemdesc->items; i++)
6440 {
6441 itemtype = dia->itemdesc->list[i].type;
6442 if ((itemtype&ITEMTYPE) == EDITTEXT)
6443 efree((CHAR *)dia->itemdesc->list[i].data);
6444 }
6445
6446 /* update dialog location if it was moved */
6447 dia->window->GetWindowRect(&rect);
6448 dx = rect.left - dia->firstpoint.x;
6449 dy = rect.top - dia->firstpoint.y;
6450 dia->itemdesc->windowRect.left += (INTSML)dx;
6451 dia->itemdesc->windowRect.right += (INTSML)dx;
6452 dia->itemdesc->windowRect.top += (INTSML)dy;
6453 dia->itemdesc->windowRect.bottom += (INTSML)dy;
6454
6455 dia->window->EndDialog(0);
6456
6457 /* free the "dia" structure */
6458 efree((CHAR *)dia);
6459 }
6460
6461 /*
6462 * Routine to change the size of the dialog
6463 */
DiaResizeDialog(void * vdia,INTBIG wid,INTBIG hei)6464 void DiaResizeDialog(void *vdia, INTBIG wid, INTBIG hei)
6465 {
6466 TDIALOG *dia;
6467 RECT rect;
6468 #define WINDOWPADWIDTH 7
6469 #define WINDOWPADHEIGHT 26
6470
6471 dia = (TDIALOG *)vdia;
6472 dia->window->GetWindowRect(&rect);
6473 dia->window->SetWindowPos(NULL, rect.left, rect.top, wid+WINDOWPADWIDTH, hei+WINDOWPADHEIGHT,
6474 SWP_NOMOVE | SWP_NOZORDER);
6475 }
6476
6477 /*
6478 * Force the dialog to be visible.
6479 */
DiaBringToTop(void * vdia)6480 void DiaBringToTop(void *vdia)
6481 {
6482 TDIALOG *dia;
6483
6484 dia = (TDIALOG *)vdia;
6485 }
6486
6487 /*
6488 * Routine to set the text in item "item" to "msg"
6489 */
DiaSetText(void * vdia,INTBIG item,CHAR * msg)6490 void DiaSetText(void *vdia, INTBIG item, CHAR *msg)
6491 {
6492 INTBIG type, highlight, len;
6493 REGISTER CHAR *pt;
6494 CWnd *wnd;
6495 CEdit *edit;
6496 TDIALOG *dia;
6497
6498 dia = (TDIALOG *)vdia;
6499 highlight = 0;
6500 if (item < 0)
6501 {
6502 item = -item;
6503 highlight = 1;
6504 }
6505 item--;
6506 for(pt = msg; *pt != 0; pt++) if (estrncmp(pt, x_("(c)"), 3) == 0)
6507 {
6508 (void)estrcpy(pt, x_("�")); /* "copyright" character */
6509 (void)estrcpy(&pt[1], &pt[3]);
6510 break;
6511 }
6512 wnd = dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6513 if (wnd == 0) return;
6514 wnd->SetWindowText(msg);
6515 type = dia->itemdesc->list[item].type;
6516 if ((type&ITEMTYPE) == EDITTEXT)
6517 {
6518 edit = (CEdit *)wnd;
6519 len = estrlen(msg);
6520 if (highlight == 0) edit->SetSel(len, len, FALSE); else
6521 {
6522 edit->SetSel(0, len, FALSE);
6523 dia->window->GotoDlgCtrl(wnd);
6524 }
6525 (void)reallocstring((CHAR **)&dia->itemdesc->list[item].data, msg, el_tempcluster);
6526 }
6527 }
6528
6529 /*
6530 * Routine to return the text in item "item"
6531 */
DiaGetText(void * vdia,INTBIG item)6532 CHAR *DiaGetText(void *vdia, INTBIG item)
6533 {
6534 static int bufnum = 0;
6535 static CHAR line[10][300];
6536 CWnd *wnd;
6537 TDIALOG *dia;
6538
6539 dia = (TDIALOG *)vdia;
6540 item--;
6541 wnd = dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6542 if (wnd == 0) return(x_(""));
6543 bufnum++;
6544 if (bufnum >= 10) bufnum = 0;
6545 wnd->GetWindowText(line[bufnum], 300);
6546 return(line[bufnum]);
6547 }
6548
6549 /*
6550 * Routine to set the value in item "item" to "value"
6551 */
DiaSetControl(void * vdia,INTBIG item,INTBIG value)6552 void DiaSetControl(void *vdia, INTBIG item, INTBIG value)
6553 {
6554 CButton *but;
6555 TDIALOG *dia;
6556
6557 dia = (TDIALOG *)vdia;
6558 item--;
6559 but = (CButton *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6560 if (but == 0) return;
6561 but->SetCheck(value);
6562 gra_logwriteaction(DIASETCONTROL, dia->windindex, item + 1, value, 0);
6563 }
6564
6565 /*
6566 * Routine to return the value in item "item"
6567 */
DiaGetControl(void * vdia,INTBIG item)6568 INTBIG DiaGetControl(void *vdia, INTBIG item)
6569 {
6570 CButton *but;
6571 TDIALOG *dia;
6572
6573 dia = (TDIALOG *)vdia;
6574 item--;
6575 but = (CButton *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6576 if (but == 0) return(0);
6577 return(but->GetCheck());
6578 }
6579
6580 /*
6581 * Routine to check item "item" to make sure that there is
6582 * text in it. If so, it returns true. Otherwise it beeps and returns false.
6583 */
DiaValidEntry(void * vdia,INTBIG item)6584 BOOLEAN DiaValidEntry(void *vdia, INTBIG item)
6585 {
6586 CHAR *msg;
6587 TDIALOG *dia;
6588
6589 dia = (TDIALOG *)vdia;
6590 msg = DiaGetText(dia, item);
6591 while (*msg == ' ' || *msg == '\t') msg++;
6592 if (*msg != 0) return(TRUE);
6593 ttybeep(SOUNDBEEP, TRUE);
6594 return(FALSE);
6595 }
6596
6597 /*
6598 * Routine to dim item "item"
6599 */
DiaDimItem(void * vdia,INTBIG item)6600 void DiaDimItem(void *vdia, INTBIG item)
6601 {
6602 CWnd *wnd, *focus;
6603 TDIALOG *dia;
6604
6605 dia = (TDIALOG *)vdia;
6606 item--;
6607 wnd = dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6608 focus = CWnd::GetFocus();
6609 if (focus == wnd)
6610 dia->window->NextDlgCtrl();
6611 wnd->EnableWindow(0);
6612 }
6613
6614 /*
6615 * Routine to un-dim item "item"
6616 */
DiaUnDimItem(void * vdia,INTBIG item)6617 void DiaUnDimItem(void *vdia, INTBIG item)
6618 {
6619 CWnd *wnd;
6620 TDIALOG *dia;
6621
6622 dia = (TDIALOG *)vdia;
6623 item--;
6624 wnd = dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6625 wnd->EnableWindow(1);
6626 }
6627
6628 /*
6629 * Routine to change item "item" to be a message rather
6630 * than editable text
6631 */
DiaNoEditControl(void * vdia,INTBIG item)6632 void DiaNoEditControl(void *vdia, INTBIG item)
6633 {
6634 TDIALOG *dia;
6635
6636 dia = (TDIALOG *)vdia;
6637 DiaDimItem(dia, item);
6638 }
6639
6640 /*
6641 * Routine to change item "item" to be editable text rather
6642 * than a message
6643 */
DiaEditControl(void * vdia,INTBIG item)6644 void DiaEditControl(void *vdia, INTBIG item)
6645 {
6646 TDIALOG *dia;
6647
6648 dia = (TDIALOG *)vdia;
6649 DiaUnDimItem(dia, item);
6650 }
6651
DiaOpaqueEdit(void * vdia,INTBIG item)6652 void DiaOpaqueEdit(void *vdia, INTBIG item)
6653 {
6654 CEdit *edit;
6655 TDIALOG *dia;
6656
6657 dia = (TDIALOG *)vdia;
6658 item--;
6659 edit = (CEdit *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6660 edit->ModifyStyle(0, ES_PASSWORD);
6661 edit->SetPasswordChar('*');
6662 }
6663
6664 /*
6665 * Routine to cause item "item" to be the default button
6666 */
DiaDefaultButton(void * vdia,INTBIG item)6667 void DiaDefaultButton(void *vdia, INTBIG item)
6668 {
6669 TDIALOG *dia;
6670
6671 dia = (TDIALOG *)vdia;
6672 dia->defaultbutton = item;
6673 dia->window->SetDefID(dia->defaultbutton-1+ID_DIALOGITEM_0);
6674 }
6675
6676 /*
6677 * Routine to change the icon in item "item" to be the 32x32 bitmap (128 bytes) at "addr".
6678 */
DiaChangeIcon(void * vdia,INTBIG item,UCHAR1 * addr)6679 void DiaChangeIcon(void *vdia, INTBIG item, UCHAR1 *addr)
6680 {
6681 HICON map;
6682 INTBIG x, y;
6683 CDC *dc;
6684 RECT rr;
6685 TDIALOG *dia;
6686 COLORREF backc;
6687
6688 dia = (TDIALOG *)vdia;
6689 item--;
6690 dia->itemdesc->list[item].data = (INTBIG)addr;
6691 map = gra_makeicon(dia->itemdesc->list[item].data);
6692
6693 /* redraw */
6694 dc = dia->window->GetDC();
6695
6696 /* erase the area */
6697 rr.left = dia->itemdesc->list[item].r.left;
6698 rr.right = dia->itemdesc->list[item].r.right;
6699 rr.top = dia->itemdesc->list[item].r.top;
6700 rr.bottom = dia->itemdesc->list[item].r.bottom;
6701 if (gra_dialogbkgrbrush == 0)
6702 {
6703 backc = 0;
6704 for(y=rr.top; y<rr.bottom; y++)
6705 {
6706 for(x=rr.left; x<rr.right; x++)
6707 {
6708 backc = dia->window->GetDC()->GetPixel(x, y);
6709 if (backc != 0) break;
6710 }
6711 if (backc != 0) break;
6712 }
6713 gra_dialogbkgrbrush = new CBrush(backc);
6714 }
6715 dc->FillRect(&rr, gra_dialogbkgrbrush);
6716
6717 /* draw the icon */
6718 x = dia->itemdesc->list[item].r.left;
6719 y = dia->itemdesc->list[item].r.top;
6720 dc->DrawIcon(x, y, map);
6721 DestroyIcon(map);
6722 dia->window->ReleaseDC(dc);
6723 }
6724
6725 /*
6726 * Routine to change item "item" into a popup with "count" entries
6727 * in "names".
6728 */
DiaSetPopup(void * vdia,INTBIG item,INTBIG count,CHAR ** names)6729 void DiaSetPopup(void *vdia, INTBIG item, INTBIG count, CHAR **names)
6730 {
6731 INTBIG i;
6732 CComboBox *cb;
6733 TDIALOG *dia;
6734
6735 dia = (TDIALOG *)vdia;
6736 item--;
6737 cb = (CComboBox *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6738 if (cb == 0) return;
6739 cb->ResetContent();
6740 for(i=0; i<count; i++) cb->AddString(names[i]);
6741 cb->SetCurSel(0);
6742 }
6743
6744 /*
6745 * Routine to change popup item "item" so that the current entry is "entry".
6746 */
DiaSetPopupEntry(void * vdia,INTBIG item,INTBIG entry)6747 void DiaSetPopupEntry(void *vdia, INTBIG item, INTBIG entry)
6748 {
6749 CComboBox *cb;
6750 TDIALOG *dia;
6751
6752 dia = (TDIALOG *)vdia;
6753 item--;
6754 cb = (CComboBox *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6755 if (cb == 0) return;
6756 cb->SetCurSel(entry);
6757 }
6758
6759 /*
6760 * Routine to return the current item in popup menu item "item".
6761 */
DiaGetPopupEntry(void * vdia,INTBIG item)6762 INTBIG DiaGetPopupEntry(void *vdia, INTBIG item)
6763 {
6764 CComboBox *cb;
6765 TDIALOG *dia;
6766
6767 dia = (TDIALOG *)vdia;
6768 item--;
6769 cb = (CComboBox *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6770 if (cb == 0) return(0);
6771 return(cb->GetCurSel());
6772 }
6773
DiaInitTextDialog(void * vdia,INTBIG item,BOOLEAN (* toplist)(CHAR **),CHAR * (* nextinlist)(void),void (* donelist)(void),INTBIG sortpos,INTBIG flags)6774 void DiaInitTextDialog(void *vdia, INTBIG item, BOOLEAN (*toplist)(CHAR **),
6775 CHAR *(*nextinlist)(void), void (*donelist)(void), INTBIG sortpos, INTBIG flags)
6776 {
6777 long add, remove;
6778 static CFont *fnt = 0;
6779 LOGFONT lf;
6780 CListBoxEx *list;
6781 TDIALOG *dia;
6782
6783 dia = (TDIALOG *)vdia;
6784 item--;
6785 list = (CListBoxEx *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6786 if (list == 0) return;
6787
6788 add = remove = 0;
6789 if ((flags&SCHORIZBAR) == 0) remove |= WS_HSCROLL; else
6790 {
6791 add |= WS_HSCROLL;
6792 list->SetHorizontalExtent(1000);
6793 }
6794 list->ModifyStyle(remove, add, SWP_NOSIZE);
6795 dia->itemdesc->list[item].data = flags;
6796 if ((flags&SCFIXEDWIDTH) != 0)
6797 {
6798 if (fnt == 0)
6799 {
6800 lf.lfHeight = -10;
6801 estrcpy(lf.lfFaceName, x_("Lucida Console"));
6802 lf.lfWidth = 0;
6803 lf.lfEscapement = 0;
6804 lf.lfOrientation = 0;
6805 lf.lfWeight = FW_NORMAL;
6806 lf.lfItalic = 0;
6807 lf.lfUnderline = 0;
6808 lf.lfStrikeOut = 0;
6809 lf.lfCharSet = 0;
6810 lf.lfOutPrecision = OUT_STROKE_PRECIS;
6811 lf.lfClipPrecision = CLIP_STROKE_PRECIS;
6812 lf.lfQuality = 1;
6813 lf.lfPitchAndFamily = FF_DONTCARE | FF_SWISS;
6814
6815 fnt = new CFont();
6816 fnt->CreateFontIndirect(&lf);
6817 }
6818 list->SetFont(fnt);
6819 }
6820 DiaLoadTextDialog(vdia, item+1, toplist, nextinlist, donelist, sortpos);
6821 }
6822
DiaLoadTextDialog(void * vdia,INTBIG item,BOOLEAN (* toplist)(CHAR **),CHAR * (* nextinlist)(void),void (* donelist)(void),INTBIG sortpos)6823 void DiaLoadTextDialog(void *vdia, INTBIG item, BOOLEAN (*toplist)(CHAR **),
6824 CHAR *(*nextinlist)(void), void (*donelist)(void), INTBIG sortpos)
6825 {
6826 CHAR *next, line[256];
6827 INTBIG i;
6828 CListBoxEx *list;
6829 TDIALOG *dia;
6830
6831 dia = (TDIALOG *)vdia;
6832 item--;
6833 list = (CListBoxEx *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6834 if (list == 0) return;
6835
6836 /* clear the list */
6837 list->ResetContent();
6838
6839 /* load the list */
6840 line[0] = 0;
6841 next = line;
6842 (void)(*toplist)(&next);
6843 for(i=0; ; i++)
6844 {
6845 next = (*nextinlist)();
6846 if (next == 0) break;
6847 if (sortpos < 0) list->InsertString(-1, next); else
6848 list->AddString(next);
6849 }
6850 (*donelist)();
6851 if (i > 0) list->SetCurSel(0);
6852 }
6853
6854 /*
6855 * Routine to stuff line "line" at the end of the edit buffer.
6856 */
DiaStuffLine(void * vdia,INTBIG item,CHAR * line)6857 void DiaStuffLine(void *vdia, INTBIG item, CHAR *line)
6858 {
6859 CListBoxEx *list;
6860 TDIALOG *dia;
6861
6862 dia = (TDIALOG *)vdia;
6863 item--;
6864 list = (CListBoxEx *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6865 if (list == 0) return;
6866 list->InsertString(-1, line);
6867 }
6868
6869 /*
6870 * Routine to select line "line" of scroll item "item".
6871 */
DiaSelectLine(void * vdia,INTBIG item,INTBIG line)6872 void DiaSelectLine(void *vdia, INTBIG item, INTBIG line)
6873 {
6874 CListBoxEx *list;
6875 INTBIG numitems, botitem, topitem, visibleitems, type;
6876 CPoint pt;
6877 BOOL outside;
6878 TDIALOG *dia;
6879
6880 dia = (TDIALOG *)vdia;
6881 item--;
6882 type = dia->itemdesc->list[item].type;
6883 list = (CListBoxEx *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6884 if (list == 0) return;
6885 pt.x = 0; pt.y = 0;
6886 topitem = list->ItemFromPoint(pt, outside);
6887 pt.x = 0; pt.y = 9999;
6888 botitem = list->ItemFromPoint(pt, outside);
6889 visibleitems = botitem - topitem;
6890 numitems = list->GetCount();
6891 if (line < topitem || line >= botitem)
6892 {
6893 topitem = line - visibleitems/2;
6894 list->SetTopIndex(topitem);
6895 }
6896 if ((type&ITEMTYPE) == SCROLL)
6897 {
6898 list->SetCurSel(line);
6899 } else
6900 {
6901 list->SetSel(-1, FALSE);
6902 list->SetSel(line, TRUE);
6903 }
6904 }
6905
6906 /*
6907 * Routine to select "count" lines in "lines" of scroll item "item".
6908 */
DiaSelectLines(void * vdia,INTBIG item,INTBIG count,INTBIG * lines)6909 void DiaSelectLines(void *vdia, INTBIG item, INTBIG count, INTBIG *lines)
6910 {
6911 CListBoxEx *list;
6912 INTBIG numitems, botitem, topitem, visibleitems, i, low, high;
6913 CPoint pt;
6914 BOOL outside;
6915 TDIALOG *dia;
6916
6917 dia = (TDIALOG *)vdia;
6918 if (count <= 0) return;
6919 item--;
6920 list = (CListBoxEx *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6921 if (list == 0) return;
6922 pt.x = 0; pt.y = 0;
6923 topitem = list->ItemFromPoint(pt, outside);
6924 pt.x = 0; pt.y = 9999;
6925 botitem = list->ItemFromPoint(pt, outside);
6926 visibleitems = botitem - topitem;
6927 numitems = list->GetCount();
6928 low = high = lines[0];
6929 for(i=1; i<count; i++)
6930 {
6931 if (lines[i] < low) low = lines[i];
6932 if (lines[i] > high) high = lines[i];
6933 }
6934 if (high < topitem || low >= botitem)
6935 {
6936 topitem = low;
6937 list->SetTopIndex(topitem);
6938 }
6939 list->SetSel(-1, FALSE);
6940 for(i=0; i<count; i++)
6941 list->SetSel(lines[i], TRUE);
6942 }
6943
6944 /*
6945 * Returns the currently selected line in the scroll list "item".
6946 */
DiaGetCurLine(void * vdia,INTBIG item)6947 INTBIG DiaGetCurLine(void *vdia, INTBIG item)
6948 {
6949 INTBIG line;
6950 CListBoxEx *list;
6951 TDIALOG *dia;
6952
6953 dia = (TDIALOG *)vdia;
6954 item--;
6955 list = (CListBoxEx *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6956 if (list == 0) return(-1);
6957 line = list->GetCurSel();
6958 if (line == LB_ERR) return(-1);
6959 return(line);
6960 }
6961
6962 /*
6963 * Returns the currently selected lines in the scroll list "item". The returned
6964 * array is terminated with -1.
6965 */
DiaGetCurLines(void * vdia,INTBIG item)6966 INTBIG *DiaGetCurLines(void *vdia, INTBIG item)
6967 {
6968 REGISTER INTBIG total, i;
6969 CListBoxEx *list;
6970 static INTBIG selitemlist[MAXSCROLLMULTISELECT];
6971 int selintlist[MAXSCROLLMULTISELECT];
6972 TDIALOG *dia;
6973
6974 dia = (TDIALOG *)vdia;
6975 item--;
6976 list = (CListBoxEx *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6977 if (list == 0) total = 0; else
6978 {
6979 total = list->GetSelItems(MAXSCROLLMULTISELECT-1, selintlist);
6980 if (total == LB_ERR) total = 0;
6981 for(i=0; i<total; i++) selitemlist[i] = selintlist[i];
6982 }
6983 selitemlist[total] = -1;
6984 return(selitemlist);
6985 }
6986
DiaGetNumScrollLines(void * vdia,INTBIG item)6987 INTBIG DiaGetNumScrollLines(void *vdia, INTBIG item)
6988 {
6989 CListBoxEx *list;
6990 TDIALOG *dia;
6991
6992 dia = (TDIALOG *)vdia;
6993 item--;
6994 list = (CListBoxEx *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
6995 if (list == 0) return(0);
6996 return (list->GetCount());
6997 }
6998
DiaGetScrollLine(void * vdia,INTBIG item,INTBIG line)6999 CHAR *DiaGetScrollLine(void *vdia, INTBIG item, INTBIG line)
7000 {
7001 static CHAR text[300];
7002 CListBoxEx *list;
7003 TDIALOG *dia;
7004
7005 dia = (TDIALOG *)vdia;
7006 item--;
7007 list = (CListBoxEx *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
7008 if (list == 0) return(x_(""));
7009 if (list->GetText(line, text) == -1) return(x_(""));
7010 return(text);
7011 }
7012
DiaSetScrollLine(void * vdia,INTBIG item,INTBIG line,CHAR * msg)7013 void DiaSetScrollLine(void *vdia, INTBIG item, INTBIG line, CHAR *msg)
7014 {
7015 CListBoxEx *list;
7016 TDIALOG *dia;
7017
7018 dia = (TDIALOG *)vdia;
7019 item--;
7020 list = (CListBoxEx *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
7021 if (list == 0) return;
7022 list->DeleteString(line);
7023 list->InsertString(line, msg);
7024 list->SetCurSel(line);
7025 }
7026
DiaSynchVScrolls(void * vdia,INTBIG item1,INTBIG item2,INTBIG item3)7027 void DiaSynchVScrolls(void *vdia, INTBIG item1, INTBIG item2, INTBIG item3)
7028 {
7029 TDIALOG *dia;
7030
7031 dia = (TDIALOG *)vdia;
7032 if (item1 <= 0 || item1 > dia->itemdesc->items) return;
7033 if (item2 <= 0 || item2 > dia->itemdesc->items) return;
7034 if (item3 < 0 || item3 > dia->itemdesc->items) return;
7035 if (dia->numlocks >= MAXLOCKS) return;
7036 dia->lock1[dia->numlocks] = item1 - 1;
7037 dia->lock2[dia->numlocks] = item2 - 1;
7038 dia->lock3[dia->numlocks] = item3 - 1;
7039 dia->numlocks++;
7040 }
7041
DiaUnSynchVScrolls(void * vdia)7042 void DiaUnSynchVScrolls(void *vdia)
7043 {
7044 TDIALOG *dia;
7045
7046 dia = (TDIALOG *)vdia;
7047 dia->numlocks = 0;
7048 }
7049
DiaItemRect(void * vdia,INTBIG item,RECTAREA * rect)7050 void DiaItemRect(void *vdia, INTBIG item, RECTAREA *rect)
7051 {
7052 TDIALOG *dia;
7053
7054 dia = (TDIALOG *)vdia;
7055 if (item <= 0 || item > dia->itemdesc->items) return;
7056 item--;
7057 *rect = dia->itemdesc->list[item].r;
7058 }
7059
DiaPercent(void * vdia,INTBIG item,INTBIG percent)7060 void DiaPercent(void *vdia, INTBIG item, INTBIG percent)
7061 {
7062 CProgressCtrl *prog;
7063 TDIALOG *dia;
7064
7065 dia = (TDIALOG *)vdia;
7066 item--;
7067 prog = (CProgressCtrl *)dia->window->GetDlgItem(item+ID_DIALOGITEM_0);
7068 prog->SetPos(percent);
7069 }
7070
DiaRedispRoutine(void * vdia,INTBIG item,void (* routine)(RECTAREA *,void *))7071 void DiaRedispRoutine(void *vdia, INTBIG item, void (*routine)(RECTAREA*, void*))
7072 {
7073 TDIALOG *dia;
7074
7075 dia = (TDIALOG *)vdia;
7076 dia->redrawroutine = routine;
7077 dia->redrawitem = item;
7078 }
7079
DiaAllowUserDoubleClick(void * vdia)7080 void DiaAllowUserDoubleClick(void *vdia)
7081 {
7082 TDIALOG *dia;
7083
7084 dia = (TDIALOG *)vdia;
7085 dia->useritemdoubleclick = 1;
7086 }
7087
DiaDrawRect(void * vdia,INTBIG item,RECTAREA * ur,INTBIG r,INTBIG g,INTBIG b)7088 void DiaDrawRect(void *vdia, INTBIG item, RECTAREA *ur, INTBIG r, INTBIG g, INTBIG b)
7089 {
7090 RECT rr;
7091 CDC *dc;
7092 CBrush *brush;
7093 COLORREF color;
7094 TDIALOG *dia;
7095
7096 dia = (TDIALOG *)vdia;
7097 rr.left = ur->left;
7098 rr.right = ur->right;
7099 rr.top = ur->top;
7100 rr.bottom = ur->bottom;
7101
7102 color = (b << 16) | (g << 8) | r;
7103 brush = new CBrush(color);
7104 dc = dia->window->GetDC();
7105 dc->FillRect(&rr, brush);
7106 dia->window->ReleaseDC(dc);
7107 delete brush;
7108 }
7109
DiaFrameRect(void * vdia,INTBIG item,RECTAREA * ur)7110 void DiaFrameRect(void *vdia, INTBIG item, RECTAREA *ur)
7111 {
7112 RECT r;
7113 CDC *dc;
7114 TDIALOG *dia;
7115
7116 dia = (TDIALOG *)vdia;
7117 r.left = ur->left;
7118 r.right = ur->right-1;
7119 r.top = ur->top;
7120 r.bottom = ur->bottom-1;
7121
7122 if (gra_dialogoffbrush == 0) gra_dialogoffbrush = new CBrush((COLORREF)0xFFFFFF);
7123 dc = dia->window->GetDC();
7124 dc->FillRect(&r, gra_dialogoffbrush);
7125 dc->MoveTo(r.left, r.top);
7126 dc->LineTo(r.right, r.top);
7127 dc->LineTo(r.right, r.bottom);
7128 dc->LineTo(r.left, r.bottom);
7129 dc->LineTo(r.left, r.top);
7130 dia->window->ReleaseDC(dc);
7131 }
7132
DiaInvertRect(void * vdia,INTBIG item,RECTAREA * ur)7133 void DiaInvertRect(void *vdia, INTBIG item, RECTAREA *ur)
7134 {
7135 RECT r;
7136 CDC *dc;
7137 TDIALOG *dia;
7138
7139 dia = (TDIALOG *)vdia;
7140 r.left = ur->left;
7141 r.right = ur->right-1;
7142 r.top = ur->top;
7143 r.bottom = ur->bottom-1;
7144
7145 dc = dia->window->GetDC();
7146 dc->InvertRect(&r);
7147 dia->window->ReleaseDC(dc);
7148 }
7149
DiaDrawLine(void * vdia,INTBIG item,INTBIG fx,INTBIG fy,INTBIG tx,INTBIG ty,INTBIG mode)7150 void DiaDrawLine(void *vdia, INTBIG item, INTBIG fx, INTBIG fy, INTBIG tx, INTBIG ty, INTBIG mode)
7151 {
7152 CDC *dc;
7153 TDIALOG *dia;
7154
7155 dia = (TDIALOG *)vdia;
7156 dc = dia->window->GetDC();
7157 switch (mode)
7158 {
7159 case DLMODEON: dc->SetROP2(R2_BLACK); break;
7160 case DLMODEOFF: dc->SetROP2(R2_WHITE); break;
7161 case DLMODEINVERT: dc->SetROP2(R2_NOT); break;
7162 }
7163 dc->MoveTo(fx, fy);
7164 dc->LineTo(tx, ty);
7165 dc->SetROP2(R2_COPYPEN);
7166 dia->window->ReleaseDC(dc);
7167 }
7168
DiaFillPoly(void * vdia,INTBIG item,INTBIG * x,INTBIG * y,INTBIG count,INTBIG r,INTBIG g,INTBIG b)7169 void DiaFillPoly(void *vdia, INTBIG item, INTBIG *x, INTBIG *y, INTBIG count, INTBIG r, INTBIG g, INTBIG b)
7170 {
7171 CBrush *polybrush;
7172 CPen *polypen;
7173 COLORREF brushcolor;
7174 POINT points[50];
7175 INTBIG i;
7176 CDC *dc;
7177 TDIALOG *dia;
7178
7179 dia = (TDIALOG *)vdia;
7180 for(i=0; i<count; i++)
7181 {
7182 points[i].x = x[i];
7183 points[i].y = y[i];
7184 }
7185
7186 brushcolor = (COLORREF)((b << 16) | (g << 8) | r);
7187 polybrush = new CBrush(brushcolor);
7188 polypen = new CPen(PS_SOLID, 0, brushcolor);
7189 dc = dia->window->GetDC();
7190 dc->SelectObject(polybrush);
7191 dc->SelectObject(polypen);
7192 dc->Polygon(points, count);
7193 delete polybrush;
7194 delete polypen;
7195 dia->window->ReleaseDC(dc);
7196 }
7197
DiaPutText(void * vdia,INTBIG item,CHAR * msg,INTBIG x,INTBIG y)7198 void DiaPutText(void *vdia, INTBIG item, CHAR *msg, INTBIG x, INTBIG y)
7199 {
7200 CFont *font;
7201 CDC *dc;
7202 UINTBIG descript[TEXTDESCRIPTSIZE];
7203 TDIALOG *dia;
7204
7205 dia = (TDIALOG *)vdia;
7206 TDCLEAR(descript);
7207 TDSETSIZE(descript, TXTSETPOINTS(dia->usertextsize));
7208 font = gra_gettextfont(NOWINDOWPART, NOTECHNOLOGY, descript);
7209 if (font == 0) return;
7210 dc = dia->window->GetDC();
7211 dc->SelectObject(font);
7212 dc->SetBkMode(TRANSPARENT);
7213 dc->TextOut(x, y, msg, estrlen(msg));
7214 dia->window->ReleaseDC(dc);
7215 }
7216
DiaSetTextSize(void * vdia,INTBIG size)7217 void DiaSetTextSize(void *vdia, INTBIG size)
7218 {
7219 TDIALOG *dia;
7220
7221 dia = (TDIALOG *)vdia;
7222 dia->usertextsize = size;
7223 }
7224
DiaGetTextInfo(void * vdia,CHAR * msg,INTBIG * wid,INTBIG * hei)7225 void DiaGetTextInfo(void *vdia, CHAR *msg, INTBIG *wid, INTBIG *hei)
7226 {
7227 CFont *font;
7228 CSize textSize;
7229 CDC *dc;
7230 UINTBIG descript[TEXTDESCRIPTSIZE];
7231 TDIALOG *dia;
7232
7233 dia = (TDIALOG *)vdia;
7234 TDCLEAR(descript);
7235 TDSETSIZE(descript, TXTSETPOINTS(dia->usertextsize));
7236 font = gra_gettextfont(NOWINDOWPART, NOTECHNOLOGY, descript);
7237 if (font == 0) return;
7238 dc = dia->window->GetDC();
7239 dc->SelectObject(font);
7240 textSize = dc->GetTextExtent(msg, estrlen(msg));
7241 *wid = textSize.cx;
7242 *hei = textSize.cy+1;
7243 dia->window->ReleaseDC(dc);
7244 }
7245
DiaTrackCursor(void * vdia,void (* eachdown)(INTBIG x,INTBIG y))7246 void DiaTrackCursor(void *vdia, void (*eachdown)(INTBIG x, INTBIG y))
7247 {
7248 TDIALOG *dia;
7249
7250 dia = (TDIALOG *)vdia;
7251 gra_trackingdialog = dia;
7252 dia->diaeachdown = eachdown;
7253 trackcursor(FALSE, us_nullup, us_nullvoid, gra_diaeachdownhandler,
7254 us_nullchar, us_nullvoid, TRACKNORMAL);
7255 gra_trackingdialog = 0;
7256 }
7257
gra_diaeachdownhandler(INTBIG ox,INTBIG oy)7258 BOOLEAN gra_diaeachdownhandler(INTBIG ox, INTBIG oy)
7259 {
7260 INTBIG x, y;
7261
7262 if (gra_trackingdialog == 0) return(FALSE);
7263 DiaGetMouse(gra_trackingdialog, &x, &y);
7264 (void)((*gra_trackingdialog->diaeachdown)(x, y));
7265 return(FALSE);
7266 }
7267
DiaGetMouse(void * vdia,INTBIG * x,INTBIG * y)7268 void DiaGetMouse(void *vdia, INTBIG *x, INTBIG *y)
7269 {
7270 POINT p, p2;
7271 TDIALOG *dia;
7272
7273 dia = (TDIALOG *)vdia;
7274 if (us_logplay != NULL)
7275 {
7276 if (!gra_loggetnextaction(0))
7277 {
7278 *x = gra_action.x;
7279 *y = gra_action.y;
7280 }
7281 }
7282 if (us_logplay == NULL)
7283 {
7284 p2.x = p2.y = 0;
7285 dia->window->MapWindowPoints(0, &p2, 1);
7286 GetCursorPos(&p);
7287 *x = p.x - p2.x; *y = p.y - p2.y;
7288 }
7289 gra_logwriteaction(DIAUSERMOUSE, dia->windindex, *x, *y, 0);
7290 }
7291
7292 /************************* DIALOG SUPPORT *************************/
7293
7294 /*
7295 * Routine to redraw user items and divider lines
7296 */
gra_diaredrawitem(CElectricDialog * cedia)7297 void gra_diaredrawitem(CElectricDialog *cedia)
7298 {
7299 RECTAREA ra;
7300 INTBIG i, itemtype, x, y;
7301 HICON map;
7302 CDC *dc;
7303 TDIALOG *dia;
7304
7305 /* find the dialog that needs to be redrawn */
7306 for(dia = gra_firstactivedialog; dia != NOTDIALOG; dia = dia->nexttdialog)
7307 if (dia->window == cedia) break;
7308 if (dia == NOTDIALOG) return;
7309
7310 /* if it has a custom redraw routine, call it */
7311 if (dia->redrawroutine != 0)
7312 {
7313 DiaItemRect(dia, dia->redrawitem, &ra);
7314 (*dia->redrawroutine)(&ra, dia);
7315 }
7316
7317 /* redraw any special items */
7318 for(i=0; i<dia->itemdesc->items; i++)
7319 {
7320 itemtype = dia->itemdesc->list[i].type;
7321 if ((itemtype&ITEMTYPE) == DIVIDELINE)
7322 {
7323 DiaDrawRect(dia, i+1, &dia->itemdesc->list[i].r, 0, 0, 0);
7324 }
7325 if ((itemtype&ITEMTYPE) == ICON)
7326 {
7327 if (dia->itemdesc->list[i].data != 0)
7328 {
7329 x = dia->itemdesc->list[i].r.left;
7330 y = dia->itemdesc->list[i].r.top;
7331 map = gra_makeicon(dia->itemdesc->list[i].data);
7332 dc = dia->window->GetDC();
7333 dc->DrawIcon(x, y, map);
7334 dia->window->ReleaseDC(dc);
7335 DestroyIcon(map);
7336 }
7337 }
7338 }
7339 }
7340
7341 /*
7342 * Routine called when a scroll item is scrolled vertically
7343 */
gra_itemvscrolled(void * vdia,int nID)7344 void gra_itemvscrolled(void *vdia, int nID)
7345 {
7346 int value, i, item, itemtype;
7347 CListBoxEx *list;
7348 TDIALOG *dia;
7349
7350 dia = (TDIALOG *)vdia;
7351 item = nID - ID_DIALOGITEM_0;
7352 itemtype = dia->itemdesc->list[item].type & ITEMTYPE;
7353 if (itemtype != SCROLL && itemtype != SCROLLMULTI) return;
7354
7355 list = (CListBoxEx *)dia->window->GetDlgItem(nID);
7356 value = list->GetTopIndex();
7357 for(i=0; i<dia->numlocks; i++)
7358 {
7359 if (dia->lock1[i] == item)
7360 {
7361 list = (CListBoxEx *)dia->window->GetDlgItem(dia->lock2[i]+ID_DIALOGITEM_0);
7362 list->SetTopIndex(value);
7363 if (dia->lock3[i] >= 0)
7364 {
7365 list = (CListBoxEx *)dia->window->GetDlgItem(dia->lock3[i]+ID_DIALOGITEM_0);
7366 list->SetTopIndex(value);
7367 }
7368 return;
7369 }
7370 if (dia->lock2[i] == item)
7371 {
7372 list = (CListBoxEx *)dia->window->GetDlgItem(dia->lock1[i]+ID_DIALOGITEM_0);
7373 list->SetTopIndex(value);
7374 if (dia->lock3[i] >= 0)
7375 {
7376 list = (CListBoxEx *)dia->window->GetDlgItem(dia->lock3[i]+ID_DIALOGITEM_0);
7377 list->SetTopIndex(value);
7378 }
7379 return;
7380 }
7381 if (dia->lock3[i] == item)
7382 {
7383 list = (CListBoxEx *)dia->window->GetDlgItem(dia->lock1[i]+ID_DIALOGITEM_0);
7384 list->SetTopIndex(value);
7385 list = (CListBoxEx *)dia->window->GetDlgItem(dia->lock2[i]+ID_DIALOGITEM_0);
7386 list->SetTopIndex(value);
7387 return;
7388 }
7389 }
7390 }
7391
7392 /*
7393 * Routine called when an item is clicked
7394 */
gra_itemclicked(CElectricDialog * diawin,int nID)7395 void gra_itemclicked(CElectricDialog *diawin, int nID)
7396 {
7397 int itemtype, line, count, item;
7398 CListBoxEx *list;
7399 CComboBox *cb;
7400 int selintlist[MAXSCROLLMULTISELECT];
7401 TDIALOG *dia;
7402
7403 for(dia = gra_firstactivedialog; dia != NOTDIALOG; dia = dia->nexttdialog)
7404 if (dia->window == diawin) break;
7405 if (dia == NOTDIALOG) return;
7406
7407 if (nID == 1)
7408 {
7409 item = dia->defaultbutton;
7410 if (dia->modelessitemhit != 0) (*dia->modelessitemhit)(dia, item); else
7411 dia->dialoghit = item;
7412 gra_logwriteaction(DIAITEMCLICK, dia->windindex, item, 0, 0);
7413 return;
7414 }
7415 if (nID == 2)
7416 {
7417 item = 2;
7418 if (dia->modelessitemhit != 0) (*dia->modelessitemhit)(dia, item); else
7419 dia->dialoghit = item;
7420 gra_logwriteaction(DIAITEMCLICK, dia->windindex, item, 0, 0);
7421 return;
7422 }
7423
7424 /* handle scroll areas */
7425 itemtype = dia->itemdesc->list[nID-ID_DIALOGITEM_0].type;
7426 if ((itemtype&ITEMTYPE) == SCROLL || (itemtype&ITEMTYPE) == SCROLLMULTI)
7427 {
7428 list = (CListBoxEx *)dia->window->GetDlgItem(nID);
7429
7430 /* log the selection */
7431 if ((itemtype&ITEMTYPE) == SCROLLMULTI)
7432 {
7433 count = list->GetSelItems(MAXSCROLLMULTISELECT-1, selintlist);
7434 if (count != LB_ERR)
7435 gra_logwriteaction(DIASCROLLSEL, dia->windindex, nID - ID_DIALOGITEM_0 + 1, count, selintlist);
7436 } else
7437 {
7438 line = list->GetCurSel();
7439 selintlist[0] = line;
7440 if (line != LB_ERR)
7441 gra_logwriteaction(DIASCROLLSEL, dia->windindex, nID - ID_DIALOGITEM_0 + 1, 1, selintlist);
7442 }
7443
7444 /* if no mouse selection allowed, deselect the list (leaves an outline, but oh well) */
7445 if ((dia->itemdesc->list[nID-ID_DIALOGITEM_0].data&SCSELMOUSE) == 0)
7446 {
7447 if (list == 0) return;
7448 list->SetCurSel(-1);
7449 return;
7450 }
7451
7452 /* ignore clicks in scroll areas that do not want hits reported */
7453 if ((dia->itemdesc->list[nID-ID_DIALOGITEM_0].data&SCREPORT) == 0)
7454 return;
7455 }
7456 if ((itemtype&ITEMTYPE) == POPUP)
7457 {
7458 cb = (CComboBox *)dia->window->GetDlgItem(nID);
7459 gra_logwriteaction(DIAPOPUPSEL, dia->windindex, nID - ID_DIALOGITEM_0 + 1, cb->GetCurSel(), 0);
7460 }
7461
7462 item = nID - ID_DIALOGITEM_0 + 1;
7463 gra_logwriteaction(DIAITEMCLICK, dia->windindex, item, 0, 0);
7464 if (dia->modelessitemhit != 0) (*dia->modelessitemhit)(dia, item); else
7465 dia->dialoghit = item;
7466 }
7467
7468 /*
7469 * Routine called when an item is double-clicked
7470 */
gra_itemdoubleclicked(CElectricDialog * diawin,int nID)7471 void gra_itemdoubleclicked(CElectricDialog *diawin, int nID)
7472 {
7473 INTBIG itemtype, item;
7474 BOOLEAN allowdouble;
7475 TDIALOG *dia;
7476
7477 for(dia = gra_firstactivedialog; dia != NOTDIALOG; dia = dia->nexttdialog)
7478 if (dia->window == diawin) break;
7479 if (dia == NOTDIALOG) return;
7480
7481 if (dia->window == 0) return;
7482 itemtype = dia->itemdesc->list[nID].type;
7483
7484 allowdouble = FALSE;
7485 if ((itemtype&ITEMTYPE) == SCROLL || (itemtype&ITEMTYPE) == SCROLLMULTI)
7486 {
7487 if ((dia->itemdesc->list[nID].data&SCDOUBLEQUIT) != 0) allowdouble = TRUE;
7488 }
7489 if ((itemtype&ITEMTYPE) == USERDRAWN)
7490 {
7491 if (dia->useritemdoubleclick != 0) allowdouble = TRUE;
7492 }
7493
7494 if (allowdouble)
7495 {
7496 item = dia->defaultbutton;
7497 if (dia->modelessitemhit != 0) (*dia->modelessitemhit)(dia, item); else
7498 dia->dialoghit = item;
7499 gra_logwriteaction(DIAITEMCLICK, dia->windindex, item, 0, 0);
7500 }
7501 }
7502
7503 /*
7504 * Called when a key is typed to a list box. Returns nonzero to accept the
7505 * keystroke, zero to ignore typed keys in the list box.
7506 */
gra_dodialoglistkey(CElectricDialog * diawin,UINT nKey,CListBox * pListBox,UINT nIndex)7507 int gra_dodialoglistkey(CElectricDialog *diawin, UINT nKey, CListBox* pListBox, UINT nIndex)
7508 {
7509 CListBoxEx *list;
7510 INTBIG i, itemtype, line, count;
7511 int selintlist[MAXSCROLLMULTISELECT];
7512 TDIALOG *dia;
7513
7514 for(dia = gra_firstactivedialog; dia != NOTDIALOG; dia = dia->nexttdialog)
7515 if (dia->window == diawin) break;
7516 if (dia == NOTDIALOG) return(0);
7517
7518 /* always allow arrow keys */
7519 if (nKey == VK_DOWN || nKey == VK_UP) return(1);
7520
7521 for(i=0; i<dia->itemdesc->items; i++)
7522 {
7523 itemtype = dia->itemdesc->list[i].type;
7524 if ((itemtype&ITEMTYPE) != SCROLL && (itemtype&ITEMTYPE) != SCROLLMULTI) continue;
7525 list = (CListBoxEx *)dia->window->GetDlgItem(i+ID_DIALOGITEM_0);
7526 if (list != pListBox) continue;
7527 if ((dia->itemdesc->list[i].data&SCSELKEY) == 0) return(0);
7528 if ((itemtype&ITEMTYPE) == SCROLLMULTI)
7529 {
7530 count = list->GetSelItems(MAXSCROLLMULTISELECT-1, selintlist);
7531 if (count != LB_ERR)
7532 gra_logwriteaction(DIASCROLLSEL, dia->windindex, i + 1, (int)count, selintlist);
7533 } else
7534 {
7535 line = list->GetCurSel();
7536 selintlist[0] = line;
7537 if (line != LB_ERR)
7538 gra_logwriteaction(DIASCROLLSEL, dia->windindex, i + 1, 1, selintlist);
7539 }
7540 break;
7541 }
7542
7543 return(1);
7544 }
7545
7546 /*
7547 * Routine called when a character is typed
7548 */
gra_dodialogtextchange(CElectricDialog * diawin,int nID)7549 void gra_dodialogtextchange(CElectricDialog *diawin, int nID)
7550 {
7551 INTBIG item;
7552 TDIALOG *dia;
7553
7554 for(dia = gra_firstactivedialog; dia != NOTDIALOG; dia = dia->nexttdialog)
7555 if (dia->window == diawin) break;
7556 if (dia == NOTDIALOG) return;
7557
7558 /* get current contents of the edit field */
7559 item = nID + 1;
7560 if (dia->modelessitemhit != 0) (*dia->modelessitemhit)(dia, item); else
7561 dia->dialoghit = item;
7562 gra_logwriteaction(DIAEDITTEXT, dia->windindex, item, 0, DiaGetText(dia, item));
7563 }
7564
7565 /*
7566 * Routine to return a nonzero item number if point (x,y) is inside a user-drawn item
7567 */
gra_dodialogisinsideuserdrawn(TDIALOG * dia,int x,int y)7568 INTBIG gra_dodialogisinsideuserdrawn(TDIALOG *dia, int x, int y)
7569 {
7570 INTBIG i, itemtype;
7571
7572 if (dia->window == 0) return(0);
7573 i = gra_getdialogitem(dia, x, y);
7574 itemtype = dia->itemdesc->list[i-1].type;
7575 if ((itemtype&ITEMTYPE) != USERDRAWN &&
7576 (itemtype&ITEMTYPE) != ICON) return(0);
7577 return(i);
7578 }
7579
7580 /*
7581 * Routine to return a nonzero item number if point (x,y) is inside a user-drawn item
7582 */
gra_getdialogitem(TDIALOG * dia,int x,int y)7583 INTBIG gra_getdialogitem(TDIALOG *dia, int x, int y)
7584 {
7585 INTBIG i;
7586
7587 if (dia->window == 0) return(0);
7588 for(i=0; i<dia->itemdesc->items; i++)
7589 {
7590 if (x < dia->itemdesc->list[i].r.left) continue;
7591 if (x > dia->itemdesc->list[i].r.right) continue;
7592 if (y < dia->itemdesc->list[i].r.top) continue;
7593 if (y > dia->itemdesc->list[i].r.bottom) continue;
7594 return(i+1);
7595 }
7596 return(0);
7597 }
7598
7599 /*
7600 * Routine to make an icon from data
7601 */
gra_makeicon(INTBIG idata)7602 HICON gra_makeicon(INTBIG idata)
7603 {
7604 UCHAR1 zero[128], *data;
7605 int i;
7606
7607 data = (UCHAR1 *)idata;
7608 for(i=0; i<128; i++)
7609 {
7610 zero[i] = 0;
7611 data[i] = ~data[i];
7612 }
7613 HICON icon = CreateIcon(0, 32, 32, 1, 1, (UCHAR1 *)data, zero);
7614 for(i=0; i<128; i++) data[i] = ~data[i];
7615 return(icon);
7616 }
7617
7618 /****************************** TCL SUPPORT ******************************/
7619
7620 #if LANGTCL
gra_initializetcl(void)7621 INTBIG gra_initializetcl(void)
7622 {
7623 INTBIG err;
7624 CHAR *newArgv[2];
7625 void *infstr;
7626
7627 /* set the program name/path */
7628 newArgv[0] = x_("Electric");
7629 newArgv[1] = NULL;
7630 (void)Tcl_FindExecutable(newArgv[0]);
7631
7632 tcl_interp = Tcl_CreateInterp();
7633 if (tcl_interp == 0) error(_("from Tcl_CreateInterp"));
7634
7635 /* tell Electric the TCL interpreter handle */
7636 el_tclinterpreter(tcl_interp);
7637
7638 /* set the Tcl library directory - for internal Tcl use */
7639 infstr = initinfstr();
7640 addstringtoinfstr(infstr, el_libdir);
7641 addstringtoinfstr(infstr, x_("tcl8.3"));
7642 if (Tcl_SetVar(tcl_interp, x_("tcl_library"), returninfstr(infstr), TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL)
7643 {
7644 ttyputerr(_("Tcl_SetVar failed: %s"), tcl_interp->result);
7645 return(1);
7646 }
7647
7648 /* Make command-line arguments available in the Tcl variables "argc" and "argv" */
7649 Tcl_SetVar(tcl_interp, x_("argv"), x_(""), TCL_GLOBAL_ONLY);
7650 Tcl_SetVar(tcl_interp, x_("argc"), x_("0"), TCL_GLOBAL_ONLY);
7651 Tcl_SetVar(tcl_interp, x_("argv0"), x_("electric"), TCL_GLOBAL_ONLY);
7652
7653 /* Set the "tcl_interactive" variable */
7654 Tcl_SetVar(tcl_interp, x_("tcl_interactive"), x_("1"), TCL_GLOBAL_ONLY);
7655
7656 /* initialize the interpreter */
7657 err = Tcl_Init(tcl_interp);
7658 if (err != TCL_OK) error(_("(from Tcl_Init) %s"), tcl_interp->result);
7659
7660 return(err);
7661 }
7662 #endif
7663
7664 /****************************** PRINTING ******************************/
7665
7666 /* call this routine to print the current window */
printewindow(void)7667 void printewindow(void)
7668 {
7669 INTBIG pagewid, pagehei, pagehpixperinch, pagevpixperinch, ypos, i, l, style,
7670 marginx, marginy, slx, shx, sly, shy, *curstate, xpos, boxsize, dashindent,
7671 ulx, uhx, uly, uhy, width, height, centerx, centery, prod1, prod2, indent,
7672 fontHeight, page, topmargin, leftmargin, savewid, savehei, resfactor,
7673 saveslx, saveshx, savesly, saveshy, bigwid, bighei, wlx, whx, wly, why,
7674 lastboxxpos, yposbox, topypos;
7675 REGISTER CHAR *name, *header, *cptr;
7676 REGISTER UCHAR1 **saverowstart, *savedata, *ptr;
7677 WINDOWPART *win;
7678 NODEPROTO *np;
7679 WINDOWFRAME *wf;
7680 REGISTER VARIABLE *var;
7681 BOOLEAN savedirty, *done;
7682 HCURSOR hCursorBusy, hCursorOld;
7683 static DOCINFO di = {sizeof(DOCINFO), x_("Electric"), NULL};
7684 RGBQUAD bmiColors[256];
7685 BITMAPINFO *bmiInfo, *savebmiinfo;
7686 CDC printDC, *pDCPrint, *saveoff;
7687 HDC hPrnDC;
7688 DEVMODE *dm;
7689 CFont *fnt;
7690 HBITMAP savebitmap;
7691 REGISTER void *infstr;
7692 CPen penBlack, penGrey;
7693
7694 /* get cell to plot */
7695 win = el_curwindowpart;
7696 if (win == NOWINDOWPART)
7697 {
7698 ttyputerr(_("No current window to print"));
7699 return;
7700 }
7701 wf = win->frame;
7702 np = win->curnodeproto;
7703
7704 /* get printing control bits */
7705 curstate = io_getstatebits();
7706
7707 if (np == NONODEPROTO)
7708 {
7709 /* allow explorer window, but nothing else */
7710 if ((win->state&WINDOWTYPE) != EXPLORERWINDOW)
7711 {
7712 ttyputerr(_("Cannot print this type of window"));
7713 return;
7714 }
7715 }
7716
7717 /* create a print structure */
7718 CPrintDialog printDlg(FALSE);
7719
7720 /* set requested orientation */
7721 if (printDlg.GetDefaults() == 0) return;
7722 dm = printDlg.GetDevMode();
7723 if ((curstate[1]&PSAUTOROTATE) != 0 && np != NONODEPROTO &&
7724 (np->cellview->viewstate&TEXTVIEW) == 0)
7725 {
7726 (void)io_getareatoprint(np, &wlx, &whx, &wly, &why, FALSE);
7727 if (whx-wlx > why-wly) curstate[0] |= PSROTATE; else
7728 curstate[0] &= ~PSROTATE;
7729 }
7730 if ((curstate[0]&PSROTATE) != 0) dm->dmOrientation = DMORIENT_LANDSCAPE; else
7731 dm->dmOrientation = DMORIENT_PORTRAIT;
7732 printDlg.m_pd.Flags &= ~PD_RETURNDEFAULT;
7733
7734 /* show the dialog */
7735 if (printDlg.DoModal() != IDOK) return;
7736
7737 /* set cursor to busy */
7738 hCursorBusy = LoadCursor(NULL, IDC_WAIT);
7739 hCursorOld = SetCursor(hCursorBusy);
7740
7741 /* collect size information about the Printer DC */
7742 hPrnDC = printDlg.m_pd.hDC; /* GetPrinterDC(); */
7743 if (hPrnDC == 0)
7744 {
7745 ttyputerr(_("Printing error: could not start print job"));
7746 return;
7747 }
7748 pDCPrint = printDC.FromHandle(hPrnDC);
7749 pagewid = pDCPrint->GetDeviceCaps(HORZRES);
7750 pagehei = pDCPrint->GetDeviceCaps(VERTRES);
7751 pagehpixperinch = pDCPrint->GetDeviceCaps(LOGPIXELSX);
7752 pagevpixperinch = pDCPrint->GetDeviceCaps(LOGPIXELSY);
7753
7754 /* start printing */
7755 pDCPrint->StartDoc(&di);
7756
7757 if (np == NONODEPROTO && (win->state&WINDOWTYPE) == EXPLORERWINDOW)
7758 {
7759 /* an explorer window: print text */
7760 us_explorerreadoutinit(win);
7761 pDCPrint->StartPage();
7762
7763 /* print the window */
7764 fontHeight = MulDiv(10, GetDeviceCaps(hPrnDC, LOGPIXELSY), 72);
7765 fnt = new CFont();
7766 fnt->CreateFont(-fontHeight, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET,
7767 OUT_DEVICE_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
7768 DEFAULT_PITCH | FF_DONTCARE, x_("Courier"));
7769 pDCPrint->SelectObject(fnt);
7770 pDCPrint->SetTextColor(RGB(0,0,0));
7771 pDCPrint->SetBkColor(RGB(255,255,255));
7772
7773 var = getval((INTBIG)io_tool, VTOOL, VFRACT, x_("IO_postscript_margin"));
7774 if (var == NOVARIABLE) i = muldiv(DEFAULTPSMARGIN, WHOLE, 75); else
7775 i = var->addr;
7776 topmargin = muldiv(i, pagevpixperinch, WHOLE);
7777 leftmargin = muldiv(i, pagehpixperinch, WHOLE);
7778
7779 ypos = topmargin;
7780 page = 1;
7781 lastboxxpos = -1;
7782 boxsize = fontHeight * 2 / 3;
7783 dashindent = boxsize / 5;
7784 penBlack.CreatePen(PS_SOLID | PS_COSMETIC, 1, RGB(0, 0, 0));
7785 penGrey.CreatePen(PS_SOLID | PS_COSMETIC, 1, RGB(128, 128, 128));
7786
7787 pDCPrint->SelectObject(&penBlack);
7788 for(;;)
7789 {
7790 name = us_explorerreadoutnext(win, &indent, &style, &done, 0);
7791 if (name == 0) break;
7792
7793 /* insert page breaks */
7794 if (ypos+fontHeight >= pagehei-topmargin)
7795 {
7796 ypos = topmargin;
7797 pDCPrint->EndPage();
7798 pDCPrint->StartPage();
7799 }
7800
7801 /* print the header */
7802 if (ypos == topmargin)
7803 {
7804 infstr = initinfstr();
7805 formatinfstr(infstr, _("Cell Explorer Page %ld"), page);
7806 header = returninfstr(infstr);
7807 pDCPrint->TextOut(leftmargin, 0, header, estrlen(header));
7808 page++;
7809 if (topmargin < fontHeight*2) ypos += fontHeight*2;
7810 }
7811 xpos = leftmargin + indent * fontHeight;
7812
7813 /* draw the box */
7814 yposbox = ypos + (fontHeight-boxsize) / 2;
7815 pDCPrint->MoveTo(xpos, yposbox);
7816 pDCPrint->LineTo(xpos+boxsize, yposbox);
7817 pDCPrint->LineTo(xpos+boxsize, yposbox+boxsize);
7818 pDCPrint->LineTo(xpos, yposbox+boxsize);
7819 pDCPrint->LineTo(xpos, yposbox);
7820 if (style >= 2)
7821 {
7822 /* draw horizontal line in box */
7823 pDCPrint->MoveTo(xpos+dashindent, yposbox+boxsize/2);
7824 pDCPrint->LineTo(xpos+boxsize-dashindent, yposbox+boxsize/2);
7825 if (style == 2)
7826 {
7827 /* draw vertical line in box */
7828 pDCPrint->MoveTo(xpos+boxsize/2, yposbox+dashindent);
7829 pDCPrint->LineTo(xpos+boxsize/2, yposbox+boxsize-dashindent);
7830 }
7831 }
7832
7833 /* draw the connecting lines */
7834 if (indent > 0)
7835 {
7836 pDCPrint->SelectObject(&penGrey);
7837 pDCPrint->MoveTo(xpos, yposbox+boxsize/2);
7838 pDCPrint->LineTo(xpos-fontHeight+boxsize/2, yposbox+boxsize/2);
7839 for(i=0; i<indent; i++)
7840 {
7841 if (done[i]) continue;
7842 l = leftmargin+i*fontHeight+boxsize/2;
7843 if (l == lastboxxpos)
7844 topypos = yposbox+boxsize/2-fontHeight+boxsize/2; else
7845 topypos = yposbox+boxsize/2-fontHeight;
7846 pDCPrint->MoveTo(l, yposbox+boxsize/2);
7847 pDCPrint->LineTo(l, topypos);
7848 }
7849 pDCPrint->SelectObject(&penBlack);
7850 }
7851 lastboxxpos = xpos + boxsize/2;
7852
7853 /* show the text */
7854 pDCPrint->TextOut(xpos+boxsize+boxsize/2, ypos, name, estrlen(name));
7855 ypos += fontHeight;
7856 }
7857 delete fnt;
7858 pDCPrint->EndPage();
7859 } else if (np != NONODEPROTO && (np->cellview->viewstate&TEXTVIEW) != 0)
7860 {
7861 /* a text window: print text */
7862 pDCPrint->StartPage();
7863
7864 /* print the window */
7865 fontHeight = MulDiv(10, GetDeviceCaps(hPrnDC, LOGPIXELSY), 72);
7866 fnt = new CFont();
7867 fnt->CreateFont(-fontHeight, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET,
7868 OUT_DEVICE_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
7869 DEFAULT_PITCH | FF_DONTCARE, x_("Courier"));
7870 pDCPrint->SelectObject(fnt);
7871 pDCPrint->SetTextColor(RGB(0,0,0));
7872 pDCPrint->SetBkColor(RGB(255,255,255));
7873
7874 var = getval((INTBIG)io_tool, VTOOL, VFRACT, x_("IO_postscript_margin"));
7875 if (var == NOVARIABLE) i = muldiv(DEFAULTPSMARGIN, WHOLE, 75); else
7876 i = var->addr;
7877 topmargin = muldiv(i, pagevpixperinch, WHOLE);
7878 leftmargin = muldiv(i, pagehpixperinch, WHOLE);
7879
7880 ypos = topmargin;
7881 page = 1;
7882 var = getvalkey((INTBIG)np, VNODEPROTO, VSTRING|VISARRAY, el_cell_message_key);
7883 if (var != NOVARIABLE)
7884 {
7885 l = getlength(var);
7886 for(i=0; i<l; i++)
7887 {
7888 cptr = ((CHAR **)var->addr)[i];
7889 if (i == l-1 && *cptr == 0) continue;
7890 if (ypos+fontHeight >= pagehei-topmargin)
7891 {
7892 ypos = topmargin;
7893 pDCPrint->EndPage();
7894 pDCPrint->StartPage();
7895 }
7896 if (ypos == topmargin)
7897 {
7898 /* print the header */
7899 infstr = initinfstr();
7900 formatinfstr(infstr, _("Library: %s Cell: %s Page %ld"), np->lib->libname,
7901 describenodeproto(np), page);
7902 header = returninfstr(infstr);
7903 pDCPrint->TextOut(leftmargin, 0, header, estrlen(header));
7904
7905 if ((us_useroptions&NODATEORVERSION) == 0 && page == 1)
7906 {
7907 infstr = initinfstr();
7908 if (np->creationdate != 0)
7909 formatinfstr(infstr, _("Created: %s"), timetostring((time_t)np->creationdate));
7910 if (np->revisiondate != 0)
7911 formatinfstr(infstr, _(" Revised: %s"), timetostring((time_t)np->revisiondate));
7912 header = returninfstr(infstr);
7913 pDCPrint->TextOut(leftmargin, fontHeight, header, estrlen(header));
7914 }
7915 page++;
7916 if (topmargin < fontHeight*2) ypos += fontHeight*2;
7917 }
7918 pDCPrint->TextOut(leftmargin, ypos, cptr, estrlen(cptr));
7919 ypos += fontHeight;
7920 }
7921 }
7922 delete fnt;
7923 pDCPrint->EndPage();
7924 } else if (np != NONODEPROTO)
7925 {
7926 /* a graphics window: get the print resolution scale factor */
7927 var = getval((INTBIG)io_tool, VTOOL, VINTEGER, x_("IO_print_resolution_scale"));
7928 if (var == NOVARIABLE) resfactor = 1; else
7929 resfactor = var->addr;
7930
7931 /* make a bigger offscreen window */
7932 bigwid = wf->swid * resfactor;
7933 bighei = wf->shei * resfactor;
7934 if (gra_getbiggeroffscreenbuffer(wf, bigwid, bighei)) return;
7935 saveoff = (CDC *)wf->hDCOff; wf->hDCOff = (void *)gra_biggeroffhdc;
7936 savebitmap = wf->hBitmap; wf->hBitmap = gra_biggeroffbitmap;
7937 savebmiinfo = wf->bminfo; wf->bminfo = gra_biggeroffbitmapinfo;
7938 savedata = wf->data; wf->data = gra_biggeroffdatabuffer;
7939 saverowstart = wf->rowstart; wf->rowstart = gra_biggeroffrowstart;
7940 savewid = wf->swid; wf->swid = bigwid;
7941 savehei = wf->shei; wf->shei = bighei;
7942 savedirty = wf->offscreendirty; wf->offscreendirty = FALSE;
7943 wf->revy = wf->shei - 1;
7944 if (wf->hPalette != 0)
7945 {
7946 (void)((CDC *)wf->hDCOff)->SelectPalette((CPalette *)wf->hPalette, TRUE);
7947 (void)((CDC *)wf->hDCOff)->RealizePalette();
7948 }
7949 slx = win->uselx; shx = win->usehx;
7950 sly = win->usely; shy = win->usehy;
7951 win->uselx *= resfactor;
7952 win->usehx *= resfactor;
7953 win->usely *= resfactor;
7954 win->usehy *= resfactor;
7955 saveslx = win->screenlx;
7956 saveshx = win->screenhx;
7957 savesly = win->screenly;
7958 saveshy = win->screenhy;
7959 if ((win->state&WINDOWTYPE) == WAVEFORMWINDOW)
7960 {
7961 wlx = win->screenlx;
7962 whx = win->screenhx;
7963 wly = win->screenly;
7964 why = win->screenhy;
7965 } else
7966 {
7967 (void)io_getareatoprint(np, &wlx, &whx, &wly, &why, FALSE);
7968 us_squarescreen(win, NOWINDOWPART, FALSE, &wlx, &whx, &wly, &why, 1);
7969 }
7970 win->screenlx = slx = wlx;
7971 win->screenhx = shx = whx;
7972 win->screenly = sly = wly;
7973 win->screenhy = shy = why;
7974 computewindowscale(win);
7975
7976 /* redraw the window in the larger buffer */
7977 gra_noflush = TRUE;
7978 if ((win->state&WINDOWTYPE) == WAVEFORMWINDOW)
7979 {
7980 (*win->redisphandler)(win);
7981 } else
7982 {
7983 us_redisplaynow(win, TRUE);
7984 us_endchanges(win);
7985 }
7986 gra_noflush = FALSE;
7987 (void)us_makescreen(&slx, &sly, &shx, ­, win);
7988
7989 /* restore the normal state of the window */
7990 wf->hDCOff = saveoff;
7991 wf->hBitmap = savebitmap;
7992 wf->bminfo = savebmiinfo;
7993 wf->data = savedata;
7994 wf->rowstart = saverowstart;
7995 wf->swid = savewid;
7996 wf->shei = savehei;
7997 wf->revy = wf->shei - 1;
7998 wf->offscreendirty = savedirty;
7999 if (wf->hPalette != 0)
8000 {
8001 (void)((CDC *)wf->hDCOff)->SelectPalette((CPalette *)wf->hPalette, TRUE);
8002 (void)((CDC *)wf->hDCOff)->RealizePalette();
8003 }
8004 win->uselx /= resfactor;
8005 win->usehx /= resfactor;
8006 win->usely /= resfactor;
8007 win->usehy /= resfactor;
8008 win->screenlx = saveslx;
8009 win->screenhx = saveshx;
8010 win->screenly = savesly;
8011 win->screenhy = saveshy;
8012 computewindowscale(win);
8013
8014 marginx = pagehpixperinch / 2;
8015 marginy = pagevpixperinch / 2;
8016
8017 /* make the plot have square pixels */
8018 ulx = marginx;
8019 uly = marginy;
8020 uhx = pagewid-marginx;
8021 uhy = pagehei-marginy;
8022 prod1 = (shx - slx) * (uhy - uly);
8023 prod2 = (shy - sly) * (uhx - ulx);
8024 if (prod1 != prod2)
8025 {
8026 /* adjust the scale */
8027 if (prod1 > prod2)
8028 {
8029 /* make it fill the width of the screen */
8030 height = muldiv(uhx - ulx, shy - sly, shx - slx);
8031 centery = (uly + uhy) / 2;
8032 uly = centery - height/2;
8033 uhy = uly + height;
8034 } else
8035 {
8036 /* make it fill the height of the screen */
8037 width = muldiv(uhy - uly, shx - slx, shy - sly);
8038 centerx = (ulx + uhx) / 2;
8039 ulx = centerx - width/2;
8040 uhx = ulx + width;
8041 }
8042 }
8043
8044 /* adjust the background color to white */
8045 i = GetDIBColorTable(gra_biggeroffhdc->m_hDC, 0, 256, bmiColors);
8046 bmiColors[0].rgbRed = 0xFF;
8047 bmiColors[0].rgbGreen = 0xFF;
8048 bmiColors[0].rgbBlue = 0xFF;
8049 bmiColors[0].rgbReserved = 0;
8050
8051 bmiInfo = (BITMAPINFO *)emalloc(sizeof(BITMAPINFOHEADER) + sizeof(bmiColors), db_cluster);
8052 if (bmiInfo == 0) return;
8053 ptr = (UCHAR1 *)bmiInfo;
8054 memcpy(ptr, gra_biggeroffbitmapinfo, sizeof(BITMAPINFOHEADER));
8055 ptr += sizeof(BITMAPINFOHEADER);
8056 memcpy(ptr, &bmiColors, sizeof(bmiColors));
8057
8058 pDCPrint->StartPage();
8059
8060 /* print the window */
8061 StretchDIBits(hPrnDC, ulx, uly, uhx-ulx, uhy-uly,
8062 slx, sly, shx-slx+1, shy-sly+1,
8063 gra_biggeroffdatabuffer, bmiInfo, DIB_RGB_COLORS, SRCCOPY);
8064 efree((CHAR *)bmiInfo);
8065
8066 pDCPrint->EndPage();
8067 }
8068
8069 /* finish printing */
8070 pDCPrint->EndDoc();
8071 pDCPrint->Detach();
8072 DeleteDC(hPrnDC);
8073
8074 /* restore original cursor */
8075 SetCursor(hCursorOld);
8076 }
8077