home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / suntar1.cpt / semimodal.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-10  |  9.9 KB  |  332 lines

  1. /*******************************************************************************\
  2.  
  3. movable modal dialog module
  4. ⌐ Gabriele Speranza  1-5 May 1991
  5.  modified on 26-27 Dec 1991 in order to use a resource
  6.  
  7. This program is public domain, feel free to use it or part of it for anything
  8.  
  9. \*******************************************************************************/
  10. #include "antiglue.h"
  11. #include "windows.h"
  12. #include "suntar.h"
  13.  
  14. /* I know that Apple has specified its rules about movable modal dialogs,
  15. but this module was written before I've seen System 7.0 or read about
  16. movable modal dialogs, hence I did it according to my personal taste and 
  17. gave it the name I felt right for it. Maybe later I'll remove those little
  18. incompatibilities with Apple guidelines.
  19. Anyway, it works with dialogs having WDEF 5 rather than 3 (it does NOT work
  20. with WDEF 1, since MultiFinder does not send an application to background
  21. when the front window has WDEF 1), with the only anomaly that the dialog
  22. may be dragged also from any point in its content, not only from the title
  23. bar
  24. */
  25.  
  26.  
  27. static WindowRecord    *sm_win_ptr;
  28. static Rect my_text_rect;
  29. static unsigned char** my_text;
  30. static int my_text_just;
  31. static Boolean my_has_default;
  32. Boolean finestra_sm_aperta=false;
  33.  
  34. #define noItem 100
  35.  
  36. int new_sm_evf(EventRecord *);
  37. static int new_sm_evf(theEvent)
  38. register EventRecord *theEvent;
  39. {
  40. /* internal event filter: it stops all events which are trying to bring
  41. to front a window which is not the semimodal dialog, and handles events
  42. regarding the window
  43. returns:
  44. 0: the event was not handled
  45. noItem: the event was handled
  46. anything else: semimodalDialog must close the window and return this code to the caller
  47. */
  48. int                code;
  49. WindowPtr        whichWindow;
  50. Point pt=theEvent->where;
  51.  
  52. switch(theEvent->what){
  53. case mouseDown:
  54.     code=FindWindow( theEvent->where, &whichWindow );
  55.     if(code==inMenuBar||code==inDesk||code==inSysWindow)
  56.         ;
  57.     else if(code==inDrag && whichWindow!=(WindowPtr)sm_win_ptr && 
  58.         (theEvent->modifiers&cmdKey))
  59.         ;        /* il tasto command comporta il non rendere corrente la finestra
  60.         -- accept a command-drag of another window
  61.          */
  62.     else if(whichWindow==(WindowPtr)sm_win_ptr){
  63.     /* inutile testare code, non puÿ essere che inContent, non ha altre aree */
  64.         GrafPtr    savePort;
  65.         ControlHandle     theControl;
  66.         int item;
  67.         GetPort( &savePort );
  68.         SetPort( sm_win_ptr );
  69.         GlobalToLocal( &pt );
  70.         if ((FindControl(pt, whichWindow, &theControl)) != 0) {
  71.             /*code=TrackControl(theControl, theEvent->where, 0L);
  72.             if(code) controlHit=theControl;     a button was pushed */
  73.             if(DialogSelect(theEvent,&whichWindow,&item)) return item;
  74.             }
  75.         else{    /* nel resto della finestra => la sposto
  76.             -- the semimodal dialog is moved by clicking on any point inside it
  77.             but outside the buttons, and dragging
  78.             */
  79.                     Rect    dragRect;
  80.                     dragRect.left=0;
  81.                     dragRect.top=MBARHEIGHT;
  82.                     dragRect.right=screenBits.bounds.right;
  83.                     dragRect.bottom=screenBits.bounds.bottom;
  84.                     InsetRect(&dragRect,20,10);
  85.                     DragWindow( sm_win_ptr, theEvent->where, &dragRect );
  86.                 }
  87.         SetPort( savePort );
  88.         return noItem;
  89.         }
  90.     else{
  91.         WindowPtr wp;
  92.         wp=FrontWindow();
  93.         if(wp!=NULL && ((WindowPeek)wp)->windowKind<userKind){
  94.         /* allora il click sulla console va reinterpretato come un click sulla finestrina
  95.         di dialogo e non va affatto ignorato
  96.         -- I've got a click on the console when the current window belonged to a desk
  97.         accessory or another task: bring to front the semimodal dialog
  98.         */
  99.             SelectWindow(sm_win_ptr);
  100.             }
  101.         return noItem;
  102.         }
  103.     break;
  104. case keyDown:
  105.     if(my_has_default && ((unsigned char)theEvent->message==CR || 
  106.                         (unsigned char)theEvent->message==enter_key) ){
  107.         short    kind;
  108.         Handle    h;
  109.         Rect    r;
  110.         GetDItem(sm_win_ptr,1,&kind,&h,&r);
  111.         SelectButton(h);
  112.         return 1;
  113.         }
  114.  
  115. }    /* fine switch */
  116. return 0;
  117. }
  118.  
  119. static void semimodal_updater(EventRecord*);
  120. static void semimodal_updater(theEvent)
  121. EventRecord*theEvent;
  122. {
  123. WindowPtr w=NULL;
  124. short item;
  125. DialogSelect(theEvent,&w,&item);
  126.  
  127. if(my_has_default)
  128.     {short    kind;
  129.     Handle    h;
  130.     Rect    r;
  131.     GetDItem(sm_win_ptr,1,&kind,&h,&r);
  132.     OutlineControl(h);
  133.     }
  134. }
  135.  
  136. pascal void redrawText(WindowPtr,short);
  137. static pascal void redrawText(theWindow,itemNo)
  138. WindowPtr theWindow;
  139. short itemNo;
  140. {
  141. HLock(my_text);
  142. TextBox ((*my_text)+1,(long)(**my_text),&my_text_rect,my_text_just);
  143. HUnlock(my_text);
  144. }
  145.  
  146. int semimodalDialog(dialog_ID,where,filter,titoli_italiani,n_titoli,p1,p2,p3,just,has_default)
  147. /* the only external entry point: create and handle a semimodal dialog: */
  148. int dialog_ID;
  149. Point *where;
  150. int (*filter)(EventRecord*);    /* an optional event filter to use during the dialog,
  151.         executed before the internal event filter. It must return on of these codes:
  152.         0: that event was not filtered, or was filtered but the standard actions 
  153.             still need be performed
  154.         1: filtered event, don't handle it
  155.         <0: filtered event, you must return immediately with this value as return code,
  156.             the caller knows what to do with that code
  157.         */
  158. char **titoli_italiani;
  159. int n_titoli;
  160. Str255 p1,p2,p3;    /* unfortunately, if I use static text items I have two problems:
  161.     1) suntar 1.0 and 1.1 used two different ways to center the messages,
  162.       with static text items that can't be done: that's bad, but it might
  163.       be tolerated
  164.     2) if a modal dialog appears (and there may be a modal dialog above a
  165.       semimodal...) the ParamText for the modal dialog overwrites the ParamText
  166.       for the semimodal, so that when it's redrawn later its messages are
  167.       changed: horrible !
  168.     Hence, I was obliged to avoid using ParamText
  169.     */
  170. int just;
  171. Boolean has_default;
  172. {
  173.     AlertTHndl    alertHandle;
  174.     int item;
  175.  
  176.     check_foreground();
  177.     SetCursor(&arrow);
  178.  
  179.     alertHandle = (AlertTHndl)Get1Resource('DLOG',dialog_ID);
  180.     if (alertHandle) {
  181.         short    kind;
  182.         Handle    h;
  183.         Rect    r;
  184.         HLock((Handle)alertHandle);
  185.         if(where==NULL||where->v<0)
  186.             PositionDialog( &((**alertHandle).boundsRect));
  187.         else{
  188.             register Rect *r=&((**alertHandle).boundsRect);
  189.             r->bottom= where->v+(r->bottom-r->top);
  190.             r->right= where->h+(r->right-r->left);
  191.             r->top=where->v;
  192.             r->left=where->h;
  193.             }
  194.         /* (**alertHandle).windowDefProc=(Handle)altDBoxProc; */
  195.         sm_win_ptr=GetNewDialog(dialog_ID,NULL,-1L);
  196.         sm_win_ptr->refCon=-1;        /* il -1 
  197.                             serve per non essere considerata 
  198.                             una "mia" finestra dal modulo windows 
  199.                             -- the windows module uses the refCon field to
  200.                             recognize its own windows, hence it can't be 0 */ 
  201.         HUnlock((Handle)alertHandle);
  202.         finestra_sm_aperta=true;
  203.         if(in_Italia && titoli_italiani){
  204.             int fatti=0;
  205.             for(item=1;fatti<n_titoli;item++){
  206.                 GetDItem(sm_win_ptr,item,&kind,&h,&r);
  207.                 if((kind&0x7F)==ctrlItem+btnCtrl){
  208.                     SetCTitle(h,*titoli_italiani++);
  209.                     fatti++;
  210.                     }
  211.                 }
  212.             }
  213.         my_has_default=has_default;
  214.         if(has_default){
  215.             GetDItem(sm_win_ptr,1,&kind,&h,&r);    /* item 1 must be the default button */
  216.             OutlineControl(h);
  217.             }
  218. /*if(p1==NULL) printf("p1=NULL "); else printf("p1=%p",p1);
  219. if(p2==NULL) printf("p2=NULL "); else printf("p2=%p",p2);
  220. if(p3==NULL) printf("p3=NULL "); else printf("p3=%p",p3);*/
  221.         if(p1!=NULL){
  222.             int i;
  223.             item=1;
  224.             do{    /* find the Rect of the useritem (p1,p2,p3): an userItem MUST exist */
  225.                 GetDItem(sm_win_ptr,++item,&kind,&h,&my_text_rect);
  226.                 }
  227.             while((kind&0x7F)!=userItem);
  228.             SetDItem (sm_win_ptr,item, kind, (Handle)redrawText, &my_text_rect);
  229.                 /* probably I could have used a static text item and SetIText,
  230.                 but then I would have got left justification */
  231.             i=p1[0]+1;
  232.             if(p2) i+=p2[0];
  233.             if(p3) i+=p3[0];
  234.             my_text=NewHandle(i);
  235.             my_text_just=just;
  236.             pStrcpy(*my_text,p1);
  237.             if(p2)pStrcat(*my_text,p2);
  238.             if(p3)pStrcat(*my_text,p3);
  239.             }
  240.         else
  241.             my_text=NULL;
  242.  
  243.         item=0;
  244.         install_handlers(sm_win_ptr,semimodal_updater,NULL);
  245.         do{
  246.             {
  247.             WindowPeek wp;
  248.             wp= gInBackground ? NULL : (WindowPeek) FrontWindow();
  249.             if(wp!=NULL &&  wp->windowKind>=userKind && wp !=sm_win_ptr)
  250.                 SelectWindow(sm_win_ptr);    /* non dovrebbe mai capitare,ma non fidarsi
  251.                                             puÿ salvare dai guai
  252.                         -- the internal event filter should prevent the console window 
  253.                         from going to front but there are a few utilities which add
  254.                         a "windows" menu to applications and can bring to front any
  255.                         window by cheating. If that happens, bring to front the semimodal
  256.                         dialog again
  257.                         */
  258.             }{
  259.             EventRecord        myEvent;
  260.             if(get_event(&myEvent)){
  261.                 if(filter){
  262.                     if ( (item=(*filter)(&myEvent))==0 )
  263.                         item=new_sm_evf(&myEvent);
  264.                     else if(item>0){
  265.                         GetDItem(sm_win_ptr,item,&kind,&h,&r);
  266.                         if(kind==ctrlItem+btnCtrl)
  267.                             SelectButton(h);
  268.                         }
  269.                     }
  270.                 else
  271.                     item=new_sm_evf(&myEvent);
  272.                 if(item==0){
  273.                     if(my_event_filter!=NULL) (*my_event_filter)(&myEvent);
  274.                     handle_event(&myEvent);
  275.                     if(is_pause_command()){
  276.                         HideWindow(sm_win_ptr);
  277.                         handle_pause();
  278.                         ShowWindow(sm_win_ptr);
  279.                         SelectWindow(sm_win_ptr);
  280.                         }
  281.                     }
  282.                 }
  283.             else{
  284.                 /* the user filter must be called for null events too... */
  285.                 if(filter){
  286.                     myEvent.what=nullEvent;
  287.                     item=(*filter)(&myEvent);
  288.                     }
  289.                 }
  290.             if(item==noItem) item=0;
  291.             }
  292.             accept_abort_command();
  293.             }
  294.         while(item==0);
  295.  
  296.         my_event_filter=NULL;
  297.  
  298.         if(where){
  299.             GrafPtr    savePort;
  300.             GetPort( &savePort );
  301.             SetPort( sm_win_ptr );
  302.             *where=*(Point*)&(sm_win_ptr->port.portRect);    /* top e left */
  303.             LocalToGlobal(where);        /* remember where the window was before closing it*/
  304.             SetPort(savePort);
  305.             }
  306.     
  307.         DisposDialog(sm_win_ptr);
  308.         remove_handlers(sm_win_ptr);
  309.         if(my_text)DisposHandle(my_text);
  310.         finestra_sm_aperta=false;
  311.         return item;
  312.         }
  313. }
  314.  
  315.  
  316. void close_semimodal()
  317. {    /* viene chiamata in caso di un longjmp che potrebbe abortire la routine precedente
  318. -- in suntar, all files or windows which may be open when the abort command is enabled
  319. or when an error may occur, must provide a "cleanup" routine to close everything (except 
  320. when their creator has a setjmp and performs directly the cleanup).
  321. Don't use for any other purpose
  322. */
  323. if(finestra_sm_aperta){
  324.     DisposDialog(sm_win_ptr);
  325.     remove_handlers(sm_win_ptr);
  326.     if(my_text)DisposHandle(my_text);
  327.     finestra_sm_aperta=false;
  328.     }
  329. }
  330.  
  331.  
  332.