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&¤tElement<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&¤tElement<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