1 // Dialog window handling
2 // Copyright (C) 2000 Core Technologies.
3 
4 // This file is part of e93.
5 //
6 // e93 is free software; you can redistribute it and/or modify
7 // it under the terms of the e93 LICENSE AGREEMENT.
8 //
9 // e93 is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // e93 LICENSE AGREEMENT for more details.
13 //
14 // You should have received a copy of the e93 LICENSE AGREEMENT
15 // along with e93; see the file "LICENSE.TXT".
16 
17 #include	"includes.h"
18 
19 #define	BACKGROUND_COLOR		0x718F9E		// color to use for dialog backgrounds
20 #define	SHADOW_COLOR_UL			0x91AFBE		// shadow colors (upper left)
21 #define	SHADOW_COLOR_LR			0x314F5E		// (lower right)
22 
ChangeFocus(DIALOG * dialog,DIALOG_ITEM * newItem)23 static void ChangeFocus(DIALOG *dialog,DIALOG_ITEM *newItem)
24 // Change the focus of dialog to newItem
25 // If the focus is already at new item, do nothing
26 // NOTE: this is DIALOG ITEM focus, not X window focus
27 {
28 	DIALOG_ITEM
29 		*oldItem;
30 
31 	oldItem=dialog->focusItem;
32 	if(oldItem!=newItem)							// make sure they are not the same, or both NULL
33 	{
34 		dialog->focusItem=newItem;
35 		if(oldItem)
36 		{
37 			if(oldItem->focusChangeProc)
38 			{
39 				oldItem->focusChangeProc(oldItem);	// tell him about it
40 			}
41 		}
42 		if(newItem)
43 		{
44 			if(newItem->focusChangeProc)
45 			{
46 				newItem->focusChangeProc(newItem);	// tell him about it
47 			}
48 		}
49 	}
50 }
51 
LocateForwardFocusItem(DIALOG * dialog)52 static DIALOG_ITEM *LocateForwardFocusItem(DIALOG *dialog)
53 // Look forward from the dialog item which currently has the focus
54 // and return the next item which should get focus
55 // If no items require focus, return NULL
56 {
57 	DIALOG_ITEM
58 		*currentItem,
59 		*nextFocusItem;
60 
61 	if((currentItem=dialog->focusItem))
62 	{
63 		currentItem=currentItem->nextItem;			// begin looking one beyond the old focus item (if there was an old one)
64 	}
65 	nextFocusItem=NULL;
66 	while(currentItem&&!nextFocusItem)
67 	{
68 		if(currentItem->wantFocus)
69 		{
70 			nextFocusItem=currentItem;				// this is the next one that wants the focus
71 		}
72 		currentItem=currentItem->nextItem;
73 	}
74 	currentItem=dialog->firstItem;					// start over at the beginning
75 	while(currentItem&&!nextFocusItem)
76 	{
77 		if(currentItem->wantFocus)
78 		{
79 			nextFocusItem=currentItem;				// this is the next one that wants the focus
80 		}
81 		currentItem=currentItem->nextItem;
82 	}
83 	return(nextFocusItem);
84 }
85 
ForwardFocus(DIALOG * dialog)86 static void ForwardFocus(DIALOG *dialog)
87 // Push the focus forward one notch, and alert the involved parties
88 // NOTE: this is DIALOG ITEM focus, not X window focus
89 {
90 	DIALOG_ITEM
91 		*nextFocusItem;
92 
93 	nextFocusItem=LocateForwardFocusItem(dialog);	// this can return NULL, which will be passed to ChangeFocus to select nothing
94 	ChangeFocus(dialog,nextFocusItem);
95 }
96 
LinkItemToDialog(DIALOG * dialog,DIALOG_ITEM * newItem)97 static void LinkItemToDialog(DIALOG *dialog,DIALOG_ITEM *newItem)
98 // Link newItem to the end of the linked list of dialog items in dialog
99 {
100 	newItem->dialog=dialog;							// point back at the dialog
101 	newItem->nextItem=NULL;
102 	if((newItem->previousItem=dialog->lastItem))
103 	{
104 		dialog->lastItem->nextItem=newItem;
105 		dialog->lastItem=newItem;
106 	}
107 	else
108 	{
109 		dialog->firstItem=dialog->lastItem=newItem;
110 	}
111 }
112 
UnlinkItemFromDialog(DIALOG_ITEM * dialogItem)113 static void UnlinkItemFromDialog(DIALOG_ITEM *dialogItem)
114 // Unlink dialogItem from the dialog list
115 {
116 	if(dialogItem->previousItem)
117 	{
118 		dialogItem->previousItem->nextItem=dialogItem->nextItem;
119 	}
120 	else
121 	{
122 		dialogItem->dialog->firstItem=dialogItem->nextItem;
123 	}
124 	if(dialogItem->nextItem)
125 	{
126 		dialogItem->nextItem->previousItem=dialogItem->previousItem;
127 	}
128 	else
129 	{
130 		dialogItem->dialog->lastItem=dialogItem->previousItem;
131 	}
132 }
133 
NewDialogItem(DIALOG * dialog,bool (* createProc)(DIALOG_ITEM * item,void * itemDescriptor),void * itemDescriptor)134 DIALOG_ITEM *NewDialogItem(DIALOG *dialog,bool (*createProc)(DIALOG_ITEM *item,void *itemDescriptor),void *itemDescriptor)
135 // Create a new dialog item, link it to dialog, call the item's creation procedure
136 // createProc must not be NULL and must return true for this to succeed
137 // If there is a problem, SetError, return NULL
138 {
139 	DIALOG_ITEM
140 		*dialogItem;
141 
142 	if((dialogItem=(DIALOG_ITEM *)MNewPtrClr(sizeof(DIALOG_ITEM))))	// make new item, clear any procedure pointers to NULL
143 	{
144 		LinkItemToDialog(dialog,dialogItem);
145 		if(createProc(dialogItem,itemDescriptor))
146 		{
147 			return(dialogItem);
148 		}
149 		UnlinkItemFromDialog(dialogItem);
150 		MDisposePtr(dialogItem);
151 	}
152 	return(NULL);
153 }
154 
DisposeDialogItem(DIALOG_ITEM * dialogItem)155 void DisposeDialogItem(DIALOG_ITEM *dialogItem)
156 // Unlink, and dispose of a dialog item, created by NewDialogItem
157 {
158 	if(dialogItem->disposeProc)
159 	{
160 		dialogItem->disposeProc(dialogItem);
161 	}
162 	UnlinkItemFromDialog(dialogItem);
163 	MDisposePtr(dialogItem);
164 }
165 
CreateDialog(EDITOR_RECT * rect,const char * title,EDITOR_COLOR background)166 static DIALOG *CreateDialog(EDITOR_RECT *rect,const char *title,EDITOR_COLOR background)
167 // Open a new empty dialog of the given size, with the given title
168 // It should not be updated until all the items have been added to it
169 // If there is a problem, SetError, return NULL
170 {
171 	DIALOG
172 		*dialog;
173 	EDITOR_WINDOW
174 		*window;
175 	WINDOW_LIST_ELEMENT
176 		*windowElement;
177 	UINT32
178 		valueMask;
179 	Atom
180 		protocols[2];														// number of protocols
181 	XWMHints
182 		hints;																// hints to tell window manager how to treat these windows
183 	XSizeHints
184 		sizeHints;															// window size info (used to REALLY convince X that I know where I want my own window)
185 	XEvent
186 		xEvent;
187 	INT32
188 		xOffset,
189 		yOffset;
190 	UINT32
191 		screenWidth,
192 		screenHeight;
193 
194 	if((dialog=(DIALOG *)MNewPtr(sizeof(DIALOG))))
195 	{
196 		dialog->backgroundColor=background;
197 		dialog->dialogComplete=false;										// not done with this yet
198 		dialog->firstItem=dialog->lastItem=dialog->focusItem=NULL;
199 		if((window=(EDITOR_WINDOW *)MNewPtr(sizeof(EDITOR_WINDOW))))		// create editor window
200 		{
201 			if((windowElement=(WINDOW_LIST_ELEMENT *)MNewPtr(sizeof(WINDOW_LIST_ELEMENT))))	// create a window list element
202 			{
203 				LinkWindowElement(windowElement);							// link it to the global window list that we maintain
204 				windowElement->editorWindow=window;							// point to our high level concept of window
205 				window->windowType=EWT_DIALOG;								// set the editor window type to "dialog"
206 				window->userData=windowElement;								// point back to the window element
207 
208 				valueMask=0;
209 				// Due to X's nasty error handling, we assume this create does not fail!!!
210 
211 				GetEditorScreenOffsetAndDimensions(&xOffset,&yOffset,&screenWidth,&screenHeight);
212 				windowElement->xWindow=XCreateWindow(xDisplay,RootWindow(xDisplay,xScreenNum),rect->x+xOffset,rect->y+yOffset,rect->w,rect->h,2,CopyFromParent,InputOutput,DefaultVisual(xDisplay,xScreenNum),valueMask,NULL);
213 
214 				sizeHints.flags=USSize|USPosition|PMinSize;					// ### LIE to X, tell it the user requested the size and position so it will honor them
215 				sizeHints.x=rect->x+xOffset;
216 				sizeHints.y=rect->y+yOffset;
217 				sizeHints.width=rect->w;
218 				sizeHints.height=rect->h;
219 				sizeHints.min_width=rect->w;
220 				sizeHints.min_height=rect->h;
221 				sizeHints.max_width=rect->w;
222 				sizeHints.max_height=rect->h;
223 				XSetWMNormalHints(xDisplay,windowElement->xWindow,&sizeHints);
224 
225 				XStoreName(xDisplay,windowElement->xWindow,title);
226 				XSelectInput(xDisplay,windowElement->xWindow,ExposureMask|ButtonPressMask|ButtonReleaseMask|FocusChangeMask|KeyPressMask|StructureNotifyMask);	// want to see these events
227 
228 				protocols[0]=takeFocusAtom;
229 				protocols[1]=deleteWindowAtom;
230 				XSetWMProtocols(xDisplay,windowElement->xWindow,&(protocols[0]),2);	// tell X we would like to participate in these protocols
231 
232 				hints.flags=InputHint|StateHint|WindowGroupHint;
233 				hints.input=True;
234 				hints.initial_state=NormalState;
235 				hints.window_group=((WINDOW_LIST_ELEMENT *)rootMenuWindow->userData)->xWindow;	// all dialogs belong to the group headed by the main menu window
236 				XSetWMHints(xDisplay,windowElement->xWindow,&hints);
237 
238 // NOTE: when setting transient below, It would be nice if the window manager would allow it to be transient for the GROUP, so that
239 // it would stay on top of all of the editor windows, but so far, I have not been able to convince it to do that :{
240 // Note that it is being set transient to itself, this provides behavior which is better than anything else I could get the WM
241 // to do!
242 //
243 // NOTE 10/13/2000 the new Gnome does not like this, so it was removed
244 //				XSetTransientForHint(xDisplay,windowElement->xWindow,windowElement->xWindow);	// tell WM this is transient (would like it to stay on top, but window manager will not oblige)
245 
246 				windowElement->invalidRegion=XCreateRegion();				// create new empty invalid region
247 
248 				windowElement->currentIcon=(Pixmap)NULL;					// no icon associated with this window
249 				dialog->parentWindow=window;								// link the dialog to the window just created
250 				window->windowInfo=dialog;									// link the window to the dialog just created
251 				XMapRaised(xDisplay,windowElement->xWindow);				// map window to the top of the display
252 				WaitUntilMapped(window);									// wait until this window is actually mapped before continuing (olwm likes to mess with the temporal ordering of our windows, this attempts to prevent its inane meddling
253 
254 				// This code asks the WM to please keep our dialog window on top
255 				xEvent.xclient.type=ClientMessage;
256 				xEvent.xclient.serial=0;
257 				xEvent.xclient.send_event=True;
258 				xEvent.xclient.display=xDisplay;
259 				xEvent.xclient.window=windowElement->xWindow;
260 				xEvent.xclient.message_type=XInternAtom(xDisplay,"_NET_WM_STATE",True);
261 				xEvent.xclient.format=32;
262 				xEvent.xclient.data.l[0]=1;					// 1 _NET_WM_STATE_ADD
263 				xEvent.xclient.data.l[1]=XInternAtom(xDisplay,"_NET_WM_STATE_ABOVE",True);
264 				xEvent.xclient.data.l[2]=XInternAtom(xDisplay,"_NET_WM_STATE_MODAL",True);
265 				xEvent.xclient.data.l[3]=1;					// source indication (1 means application)
266 				xEvent.xclient.data.l[4]=0;
267 				XSendEvent(xDisplay,XDefaultRootWindow(xDisplay),False,SubstructureRedirectMask|SubstructureNotifyMask,&xEvent);
268 
269 				return(dialog);
270 			}
271 			MDisposePtr(window);
272 		}
273 		MDisposePtr(dialog);
274 	}
275 	return(NULL);
276 }
277 
DisposeDialog(DIALOG * dialog)278 static void DisposeDialog(DIALOG *dialog)
279 // Close a dialog window, kill any items it may have linked to it
280 {
281 	WINDOW_LIST_ELEMENT
282 		*windowElement;
283 
284 	while(dialog->firstItem)
285 	{
286 		DisposeDialogItem(dialog->firstItem);								// remove any items
287 	}
288 	FocusAwayFrom(dialog->parentWindow);									// trick X by moving focus so window manager will not try to when this window dies
289 	windowElement=(WINDOW_LIST_ELEMENT *)dialog->parentWindow->userData;	// get the x window associated with this document window
290 	XDestroyRegion(windowElement->invalidRegion);							// destroy invalid region
291 	XDestroyWindow(xDisplay,windowElement->xWindow);						// tell x to make the window go away
292 	WaitUntilDestroyed(dialog->parentWindow);
293 	UnlinkWindowElement(windowElement);										// unlink it from our list
294 	MDisposePtr(windowElement);
295 	MDisposePtr(dialog->parentWindow);
296 	MDisposePtr(dialog);
297 	UpdateEditorWindows();													// update the display
298 }
299 
CreateCenteredDialog(UINT32 width,UINT32 height,const char * title,EDITOR_COLOR background)300 static DIALOG *CreateCenteredDialog(UINT32 width,UINT32 height,const char *title,EDITOR_COLOR background)
301 // Open a new dialog window of width, height centered
302 // nicely on the screen
303 // If there is a problem, SetError, and return NULL
304 {
305 	EDITOR_RECT
306 		dialogRect;
307 	INT32
308 		xOffset,
309 		yOffset;
310 	UINT32
311 		screenWidth,
312 		screenHeight;
313 
314 	GetEditorScreenOffsetAndDimensions(&xOffset,&yOffset,&screenWidth,&screenHeight);
315 	dialogRect.x=screenWidth/2-width/2;						// half the way across
316 	dialogRect.y=screenHeight/3-height/2;					// 1/3 the way down
317 	dialogRect.w=width;
318 	dialogRect.h=height;
319 	return(CreateDialog(&dialogRect,title,background));
320 }
321 
DrawDialog(DIALOG * dialog)322 static void DrawDialog(DIALOG *dialog)
323 // Draw the dialog, and all items that request it
324 // Drawing focus is handled from here
325 {
326 	DIALOG_ITEM
327 		*currentItem;
328 	WINDOW_LIST_ELEMENT
329 		*windowElement;
330 	Window
331 		xWindow;
332 	XWindowAttributes
333 		attributes;
334 	EDITOR_RECT
335 		rect;
336 	Pixmap
337 		imageBuffer;
338 	bool
339 		bufferedUpdate;		// tells if update is buffered
340 
341 	windowElement=(WINDOW_LIST_ELEMENT *)dialog->parentWindow->userData;		// get the x window information associated with this window
342 	xWindow=windowElement->xWindow;												// get x window for this window
343 
344 	XGetWindowAttributes(xDisplay,xWindow,&attributes);
345 	rect.x=0;
346 	rect.y=0;
347 	rect.w=attributes.width;
348 	rect.h=attributes.height;
349 
350 	imageBuffer=GetWindowUpdatePixmap(attributes.width,attributes.height);		// go get a pixmap
351 	bufferedUpdate=true;
352 	if(imageBuffer==None)		// if we failed to get an offscreen buffer, just update directly
353 	{
354 		imageBuffer=xWindow;
355 		bufferedUpdate=false;
356 	}
357 
358 	XSetRegion(xDisplay,xGraphicsContext,windowElement->invalidRegion);			// set clipping to what's invalid
359 	XSetFillStyle(xDisplay,xGraphicsContext,FillSolid);
360 	XSetForeground(xDisplay,xGraphicsContext,EditorColorToXPixel(dialog->backgroundColor));
361 	XFillRectangle(xDisplay,imageBuffer,xGraphicsContext,0,0,attributes.width,attributes.height);
362 	OutlineShadowRectangle(imageBuffer,&rect,SHADOW_COLOR_UL,SHADOW_COLOR_LR,2);	// drop in border
363 
364 	currentItem=dialog->firstItem;
365 	while(currentItem)
366 	{
367 		if(currentItem->drawProc)
368 		{
369 			currentItem->drawProc(currentItem,imageBuffer,windowElement->invalidRegion);
370 		}
371 		currentItem=currentItem->nextItem;
372 	}
373 
374 	if(bufferedUpdate)			// if the update was buffered, the move the data to the screen
375 	{
376 		XSetRegion(xDisplay,xGraphicsContext,windowElement->invalidRegion);		// only copy what's needed
377 		XCopyArea(xDisplay,imageBuffer,xWindow,xGraphicsContext,0,0,attributes.width,attributes.height,0,0);	// copy the updates
378 		XSetClipMask(xDisplay,xGraphicsContext,None);							// get rid of clip mask
379 	}
380 }
381 
UpdateDialogWindow(EDITOR_WINDOW * window)382 void UpdateDialogWindow(EDITOR_WINDOW *window)
383 // Make sure window is up to date
384 {
385 	WINDOW_LIST_ELEMENT
386 		*windowElement;
387 	DIALOG
388 		*dialog;
389 
390 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;				// get the X window information associated with this document window
391 	if(!XEmptyRegion(windowElement->invalidRegion))						// see if it has an invalid area
392 	{
393 		dialog=(DIALOG *)window->windowInfo;
394 		DrawDialog(dialog);
395 		XDestroyRegion(windowElement->invalidRegion);					// clear out the invalid region now that the window has been drawn
396 		windowElement->invalidRegion=XCreateRegion();
397 	}
398 }
399 
AdjustDialogWindowForNewSize(EDITOR_WINDOW * window)400 void AdjustDialogWindowForNewSize(EDITOR_WINDOW *window)
401 // If the window has changed size, then the
402 // controls will be needing update, so adjust them for the new
403 // size
404 {
405 	DIALOG
406 		*dialog;
407 	DIALOG_ITEM
408 		*currentItem;
409 
410 	dialog=(DIALOG *)window->windowInfo;
411 
412 	currentItem=dialog->firstItem;
413 	while(currentItem)							// run through all the items and ask them to resize
414 	{
415 		if(currentItem->resizeProc)
416 		{
417 			currentItem->resizeProc(currentItem);
418 		}
419 		currentItem=currentItem->nextItem;
420 	}
421 }
422 
DialogButtonPress(DIALOG * dialog,XEvent * event)423 static void DialogButtonPress(DIALOG *dialog,XEvent *event)
424 // Handle button press events for a dialog (see what the user is clicking
425 // on, and attempt to deal with it)
426 // This runs through the items backwards so that it finds the top-most
427 // item first.
428 {
429 	DIALOG_ITEM
430 		*currentItem;
431 	bool
432 		handled;
433 
434 	handled=false;
435 	currentItem=dialog->lastItem;
436 	while(currentItem&&!handled)
437 	{
438 		if(currentItem->trackProc)
439 		{
440 			handled=currentItem->trackProc(currentItem,event);
441 		}
442 		currentItem=currentItem->previousItem;
443 	}
444 }
445 
DialogKeyPress(DIALOG * dialog,XEvent * event)446 static void DialogKeyPress(DIALOG *dialog,XEvent *event)
447 // A keyboard event has arrived for window
448 // Decide who it should go to, and handle it
449 // If a focus change key comes in, and it is not grabbed early, it will
450 // be used to change the focus, and not sent to the focus item
451 {
452 	DIALOG_ITEM
453 		*currentItem;
454 	bool
455 		handled;
456 	KeySym
457 		keySym;
458 
459 	handled=false;
460 	currentItem=dialog->firstItem;
461 	while(currentItem&&!handled)
462 	{
463 		if(currentItem->earlyKeyProc)
464 		{
465 			handled=currentItem->earlyKeyProc(currentItem,event);
466 		}
467 		currentItem=currentItem->nextItem;
468 	}
469 	if(!handled)
470 	{
471 		ComposeXLookupString((XKeyEvent *)event,NULL,0,&keySym);
472 		if(keySym!=XK_Tab)
473 		{
474 			if(dialog->focusItem)
475 			{
476 				if(dialog->focusItem->focusKeyProc)
477 				{
478 					dialog->focusItem->focusKeyProc(dialog->focusItem,event);
479 				}
480 			}
481 		}
482 		else
483 		{
484 			ForwardFocus(dialog);
485 		}
486 	}
487 }
488 
DialogPeriodicProc(EDITOR_WINDOW * window)489 void DialogPeriodicProc(EDITOR_WINDOW *window)
490 // This is called roughly twice a second to flash cursors, or do whatever in the dialog
491 // when the dialog has focus
492 {
493 	DIALOG
494 		*dialog;
495 
496 	dialog=(DIALOG *)window->windowInfo;
497 	if(dialog->focusItem)
498 	{
499 		if(dialog->focusItem->focusPeriodicProc)
500 		{
501 			dialog->focusItem->focusPeriodicProc(dialog->focusItem);
502 		}
503 	}
504 }
505 
DialogTakeFocus(DIALOG_ITEM * item)506 void DialogTakeFocus(DIALOG_ITEM *item)
507 // An item in the dialog window has decided that it wants the focus, so change the focus to it
508 {
509 	ChangeFocus(item->dialog,item);
510 }
511 
DialogWindowEvent(EDITOR_WINDOW * window,XEvent * event)512 void DialogWindowEvent(EDITOR_WINDOW *window,XEvent *event)
513 // Handle an event arriving for a dialog window
514 {
515 	WINDOW_LIST_ELEMENT
516 		*windowElement;
517 
518 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
519 	switch(event->type)
520 	{
521 		case ButtonPress:
522 			XRaiseWindow(xDisplay,windowElement->xWindow);							// make sure dialog is on top
523 			XSetInputFocus(xDisplay,windowElement->xWindow,RevertToPointerRoot,event->xbutton.time);	// give me the focus
524 			DialogButtonPress((DIALOG *)window->windowInfo,event);					// go handle the button press
525 			break;
526 		case KeyPress:
527 			DialogKeyPress((DIALOG *)window->windowInfo,event);						// go handle the key press
528 			break;
529 		case ClientMessage:
530 			break;
531 		default:
532 			break;
533 	}
534 }
535 
HandleDialog(DIALOG * dialog)536 static void HandleDialog(DIALOG *dialog)
537 // Handle events for dialog
538 {
539 	ForwardFocus(dialog);									// place focus on first item that wants it
540 	DialogEventLoop(dialog->parentWindow,&(dialog->dialogComplete));
541 }
542 
ExitPress(void * parameters)543 static void ExitPress(void *parameters)
544 // button was pressed, say that dialog is complete
545 {
546 	((DIALOG *)parameters)->dialogComplete=true;			// set completion flag to true
547 }
548 
549 // ----------------------------------------------------------------------------
OkDialogStatTextResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)550 static void OkDialogStatTextResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
551 // Resize the static text area
552 {
553 	WINDOW_LIST_ELEMENT
554 		*windowElement;
555 	XWindowAttributes
556 		attributes;
557 
558 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
559 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
560 
561 	rect->x=10;
562 	rect->y=10;
563 	if(attributes.width>20)
564 	{
565 		rect->w=attributes.width-20;
566 	}
567 	else
568 	{
569 		rect->w=0;
570 	}
571 	if(attributes.height>50)
572 	{
573 		rect->h=attributes.height-50;
574 	}
575 	else
576 	{
577 		rect->h=0;
578 	}
579 }
580 
OkDialogSeparatorResize(EDITOR_WINDOW * window,INT32 * x,INT32 * y,UINT32 * length)581 static void OkDialogSeparatorResize(EDITOR_WINDOW *window,INT32 *x,INT32 *y,UINT32 *length)
582 // Resize the separator
583 {
584 	WINDOW_LIST_ELEMENT
585 		*windowElement;
586 	XWindowAttributes
587 		attributes;
588 
589 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
590 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
591 
592 	*x=10;
593 
594 	if(attributes.height>45)
595 	{
596 		*y=attributes.height-45;
597 	}
598 	else
599 	{
600 		*y=0;
601 	}
602 
603 	if(attributes.width>20)
604 	{
605 		*length=attributes.width-20;
606 	}
607 	else
608 	{
609 		*length=0;
610 	}
611 }
612 
OkDialogButtonOkResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)613 static void OkDialogButtonOkResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
614 // Resize the ok button
615 {
616 	WINDOW_LIST_ELEMENT
617 		*windowElement;
618 	XWindowAttributes
619 		attributes;
620 
621 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
622 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
623 
624 	rect->w=50;
625 	rect->h=25;
626 
627 	rect->x=attributes.width/2-rect->w/2;
628 
629 	if(attributes.height>35)
630 	{
631 		rect->y=attributes.height-35;
632 	}
633 	else
634 	{
635 		rect->y=0;
636 	}
637 }
638 
OkDialog(const char * text)639 bool OkDialog(const char *text)
640 // Bring up an ok dialog, with text
641 // Wait for the user to click on ok, then return
642 // If there is a problem, SetError, and return false
643 {
644 	DIALOG
645 		*dialog;
646 	STATIC_TEXT_DESCRIPTOR
647 		textDescriptor;
648 	SEPARATOR_DESCRIPTOR
649 		separatorDescriptor;
650 	BUTTON_DESCRIPTOR
651 		buttonDescriptor;
652 	bool
653 		result;
654 
655 	result=false;
656 	if((dialog=CreateCenteredDialog(500,250," ",BACKGROUND_COLOR)))			// make new empty dialog
657 	{
658 		textDescriptor.resizeFunction=OkDialogStatTextResize;
659 		textDescriptor.backgroundColor=BACKGROUND_COLOR;
660 		textDescriptor.foregroundColor=BLACK;
661 		textDescriptor.string=text;
662 		textDescriptor.fontName=defaultDialogTextFont;
663 
664 		if(NewDialogItem(dialog,CreateStaticTextItem,&textDescriptor))
665 		{
666 			separatorDescriptor.resizeFunction=OkDialogSeparatorResize;
667 			separatorDescriptor.horizontal=true;
668 
669 			if(NewDialogItem(dialog,CreateSeparatorItem,&separatorDescriptor))
670 			{
671 				buttonDescriptor.resizeFunction=OkDialogButtonOkResize;
672 				buttonDescriptor.buttonName="Ok";
673 				buttonDescriptor.fontName=defaultDialogButtonFont;
674 				buttonDescriptor.hasKey=true;
675 				buttonDescriptor.keySym=XK_Return;
676 				buttonDescriptor.pressedProc=ExitPress;
677 				buttonDescriptor.pressedProcParameters=dialog;	// pass pointer to the dialog
678 				buttonDescriptor.pressedState=NULL;
679 
680 				if(NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor))
681 				{
682 					HandleDialog(dialog);						// deal with this dialog
683 					result=true;
684 				}
685 			}
686 		}
687 		DisposeDialog(dialog);
688 	}
689 	return(result);
690 }
691 
692 // ----------------------------------------------------------------------------
OkCancelDialogStatTextResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)693 static void OkCancelDialogStatTextResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
694 // Resize the static text area
695 {
696 	WINDOW_LIST_ELEMENT
697 		*windowElement;
698 	XWindowAttributes
699 		attributes;
700 
701 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
702 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
703 
704 	rect->x=10;
705 	rect->y=10;
706 	if(attributes.width>20)
707 	{
708 		rect->w=attributes.width-20;
709 	}
710 	else
711 	{
712 		rect->w=0;
713 	}
714 	if(attributes.height>50)
715 	{
716 		rect->h=attributes.height-50;
717 	}
718 	else
719 	{
720 		rect->h=0;
721 	}
722 }
723 
OkCancelDialogSeparatorResize(EDITOR_WINDOW * window,INT32 * x,INT32 * y,UINT32 * length)724 static void OkCancelDialogSeparatorResize(EDITOR_WINDOW *window,INT32 *x,INT32 *y,UINT32 *length)
725 // Resize the separator
726 {
727 	WINDOW_LIST_ELEMENT
728 		*windowElement;
729 	XWindowAttributes
730 		attributes;
731 
732 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
733 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
734 
735 	*x=10;
736 
737 	if(attributes.height>45)
738 	{
739 		*y=attributes.height-45;
740 	}
741 	else
742 	{
743 		*y=0;
744 	}
745 
746 	if(attributes.width>20)
747 	{
748 		*length=attributes.width-20;
749 	}
750 	else
751 	{
752 		*length=0;
753 	}
754 }
755 
OkCancelDialogButtonOkResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)756 static void OkCancelDialogButtonOkResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
757 // Resize the ok button
758 {
759 	WINDOW_LIST_ELEMENT
760 		*windowElement;
761 	XWindowAttributes
762 		attributes;
763 
764 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
765 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
766 
767 	rect->w=50;
768 	rect->h=25;
769 
770 	rect->x=attributes.width/5-rect->w/2;
771 
772 	if(attributes.height>35)
773 	{
774 		rect->y=attributes.height-35;
775 	}
776 	else
777 	{
778 		rect->y=0;
779 	}
780 }
781 
OkCancelDialogButtonCancelResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)782 static void OkCancelDialogButtonCancelResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
783 // Resize the cancel button
784 {
785 	WINDOW_LIST_ELEMENT
786 		*windowElement;
787 	XWindowAttributes
788 		attributes;
789 
790 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
791 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
792 
793 	rect->w=70;
794 	rect->h=25;
795 
796 	rect->x=4*attributes.width/5-rect->w/2;
797 
798 	if(attributes.height>35)
799 	{
800 		rect->y=attributes.height-35;
801 	}
802 	else
803 	{
804 		rect->y=0;
805 	}
806 }
807 
OkCancelDialog(const char * text,bool * cancel)808 bool OkCancelDialog(const char *text,bool *cancel)
809 // Bring up an ok/cancel dialog, with text
810 // If there is a problem, SetError, return false
811 // Otherwise, return true in cancel if the user
812 // canceled, false if not
813 {
814 	DIALOG
815 		*dialog;
816 	STATIC_TEXT_DESCRIPTOR
817 		textDescriptor;
818 	SEPARATOR_DESCRIPTOR
819 		separatorDescriptor;
820 	BUTTON_DESCRIPTOR
821 		buttonDescriptor;
822 	bool
823 		result;
824 
825 	result=false;
826 	*cancel=false;
827 	if((dialog=CreateCenteredDialog(500,250," ",BACKGROUND_COLOR)))			// make new empty dialog
828 	{
829 		textDescriptor.resizeFunction=OkCancelDialogStatTextResize;
830 		textDescriptor.backgroundColor=BACKGROUND_COLOR;
831 		textDescriptor.foregroundColor=BLACK;
832 		textDescriptor.string=text;
833 		textDescriptor.fontName=defaultDialogTextFont;
834 
835 		if(NewDialogItem(dialog,CreateStaticTextItem,&textDescriptor))
836 		{
837 			separatorDescriptor.resizeFunction=OkCancelDialogSeparatorResize;
838 			separatorDescriptor.horizontal=true;
839 
840 			if(NewDialogItem(dialog,CreateSeparatorItem,&separatorDescriptor))
841 			{
842 				buttonDescriptor.resizeFunction=OkCancelDialogButtonOkResize;
843 				buttonDescriptor.buttonName="Ok";
844 				buttonDescriptor.fontName=defaultDialogButtonFont;
845 				buttonDescriptor.hasKey=true;
846 				buttonDescriptor.keySym=XK_Return;
847 				buttonDescriptor.pressedProc=ExitPress;
848 				buttonDescriptor.pressedProcParameters=dialog;
849 				buttonDescriptor.pressedState=NULL;
850 
851 				if(NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor))
852 				{
853 					buttonDescriptor.resizeFunction=OkCancelDialogButtonCancelResize;
854 					buttonDescriptor.buttonName="Cancel";
855 					buttonDescriptor.fontName=defaultDialogButtonFont;
856 					buttonDescriptor.hasKey=true;
857 					buttonDescriptor.keySym=XK_Escape;
858 					buttonDescriptor.pressedProc=ExitPress;
859 					buttonDescriptor.pressedProcParameters=dialog;
860 					buttonDescriptor.pressedState=cancel;
861 
862 					if(NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor))
863 					{
864 						HandleDialog(dialog);					// deal with this dialog
865 						result=true;
866 					}
867 				}
868 			}
869 		}
870 		DisposeDialog(dialog);
871 	}
872 	return(result);
873 }
874 
875 // ----------------------------------------------------------------------------
YesNoCancelDialogStatTextResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)876 static void YesNoCancelDialogStatTextResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
877 // Resize the static text area
878 {
879 	WINDOW_LIST_ELEMENT
880 		*windowElement;
881 	XWindowAttributes
882 		attributes;
883 
884 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
885 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
886 
887 	rect->x=10;
888 	rect->y=10;
889 	if(attributes.width>20)
890 	{
891 		rect->w=attributes.width-20;
892 	}
893 	else
894 	{
895 		rect->w=0;
896 	}
897 	if(attributes.height>50)
898 	{
899 		rect->h=attributes.height-50;
900 	}
901 	else
902 	{
903 		rect->h=0;
904 	}
905 }
906 
YesNoCancelDialogSeparatorResize(EDITOR_WINDOW * window,INT32 * x,INT32 * y,UINT32 * length)907 static void YesNoCancelDialogSeparatorResize(EDITOR_WINDOW *window,INT32 *x,INT32 *y,UINT32 *length)
908 // Resize the separator
909 {
910 	WINDOW_LIST_ELEMENT
911 		*windowElement;
912 	XWindowAttributes
913 		attributes;
914 
915 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
916 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
917 
918 	*x=10;
919 
920 	if(attributes.height>45)
921 	{
922 		*y=attributes.height-45;
923 	}
924 	else
925 	{
926 		*y=0;
927 	}
928 
929 	if(attributes.width>20)
930 	{
931 		*length=attributes.width-20;
932 	}
933 	else
934 	{
935 		*length=0;
936 	}
937 }
938 
YesNoCancelDialogButtonYesResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)939 static void YesNoCancelDialogButtonYesResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
940 // Resize the yes button
941 {
942 	WINDOW_LIST_ELEMENT
943 		*windowElement;
944 	XWindowAttributes
945 		attributes;
946 
947 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
948 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
949 
950 	rect->w=50;
951 	rect->h=25;
952 
953 	rect->x=attributes.width/5-rect->w/2;
954 
955 	if(attributes.height>35)
956 	{
957 		rect->y=attributes.height-35;
958 	}
959 	else
960 	{
961 		rect->y=0;
962 	}
963 }
964 
YesNoCancelDialogButtonNoResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)965 static void YesNoCancelDialogButtonNoResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
966 // Resize the no button
967 {
968 	WINDOW_LIST_ELEMENT
969 		*windowElement;
970 	XWindowAttributes
971 		attributes;
972 
973 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
974 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
975 
976 	rect->w=50;
977 	rect->h=25;
978 
979 	rect->x=2*attributes.width/5-rect->w/2;
980 
981 	if(attributes.height>35)
982 	{
983 		rect->y=attributes.height-35;
984 	}
985 	else
986 	{
987 		rect->y=0;
988 	}
989 }
990 
YesNoCancelDialogButtonCancelResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)991 static void YesNoCancelDialogButtonCancelResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
992 // Resize the cancel button
993 {
994 	WINDOW_LIST_ELEMENT
995 		*windowElement;
996 	XWindowAttributes
997 		attributes;
998 
999 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1000 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1001 
1002 	rect->w=70;
1003 	rect->h=25;
1004 
1005 	rect->x=4*attributes.width/5-rect->w/2;
1006 
1007 	if(attributes.height>35)
1008 	{
1009 		rect->y=attributes.height-35;
1010 	}
1011 	else
1012 	{
1013 		rect->y=0;
1014 	}
1015 }
1016 
YesNoCancelDialog(const char * text,bool * yes,bool * cancel)1017 bool YesNoCancelDialog(const char *text,bool *yes,bool *cancel)
1018 // Bring up a yes, no, or cancel dialog, with text
1019 // If there is a problem, SetError, return false
1020 // Otherwise, if cancel is true the user canceled,
1021 // otherwise, if yes is true, yes was hit,
1022 // otherwise no was hit.
1023 {
1024 	DIALOG
1025 		*dialog;
1026 	STATIC_TEXT_DESCRIPTOR
1027 		textDescriptor;
1028 	SEPARATOR_DESCRIPTOR
1029 		separatorDescriptor;
1030 	BUTTON_DESCRIPTOR
1031 		buttonDescriptor;
1032 	bool
1033 		result;
1034 
1035 	result=false;
1036 	*yes=*cancel=false;
1037 	if((dialog=CreateCenteredDialog(500,250," ",BACKGROUND_COLOR)))			// make new empty dialog
1038 	{
1039 		textDescriptor.resizeFunction=YesNoCancelDialogStatTextResize;
1040 		textDescriptor.backgroundColor=BACKGROUND_COLOR;
1041 		textDescriptor.foregroundColor=BLACK;
1042 		textDescriptor.string=text;
1043 		textDescriptor.fontName=defaultDialogTextFont;
1044 
1045 		if(NewDialogItem(dialog,CreateStaticTextItem,&textDescriptor))
1046 		{
1047 			separatorDescriptor.resizeFunction=YesNoCancelDialogSeparatorResize;
1048 			separatorDescriptor.horizontal=true;
1049 
1050 			if(NewDialogItem(dialog,CreateSeparatorItem,&separatorDescriptor))
1051 			{
1052 				buttonDescriptor.resizeFunction=YesNoCancelDialogButtonYesResize;
1053 				buttonDescriptor.buttonName="Yes";
1054 				buttonDescriptor.fontName=defaultDialogButtonFont;
1055 				buttonDescriptor.hasKey=true;
1056 				buttonDescriptor.keySym=XK_y;
1057 				buttonDescriptor.pressedProc=ExitPress;
1058 				buttonDescriptor.pressedProcParameters=dialog;
1059 				buttonDescriptor.pressedState=yes;
1060 
1061 				if(NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor))
1062 				{
1063 					buttonDescriptor.resizeFunction=YesNoCancelDialogButtonNoResize;
1064 					buttonDescriptor.buttonName="No";
1065 					buttonDescriptor.fontName=defaultDialogButtonFont;
1066 					buttonDescriptor.hasKey=true;
1067 					buttonDescriptor.keySym=XK_n;
1068 					buttonDescriptor.pressedProc=ExitPress;
1069 					buttonDescriptor.pressedProcParameters=dialog;
1070 					buttonDescriptor.pressedState=NULL;
1071 
1072 					if(NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor))
1073 					{
1074 						buttonDescriptor.resizeFunction=YesNoCancelDialogButtonCancelResize;
1075 						buttonDescriptor.buttonName="Cancel";
1076 						buttonDescriptor.fontName=defaultDialogButtonFont;
1077 						buttonDescriptor.hasKey=true;
1078 						buttonDescriptor.keySym=XK_Escape;
1079 						buttonDescriptor.pressedProc=ExitPress;
1080 						buttonDescriptor.pressedProcParameters=dialog;
1081 						buttonDescriptor.pressedState=cancel;
1082 
1083 						if(NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor))
1084 						{
1085 							HandleDialog(dialog);					// deal with this dialog
1086 							result=true;
1087 						}
1088 					}
1089 				}
1090 			}
1091 		}
1092 		DisposeDialog(dialog);
1093 	}
1094 	return(result);
1095 }
1096 
1097 // ----------------------------------------------------------------------------
GetSimpleTextDialogStatTextResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1098 static void GetSimpleTextDialogStatTextResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1099 // Resize the static text area
1100 {
1101 	WINDOW_LIST_ELEMENT
1102 		*windowElement;
1103 	XWindowAttributes
1104 		attributes;
1105 
1106 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1107 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1108 
1109 	rect->x=10;
1110 	rect->y=10;
1111 	if(attributes.width>20)
1112 	{
1113 		rect->w=attributes.width-20;
1114 	}
1115 	else
1116 	{
1117 		rect->w=0;
1118 	}
1119 	rect->h=20;
1120 }
1121 
GetSimpleTextDialogButtonOkResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1122 static void GetSimpleTextDialogButtonOkResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1123 // Resize the ok button
1124 {
1125 	WINDOW_LIST_ELEMENT
1126 		*windowElement;
1127 	XWindowAttributes
1128 		attributes;
1129 
1130 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1131 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1132 
1133 	rect->w=50;
1134 	rect->h=25;
1135 
1136 	rect->x=attributes.width/5-rect->w/2;
1137 
1138 	if(attributes.height>35)
1139 	{
1140 		rect->y=attributes.height-35;
1141 	}
1142 	else
1143 	{
1144 		rect->y=0;
1145 	}
1146 }
1147 
GetSimpleTextDialogTextBoxResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1148 static void GetSimpleTextDialogTextBoxResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1149 // Resize the text box
1150 {
1151 	WINDOW_LIST_ELEMENT
1152 		*windowElement;
1153 	XWindowAttributes
1154 		attributes;
1155 
1156 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1157 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1158 
1159 	rect->x=10;
1160 	rect->y=30;
1161 	if(attributes.width>20)
1162 	{
1163 		rect->w=attributes.width-20;
1164 	}
1165 	else
1166 	{
1167 		rect->w=0;
1168 	}
1169 	if(attributes.height>80)
1170 	{
1171 		rect->h=attributes.height-80;
1172 	}
1173 	else
1174 	{
1175 		rect->h=0;
1176 	}
1177 }
1178 
GetSimpleTextDialogButtonCancelResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1179 static void GetSimpleTextDialogButtonCancelResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1180 // Resize the cancel button
1181 {
1182 	WINDOW_LIST_ELEMENT
1183 		*windowElement;
1184 	XWindowAttributes
1185 		attributes;
1186 
1187 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1188 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1189 
1190 	rect->w=70;
1191 	rect->h=25;
1192 
1193 	rect->x=4*attributes.width/5-rect->w/2;
1194 
1195 	if(attributes.height>35)
1196 	{
1197 		rect->y=attributes.height-35;
1198 	}
1199 	else
1200 	{
1201 		rect->y=0;
1202 	}
1203 }
1204 
GetSimpleTextDialog(const char * title,char * enteredText,UINT32 stringBytes,bool * cancel)1205 bool GetSimpleTextDialog(const char *title,char *enteredText,UINT32 stringBytes,bool *cancel)
1206 // Open a string input dialog with title,
1207 // If there is a problem, SetError, return false
1208 // Otherwise, if cancel is true, the user canceled
1209 // otherwise, enteredText will be set to the text that the user entered in the box
1210 // If enteredText is set to something on entry, it will be placed in the box
1211 {
1212 	DIALOG
1213 		*dialog;
1214 	EDITOR_BUFFER
1215 		*buffer;
1216 	CHUNK_HEADER
1217 		*chunk;
1218 	UINT32
1219 		offset;
1220 	TEXT_BOX_DESCRIPTOR
1221 		textBoxDescriptor;
1222 	STATIC_TEXT_DESCRIPTOR
1223 		textDescriptor;
1224 	BUTTON_DESCRIPTOR
1225 		buttonDescriptor;
1226 	bool
1227 		result;
1228 
1229 	result=false;
1230 	*cancel=false;
1231 	if((buffer=EditorNewBuffer("simple text")))		// create a buffer in which to collect the text
1232 	{
1233 		if(InsertUniverseText(buffer->textUniverse,buffer->textUniverse->totalBytes,(UINT8 *)enteredText,strlen(enteredText)))
1234 		{
1235 			if(EditorSelectAll(buffer))				// select it all
1236 			{
1237 				if((dialog=CreateCenteredDialog(600,300," ",BACKGROUND_COLOR)))			// make new empty dialog
1238 				{
1239 					textDescriptor.resizeFunction=GetSimpleTextDialogStatTextResize;
1240 					textDescriptor.backgroundColor=BACKGROUND_COLOR;
1241 					textDescriptor.foregroundColor=BLACK;
1242 					textDescriptor.string=title;
1243 					textDescriptor.fontName=defaultDialogTextFont;
1244 
1245 					if(NewDialogItem(dialog,CreateStaticTextItem,&textDescriptor))
1246 					{
1247 						textBoxDescriptor.buffer=buffer;
1248 						textBoxDescriptor.resizeFunction=GetSimpleTextDialogTextBoxResize;
1249 						textBoxDescriptor.topLine=0;
1250 						textBoxDescriptor.leftPixel=0;
1251 						textBoxDescriptor.tabSize=4;
1252 						textBoxDescriptor.focusBackgroundColor=GRAY_3;
1253 						textBoxDescriptor.focusForegroundColor=BLACK;
1254 						textBoxDescriptor.nofocusBackgroundColor=GRAY_3;
1255 						textBoxDescriptor.nofocusForegroundColor=GRAY_1;
1256 						textBoxDescriptor.fontName=defaultViewFont;
1257 
1258 						if(NewDialogItem(dialog,CreateTextBoxItem,&textBoxDescriptor))
1259 						{
1260 							buttonDescriptor.resizeFunction=GetSimpleTextDialogButtonOkResize;
1261 							buttonDescriptor.buttonName="Ok";
1262 							buttonDescriptor.fontName=defaultDialogButtonFont;
1263 							buttonDescriptor.hasKey=true;
1264 							buttonDescriptor.keySym=XK_Return;
1265 							buttonDescriptor.pressedProc=ExitPress;
1266 							buttonDescriptor.pressedProcParameters=dialog;
1267 							buttonDescriptor.pressedState=NULL;
1268 
1269 							if(NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor))
1270 							{
1271 								buttonDescriptor.resizeFunction=GetSimpleTextDialogButtonCancelResize;
1272 								buttonDescriptor.buttonName="Cancel";
1273 								buttonDescriptor.fontName=defaultDialogButtonFont;
1274 								buttonDescriptor.hasKey=true;
1275 								buttonDescriptor.keySym=XK_Escape;
1276 								buttonDescriptor.pressedProc=ExitPress;
1277 								buttonDescriptor.pressedProcParameters=dialog;
1278 								buttonDescriptor.pressedState=cancel;
1279 
1280 								if(NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor))
1281 								{
1282 									HandleDialog(dialog);					// deal with this dialog
1283 									result=true;
1284 								}
1285 							}
1286 						}
1287 					}
1288 					DisposeDialog(dialog);
1289 				}
1290 			}
1291 		}
1292 		if(result&&!(*cancel))
1293 		{
1294 			if(ExtractUniverseText(buffer->textUniverse,buffer->textUniverse->firstChunkHeader,0,(UINT8 *)enteredText,stringBytes,&chunk,&offset))
1295 			{
1296 				if(buffer->textUniverse->totalBytes<stringBytes)
1297 				{
1298 					enteredText[buffer->textUniverse->totalBytes]='\0';
1299 				}
1300 				else
1301 				{
1302 					if(stringBytes)
1303 					{
1304 						enteredText[stringBytes-1]='\0';
1305 					}
1306 				}
1307 			}
1308 			else
1309 			{
1310 				result=false;
1311 			}
1312 		}
1313 		EditorCloseBuffer(buffer);
1314 	}
1315 	return(result);
1316 }
1317 
1318 // ----------------------------------------------------------------------------
SearchReplaceDialogFindStatTextResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1319 static void SearchReplaceDialogFindStatTextResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1320 // Resize the static text area
1321 {
1322 	WINDOW_LIST_ELEMENT
1323 		*windowElement;
1324 	XWindowAttributes
1325 		attributes;
1326 
1327 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1328 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1329 
1330 	rect->x=10;
1331 	rect->y=10;
1332 	if(attributes.width>20)
1333 	{
1334 		rect->w=attributes.width-20;
1335 	}
1336 	else
1337 	{
1338 		rect->w=0;
1339 	}
1340 	rect->h=20;
1341 }
1342 
SearchReplaceDialogReplaceStatTextResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1343 static void SearchReplaceDialogReplaceStatTextResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1344 // Resize the static text area
1345 {
1346 	WINDOW_LIST_ELEMENT
1347 		*windowElement;
1348 	XWindowAttributes
1349 		attributes;
1350 
1351 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1352 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1353 
1354 	rect->x=10;
1355 
1356 	if(attributes.height>150)
1357 	{
1358 		rect->y=(attributes.height-150)/2+10;
1359 	}
1360 	else
1361 	{
1362 		rect->y=0;
1363 	}
1364 
1365 	if(attributes.width>20)
1366 	{
1367 		rect->w=attributes.width-20;
1368 	}
1369 	else
1370 	{
1371 		rect->w=0;
1372 	}
1373 	rect->h=20;
1374 }
1375 
SearchReplaceDialogTextBoxFindResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1376 static void SearchReplaceDialogTextBoxFindResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1377 // Resize the find text box
1378 {
1379 	WINDOW_LIST_ELEMENT
1380 		*windowElement;
1381 	XWindowAttributes
1382 		attributes;
1383 	INT32
1384 		yStart;
1385 	UINT32
1386 		height;
1387 
1388 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1389 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1390 
1391 	rect->x=10;
1392 	if(attributes.width>20)
1393 	{
1394 		rect->w=attributes.width-20;
1395 	}
1396 	else
1397 	{
1398 		rect->w=0;
1399 	}
1400 
1401 	if(attributes.height>150)
1402 	{
1403 		yStart=0;
1404 		height=(UINT32)(attributes.height-150)/2;
1405 		if(height>30)			// leave 10 for space above label, 20 for text label
1406 		{
1407 			rect->y=yStart+30;	// move just below the text
1408 			rect->h=height-30;	// take up remaining space
1409 		}
1410 		else
1411 		{
1412 			rect->y=0;
1413 			rect->h=0;
1414 		}
1415 	}
1416 	else
1417 	{
1418 		rect->y=0;
1419 		rect->h=0;
1420 	}
1421 }
1422 
SearchReplaceDialogTextBoxReplaceResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1423 static void SearchReplaceDialogTextBoxReplaceResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1424 // Resize the find text box
1425 {
1426 	WINDOW_LIST_ELEMENT
1427 		*windowElement;
1428 	XWindowAttributes
1429 		attributes;
1430 	INT32
1431 		yStart;
1432 	UINT32
1433 		height;
1434 
1435 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1436 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1437 
1438 	rect->x=10;
1439 
1440 	if(attributes.width>20)
1441 	{
1442 		rect->w=attributes.width-20;
1443 	}
1444 	else
1445 	{
1446 		rect->w=0;
1447 	}
1448 
1449 	// get Y location where replace label and text window go
1450 	if(attributes.height>150)
1451 	{
1452 		yStart=(attributes.height-150)/2;
1453 		height=(UINT32)(attributes.height-150)/2;
1454 		if(height>30)			// leave 10 for space above label, 20 for text label
1455 		{
1456 			rect->y=yStart+30;	// move just below the text
1457 			rect->h=height-30;	// take up remaining space
1458 		}
1459 		else
1460 		{
1461 			rect->y=0;
1462 			rect->h=0;
1463 		}
1464 	}
1465 	else
1466 	{
1467 		rect->y=0;
1468 		rect->h=0;
1469 	}
1470 }
1471 
SearchReplaceDialogCheckBoxBackwardsResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1472 static void SearchReplaceDialogCheckBoxBackwardsResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1473 // Resize the search backwards check box
1474 {
1475 	WINDOW_LIST_ELEMENT
1476 		*windowElement;
1477 	XWindowAttributes
1478 		attributes;
1479 
1480 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1481 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1482 
1483 	rect->x=10;
1484 
1485 	if(attributes.height>140)
1486 	{
1487 		rect->y=attributes.height-140;
1488 	}
1489 	else
1490 	{
1491 		rect->y=0;
1492 	}
1493 
1494 	if(attributes.width/2>20)
1495 	{
1496 		rect->w=attributes.width/2-20;
1497 	}
1498 	else
1499 	{
1500 		rect->w=0;
1501 	}
1502 	rect->h=20;
1503 }
1504 
SearchReplaceDialogCheckBoxWrapResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1505 static void SearchReplaceDialogCheckBoxWrapResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1506 // Resize the search wrap around check box
1507 {
1508 	WINDOW_LIST_ELEMENT
1509 		*windowElement;
1510 	XWindowAttributes
1511 		attributes;
1512 
1513 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1514 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1515 
1516 	rect->x=10;
1517 
1518 	if(attributes.height>115)
1519 	{
1520 		rect->y=attributes.height-115;
1521 	}
1522 	else
1523 	{
1524 		rect->y=0;
1525 	}
1526 
1527 	if(attributes.width/2>20)
1528 	{
1529 		rect->w=attributes.width/2-20;
1530 	}
1531 	else
1532 	{
1533 		rect->w=0;
1534 	}
1535 	rect->h=20;
1536 }
1537 
SearchReplaceDialogCheckBoxExpressionResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1538 static void SearchReplaceDialogCheckBoxExpressionResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1539 // Resize the search expression check box
1540 {
1541 	WINDOW_LIST_ELEMENT
1542 		*windowElement;
1543 	XWindowAttributes
1544 		attributes;
1545 
1546 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1547 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1548 
1549 	rect->x=attributes.width/2+10;
1550 
1551 	if(attributes.height>140)
1552 	{
1553 		rect->y=attributes.height-140;
1554 	}
1555 	else
1556 	{
1557 		rect->y=0;
1558 	}
1559 
1560 	if(attributes.width/2>20)
1561 	{
1562 		rect->w=attributes.width/2-20;
1563 	}
1564 	else
1565 	{
1566 		rect->w=0;
1567 	}
1568 	rect->h=20;
1569 }
1570 
SearchReplaceDialogCheckBoxIgnoreCaseResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1571 static void SearchReplaceDialogCheckBoxIgnoreCaseResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1572 // Resize the search ignore case check box
1573 {
1574 	WINDOW_LIST_ELEMENT
1575 		*windowElement;
1576 	XWindowAttributes
1577 		attributes;
1578 
1579 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1580 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1581 
1582 	rect->x=attributes.width/2+10;
1583 
1584 	if(attributes.height>115)
1585 	{
1586 		rect->y=attributes.height-115;
1587 	}
1588 	else
1589 	{
1590 		rect->y=0;
1591 	}
1592 
1593 	if(attributes.width/2>20)
1594 	{
1595 		rect->w=attributes.width/2-20;
1596 	}
1597 	else
1598 	{
1599 		rect->w=0;
1600 	}
1601 	rect->h=20;
1602 }
1603 
SearchReplaceDialogCheckBoxLimitScopeResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1604 static void SearchReplaceDialogCheckBoxLimitScopeResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1605 // Resize the search limit scope check box
1606 {
1607 	WINDOW_LIST_ELEMENT
1608 		*windowElement;
1609 	XWindowAttributes
1610 		attributes;
1611 
1612 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1613 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1614 
1615 	rect->x=10;
1616 
1617 	if(attributes.height>90)
1618 	{
1619 		rect->y=attributes.height-90;
1620 	}
1621 	else
1622 	{
1623 		rect->y=0;
1624 	}
1625 
1626 	if(attributes.width>20)
1627 	{
1628 		rect->w=attributes.width-20;
1629 	}
1630 	else
1631 	{
1632 		rect->w=0;
1633 	}
1634 	rect->h=20;
1635 }
1636 
SearchReplaceDialogCheckBoxTclResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1637 static void SearchReplaceDialogCheckBoxTclResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1638 // Resize the search Tcl replacement check box
1639 {
1640 	WINDOW_LIST_ELEMENT
1641 		*windowElement;
1642 	XWindowAttributes
1643 		attributes;
1644 
1645 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1646 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1647 
1648 	rect->x=10;
1649 
1650 	if(attributes.height>65)
1651 	{
1652 		rect->y=attributes.height-65;
1653 	}
1654 	else
1655 	{
1656 		rect->y=0;
1657 	}
1658 
1659 	if(attributes.width>20)
1660 	{
1661 		rect->w=attributes.width-20;
1662 	}
1663 	else
1664 	{
1665 		rect->w=0;
1666 	}
1667 	rect->h=20;
1668 }
1669 
GetFindButtonX(UINT32 index,UINT32 windowWidth)1670 static INT32 GetFindButtonX(UINT32 index,UINT32 windowWidth)
1671 // Work out the X index for a button in the find window
1672 // Index is passed as the index of the button (0 through 5)
1673 // There is usually no button at index 4.
1674 // All the buttons are assumed to be 100 pixels wide.
1675 // This is a bit of a hack -- later make all of this work
1676 // better.
1677 {
1678 	if(windowWidth>=(20+100))
1679 	{
1680 		return(10+(windowWidth-(20+100))*index/5);
1681 	}
1682 	return(10);
1683 }
1684 
SearchReplaceDialogButtonFindResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1685 static void SearchReplaceDialogButtonFindResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1686 // Resize the find button
1687 {
1688 	WINDOW_LIST_ELEMENT
1689 		*windowElement;
1690 	XWindowAttributes
1691 		attributes;
1692 
1693 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1694 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1695 
1696 	rect->w=100;
1697 	rect->h=25;
1698 
1699 	rect->x=GetFindButtonX(0,attributes.width);
1700 
1701 	if(attributes.height>35)
1702 	{
1703 		rect->y=attributes.height-35;
1704 	}
1705 	else
1706 	{
1707 		rect->y=0;
1708 	}
1709 }
1710 
SearchReplaceDialogButtonFindAllResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1711 static void SearchReplaceDialogButtonFindAllResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1712 // Resize the find all button
1713 {
1714 	WINDOW_LIST_ELEMENT
1715 		*windowElement;
1716 	XWindowAttributes
1717 		attributes;
1718 
1719 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1720 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1721 
1722 	rect->w=100;
1723 	rect->h=25;
1724 
1725 	rect->x=GetFindButtonX(1,attributes.width);
1726 
1727 	if(attributes.height>35)
1728 	{
1729 		rect->y=attributes.height-35;
1730 	}
1731 	else
1732 	{
1733 		rect->y=0;
1734 	}
1735 }
1736 
SearchReplaceDialogButtonReplaceResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1737 static void SearchReplaceDialogButtonReplaceResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1738 // Resize the replace button
1739 {
1740 	WINDOW_LIST_ELEMENT
1741 		*windowElement;
1742 	XWindowAttributes
1743 		attributes;
1744 
1745 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1746 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1747 
1748 	rect->w=100;
1749 	rect->h=25;
1750 
1751 	rect->x=GetFindButtonX(2,attributes.width);
1752 
1753 	if(attributes.height>35)
1754 	{
1755 		rect->y=attributes.height-35;
1756 	}
1757 	else
1758 	{
1759 		rect->y=0;
1760 	}
1761 }
1762 
SearchReplaceDialogButtonReplaceAllResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1763 static void SearchReplaceDialogButtonReplaceAllResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1764 // Resize the replace all button
1765 {
1766 	WINDOW_LIST_ELEMENT
1767 		*windowElement;
1768 	XWindowAttributes
1769 		attributes;
1770 
1771 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1772 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1773 
1774 	rect->w=100;
1775 	rect->h=25;
1776 
1777 	rect->x=GetFindButtonX(3,attributes.width);
1778 
1779 	if(attributes.height>35)
1780 	{
1781 		rect->y=attributes.height-35;
1782 	}
1783 	else
1784 	{
1785 		rect->y=0;
1786 	}
1787 }
1788 
SearchReplaceDialogButtonCancelResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)1789 static void SearchReplaceDialogButtonCancelResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
1790 // Resize the cancel button
1791 {
1792 	WINDOW_LIST_ELEMENT
1793 		*windowElement;
1794 	XWindowAttributes
1795 		attributes;
1796 
1797 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
1798 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
1799 
1800 	rect->w=100;
1801 	rect->h=25;
1802 
1803 	rect->x=GetFindButtonX(5,attributes.width);
1804 
1805 	if(attributes.height>35)
1806 	{
1807 		rect->y=attributes.height-35;
1808 	}
1809 	else
1810 	{
1811 		rect->y=0;
1812 	}
1813 }
1814 
SearchReplaceDialog(EDITOR_BUFFER * searchBuffer,EDITOR_BUFFER * replaceBuffer,bool * backwards,bool * wrapAround,bool * selectionExpr,bool * ignoreCase,bool * limitScope,bool * replaceProc,UINT16 * searchType,bool * cancel)1815 bool SearchReplaceDialog(EDITOR_BUFFER *searchBuffer,EDITOR_BUFFER *replaceBuffer,bool *backwards,bool *wrapAround,bool *selectionExpr,bool *ignoreCase,bool *limitScope,bool *replaceProc,UINT16 *searchType,bool *cancel)
1816 // Open the search/replace dialog
1817 // If there is a problem, SetError, return false
1818 // Otherwise, if cancel is true, the user canceled
1819 // Otherwise, return the enumerated mode that the user chose, as well as
1820 // the states of backwards, wrapAround, selectionExpr, ignoreCase,
1821 // limitScope, replaceProc
1822 {
1823 	DIALOG
1824 		*dialog;
1825 	TEXT_BOX_DESCRIPTOR
1826 		textBoxDescriptor;
1827 	STATIC_TEXT_DESCRIPTOR
1828 		textDescriptor;
1829 	BUTTON_DESCRIPTOR
1830 		buttonDescriptor;
1831 	CHECK_BOX_DESCRIPTOR
1832 		checkDescriptor;
1833 	bool
1834 		result;
1835 	bool
1836 		hadFind,
1837 		hadFindAll,
1838 		hadReplace,
1839 		hadReplaceAll;
1840 
1841 	result=false;
1842 	*cancel=false;
1843 	hadFind=false;
1844 	hadFindAll=false;
1845 	hadReplace=false;
1846 	hadReplaceAll=false;
1847 
1848 	if(EditorSelectAll(searchBuffer))							// select it all
1849 	{
1850 		if(EditorSelectAll(replaceBuffer))						// select it all
1851 		{
1852 			if((dialog=CreateCenteredDialog(620,430," ",BACKGROUND_COLOR)))	// make new empty dialog
1853 			{
1854 				textDescriptor.resizeFunction=SearchReplaceDialogFindStatTextResize;
1855 				textDescriptor.backgroundColor=BACKGROUND_COLOR;
1856 				textDescriptor.foregroundColor=BLACK;
1857 				textDescriptor.string="Find:";
1858 				textDescriptor.fontName=defaultDialogTextFont;
1859 
1860 				if(NewDialogItem(dialog,CreateStaticTextItem,&textDescriptor))
1861 				{
1862 					textBoxDescriptor.buffer=searchBuffer;
1863 					textBoxDescriptor.resizeFunction=SearchReplaceDialogTextBoxFindResize;
1864 					textBoxDescriptor.topLine=0;
1865 					textBoxDescriptor.leftPixel=0;
1866 					textBoxDescriptor.tabSize=4;
1867 					textBoxDescriptor.focusBackgroundColor=GRAY_3;
1868 					textBoxDescriptor.focusForegroundColor=BLACK;
1869 					textBoxDescriptor.nofocusBackgroundColor=GRAY_3;
1870 					textBoxDescriptor.nofocusForegroundColor=GRAY_1;
1871 					textBoxDescriptor.fontName=defaultViewFont;
1872 
1873 					if(NewDialogItem(dialog,CreateTextBoxItem,&textBoxDescriptor))
1874 					{
1875 						textDescriptor.resizeFunction=SearchReplaceDialogReplaceStatTextResize;
1876 						textDescriptor.backgroundColor=BACKGROUND_COLOR;
1877 						textDescriptor.foregroundColor=BLACK;
1878 						textDescriptor.string="Replace with:";
1879 						textDescriptor.fontName=defaultDialogTextFont;
1880 
1881 						if(NewDialogItem(dialog,CreateStaticTextItem,&textDescriptor))
1882 						{
1883 							textBoxDescriptor.buffer=replaceBuffer;
1884 							textBoxDescriptor.resizeFunction=SearchReplaceDialogTextBoxReplaceResize;
1885 							textBoxDescriptor.topLine=0;
1886 							textBoxDescriptor.leftPixel=0;
1887 							textBoxDescriptor.tabSize=4;
1888 							textBoxDescriptor.focusBackgroundColor=GRAY_3;
1889 							textBoxDescriptor.focusForegroundColor=BLACK;
1890 							textBoxDescriptor.nofocusBackgroundColor=GRAY_3;
1891 							textBoxDescriptor.nofocusForegroundColor=GRAY_1;
1892 							textBoxDescriptor.fontName=defaultViewFont;
1893 
1894 							if(NewDialogItem(dialog,CreateTextBoxItem,&textBoxDescriptor))
1895 							{
1896 								// check boxes
1897 								checkDescriptor.resizeFunction=SearchReplaceDialogCheckBoxBackwardsResize;
1898 								checkDescriptor.checkBoxName="Search Backwards";
1899 								checkDescriptor.fontName=defaultDialogTextFont;
1900 								checkDescriptor.hasKey=false;
1901 								checkDescriptor.pressedProc=NULL;
1902 								checkDescriptor.pressedProcParameters=NULL;
1903 								checkDescriptor.pressedState=backwards;
1904 
1905 								if(NewDialogItem(dialog,CreateCheckBoxItem,&checkDescriptor))
1906 								{
1907 									checkDescriptor.resizeFunction=SearchReplaceDialogCheckBoxWrapResize;
1908 									checkDescriptor.checkBoxName="Wrap Around";
1909 									checkDescriptor.fontName=defaultDialogTextFont;
1910 									checkDescriptor.hasKey=false;
1911 									checkDescriptor.pressedProc=NULL;
1912 									checkDescriptor.pressedProcParameters=NULL;
1913 									checkDescriptor.pressedState=wrapAround;
1914 
1915 									if(NewDialogItem(dialog,CreateCheckBoxItem,&checkDescriptor))
1916 									{
1917 										checkDescriptor.resizeFunction=SearchReplaceDialogCheckBoxExpressionResize;
1918 										checkDescriptor.checkBoxName="Selection Expression";
1919 										checkDescriptor.fontName=defaultDialogTextFont;
1920 										checkDescriptor.hasKey=false;
1921 										checkDescriptor.pressedProc=NULL;
1922 										checkDescriptor.pressedProcParameters=NULL;
1923 										checkDescriptor.pressedState=selectionExpr;
1924 
1925 										if(NewDialogItem(dialog,CreateCheckBoxItem,&checkDescriptor))
1926 										{
1927 											checkDescriptor.resizeFunction=SearchReplaceDialogCheckBoxIgnoreCaseResize;
1928 											checkDescriptor.checkBoxName="Ignore Case";
1929 											checkDescriptor.fontName=defaultDialogTextFont;
1930 											checkDescriptor.hasKey=false;
1931 											checkDescriptor.pressedProc=NULL;
1932 											checkDescriptor.pressedProcParameters=NULL;
1933 											checkDescriptor.pressedState=ignoreCase;
1934 
1935 											if(NewDialogItem(dialog,CreateCheckBoxItem,&checkDescriptor))
1936 											{
1937 												checkDescriptor.resizeFunction=SearchReplaceDialogCheckBoxLimitScopeResize;
1938 												checkDescriptor.checkBoxName="Limit scope of 'Find All'/'Replace All' to current selection";
1939 												checkDescriptor.fontName=defaultDialogTextFont;
1940 												checkDescriptor.hasKey=false;
1941 												checkDescriptor.pressedProc=NULL;
1942 												checkDescriptor.pressedProcParameters=NULL;
1943 												checkDescriptor.pressedState=limitScope;
1944 
1945 												if(NewDialogItem(dialog,CreateCheckBoxItem,&checkDescriptor))
1946 												{
1947 													checkDescriptor.resizeFunction=SearchReplaceDialogCheckBoxTclResize;
1948 													checkDescriptor.checkBoxName="Treat replace text as Tcl procedure -- substitute results";
1949 													checkDescriptor.fontName=defaultDialogTextFont;
1950 													checkDescriptor.hasKey=false;
1951 													checkDescriptor.pressedProc=NULL;
1952 													checkDescriptor.pressedProcParameters=NULL;
1953 													checkDescriptor.pressedState=replaceProc;
1954 
1955 													if(NewDialogItem(dialog,CreateCheckBoxItem,&checkDescriptor))
1956 													{
1957 														buttonDescriptor.resizeFunction=SearchReplaceDialogButtonFindResize;
1958 														buttonDescriptor.buttonName="Find";
1959 														buttonDescriptor.fontName=defaultDialogButtonFont;
1960 														buttonDescriptor.hasKey=true;
1961 														buttonDescriptor.keySym=XK_Return;
1962 														buttonDescriptor.pressedProc=ExitPress;
1963 														buttonDescriptor.pressedProcParameters=dialog;
1964 														buttonDescriptor.pressedState=&hadFind;
1965 
1966 														if(NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor))
1967 														{
1968 															buttonDescriptor.resizeFunction=SearchReplaceDialogButtonFindAllResize;
1969 															buttonDescriptor.buttonName="Find All";
1970 															buttonDescriptor.fontName=defaultDialogButtonFont;
1971 															buttonDescriptor.hasKey=false;
1972 															buttonDescriptor.pressedProc=ExitPress;
1973 															buttonDescriptor.pressedProcParameters=dialog;
1974 															buttonDescriptor.pressedState=&hadFindAll;
1975 
1976 															if(NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor))
1977 															{
1978 															buttonDescriptor.resizeFunction=SearchReplaceDialogButtonReplaceResize;
1979 																buttonDescriptor.buttonName="Replace";
1980 																buttonDescriptor.fontName=defaultDialogButtonFont;
1981 																buttonDescriptor.hasKey=false;
1982 																buttonDescriptor.pressedProc=ExitPress;
1983 																buttonDescriptor.pressedProcParameters=dialog;
1984 																buttonDescriptor.pressedState=&hadReplace;
1985 
1986 																if(NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor))
1987 																{
1988 																	buttonDescriptor.resizeFunction=SearchReplaceDialogButtonReplaceAllResize;
1989 																	buttonDescriptor.buttonName="Replace All";
1990 																	buttonDescriptor.fontName=defaultDialogButtonFont;
1991 																	buttonDescriptor.hasKey=false;
1992 																	buttonDescriptor.pressedProc=ExitPress;
1993 																	buttonDescriptor.pressedProcParameters=dialog;
1994 																	buttonDescriptor.pressedState=&hadReplaceAll;
1995 
1996 																	if(NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor))
1997 																	{
1998 																		buttonDescriptor.resizeFunction=SearchReplaceDialogButtonCancelResize;
1999 																		buttonDescriptor.buttonName="Cancel";
2000 																		buttonDescriptor.fontName=defaultDialogButtonFont;
2001 																		buttonDescriptor.hasKey=true;
2002 																		buttonDescriptor.keySym=XK_Escape;
2003 																		buttonDescriptor.pressedProc=ExitPress;
2004 																		buttonDescriptor.pressedProcParameters=dialog;
2005 																		buttonDescriptor.pressedState=cancel;
2006 
2007 																		if(NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor))
2008 																		{
2009 																			HandleDialog(dialog);					// deal with this dialog
2010 																			result=true;
2011 																		}
2012 																	}
2013 																}
2014 															}
2015 														}
2016 													}
2017 												}
2018 											}
2019 										}
2020 									}
2021 								}
2022 							}
2023 						}
2024 					}
2025 				}
2026 				DisposeDialog(dialog);
2027 			}
2028 		}
2029 	}
2030 	if(result)
2031 	{
2032 		if(hadFind)
2033 		{
2034 			(*searchType)=ST_FIND;
2035 		}
2036 		if(hadFindAll)
2037 		{
2038 			(*searchType)=ST_FINDALL;
2039 		}
2040 		if(hadReplace)
2041 		{
2042 			(*searchType)=ST_REPLACE;
2043 		}
2044 		if(hadReplaceAll)
2045 		{
2046 			(*searchType)=ST_REPLACEALL;
2047 		}
2048 	}
2049 	return(result);
2050 }
2051 
2052 // ----------------------------------------------------------------------------
SimpleListBoxDialogStatTextResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)2053 static void SimpleListBoxDialogStatTextResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
2054 // Resize the static text area
2055 {
2056 	WINDOW_LIST_ELEMENT
2057 		*windowElement;
2058 	XWindowAttributes
2059 		attributes;
2060 
2061 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
2062 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
2063 
2064 	rect->x=10;
2065 	rect->y=10;
2066 	if(attributes.width>20)
2067 	{
2068 		rect->w=attributes.width-20;
2069 	}
2070 	else
2071 	{
2072 		rect->w=0;
2073 	}
2074 	rect->h=20;
2075 }
2076 
SimpleListBoxDialogListBoxResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)2077 static void SimpleListBoxDialogListBoxResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
2078 // Resize the list box area
2079 {
2080 	WINDOW_LIST_ELEMENT
2081 		*windowElement;
2082 	XWindowAttributes
2083 		attributes;
2084 
2085 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
2086 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
2087 
2088 	rect->x=10;
2089 	rect->y=30;
2090 	if(attributes.width>20)
2091 	{
2092 		rect->w=attributes.width-20;
2093 	}
2094 	else
2095 	{
2096 		rect->w=0;
2097 	}
2098 	if(attributes.height>80)
2099 	{
2100 		rect->h=attributes.height-80;
2101 	}
2102 	else
2103 	{
2104 		rect->h=0;
2105 	}
2106 }
2107 
SimpleListDialogButtonOkResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)2108 static void SimpleListDialogButtonOkResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
2109 // Resize the ok button
2110 {
2111 	WINDOW_LIST_ELEMENT
2112 		*windowElement;
2113 	XWindowAttributes
2114 		attributes;
2115 
2116 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
2117 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
2118 
2119 	rect->w=50;
2120 	rect->h=25;
2121 
2122 	rect->x=attributes.width/5-rect->w/2;
2123 
2124 	if(attributes.height>35)
2125 	{
2126 		rect->y=attributes.height-35;
2127 	}
2128 	else
2129 	{
2130 		rect->y=0;
2131 	}
2132 }
2133 
SimpleListDialogButtonCancelResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)2134 static void SimpleListDialogButtonCancelResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
2135 // Resize the cancel button
2136 {
2137 	WINDOW_LIST_ELEMENT
2138 		*windowElement;
2139 	XWindowAttributes
2140 		attributes;
2141 
2142 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
2143 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
2144 
2145 	rect->w=70;
2146 	rect->h=25;
2147 
2148 	rect->x=4*attributes.width/5-rect->w/2;
2149 
2150 	if(attributes.height>35)
2151 	{
2152 		rect->y=attributes.height-35;
2153 	}
2154 	else
2155 	{
2156 		rect->y=0;
2157 	}
2158 }
2159 
ListExitPress(void * parameters)2160 static void ListExitPress(void *parameters)
2161 // When the simple list is double clicked in, it is just like
2162 // pressing the Ok button, so we do that!
2163 {
2164 	DIALOG
2165 		*dialog;
2166 
2167 	dialog=(DIALOG *)parameters;
2168 	PressButtonItem((DIALOG_ITEM *)dialog->dialogLocal);
2169 }
2170 
SimpleListBoxDialog(const char * title,UINT32 numElements,const char ** listElements,bool * selectedElements,bool * cancel)2171 bool SimpleListBoxDialog(const char *title,UINT32 numElements,const char **listElements,bool *selectedElements,bool *cancel)
2172 // Open a list selection dialog box with two buttons (ok, cancel)
2173 // The list dialog will be used to modify the selectionListArray, to tell
2174 // which items were selected, and which were not
2175 // If there is a problem, SetError, return false
2176 // Otherwise, if cancel is true, the user canceled
2177 // Otherwise, selectedElements is modified to reflect which items
2178 // have been selected
2179 {
2180 	DIALOG
2181 		*dialog;
2182 	LIST_BOX_DESCRIPTOR
2183 		listBoxDescriptor;
2184 	STATIC_TEXT_DESCRIPTOR
2185 		textDescriptor;
2186 	BUTTON_DESCRIPTOR
2187 		buttonDescriptor;
2188 	bool
2189 		done,
2190 		result;
2191 	UINT32
2192 		index;
2193 
2194 	result=false;
2195 	*cancel=false;
2196 
2197 	if((dialog=CreateCenteredDialog(600,300," ",BACKGROUND_COLOR)))			// make new empty dialog
2198 	{
2199 
2200 		textDescriptor.resizeFunction=SimpleListBoxDialogStatTextResize;
2201 		textDescriptor.backgroundColor=BACKGROUND_COLOR;
2202 		textDescriptor.foregroundColor=BLACK;
2203 		textDescriptor.string=title;
2204 		textDescriptor.fontName=defaultDialogTextFont;
2205 
2206 		if(NewDialogItem(dialog,CreateStaticTextItem,&textDescriptor))
2207 		{
2208 			listBoxDescriptor.resizeFunction=SimpleListBoxDialogListBoxResize;
2209 			listBoxDescriptor.topLine=0;						// if no selection found, take top as 0
2210 			done=false;
2211 			for(index=0;!done&&index<numElements;index++)		// make top line the first selection if possible
2212 			{
2213 				if(selectedElements[index])
2214 				{
2215 					listBoxDescriptor.topLine=index;
2216 					done=true;
2217 				}
2218 			}
2219 			listBoxDescriptor.focusBackgroundColor=GRAY_3;
2220 			listBoxDescriptor.focusForegroundColor=BLACK;
2221 			listBoxDescriptor.nofocusBackgroundColor=GRAY_3;
2222 			listBoxDescriptor.nofocusForegroundColor=BLACK;
2223 			listBoxDescriptor.numElements=numElements;
2224 			listBoxDescriptor.listElements=listElements;
2225 			listBoxDescriptor.selectedElements=selectedElements;
2226 			listBoxDescriptor.fontName=defaultViewFont;
2227 			listBoxDescriptor.pressedProc=ListExitPress;
2228 			listBoxDescriptor.pressedProcParameters=dialog;
2229 
2230 			if(NewDialogItem(dialog,CreateListBoxItem,&listBoxDescriptor))
2231 			{
2232 				buttonDescriptor.resizeFunction=SimpleListDialogButtonOkResize;
2233 				buttonDescriptor.buttonName="Ok";
2234 				buttonDescriptor.fontName=defaultDialogButtonFont;
2235 				buttonDescriptor.hasKey=true;
2236 				buttonDescriptor.keySym=XK_Return;
2237 				buttonDescriptor.pressedProc=ExitPress;
2238 				buttonDescriptor.pressedProcParameters=dialog;
2239 				buttonDescriptor.pressedState=NULL;
2240 
2241 				if((dialog->dialogLocal=NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor)))	// remember this button
2242 				{
2243 					buttonDescriptor.resizeFunction=SimpleListDialogButtonCancelResize;
2244 					buttonDescriptor.buttonName="Cancel";
2245 					buttonDescriptor.fontName=defaultDialogButtonFont;
2246 					buttonDescriptor.hasKey=true;
2247 					buttonDescriptor.keySym=XK_Escape;
2248 					buttonDescriptor.pressedProc=ExitPress;
2249 					buttonDescriptor.pressedProcParameters=dialog;
2250 					buttonDescriptor.pressedState=cancel;
2251 
2252 					if(NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor))
2253 					{
2254 						HandleDialog(dialog);					// deal with this dialog
2255 						result=true;
2256 					}
2257 				}
2258 			}
2259 		}
2260 		DisposeDialog(dialog);
2261 	}
2262 	return(result);
2263 }
2264 
2265 // ----------------------------------------------------------------------------
2266 // Stuff dealing with open/save dialogs
2267 
2268 // This structure is hung off of the open/save dialogs, it allows the dialog item
2269 // procedures access to some things they need
2270 
2271 typedef struct
2272 {
2273 	EDITOR_BUFFER
2274 		*buffer;
2275 	char
2276 		pathString[MAXPATHLEN+1];
2277 	char
2278 		**list;
2279 	bool
2280 		*selectionList;
2281 	UINT32
2282 		numElements;
2283 	char
2284 		**outputList;
2285 	UINT32
2286 		outputElements;
2287 	bool
2288 		justOne,
2289 		justPaths;
2290 	DIALOG_ITEM
2291 		*pathText,
2292 		*listBox,
2293 		*textBox,
2294 		*OkButton;
2295 } FILE_DIALOG_PARAMETERS;
2296 
FileDialogStatTextTitleResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)2297 static void FileDialogStatTextTitleResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
2298 // Resize the static text area
2299 {
2300 	WINDOW_LIST_ELEMENT
2301 		*windowElement;
2302 	XWindowAttributes
2303 		attributes;
2304 
2305 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
2306 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
2307 
2308 	rect->x=10;
2309 	rect->y=10;
2310 	if(attributes.width>20)
2311 	{
2312 		rect->w=attributes.width-20;
2313 	}
2314 	else
2315 	{
2316 		rect->w=0;
2317 	}
2318 	rect->h=20;
2319 }
2320 
FileDialogStatTextPathResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)2321 static void FileDialogStatTextPathResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
2322 // Resize the static text area
2323 {
2324 	WINDOW_LIST_ELEMENT
2325 		*windowElement;
2326 	XWindowAttributes
2327 		attributes;
2328 
2329 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
2330 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
2331 
2332 	rect->x=10;
2333 	rect->y=30;
2334 	if(attributes.width>20)
2335 	{
2336 		rect->w=attributes.width-20;
2337 	}
2338 	else
2339 	{
2340 		rect->w=0;
2341 	}
2342 	rect->h=40;
2343 }
2344 
FileDialogTextBoxResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)2345 static void FileDialogTextBoxResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
2346 // Resize the file dialog path entry box
2347 {
2348 	WINDOW_LIST_ELEMENT
2349 		*windowElement;
2350 	XWindowAttributes
2351 		attributes;
2352 
2353 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
2354 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
2355 
2356 	rect->x=10;
2357 	rect->y=66;
2358 	if(attributes.width>20)
2359 	{
2360 		rect->w=attributes.width-20;
2361 	}
2362 	else
2363 	{
2364 		rect->w=0;
2365 	}
2366 	rect->h=30;
2367 }
2368 
FileDialogListBoxResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)2369 static void FileDialogListBoxResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
2370 // Resize the file dialog list box
2371 {
2372 	WINDOW_LIST_ELEMENT
2373 		*windowElement;
2374 	XWindowAttributes
2375 		attributes;
2376 
2377 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
2378 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
2379 
2380 	rect->x=10;
2381 	rect->y=110;
2382 	if(attributes.width>20)
2383 	{
2384 		rect->w=attributes.width-20;
2385 	}
2386 	else
2387 	{
2388 		rect->w=0;
2389 	}
2390 
2391 	if(attributes.height>160)
2392 	{
2393 		rect->h=attributes.height-160;
2394 	}
2395 	else
2396 	{
2397 		rect->h=0;
2398 	}
2399 }
2400 
FileDialogButtonOkResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)2401 static void FileDialogButtonOkResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
2402 // Resize the ok button
2403 {
2404 	WINDOW_LIST_ELEMENT
2405 		*windowElement;
2406 	XWindowAttributes
2407 		attributes;
2408 
2409 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
2410 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
2411 
2412 	rect->w=50;
2413 	rect->h=25;
2414 
2415 	rect->x=attributes.width/5-rect->w/2;
2416 
2417 	if(attributes.height>35)
2418 	{
2419 		rect->y=attributes.height-35;
2420 	}
2421 	else
2422 	{
2423 		rect->y=0;
2424 	}
2425 }
2426 
FileDialogButtonCancelResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)2427 static void FileDialogButtonCancelResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
2428 // Resize the cancel button
2429 {
2430 	WINDOW_LIST_ELEMENT
2431 		*windowElement;
2432 	XWindowAttributes
2433 		attributes;
2434 
2435 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
2436 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
2437 
2438 	rect->w=70;
2439 	rect->h=25;
2440 
2441 	rect->x=4*attributes.width/5-rect->w/2;
2442 
2443 	if(attributes.height>35)
2444 	{
2445 		rect->y=attributes.height-35;
2446 	}
2447 	else
2448 	{
2449 		rect->y=0;
2450 	}
2451 }
2452 
FileDialogButtonAcceptPathResize(EDITOR_WINDOW * window,EDITOR_RECT * rect)2453 static void FileDialogButtonAcceptPathResize(EDITOR_WINDOW *window,EDITOR_RECT *rect)
2454 // Resize the accept path button
2455 {
2456 	WINDOW_LIST_ELEMENT
2457 		*windowElement;
2458 	XWindowAttributes
2459 		attributes;
2460 
2461 	windowElement=(WINDOW_LIST_ELEMENT *)window->userData;
2462 	XGetWindowAttributes(xDisplay,windowElement->xWindow,&attributes);
2463 
2464 	rect->w=100;
2465 	rect->h=25;
2466 
2467 	rect->x=attributes.width/2-rect->w/2;
2468 
2469 	if(attributes.height>35)
2470 	{
2471 		rect->y=attributes.height-35;
2472 	}
2473 	else
2474 	{
2475 		rect->y=0;
2476 	}
2477 }
2478 
ProcessDirectoryList(const char * pathString,char ** list,UINT32 inElements,UINT32 * outElements,bool justPaths)2479 static char **ProcessDirectoryList(const char *pathString,char **list,UINT32 inElements,UINT32 *outElements,bool justPaths)
2480 // Given a path string, and a sorted raw list of files at the end of the path
2481 // create a new list which contains the processed versions of each entry
2482 // (place PATH_SEP after directories, eliminate files if justPaths is true)
2483 // If there is a problem, SetError, return NULL
2484 // NOTE: this does not dispose of the incoming list
2485 // the output list must be disposed of by calling FreeStringList
2486 {
2487 	char
2488 		**outList;
2489 	char
2490 		tempPath[MAXPATHLEN+1];
2491 	int
2492 		length;
2493 	UINT32
2494 		inElement;
2495 	struct stat
2496 		statOut;
2497 
2498 	*outElements=0;
2499 	if((outList=NewStringList()))
2500 	{
2501 		for(inElement=0;inElement<inElements;inElement++)
2502 		{
2503 			ConcatPathAndFile(pathString,list[inElement],tempPath);
2504 			if(stat(tempPath,&statOut)!=-1)				// if this fails, then do not copy the name
2505 			{
2506 				if(S_ISDIR(statOut.st_mode))
2507 				{
2508 					length=strlen(list[inElement]);
2509 					if(length<MAXPATHLEN)
2510 					{
2511 						strcpy(tempPath,list[inElement]);
2512 						tempPath[length++]=PATH_SEP;	// drop PATH_SEP onto the string
2513 						tempPath[length]='\0';
2514 						AddStringToList(tempPath,&outList,outElements);	// ignore errors here
2515 					}
2516 				}
2517 				else
2518 				{
2519 					if(!justPaths)						// see if file names should be added
2520 					{
2521 						AddStringToList(list[inElement],&outList,outElements);	// ignore errors here
2522 					}
2523 				}
2524 			}
2525 		}
2526 	}
2527 	return(outList);
2528 }
2529 
DisposeSelectionFiles(char ** list,bool * selectionList)2530 static void DisposeSelectionFiles(char **list,bool *selectionList)
2531 // Dispose of the two lists returned by GetPathAndSelectionFiles
2532 {
2533 	MDisposePtr(selectionList);
2534 	FreeStringList(list);
2535 }
2536 
GetSelectionFiles(const char * pathString,UINT32 * numElements,bool ** selectionList,bool justPaths)2537 static char **GetSelectionFiles(const char *pathString,UINT32 *numElements,bool **selectionList,bool justPaths)
2538 // Given pathString, create a list of the files/directories at the end of the path
2539 // DisposeSelectionFiles must be called on list, and selectionList to dispose of them
2540 // If there is a problem, SetError, return NULL
2541 {
2542 	char
2543 		**rawList,
2544 		**list;
2545 	UINT32
2546 		rawElements;
2547 
2548 	if((rawList=GlobAll(pathString,&rawElements)))
2549 	{
2550 		list=ProcessDirectoryList(pathString,rawList,rawElements,numElements,justPaths);
2551 		FreeStringList(rawList);					// get rid of the raw list
2552 		if(list)
2553 		{
2554 			if((*selectionList=(bool *)MNewPtrClr((*numElements)*sizeof(bool))))
2555 			{
2556 				return(list);
2557 			}
2558 			FreeStringList(list);
2559 		}
2560 	}
2561 
2562 	*selectionList=NULL;
2563 	*numElements=0;
2564 
2565 	return(NULL);
2566 }
2567 
FileListPress(void * parameters)2568 static void FileListPress(void *parameters)
2569 // When a selection has been made from the file list, this
2570 // will decide what to do
2571 {
2572 	DIALOG
2573 		*dialog;
2574 	FILE_DIALOG_PARAMETERS
2575 		*dialogParameters;
2576 
2577 	dialog=(DIALOG *)parameters;
2578 	dialogParameters=(FILE_DIALOG_PARAMETERS *)dialog->dialogLocal;
2579 	PressButtonItem(dialogParameters->OkButton);		// behave as if Ok was pressed
2580 }
2581 
AddPathAndFileToList(const char * path,const char * file,char *** list,UINT32 * numElements)2582 static bool AddPathAndFileToList(const char *path,const char *file,char ***list,UINT32 *numElements)
2583 // Like AddStringToList, but takes a path, and a filename which are
2584 // concatenated into a complete path, and added to the list
2585 // If there is a problem, SetError, and return false
2586 {
2587 	char
2588 		fullPath[MAXPATHLEN+1];
2589 
2590 	ConcatPathAndFile(path,file,fullPath);
2591 	return(AddStringToList(fullPath,list,numElements));
2592 }
2593 
FileOkInText(DIALOG * dialog,FILE_DIALOG_PARAMETERS * dialogParameters)2594 static bool FileOkInText(DIALOG *dialog,FILE_DIALOG_PARAMETERS *dialogParameters)
2595 // Ok was pressed while the text was active
2596 {
2597 	CHUNK_HEADER
2598 		*chunk;
2599 	UINT32
2600 		offset;
2601 	char
2602 		globPath[MAXPATHLEN+1];
2603 	char
2604 		**globList;
2605 	UINT32
2606 		currentElement,
2607 		globElements;
2608 	bool
2609 		fail;
2610 
2611 	fail=false;
2612 
2613 	if((dialogParameters->outputList=NewStringList()))
2614 	{
2615 		dialogParameters->outputElements=0;
2616 		if(ExtractUniverseText(dialogParameters->buffer->textUniverse,dialogParameters->buffer->textUniverse->firstChunkHeader,0,(UINT8 *)globPath,MAXPATHLEN,&chunk,&offset))
2617 		{
2618 			if(dialogParameters->buffer->textUniverse->totalBytes<MAXPATHLEN)
2619 			{
2620 				globPath[dialogParameters->buffer->textUniverse->totalBytes]='\0';
2621 			}
2622 			else
2623 			{
2624 				globPath[MAXPATHLEN]='\0';
2625 			}
2626 			if((globList=Glob(&(dialogParameters->pathString[0]),globPath,false,true,&globElements)))
2627 			{
2628 				for(currentElement=0;!fail&&currentElement<globElements;currentElement++)
2629 				{
2630 					fail=!AddPathAndFileToList(&(dialogParameters->pathString[0]),globList[currentElement],&dialogParameters->outputList,&dialogParameters->outputElements);
2631 				}
2632 				FreeStringList(globList);
2633 			}
2634 			else
2635 			{
2636 				fail=true;
2637 			}
2638 		}
2639 		else
2640 		{
2641 			fail=true;
2642 		}
2643 		if(fail)
2644 		{
2645 			FreeStringList(dialogParameters->outputList);
2646 			dialogParameters->outputElements=0;
2647 		}
2648 	}
2649 	return(!fail);
2650 }
2651 
FileOkInList(DIALOG * dialog,FILE_DIALOG_PARAMETERS * dialogParameters)2652 static bool FileOkInList(DIALOG *dialog,FILE_DIALOG_PARAMETERS *dialogParameters)
2653 // Ok was pressed while the list was active
2654 // Create an output list which contains all the selected items
2655 // If there is a problem, SetError, return false
2656 // NOTE: to make the interface seem more intuitive, if there
2657 // are no selected items in the list, this will revert to making
2658 // a list from the text box
2659 {
2660 	UINT32
2661 		currentElement;
2662 	bool
2663 		noneSelected,
2664 		fail;
2665 
2666 	fail=false;
2667 	noneSelected=true;
2668 	if((dialogParameters->outputList=NewStringList()))
2669 	{
2670 		dialogParameters->outputElements=0;
2671 		for(currentElement=0;!fail&&currentElement<dialogParameters->numElements;currentElement++)
2672 		{
2673 			if(dialogParameters->selectionList[currentElement])	// is this one selected?
2674 			{
2675 				noneSelected=false;
2676 				fail=!AddPathAndFileToList(&(dialogParameters->pathString[0]),dialogParameters->list[currentElement],&dialogParameters->outputList,&dialogParameters->outputElements);
2677 			}
2678 		}
2679 		if(fail||noneSelected)
2680 		{
2681 			FreeStringList(dialogParameters->outputList);
2682 			dialogParameters->outputElements=0;
2683 		}
2684 	}
2685 	if(!fail)
2686 	{
2687 		if(noneSelected)									// if not failure, but nothing selected, use dialog text
2688 		{
2689 			return(FileOkInText(dialog,dialogParameters));
2690 		}
2691 		else
2692 		{
2693 			return(true);
2694 		}
2695 	}
2696 	return(false);
2697 }
2698 
FileOkPress(void * parameters)2699 static void FileOkPress(void *parameters)
2700 // The user pressed "Ok" in the dialog (or it was pressed for him)
2701 // take appropriate action
2702 {
2703 	DIR
2704 		*directory;
2705 	DIALOG
2706 		*dialog;
2707 	FILE_DIALOG_PARAMETERS
2708 		*dialogParameters;
2709 	bool
2710 		fail;
2711 
2712 	ClearErrorTrace();
2713 	dialog=(DIALOG *)parameters;
2714 	dialogParameters=(FILE_DIALOG_PARAMETERS *)dialog->dialogLocal;
2715 	fail=false;
2716 	if(dialog->focusItem==dialogParameters->listBox)	// if list has focus, then build a list out of what's selected
2717 	{
2718 		fail=!FileOkInList(dialog,dialogParameters);
2719 	}
2720 	else
2721 	{
2722 		fail=!FileOkInText(dialog,dialogParameters);
2723 	}
2724 
2725 	if(!fail)
2726 	{
2727 		if(dialogParameters->outputElements==1)			// if only one element, then see if directory
2728 		{
2729 			if((directory=opendir(dialogParameters->outputList[0])))	// see if it is a directory, and we are allowed to open it
2730 			{
2731 				closedir(directory);					// did not want it open, just wanted to see if we could
2732 				if(!(dialog->focusItem==dialogParameters->listBox))
2733 				{
2734 					ClearBuffer(dialogParameters->buffer);	// get rid of any text in the view
2735 				}
2736 				if(dialogParameters->list)
2737 				{
2738 					DisposeSelectionFiles(dialogParameters->list,dialogParameters->selectionList);
2739 				}
2740 				realpath2(dialogParameters->outputList[0],&(dialogParameters->pathString[0]));	// this is the new path
2741 				dialogParameters->list=GetSelectionFiles(&(dialogParameters->pathString[0]),&dialogParameters->numElements,&dialogParameters->selectionList,dialogParameters->justPaths);
2742 				ResetStaticTextItemText(dialogParameters->pathText,&(dialogParameters->pathString[0]));
2743 				ResetListBoxItemLists(dialogParameters->listBox,dialogParameters->numElements,(const char **)dialogParameters->list,dialogParameters->selectionList);
2744 				ResetMultipleClicks();					// reset multiple click timers
2745 			}
2746 			else
2747 			{
2748 				if(errno==ENOTDIR||errno==ENOENT)
2749 				{
2750 					if(!dialogParameters->justPaths)
2751 					{
2752 						dialog->dialogComplete=true;		// if not a directory, or known file, return it
2753 					}
2754 					else
2755 					{
2756 						ReportMessage("%s\nNot a directory\n",dialogParameters->outputList[0]);	// let user know what's wrong
2757 					}
2758 				}
2759 				else
2760 				{
2761 					SetStdCLibError();						// report whatever error we got
2762 					ReportMessage("%s\n",GetErrorTrace());	// let user know what's wrong
2763 				}
2764 			}
2765 		}
2766 		else
2767 		{
2768 			if(dialogParameters->justOne||dialogParameters->justPaths)
2769 			{
2770 				ReportMessage("Path is ambiguous\n");		// got more elements than asked for, so complain, and keep going
2771 			}
2772 			else
2773 			{
2774 				dialog->dialogComplete=true;				// if anything other that 1 element, pass it back as the result
2775 			}
2776 		}
2777 		if(!dialog->dialogComplete)
2778 		{
2779 			FreeStringList(dialogParameters->outputList);	// not leaving, so kill the list
2780 		}
2781 	}
2782 	else
2783 	{
2784 		ReportMessage("%s\n",GetErrorTrace());				// let user know what's wrong
2785 	}
2786 }
2787 
FileDialog(const char * title,char * fullPath,UINT32 stringBytes,char *** list,bool justOne,bool justPaths,bool * cancel)2788 static bool FileDialog(const char *title,char *fullPath,UINT32 stringBytes,char ***list,bool justOne,bool justPaths,bool *cancel)
2789 // Bring up a file open/save dialog
2790 // If there is a problem, SetError, return false
2791 // Otherwise, cancel is true if the user canceled the dialog
2792 //
2793 // Otherwise, if justPaths is true, return the final path chosen in the
2794 // dialog in fullPath, truncating to stringBytes in length
2795 //
2796 // Otherwise, listElements contains the pointer to the start of an array of
2797 // pointers to char which are the selections.
2798 // It must be disposed of at some later time with a call to FreeFileDialogPaths
2799 // NOTE: the array is terminated with a pointer to NULL
2800 {
2801 	DIALOG
2802 		*dialog;
2803 	TEXT_BOX_DESCRIPTOR
2804 		textBoxDescriptor;
2805 	LIST_BOX_DESCRIPTOR
2806 		listBoxDescriptor;
2807 	STATIC_TEXT_DESCRIPTOR
2808 		textDescriptor;
2809 	BUTTON_DESCRIPTOR
2810 		buttonDescriptor;
2811 	FILE_DIALOG_PARAMETERS
2812 		dialogParameters;
2813 	bool
2814 		result;
2815 	char
2816 		filePart[MAXPATHLEN+1];
2817 
2818 	result=false;
2819 	*cancel=false;
2820 
2821 	dialogParameters.justOne=justOne;
2822 	dialogParameters.justPaths=justPaths;
2823 
2824 	if((dialogParameters.buffer=EditorNewBuffer("file dialog")))			// create a buffer in which to collect the file name
2825 	{
2826 		SplitPathAndFile(fullPath,dialogParameters.pathString,filePart);	// split the incoming name into file and path components
2827 		if(InsertUniverseText(dialogParameters.buffer->textUniverse,dialogParameters.buffer->textUniverse->totalBytes,(UINT8 *)filePart,strlen(filePart)))
2828 		{
2829 			if(EditorSelectAll(dialogParameters.buffer))					// select it all
2830 			{
2831 				if((dialog=CreateCenteredDialog(440,470," ",BACKGROUND_COLOR)))		// make new empty dialog
2832 				{
2833 					dialog->dialogLocal=&dialogParameters;				// hang parameter list off of the dialog
2834 
2835 					dialogParameters.list=GetSelectionFiles(&(dialogParameters.pathString[0]),&dialogParameters.numElements,&dialogParameters.selectionList,justPaths);	// ignore failure, since list box will handle a NULL list
2836 
2837 					textDescriptor.resizeFunction=FileDialogStatTextTitleResize;
2838 					textDescriptor.backgroundColor=BACKGROUND_COLOR;
2839 					textDescriptor.foregroundColor=BLACK;
2840 					textDescriptor.string=title;
2841 					textDescriptor.fontName=defaultDialogTextFont;
2842 
2843 					if(NewDialogItem(dialog,CreateStaticTextItem,&textDescriptor))
2844 					{
2845 						textDescriptor.resizeFunction=FileDialogStatTextPathResize;
2846 						textDescriptor.backgroundColor=BACKGROUND_COLOR;
2847 						textDescriptor.foregroundColor=BLACK;
2848 						textDescriptor.string=&(dialogParameters.pathString[0]);
2849 						textDescriptor.fontName=defaultViewFont;
2850 
2851 						if((dialogParameters.pathText=NewDialogItem(dialog,CreateStaticTextItem,&textDescriptor)))
2852 						{
2853 
2854 							textBoxDescriptor.buffer=dialogParameters.buffer;
2855 							textBoxDescriptor.resizeFunction=FileDialogTextBoxResize;
2856 							textBoxDescriptor.topLine=0;
2857 							textBoxDescriptor.leftPixel=0;
2858 							textBoxDescriptor.tabSize=4;
2859 							textBoxDescriptor.focusBackgroundColor=GRAY_3;
2860 							textBoxDescriptor.focusForegroundColor=BLACK;
2861 							textBoxDescriptor.nofocusBackgroundColor=GRAY_3;
2862 							textBoxDescriptor.nofocusForegroundColor=GRAY_1;
2863 							textBoxDescriptor.fontName=defaultViewFont;
2864 
2865 							if((dialogParameters.textBox=NewDialogItem(dialog,CreateTextBoxItem,&textBoxDescriptor)))
2866 							{
2867 								listBoxDescriptor.resizeFunction=FileDialogListBoxResize;
2868 								listBoxDescriptor.topLine=0;
2869 								listBoxDescriptor.focusBackgroundColor=GRAY_3;
2870 								listBoxDescriptor.focusForegroundColor=BLACK;
2871 								listBoxDescriptor.nofocusBackgroundColor=GRAY_3;
2872 								listBoxDescriptor.nofocusForegroundColor=GRAY_1;
2873 								listBoxDescriptor.numElements=dialogParameters.numElements;
2874 								listBoxDescriptor.listElements=(const char **)dialogParameters.list;
2875 								listBoxDescriptor.selectedElements=dialogParameters.selectionList;
2876 								listBoxDescriptor.fontName=defaultViewFont;
2877 								listBoxDescriptor.pressedProc=FileListPress;
2878 								listBoxDescriptor.pressedProcParameters=dialog;
2879 
2880 								if((dialogParameters.listBox=NewDialogItem(dialog,CreateListBoxItem,&listBoxDescriptor)))
2881 								{
2882 									buttonDescriptor.resizeFunction=FileDialogButtonOkResize;
2883 									buttonDescriptor.buttonName="Ok";
2884 									buttonDescriptor.fontName=defaultDialogButtonFont;
2885 									buttonDescriptor.hasKey=true;
2886 									buttonDescriptor.keySym=XK_Return;
2887 									buttonDescriptor.pressedProc=FileOkPress;
2888 									buttonDescriptor.pressedProcParameters=dialog;
2889 									buttonDescriptor.pressedState=NULL;
2890 
2891 									if((dialogParameters.OkButton=NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor)))	// remember this button
2892 									{
2893 										buttonDescriptor.resizeFunction=FileDialogButtonCancelResize;
2894 										buttonDescriptor.buttonName="Cancel";
2895 										buttonDescriptor.fontName=defaultDialogButtonFont;
2896 										buttonDescriptor.hasKey=true;
2897 										buttonDescriptor.keySym=XK_Escape;
2898 										buttonDescriptor.pressedProc=ExitPress;
2899 										buttonDescriptor.pressedProcParameters=dialog;
2900 										buttonDescriptor.pressedState=cancel;
2901 
2902 										if(NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor))
2903 										{
2904 											if(justPaths)			// add another button for paths (use enter to select)
2905 											{
2906 												buttonDescriptor.resizeFunction=FileDialogButtonAcceptPathResize;
2907 												buttonDescriptor.buttonName="Accept Path";
2908 												buttonDescriptor.fontName=defaultDialogButtonFont;
2909 												buttonDescriptor.hasKey=true;
2910 												buttonDescriptor.keySym=XK_KP_Enter;
2911 												buttonDescriptor.pressedProc=ExitPress;
2912 												buttonDescriptor.pressedProcParameters=dialog;
2913 												buttonDescriptor.pressedState=NULL;
2914 
2915 												if(NewDialogItem(dialog,CreateButtonItem,&buttonDescriptor))
2916 												{
2917 													HandleDialog(dialog);	// deal with this dialog
2918 													result=true;
2919 												}
2920 											}
2921 											else
2922 											{
2923 												HandleDialog(dialog);	// deal with this dialog
2924 												result=true;
2925 											}
2926 										}
2927 									}
2928 								}
2929 							}
2930 						}
2931 					}
2932 					if(dialogParameters.list)							// delete any lists that are hanging around
2933 					{
2934 						DisposeSelectionFiles(dialogParameters.list,dialogParameters.selectionList);
2935 					}
2936 					DisposeDialog(dialog);
2937 				}
2938 			}
2939 		}
2940 		EditorCloseBuffer(dialogParameters.buffer);
2941 	}
2942 	if(justPaths)
2943 	{
2944 		if(stringBytes)
2945 		{
2946 			strncpy(fullPath,dialogParameters.pathString,stringBytes);	// return the path
2947 			fullPath[stringBytes-1]='\0';
2948 		}
2949 	}
2950 	if(result&&!(*cancel)&&(!justPaths))
2951 	{
2952 		*list=dialogParameters.outputList;
2953 	}
2954 	return(result);
2955 }
2956 
FreeFileDialogPaths(char ** paths)2957 static void FreeFileDialogPaths(char **paths)
2958 // Free an array of paths that was returned from FileDialog
2959 {
2960 	FreeStringList(paths);
2961 }
2962 
OpenFileDialog(const char * title,char * fullPath,UINT32 stringBytes,char *** listElements,bool * cancel)2963 bool OpenFileDialog(const char *title,char *fullPath,UINT32 stringBytes,char ***listElements,bool *cancel)
2964 // Bring up a file open dialog
2965 // If there is a problem, SetError, return false
2966 // Otherwise, cancel is true if the user canceled the dialog
2967 //
2968 // Otherwise, listElements contains the pointer to the start of an array of
2969 // pointers to char which are the selections
2970 // It must be disposed of at some later time with a call to FreeOpenFileDialogPaths
2971 // NOTE: the array is terminated with a pointer to NULL
2972 //
2973 // NOTE: this is NOT allowed to change the current directory of the editor
2974 {
2975 	return(FileDialog(title,fullPath,stringBytes,listElements,false,false,cancel));
2976 }
2977 
FreeOpenFileDialogPaths(char ** paths)2978 void FreeOpenFileDialogPaths(char **paths)
2979 // free an array of paths that was returned from OpenFileDialog
2980 {
2981 	FreeFileDialogPaths(paths);
2982 }
2983 
SaveFileDialog(const char * title,char * fullPath,UINT32 stringBytes,bool * cancel)2984 bool SaveFileDialog(const char *title,char *fullPath,UINT32 stringBytes,bool *cancel)
2985 // Bring up a file save dialog
2986 // If there is a problem, SetError, return false
2987 // Otherwise, if cancel is true, the user canceled
2988 // Otherwise, return the full path name of the chosen file
2989 // NOTE: if the fullPath (including terminator) would be larger than stringBytes,
2990 // then it will be truncated to fit
2991 // NOTE ALSO: fullPath may be sent to this routine with a pathname, and the save
2992 // dialog will open to that path (as best as it can)
2993 //
2994 // NOTE: this is NOT allowed to change the current directory of the editor
2995 {
2996 	char
2997 		**paths;
2998 	bool
2999 		result;
3000 
3001 	result=false;
3002 	if(FileDialog(title,fullPath,stringBytes,&paths,true,false,cancel))
3003 	{
3004 		if(!(*cancel))
3005 		{
3006 			if(stringBytes)
3007 			{
3008 				strncpy(fullPath,paths[0],stringBytes);
3009 				fullPath[stringBytes-1]='\0';
3010 			}
3011 			FreeFileDialogPaths(paths);
3012 		}
3013 		result=true;
3014 	}
3015 	return(result);
3016 }
3017 
ChoosePathDialog(const char * title,char * fullPath,UINT32 stringBytes,bool * cancel)3018 bool ChoosePathDialog(const char *title,char *fullPath,UINT32 stringBytes,bool *cancel)
3019 // Bring up a path choose dialog
3020 // If there is a problem, SetError, return false
3021 // Otherwise, if cancel is true, the user canceled
3022 // Otherwise, return the full path name of the chosen path
3023 // NOTE: if the fullPath (including terminator) would be larger than stringBytes,
3024 // then it will be truncated to fit
3025 // NOTE ALSO: fullPath may be sent to this routine with a pathname, and the
3026 // dialog will open to that path (as best as it can)
3027 //
3028 // NOTE: this is NOT allowed to change the current directory of the editor
3029 {
3030 	return(FileDialog(title,fullPath,stringBytes,NULL,true,true,cancel));
3031 }
3032 
GetSortedFontList(UINT32 * numElements)3033 static char **GetSortedFontList(UINT32 *numElements)
3034 // Return a sorted list of fonts, or SetError, and return NULL if there is a problem
3035 // If a list is returned, it must be freed with FreeStringList
3036 {
3037 	int
3038 		actualCount;
3039 	char
3040 		**list,
3041 		**newList;
3042 	UINT32
3043 		index;
3044 	bool
3045 		fail;
3046 
3047 	newList=NULL;
3048 	if((list=XListFonts(xDisplay,"*",32767,&actualCount)))
3049 	{
3050 		if((newList=NewStringList()))							// copy the returned list, so it can be sorted (since it is not nice to sort the passed list, because we do not really own it, and should not be able to write to it)
3051 		{
3052 			fail=false;
3053 			*numElements=0;
3054 			for(index=0;!fail&&(int)index<actualCount;index++)
3055 			{
3056 				fail=!AddStringToList(list[index],&newList,numElements);
3057 			}
3058 			if(!fail)
3059 			{
3060 				SortStringList(newList,*numElements);
3061 			}
3062 			else
3063 			{
3064 				FreeStringList(newList);
3065 				newList=NULL;
3066 			}
3067 		}
3068 		XFreeFontNames(list);
3069 	}
3070 	else
3071 	{
3072 		SetError("No Fonts Located");
3073 	}
3074 	return(newList);
3075 }
3076 
MatchLength(const char * stringA,const char * stringB)3077 static UINT32 MatchLength(const char *stringA,const char *stringB)
3078 // Return the number of matching characters between stringA, and stringB
3079 // (the check is case insensitive)
3080 {
3081 	UINT32
3082 		matchIndex;
3083 
3084 	matchIndex=0;
3085 	while(stringA[matchIndex]&&(toupper(stringA[matchIndex])==toupper(stringB[matchIndex])))
3086 	{
3087 		matchIndex++;
3088 	}
3089 	return(matchIndex);
3090 }
3091 
GetBestMatchIndex(const char ** list,UINT32 numElements,const char * font)3092 static UINT32 GetBestMatchIndex(const char **list,UINT32 numElements,const char *font)
3093 // Try to match font against list, return the index of the
3094 // element of list which matches best
3095 {
3096 	UINT32
3097 		currentMatch,
3098 		bestMatch,
3099 		bestMatchPosition;
3100 	UINT32
3101 		index;
3102 
3103 	bestMatch=0;
3104 	bestMatchPosition=0;
3105 	for(index=0;index<numElements;index++)
3106 	{
3107 		if((currentMatch=MatchLength(font,list[index]))>bestMatch)
3108 		{
3109 			bestMatch=currentMatch;
3110 			bestMatchPosition=index;
3111 		}
3112 	}
3113 	return(bestMatchPosition);
3114 }
3115 
3116 // ----------------------------------------------------------------------------
ChooseFontDialog(const char * title,char * font,UINT32 stringBytes,bool * cancel)3117 bool ChooseFontDialog(const char *title,char *font,UINT32 stringBytes,bool *cancel)
3118 // Bring up a font choose dialog
3119 // If there is a problem, SetError, return false
3120 // Otherwise, if cancel is true, the user canceled
3121 // Otherwise, return the name of the chosen font in font
3122 // NOTE: if the font (including terminator) would be larger than stringBytes,
3123 // then it will be truncated to fit
3124 // NOTE ALSO: font may be sent to this routine with a font name, and the
3125 // dialog will open to that font (as best as it can)
3126 {
3127 	char
3128 		**list;
3129 	UINT32
3130 		actualCount;
3131 	bool
3132 		*selectionList,
3133 		done,
3134 		result;
3135 	int
3136 		index;
3137 
3138 	if((list=GetSortedFontList(&actualCount)))
3139 	{
3140 		result=false;
3141 		if((selectionList=(bool *)MNewPtrClr(actualCount*sizeof(bool))))
3142 		{
3143 			selectionList[GetBestMatchIndex((const char **)list,actualCount,font)]=true;	// select the item which is closest to the current font
3144 			if((result=SimpleListBoxDialog(title,actualCount,(const char **)list,selectionList,cancel)))
3145 			{
3146 				if(!*cancel)
3147 				{
3148 					done=false;
3149 					for(index=0;!done&&index<(int)actualCount;index++)
3150 					{
3151 						if(selectionList[index])	// find first selected item
3152 						{
3153 							if(stringBytes)
3154 							{
3155 								strncpy(font,list[index],stringBytes);
3156 								font[stringBytes-1]='\0';
3157 							}
3158 							done=true;
3159 						}
3160 					}
3161 					*cancel=!done;				// if none highlighted, take it as a cancel request
3162 				}
3163 			}
3164 			MDisposePtr(selectionList);
3165 		}
3166 		FreeStringList(list);
3167 		return(result);
3168 	}
3169 	return(false);
3170 }
3171