home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc Source Code / Utilities / DlogUtil.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-22  |  36.8 KB  |  1,422 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DlogUtil.cpp
  3.  
  4.     Contains:    implementation of dialog utility functions
  5.  
  6.     Owned by:    Tantek Çelik
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <4>      1/5/96    eeh        1298401: don't disable keyboard changes
  13.          <3>      1/4/96    eeh        fix header
  14.          <2>      1/4/96    eeh        1226961: make ActivateAllControls
  15.                                     non-static
  16.  
  17.     To Do:
  18. */
  19.  
  20. #ifndef _EXCEPT_
  21. #include <Except.h>
  22. #endif
  23.  
  24. #ifndef SOM_Module_OpenDoc_Errors_defined
  25. #include <ErrorDef.xh>
  26. #endif
  27.  
  28. #ifndef _DLOGUTIL_
  29. #include <DlogUtil.h>
  30. #endif
  31.  
  32. #ifndef _PLFMDEF_
  33. #include <PlfmDef.h>
  34. #endif
  35.  
  36. #ifndef _ODUTILS_
  37. #include <ODUtils.h>
  38. #endif
  39.  
  40. #ifndef SOM_ODMenuBar_xh
  41. #include <MenuBar.xh>
  42. #endif
  43.  
  44. #ifndef SOM_ODDispatcher_xh
  45. #include <Disptch.xh>
  46. #endif
  47.  
  48. #ifndef SOM_ODSession_xh
  49. #include <ODSessn.xh>
  50. #endif
  51.  
  52. #ifndef SOM_ODWindowState_xh
  53. #include <WinStat.xh>
  54. #endif
  55.  
  56. #ifndef SOM_ODClipboard_xh
  57. #include <Clipbd.xh>
  58. #endif
  59.  
  60. #ifndef _ODMEMORY_
  61. #include <ODMemory.h>
  62. #endif
  63.  
  64. #ifndef __GESTALTEQU__
  65. #include <GestaltEqu.h>
  66. #endif
  67.  
  68. #ifndef __TOOLUTILS__
  69. #include <ToolUtils.h>
  70. #endif
  71.  
  72. #ifndef _PASCLSTR_
  73. #include <PasclStr.h>
  74. #endif
  75.  
  76. #ifndef __DIALOGS__
  77. #include <Dialogs.h>
  78. #endif
  79.  
  80. #ifndef __TEXTEDIT__
  81. #include <TextEdit.h>
  82. #endif
  83.  
  84. #ifndef __PALETTES__
  85. #include <Palettes.h>
  86. #endif
  87.  
  88. #ifndef _MEMMGR_
  89. #include <MemMgr.h>
  90. #endif
  91.  
  92. #ifndef _ODDEBUG_
  93. #include <ODDebug.h>
  94. #endif
  95.  
  96. #ifndef _USERSRCM_
  97. #include <UseRsrcM.h>
  98. #endif
  99.  
  100. #ifndef SOM_ODNameSpaceManager_xh
  101. #include <NmSpcMg.xh>
  102. #endif
  103.  
  104. #ifndef SOM_Module_OpenDoc_Commands_defined
  105. #include <CmdDefs.xh>
  106. #endif
  107.  
  108. #ifndef SOM_ODStorageSystem_xh
  109. #include <ODStor.xh>
  110. #endif
  111.  
  112. #ifndef SOM_ODPlatformTypeList_xh
  113. #include <PfTypLs.xh>
  114. #endif
  115.  
  116. #ifndef _TEMPOBJ_
  117. #include "TempObj.h"
  118. #endif
  119.  
  120. // Types
  121. struct _MenuItemInfo
  122. {
  123.     MenuHandle    menu;
  124.     short        item;
  125.     Str255        text;
  126.     short        cmdChar;
  127.     short        iconID;
  128.     short        markChar;
  129.     Style        textStyle;
  130. };
  131. typedef struct _MenuItemInfo MenuItemInfo;
  132.  
  133. struct _DialogBoxInfo
  134. {
  135.     MenuItemInfo    redo;
  136.     // Can put other things in here later on
  137.     // like supporting movable modals, etc.
  138. };
  139. typedef struct _DialogBoxInfo DialogBoxInfo;
  140.  
  141. // Key codes
  142. // const char kEscapeKey        = 0x1B;
  143. // const char kUpArrowKey        = 0x1E;
  144. // const char kDownArrowKey    = 0x1F;
  145. const char kPageUpKey        = 0x0B;
  146. const char kPageDownKey        = 0x0C;
  147. const char kHomeKey            = 0x01;
  148. const char kEndKey            = 0x04;
  149.  
  150. // Control settings
  151. const short kControlInactive = 255;
  152. const short kControlActive = 0;
  153.  
  154. // Dialog item assumptions
  155. const short kOKButton = 1;
  156. const short kCancelButton = 2;
  157.  
  158. // Memory requirements
  159. const size_t kODMinFreeSpaceToShowDialog = 4 * 1024;
  160.     
  161. static Environment        *sEv;
  162. static ODSession        *sSession;
  163. static ModalFilterUPP    sFilter = kODNULL;
  164. static ModalFilterUPP    sButtonKeyFilter = kODNULL;
  165. static ModalFilterUPP    sArrowKeyFilter = kODNULL;
  166. static UserItemUPP        sOutlineDrawProc = kODNULL;
  167. static short            sCmdKeyStrResID = 0;    
  168. static DialogScriptData*
  169.                         sDlogScriptData = kODNULL;    
  170.     // Res ID of STR# that contains cmd-keys for buttons
  171.  
  172. static DialogBoxInfo* sDialogInfo = kODNULL;
  173.  
  174. // Private functions
  175. static void SaveAndDeleteMenuItem( MenuHandle menu, short item, MenuItemInfo *savedItem );
  176. static void RestoreMenuItem( MenuItemInfo *savedItem );
  177.  
  178.  
  179. //==============================================================================
  180. // Preflighting Dialogs and Alerts
  181. //==============================================================================
  182.  
  183. //------------------------------------------------------------------------------
  184. // Centering
  185. //------------------------------------------------------------------------------
  186.  
  187. static ODBoolean
  188. GetFrontWindowBounds( Rect &bounds )
  189. {
  190.     WindowPtr wp;
  191.     {
  192.         TempODWindow win = sSession->GetWindowState(sEv)->AcquireActiveWindow(sEv);
  193.         wp = win ? win->GetPlatformWindow(sEv) : FrontWindow();
  194.     }
  195.     
  196.     if( wp ) {
  197.         bounds = wp->portRect;
  198.         Rect *mapBounds;
  199.         if( wp->portBits.rowBytes & 0xC000 )            // Color port
  200.             mapBounds= &(**((CGrafPtr)wp)->portPixMap).bounds;
  201.         else
  202.             mapBounds= &wp->portBits.bounds;
  203.         OffsetRect(&bounds,-mapBounds->left,-mapBounds->top);
  204.         return kODTrue;
  205.     } else {
  206.         bounds = ODQDGlobals.screenBits.bounds;        // No win, use main screen
  207.         bounds.top += GetMBarHeight();
  208.         return kODFalse;
  209.     }
  210. }
  211.  
  212.  
  213. static void
  214. GetWindowsMainScreen( const Rect &windowBounds, Rect &screenBounds )
  215. {
  216.     long area=0;
  217.     
  218.     GDHandle gdh;
  219.     Rect devBounds,sectBounds;
  220.     long maxArea=0;
  221.     
  222.     for( gdh = GetDeviceList(); gdh; gdh = GetNextDevice(gdh) ) {
  223.         devBounds = (**gdh).gdRect;
  224.         if( gdh == GetMainDevice() )
  225.             devBounds.top += GetMBarHeight();
  226.         if( SectRect(&devBounds,&windowBounds,§Bounds) ) {
  227.             area = (sectBounds.right-sectBounds.left) * (long)(sectBounds.bottom-sectBounds.top);
  228.             if( area > maxArea ) {
  229.                 maxArea = area;                    // Best screen so far
  230.                 screenBounds = devBounds;
  231.                 if( gdh==GetMainDevice() )
  232.                     screenBounds.right -= 30;    // Leave room for Finder disk icons
  233.             }
  234.         }
  235.     }
  236.     if( area==0 ) {
  237.         screenBounds = ODQDGlobals.screenBits.bounds;        // Default: use main screen
  238.         screenBounds.top += GetMBarHeight();
  239.     }
  240. }
  241.  
  242.  
  243. static void
  244. CenterDialog( short ¢erFlag, Rect &bounds )
  245. {
  246.     /* Do centering manually. Why? Even though the Dialog Manager handles
  247.        automatic centering, it calls FrontWindow to find the parent window.
  248.        This will return an incorrect window (a floater) if there are floating
  249.        windows. We have to reproduce the centering effect but using the
  250.        actual frontmost non-floating window. */
  251.     const short noAutoCenter                    = 0x0000;
  252.     const short centerParentWindowScreen        = 0x680A;        // From Types.r
  253.     const short alertPositionParentWindowScreen = 0x700A;
  254.     const short centerParentWindow                = 0xA80A;
  255.     const short alertPositionParentWindow        = 0xB00A;
  256.     // We don't do anything for other flags.
  257.     
  258.     if( centerFlag == noAutoCenter )
  259.         return;
  260.     
  261.     Rect centerBounds;
  262.     if( GetFrontWindowBounds(centerBounds)
  263.             && (centerFlag==centerParentWindowScreen ||
  264.                 centerFlag==alertPositionParentWindowScreen) ) {
  265.         Rect screenBounds;
  266.         GetWindowsMainScreen(centerBounds,screenBounds);
  267.         centerBounds = screenBounds;
  268.     }
  269.     
  270.     Point pos;
  271.     pos.h = ((centerBounds.right-centerBounds.left)-(bounds.right-bounds.left)) >>1;
  272.     pos.v = ((centerBounds.bottom-centerBounds.top)-(bounds.bottom-bounds.top));
  273.     if( centerFlag==centerParentWindowScreen || centerFlag==centerParentWindow )
  274.         pos.v /= 2;
  275.     else if( centerFlag==alertPositionParentWindowScreen || centerFlag==alertPositionParentWindow )
  276.         pos.v /= 3;
  277.     else
  278.         return;                            // Ignore other flags
  279.         
  280.     pos.h += centerBounds.left;
  281.     pos.v += centerBounds.top;
  282.     OffsetRect(&bounds, pos.h-bounds.left, pos.v-bounds.top);
  283.     centerFlag = noAutoCenter;            // It's already centered now
  284. }
  285.  
  286.  
  287. //------------------------------------------------------------------------------
  288. // PreflightDialog
  289. //------------------------------------------------------------------------------
  290.  
  291. static Handle
  292. PreflightDialog( ODBoolean isDLOG, short id )
  293. {
  294.     Handle rsrc;
  295.     ODBoolean ok;
  296.     
  297.     if( isDLOG ) {
  298.         // Load DLOG and DITL:
  299.         rsrc = Get1Resource('DLOG', id);
  300.         DialogTemplate** dlogTemplate = (DialogTemplate**)rsrc;
  301.         ok = dlogTemplate && Get1Resource('DITL', (*dlogTemplate)->itemsID);
  302.         if( ok ) {
  303.             // Get the centering flag & adjust dialog centering:
  304.             HLock(rsrc);
  305.             size_t centerFlag = (size_t) &(**dlogTemplate).title;
  306.             centerFlag += *(unsigned char*)centerFlag +1;    // skip title
  307.             centerFlag += (centerFlag & 1);                    // word align
  308.             CenterDialog(*(short*)centerFlag, (**dlogTemplate).boundsRect);
  309.             HUnlock(rsrc);
  310.         }
  311.     } else {
  312.         // Load ALRT and DITL:
  313.         rsrc = Get1Resource('ALRT', id);
  314.         AlertTemplate** alrtTemplate = (AlertTemplate**)rsrc;
  315.         ok = alrtTemplate && Get1Resource('DITL', (*alrtTemplate)->itemsID);
  316.         if( ok ) {
  317.             // Get the centering flag & adjust alert centering:
  318.             HLock(rsrc);
  319.             short *centerFlag = (short*)( (size_t)*alrtTemplate + sizeof(AlertTemplate) );
  320.             CenterDialog(*centerFlag,(**alrtTemplate).boundsRect);
  321.             HUnlock(rsrc);
  322.         }
  323.     }
  324.     
  325.     if( !ok ) {
  326. #if ODDebug
  327.         OSErr err = ResError();
  328.         if( err != noErr && err != resNotFound )
  329.             WARN("Could not load dialog/alert %hd: error %hd",id,err);
  330. #endif
  331.         SysBeep(2);                            // At least give some indication
  332.         rsrc = kODNULL;
  333.     } else {
  334.         // Bail if space is really, really low. Don't even beep, this might cause
  335.         // a large 'snd' to be loaded.
  336.         if( !ODHaveFreeSpace(kODMinFreeSpaceToShowDialog,kODMinFreeSpaceToShowDialog,
  337.                              kODTrue) ) {
  338.             WARN("Whoa, not enough memory to show a dialog/alert!");
  339.             ReleaseResource(rsrc);
  340.             rsrc = kODNULL;
  341.         }
  342.     }
  343.     
  344.     return rsrc;
  345. }
  346.  
  347.  
  348. //==============================================================================
  349. // Displaying Dialogs and Alerts
  350. //==============================================================================
  351.  
  352. DialogPtr
  353. ODGetNewDialog( Environment *ev, short resID, ODSession *session, ODBoolean defaultButtons )
  354. {
  355.     ASSERT(session!=kODNULL, kODErrIllegalNullInput);
  356.  
  357.     sEv = ev ?ev :somGetGlobalEnvironment();
  358.     sSession = session;
  359.  
  360.     Handle dlogRsrc = PreflightDialog(kODTrue,resID);
  361.     if( ! dlogRsrc )
  362.         return kODNULL;
  363.  
  364.     DialogPtr dlog = ::GetNewDialog(resID,kODNULL,(WindowPtr)-1L);
  365.     if( dlog ) {
  366.         if( defaultButtons ) {
  367.             ::SetDialogDefaultItem(dlog,kStdOkItemIndex);
  368.             ::SetDialogCancelItem(dlog,kStdCancelItemIndex);
  369.         }
  370.         ::SetDialogTracksCursor(dlog,kODTrue);
  371.         
  372.         sCmdKeyStrResID = 0;    // Don't use command-key lookup unless told to
  373.         
  374.         InitCursor();            // Show arrow
  375.     }
  376.     
  377.     ReleaseResource(dlogRsrc);
  378.     
  379.     return dlog;
  380. }
  381.  
  382. ODSShort
  383. ShowAlert(Environment *ev, ODSShort alertID, ModalFilterUPP modalFilter, ODSession *session)
  384. {
  385.     ASSERT(session != kODNULL, kODErrIllegalNullInput);
  386.  
  387.     CUsingLibraryResources r;
  388.  
  389.     SetCursor(&(ODQDGlobals.arrow));
  390.  
  391.     sEv = ev ?ev :somGetGlobalEnvironment();
  392.     sSession = session;
  393.  
  394.     Handle alrtRsrc = PreflightDialog(kODFalse,alertID);
  395.     if( ! alrtRsrc )
  396.         return cancel;
  397.     
  398.     // Success at last!
  399.  
  400.     short alertReturn = Alert(alertID, modalFilter);
  401.     
  402.     ReleaseResource(alrtRsrc);
  403.  
  404.     return alertReturn;
  405. }
  406.  
  407. pascal Boolean
  408. ODDialogFilterProc( DialogPtr dp, EventRecord *event, short *item )
  409. {
  410.     ODBoolean dispatch = kODFalse;
  411.     
  412.     if( event->what==updateEvt || event->what==activateEvt ) {
  413.         if( (WindowPtr)event->message != dp )    // Dispatch updates/activates of other windows
  414.             dispatch = kODTrue;
  415.             
  416.     } else if( event->what==nullEvent || event->what==osEvt )    // Ditto null/suspend/resume
  417.         dispatch = kODTrue;
  418.     
  419.     else if( event->what==mouseDown ) {
  420.         WindowPtr wp;
  421.         if( ::FindWindow(event->where,&wp)==inDrag && wp==dp ) {    // Dragging me!
  422.             Rect bounds = ODQDGlobals.screenBits.bounds;
  423.             DragWindow(dp,event->where,&bounds);
  424.             event->what = nullEvent;
  425.         }
  426.         
  427.     } else if( event->what==keyDown ) {
  428.         // Cmd-A means select all if there is editable text:
  429.         short curTextItem = ((DialogPeek)dp)->editField + 1;
  430.         char key = event->message & charCodeMask;
  431.         if( curTextItem>0 && (key=='a' || key=='A') && (event->modifiers & cmdKey) )
  432.             SelectDialogItemText(dp, curTextItem, 0, 32767);
  433. #ifdef TO_BE_DELETED
  434.         else
  435.         {
  436.             long scriptNum = GetScriptManagerVariable( smKeyScript );
  437.             long curScript = FontToScript(dp->txFont);
  438.             if ( curScript != scriptNum )
  439.             {
  440. //                DebugStr( "\pChanging system font;g" );
  441.                 short myFont = GetScriptVariable( scriptNum, smScriptAppFond );
  442.                 WindowPtr savePort;
  443.                 GetPort(&savePort);
  444.                 SetPort(dp);
  445.                 TextFont( myFont );
  446.                 SetPort(savePort);
  447.             }
  448.         }
  449. #endif /* TO_BE_DELETED */
  450.     }
  451.     
  452.     if( dispatch ) {
  453.         TRY{
  454.             ODDispatcher* dispatcher = sSession->GetDispatcher(sEv);
  455.             if (dispatcher)
  456.                 dispatcher->Dispatch(sEv, (ODEventData*)event);
  457.         }CATCH_ALL{
  458.         }ENDTRY
  459.     }
  460.     
  461.     // Forward other events to the standard filter-proc:    
  462.     ModalFilterUPP proc;
  463.     OSErr err= GetStdFilterProc(&proc);
  464.     if( err==noErr )
  465.         return CallModalFilterProc(proc, dp,event,item);    // Call through to std filter-proc
  466.     else {
  467.         WARN("Couldn't get std filter proc!");
  468.         return false;
  469.     }
  470. }
  471.  
  472.  
  473. ModalFilterUPP
  474. GetODDialogFilter( )
  475. {
  476.     if( !sFilter )
  477.         sFilter = NewModalFilterProc(&ODDialogFilterProc);
  478.     return sFilter;
  479. }
  480.  
  481.  
  482. //==============================================================================
  483. // Filter Procs & Such
  484. //==============================================================================
  485.  
  486. static void
  487. ActivateControl(DialogPtr dialog, short item, Boolean isActivate)
  488. {
  489.     short            itemType;
  490.     Rect            itemRect;
  491.     ControlHandle    cntrlHandle;
  492.  
  493.     GetDialogItem(dialog, item, &itemType, (Handle*) &cntrlHandle, &itemRect);
  494.     ASSERT_CONTROL_ITEM(itemType);
  495.     
  496.     CUsingLibraryResources r;
  497.  
  498.     if ( isActivate )
  499.     {
  500.         HiliteControl(cntrlHandle, GetControlReference(cntrlHandle));
  501.     }
  502.     else
  503.     {
  504.         SetControlReference(cntrlHandle, (**cntrlHandle).contrlHilite);
  505.         HiliteControl(cntrlHandle, kControlInactive);
  506.     }
  507. }
  508.  
  509. void
  510. ActivateAllControls(DialogPtr dialog, Boolean isActivate)
  511. {
  512.     short            itemType;
  513.     Rect            itemRect;
  514.     ControlHandle    cntrlHandle;
  515.     short            item;
  516.  
  517.     for (item = 1; item <= CountDITL(dialog); ++item)
  518.     {
  519.         GetDialogItem(dialog, item, &itemType, (Handle*) &cntrlHandle, &itemRect);
  520.         itemType &= ~kItemDisableBit;
  521.         if ( itemType>=ctrlItem && itemType<=ctrlItem+resCtrl )
  522.             ActivateControl(dialog, item, isActivate);
  523.     }
  524. }
  525.  
  526.  
  527. pascal Boolean ODArrowKeyFilterProc( DialogPtr dlg, ODEventData* event,
  528.         short* itemHit )
  529. {
  530.     Boolean result;
  531.     if ( event->what == keyDown || event->what == autoKey )
  532.     {
  533.         result = kODTrue;
  534.         char key = event->message & charCodeMask;
  535.         ODBoolean cmdKeyDown = (event->modifiers & cmdKey) != 0;
  536.         ODBoolean optionKeyDown = (event->modifiers & optionKey) != 0;
  537.         switch ( key )
  538.         {
  539.             case kUpArrowKey:
  540.                 *itemHit = cmdKeyDown ? optionKeyDown ? kODHomeArrowItem :
  541.                         kODPageUpArrowItem : kODUpArrowItem;
  542.                 break;
  543.             case kDownArrowKey:
  544.                 *itemHit = cmdKeyDown ? optionKeyDown ? kODEndArrowItem :
  545.                         kODPageDownArrowItem : kODDownArrowItem;
  546.                 break;
  547.  
  548.             case kPageUpKey:
  549.                 *itemHit = kODPageUpArrowItem;
  550.                 break;
  551.             case kPageDownKey:
  552.                 *itemHit = kODPageDownArrowItem;
  553.                 break;
  554.             case kHomeKey:
  555.                 *itemHit = kODHomeArrowItem;
  556.                 break;
  557.             case kEndKey:
  558.                 *itemHit = kODEndArrowItem;
  559.                 break;
  560.  
  561.             default:
  562.                 result = kODFalse;
  563.         }
  564.     }
  565.     else
  566.         result = kODFalse;
  567.     return result || ODButtonKeyFilterProc( dlg, event, itemHit );
  568. }
  569.  
  570.  
  571. ModalFilterUPP
  572. GetODArrowKeyFilterProc( )
  573. {
  574.     if( !sArrowKeyFilter )
  575.         sArrowKeyFilter = NewModalFilterProc(&ODArrowKeyFilterProc);
  576.     return sArrowKeyFilter;
  577. }
  578.  
  579. // DMc: this debugging code disables use of enter to mean 'OK' when this var is set:
  580. // #if ODDebug
  581. // int gODButtonKeyNoEnterOkay = 0; // set to non-zero to disable enter for okay
  582. // #endif
  583.  
  584. pascal Boolean
  585. ODButtonKeyFilterProc(DialogPtr dialog, EventRecord *event, short *itemHit)
  586. {    
  587.     Rect            itemRect;
  588.     short            itemType;
  589.     Handle            itemHandle;
  590.     short            myItemHit = 0;
  591.  
  592.     const short        kEscKeyCode = 0x35;    // Virtual key code for the escape key
  593.  
  594.     if ( event->what == keyDown )
  595.     {
  596.         char key = event->message & charCodeMask;
  597.         switch ( key )
  598.         {
  599.             case kReturnKey:
  600.             case kEnterKey:
  601.                 GetDialogItem(dialog, kOKButton, &itemType, &itemHandle, &itemRect);
  602.                 ASSERT_CONTROL_ITEM(itemType);
  603.  
  604. // DMc: this debugging code disables use of enter to mean 'OK' when a var is set:
  605. // #if ODDebug
  606. //                 if ( !gODButtonKeyNoEnterOkay || key != kEnterKey )
  607. //                 {
  608. //                     if ( (**(ControlHandle)itemHandle).contrlHilite == kControlActive )
  609. //                         myItemHit = kOKButton;
  610. //                 }
  611. // #else
  612.                 if ( (**(ControlHandle)itemHandle).contrlHilite == kControlActive )
  613.                     myItemHit = kOKButton;
  614. // #endif /*ODDebug*/
  615.                     
  616.                 break;
  617.             
  618.             case kEscapeKey:
  619.                 // Ensure that the escape key, not the clear key, was pressed
  620.                 if ( (event->message & keyCodeMask) == (kEscKeyCode << 8) )
  621.                 {
  622.                     GetDialogItem(dialog, kCancelButton, &itemType, &itemHandle, &itemRect);
  623.                     if ( (itemType & ~kItemDisableBit) == (ctrlItem+btnCtrl) )
  624.                         myItemHit = kCancelButton;
  625.                 }
  626.                 break;
  627.  
  628.             case '.':        // cmd-period means cancel
  629.                 if ( event->modifiers & cmdKey )
  630.                 {
  631.                     GetDialogItem(dialog, kCancelButton, &itemType, &itemHandle, &itemRect);
  632.                     if ( (itemType & ~kItemDisableBit) == (ctrlItem+btnCtrl) )
  633.                         myItemHit = kCancelButton;
  634.                 }
  635.                 break;
  636.  
  637.             default:
  638.                 if ( (sCmdKeyStrResID != 0)  && (event->modifiers & cmdKey) )
  639.                 {
  640.                     // Attempt to match the key to a key found in the STR# resource
  641.                     Handle stringsHandle = GetResource( 'STR#', sCmdKeyStrResID );
  642.                     if ( stringsHandle )
  643.                     {
  644.                         short     i;
  645.                         short    numStrings = **(short**)stringsHandle;
  646.                         Str255    cmdKeyCode;
  647.                         for ( i = 1; i <= numStrings; ++i )
  648.                         {
  649.                           GetIndString( cmdKeyCode, sCmdKeyStrResID, i );
  650.                           if ( cmdKeyCode[0] && cmdKeyCode[1] == key )
  651.                           {
  652.                             GetDialogItem(dialog, i, &itemType, &itemHandle, &itemRect);
  653.                             ASSERT_CONTROL_ITEM(itemType);
  654.                             if ( (**(ControlHandle)itemHandle).contrlHilite == kControlActive )
  655.                             {
  656.                               myItemHit = i;    // Cool--record the item number that is hit
  657.                               break;
  658.                             }
  659.                           }
  660.                         }
  661.                     } 
  662.                 }
  663.                 break;
  664.         }
  665.  
  666.         if ( myItemHit != 0 )    // need to hilite a button
  667.         {
  668.             FlashButtonItem( dialog, myItemHit );
  669.             *itemHit = myItemHit;
  670.             return kODTrue;
  671.         }
  672.     
  673.     }
  674.     else if ( event->what == activateEvt )
  675.     {
  676.         Boolean isActivate = ((event->modifiers & activeFlag) != 0 );
  677.         ActivateAllControls(dialog, isActivate);
  678.     }
  679.  
  680.     // we only get here if we'd otherwise be returning false; all successes
  681.     // exit at "return kODTrue" above
  682.     return ODDialogFilterProc(dialog,event,itemHit);
  683. }
  684.  
  685.  
  686. ModalFilterUPP
  687. GetODButtonKeyFilterProc( )
  688. {
  689.     if( !sButtonKeyFilter )
  690.         sButtonKeyFilter = NewModalFilterProc(&ODButtonKeyFilterProc);
  691.     return sButtonKeyFilter;
  692. }
  693.  
  694.  
  695. void
  696. ODUseCommandKeyStringsResource( short resID )
  697. {
  698.     sCmdKeyStrResID = resID;
  699. }
  700.  
  701.  
  702. //==============================================================================
  703. // Updating the Menu Bar
  704. //==============================================================================
  705.  
  706. void ODDialogBegin( Environment* ev, ODSession* session, 
  707.             ODMenuBar* currentMenuBar, DialogPtr dialog )
  708. {
  709.     ODUnused(dialog);    // Later on, we can use this to support movable modals
  710.     
  711.     if ( sEv == kODNULL )
  712.         sEv = ev;
  713.  
  714.     if ( sSession == kODNULL )
  715.         sSession = session;
  716.  
  717.     ASSERT(currentMenuBar!=kODNULL,kODErrIllegalNullInput);
  718.     ASSERT(sSession!=kODNULL,kODErrIllegalNullInput);
  719.     
  720.     // Cleanup if needed
  721.     if ( sDialogInfo )
  722.         ODDisposePtr(sDialogInfo);
  723.  
  724.     // Allocate a new menu info record
  725.     sDialogInfo = (DialogBoxInfo*)ODNewPtrClear(sizeof(DialogBoxInfo),kDefaultHeapID);
  726.  
  727.     if ( sDialogInfo )
  728.     {
  729.         ODMenuID        editMenuID = 0;
  730.         ODPlatformMenu    editMenu = kODNULL;
  731.         short            redoItem;
  732.  
  733.         // Delete the Redo menu item so ModalDialog will handle the Edit menu right.
  734.         if ( currentMenuBar->IsCommandRegistered( sEv, kODCommandRedo ) )
  735.         {
  736.             currentMenuBar->GetMenuAndItem(sEv, kODCommandRedo, &editMenuID, &redoItem);
  737.             editMenu = currentMenuBar->GetMenu(sEv, editMenuID );
  738.         }
  739.         if ( editMenu )
  740.             SaveAndDeleteMenuItem(editMenu, redoItem, &sDialogInfo->redo);
  741.         else
  742.         {
  743.             ODDisposePtr(sDialogInfo);
  744.             sDialogInfo = kODNULL;
  745.         }
  746.     }
  747.     
  748.     // Lastly, export the OD clipboard in case the user pastes into the dialog
  749.     ODPlatformTypeList* types = session->GetStorageSystem(ev)->CreatePlatformTypeList(ev, kODNULL);
  750.     types->AddLast(sEv, 'TEXT');
  751.     types->AddLast(sEv, 'PICT');
  752.     sSession->GetClipboard(sEv)->SetPlatformClipboard(sEv, types);
  753.     ODDeleteObject(types);
  754. }
  755.  
  756.  
  757. void ODDialogEnd()
  758. {
  759.     // Restore the Redo menu item deleted by DialogBegin
  760.     if ( sDialogInfo )
  761.     {
  762.         RestoreMenuItem(&sDialogInfo->redo);
  763.         ODDisposePtr(sDialogInfo);
  764.         sDialogInfo = kODNULL;        // Don't allow to be called again
  765.     }
  766. }
  767.  
  768.  
  769. void SaveAndDeleteMenuItem( MenuHandle menu, short item, MenuItemInfo *savedItem )
  770. {
  771.     savedItem->menu = menu;
  772.     savedItem->item = item;
  773.     GetMenuItemText(menu, item, savedItem->text);
  774.     GetItemCmd(menu, item, &savedItem->cmdChar);
  775.     GetItemIcon(menu, item, &savedItem->iconID);
  776.     GetItemMark(menu, item, &savedItem->markChar);
  777.     GetItemStyle(menu, item, &savedItem->textStyle);
  778.     DeleteMenuItem(menu, item);
  779.     InvalMenuBar();
  780. }
  781.  
  782.  
  783. void RestoreMenuItem( MenuItemInfo *savedItem )
  784. {
  785.     InsertMenuItem(savedItem->menu, savedItem->text, savedItem->item -1);
  786.         // Still set item text in case of non-meta meta-characters.
  787.     SetMenuItemText(savedItem->menu, savedItem->item, savedItem->text);
  788.     SetItemCmd(savedItem->menu, savedItem->item, savedItem->cmdChar);
  789.     SetItemIcon(savedItem->menu, savedItem->item, savedItem->iconID);
  790.     SetItemMark(savedItem->menu, savedItem->item, savedItem->markChar);
  791.     SetItemStyle(savedItem->menu, savedItem->item, savedItem->textStyle);
  792.     InvalMenuBar();
  793. }
  794.  
  795.  
  796. pascal void
  797. ODOutlineDefaultButtonDrawProc(DialogPtr theDialog, short theItem)
  798. {
  799.     // NOTE: this proc only works on buttons whose DITL ID is 1.  theItem
  800.     // is unused, and so it doesn't matter whether the user item to which
  801.     // this proc is assigned (via SetDialogItem) has any geographical
  802.     // relation to the button.
  803.     
  804.     ODUnused(theItem);
  805.     Rect         itemRect;
  806.     Handle        itemHandle;
  807.     short        itemKind;
  808.  
  809.     WindowPtr    buttonWindow;
  810.     WindowPtr    savePort;
  811.     PenState    savePen;
  812.     short        buttonOval;
  813.     Boolean        isColorPort;
  814.  
  815.     const short kColorPort = 0xC000;
  816.  
  817.     GetDialogItem(theDialog, kOKButton, &itemKind, &itemHandle, &itemRect);
  818.     ASSERT_CONTROL_ITEM(itemKind);
  819.  
  820.     GetPort(&savePort);
  821.     buttonWindow = (**(ControlHandle)itemHandle).contrlOwner;
  822.     SetPort(buttonWindow);
  823.     GetPenState(&savePen);
  824.     PenNormal();
  825.  
  826.     InsetRect(&itemRect, -4, -4);
  827.     FrameRoundRect(&itemRect, 16, 16);
  828.     buttonOval = ((itemRect.bottom - itemRect.top)/2)+2;
  829.  
  830.     isColorPort = ((((CGrafPtr)buttonWindow)->portVersion & kColorPort) == kColorPort);
  831.     
  832.     if ( (**(ControlHandle)itemHandle).contrlHilite == kControlInactive )
  833.     {
  834.         // Button is inactive, so outline with gray
  835.  
  836.         RGBColor    fgSaveColor;
  837.         RGBColor    fgNewColor;
  838.         RGBColor    bgColor;
  839.         Boolean        newGray = false;
  840.  
  841.         if ( isColorPort )
  842.         {
  843.             GetBackColor(&bgColor);
  844.             GetForeColor(&fgSaveColor);
  845.             fgNewColor = fgSaveColor;
  846.             
  847.             Rect globalRect = itemRect;
  848.             LocalToGlobal((Point *)&(globalRect.top));
  849.             LocalToGlobal((Point *)&(globalRect.bottom));
  850.             GDHandle targetDevice = GetMaxDevice(&globalRect);
  851.             
  852.             newGray = GetGray(targetDevice, &bgColor, &fgNewColor);
  853.         }
  854.  
  855.         if ( newGray )
  856.             RGBForeColor(&fgNewColor);
  857.         else
  858. #ifdef THINK_CPLUS
  859.             PenPat(ODQDGlobals.gray);
  860. #else
  861.             PenPat(&ODQDGlobals.gray);
  862. #endif
  863.  
  864.         PenSize(3, 3);
  865.         FrameRoundRect(&itemRect, buttonOval, buttonOval);
  866.         
  867.         if ( isColorPort )
  868.             RGBForeColor(&fgSaveColor);
  869.     }
  870.     else
  871.     {
  872.         // Button is active, so outline with black
  873. #ifdef THINK_CPLUS
  874.         PenPat(ODQDGlobals.black);
  875. #else
  876.         PenPat(&ODQDGlobals.black);
  877. #endif
  878.         PenSize(3, 3);
  879.         FrameRoundRect(&itemRect, buttonOval, buttonOval);
  880.     }
  881.  
  882.     SetPenState(&savePen);
  883.     SetPort(savePort);
  884. }
  885.  
  886.  
  887. UserItemUPP
  888. GetODOutlineDefaultButtonDrawProc( )
  889. {
  890.     if( !sOutlineDrawProc )
  891.         sOutlineDrawProc = NewUserItemProc(&ODOutlineDefaultButtonDrawProc);
  892.     return sOutlineDrawProc;
  893. }
  894.  
  895.  
  896. void
  897. ODUseDialogScriptData( DialogScriptData* dsd, DialogPtr dialog )
  898. {
  899.     sDlogScriptData = dsd;
  900.     dsd->SetDialog( dialog );
  901. }
  902.  
  903. pascal ODBoolean CheckKeyScriptChangeFilterProc( DialogPtr dialog,
  904.         EventRecord *event, short *itemHit)
  905. {
  906.     TEHandle teh = ((DialogPeek)dialog)->textH;
  907.     DialogScriptData* dsd = sDlogScriptData;
  908.     WASSERT( dsd );
  909.  
  910.     if ( dsd->Script() == ksmUninited )
  911.         dsd->SetScriptAndLockKeyboard();
  912.  
  913.     if ( event->what == keyDown )
  914.     {
  915.         if ( !dsd->ScriptChanged() )
  916.         {
  917.             ODScriptCode newScript = GetScriptManagerVariable(smKeyScript);
  918.             ODScriptCode fontScript = FontToScript((*teh)->txFont);
  919.             WASSERT( fontScript == dsd->Script() );
  920.             if ( fontScript != newScript )
  921.             {
  922.                 short newFont = GetScriptVariable( newScript, smScriptAppFond );
  923.                 (*teh)->txFont = newFont;
  924. //                TextFont(newFont);
  925.  
  926.                 dsd->SetScriptAndLockKeyboard( FontToScript(newFont) );
  927.             }
  928.         }
  929.     }
  930.  
  931.     // if this is the first time in this edit item, redraw in case
  932.     // we've switched fonts/scripts.
  933.     short currentItem = ((DialogPeek)dialog)->editField;
  934.     if ( dsd->ScriptChanged() && !dsd->ItemRedrawn(currentItem) )
  935.     {
  936.         dsd->SetRedrawn(currentItem);
  937.         short itemKind;
  938.         Handle ignoreH;
  939.         Rect ignoreR;
  940.         GetDialogItem( dialog, currentItem+1, &itemKind, &ignoreH, &ignoreR );
  941.         if ( itemKind == editText )
  942.         {
  943.             TECalText( teh );
  944.             Rect viewRect = (*teh)->viewRect;
  945.             TEUpdate( &viewRect, teh );
  946.         }
  947.     }
  948.  
  949.     // pass to the next filter proc.  This one just changes state, never
  950.     // consuming the event.
  951.     return kODFalse;
  952. }
  953.  
  954. void EnableOkButton(DialogPtr dlog, ODBoolean enable)
  955. {
  956.     Environment*    ev = somGetGlobalEnvironment();
  957.     short            itemType;
  958.     Handle            itemHandle;
  959.     Rect            itemRect;
  960.     ODBoolean        okEnabled;
  961.  
  962.     const short kButtonFrameInset = -4;
  963.  
  964.     GetDialogItem(dlog, kOKButton, &itemType, &itemHandle, &itemRect);    
  965.     ASSERT_CONTROL_ITEM(itemType);
  966.     okEnabled = (**(ControlHandle)itemHandle).contrlHilite == kControlActive;
  967.  
  968.     // there's nothing to do if the button is as it should be already
  969.     if ( enable != okEnabled )
  970.     {
  971.         HiliteControl((ControlHandle)itemHandle, enable ? kControlActive : kControlInactive);
  972.  
  973.         // Invalidate the default button frame so it will be redrawn dim
  974.         WindowPtr savePort;
  975.         GetPort(&savePort);
  976.         SetPort(dlog);
  977.         InsetRect(&itemRect, kButtonFrameInset, kButtonFrameInset);
  978.         InvalRect(&itemRect);
  979.         SetPort(savePort);
  980.     }
  981. }
  982.  
  983. //    DrawGrayBox draws a gray box to be used as a separator.
  984. //    On a ColorQD machine, a true-gray line is attempted.
  985. //  On a B&W machine, a 50% pattern is used.
  986.  
  987. static pascal void DrawGrayBox(Rect *theBox)
  988. {
  989.     PenState    penState;
  990.     GetPenState(&penState);
  991.  
  992.     PixPatHandle ppat = kODNULL;
  993.     
  994.     /* check if Color QuickDraw is available */    
  995.     long response;
  996.     if( Gestalt(gestaltQuickdrawFeatures, &response)==noErr
  997.                 && BitTst(&response, 31-gestaltHasColor) ) {
  998.         const RGBColor gray = {0x7FFF,0x7FFF,0x7FFF};
  999.         ppat = NewPixPat();
  1000.         if( ppat )
  1001.             MakeRGBPat(ppat,&gray);
  1002.     }
  1003.  
  1004.     if( ppat )
  1005.         PenPixPat(ppat);
  1006.     else
  1007.         PenPat(&ODQDGlobals.gray);
  1008.         
  1009.     FrameRect(theBox);
  1010.     
  1011.     SetPenState(&penState);
  1012.  
  1013.     if( ppat )
  1014.         DisposePixPat(ppat);
  1015. }
  1016.  
  1017. pascal void DrawGrayBoxItem(DialogPtr theDialog, short theItem)
  1018. {
  1019.     Rect     boxRect;
  1020.     Handle    scratchHandle;
  1021.     short    scratchKind;
  1022.     
  1023.     GetDialogItem(theDialog, theItem, &scratchKind, &scratchHandle, &boxRect);
  1024.     DrawGrayBox(&boxRect);
  1025. }
  1026.  
  1027. pascal void DrawItemFrame(DialogPtr theDialog, short theItem)
  1028. {
  1029.     Rect     frameRect;
  1030.     Handle    scratchHandle;
  1031.     short    scratchKind;
  1032.     
  1033.     GetDialogItem(theDialog, theItem, &scratchKind, &scratchHandle, &frameRect);
  1034.     FrameRect(&frameRect);
  1035. }
  1036.  
  1037. ////////////////////////////////////////////////////////////////////////////////
  1038. // DrawITextInDlogBox
  1039. // Given a dialog, a rect and an ODIText*, truncate the text to fit in the
  1040. // rect and then draw it in the dialog.  Return result telling whether any
  1041. // change was made.
  1042. ////////////////////////////////////////////////////////////////////////////////
  1043.  
  1044. ODBoolean DrawITextInDlogBox( ODIText* itext, const Rect* textRect,
  1045.         DialogPtr dlog, ODBoolean tryToTruncate )
  1046. {
  1047.     WASSERT(dlog);
  1048.     WindowPtr savePort;
  1049.     GetPort(&savePort);
  1050.     SetPort(dlog);
  1051.  
  1052.     PenState savedPenState;
  1053.     GetPenState(&savedPenState);
  1054.     PenNormal();
  1055.  
  1056.     short saveFont = dlog->txFont;
  1057.     short savedTextMode = dlog->txMode;
  1058.     
  1059.     ODScriptCode scriptCode = GetITextScriptCode(itext);
  1060.     if ( scriptCode != FontToScript(saveFont) )
  1061.         TextFont(GetScriptVariable(scriptCode,smScriptAppFond));
  1062.     
  1063.     char buffer[256];
  1064.     ODSShort len = GetITextStringLength(itext);
  1065.     if ( len > 255 ) len = 255;
  1066.     ODBlockMove( GetITextPtr( itext ), buffer, len );
  1067.     short truncResult;
  1068.     if ( tryToTruncate )
  1069.         truncResult = TruncText( textRect->right - textRect->left - 1,
  1070.             buffer, &len, truncEnd);
  1071.     TETextBox( buffer, len,    textRect, teFlushDefault );
  1072.  
  1073.     TextFont(saveFont);
  1074.     TextMode(savedTextMode);
  1075.     SetPenState(&savedPenState);
  1076.     SetPort(savePort);
  1077.     return tryToTruncate? truncResult == 1 : kODFalse;    // 1 means truncation needed and successful
  1078. }
  1079.  
  1080. ////////////////////////////////////////////////////////////////////////////////
  1081. // FlashButtonItem
  1082. // Given a dialog and an item representing a button, flash that button,
  1083. // highlighting it for 8 ticks and then reverting.
  1084. ////////////////////////////////////////////////////////////////////////////////
  1085. void FlashButtonItem( DialogPtr dialog, short itemHit )
  1086. {
  1087.     Rect itemRect;
  1088.     short itemType;
  1089.     Handle itemHandle;
  1090.  
  1091.     GetDialogItem( dialog, itemHit, &itemType, &itemHandle, &itemRect);
  1092.     ASSERT_CONTROL_ITEM(itemType);
  1093.     HiliteControl((ControlHandle)itemHandle, kControlButtonPart);
  1094.     unsigned long ticks = TickCount() + 8;
  1095.     while ( TickCount() < ticks ) ;
  1096.     HiliteControl((ControlHandle)itemHandle, kControlActive);    // Turn off hilite
  1097. }
  1098.  
  1099. ////////////////////////////////////////////////////////////////////////////////
  1100. // ArrowKeyScrollList
  1101. // Given an "item" representing an up or down arrow or any of the other keys
  1102. // recognized by ODArrowKeyFilterProc above, a ListHandle indicating the list
  1103. // in which scrolling is taking place, pageSize giving the number of entries to
  1104. // be skipped by a "page down" command, and the zero-based index of the last
  1105. // entry in the list, do the right thing for the key selected.  So far this
  1106. // routine is used for lists embedded in dialogs, and it's up to the caller
  1107. // to determine which list is meant if there is more than one.
  1108. // NOTE that nothing happens currently if no list item is selected.  There needs
  1109. // to be a starting point for scrolling.
  1110. ////////////////////////////////////////////////////////////////////////////////
  1111.  
  1112. void ArrowKeyScrollList( ODSShort arrowItem, ListHandle listH,
  1113.         ODSShort pageSize, ODSShort lastEntry )
  1114. {
  1115.     ODSShort limitCell;
  1116.     ODSShort delta;
  1117.     switch( arrowItem )
  1118.     {
  1119.         case kODUpArrowItem:
  1120.             limitCell = 0;
  1121.             delta = -1;
  1122.             break;
  1123.  
  1124.         case kODDownArrowItem:
  1125.             limitCell = lastEntry;
  1126.             delta = 1;
  1127.             break;
  1128.  
  1129.         case kODPageUpArrowItem:
  1130.             limitCell = 0;
  1131.             delta = 0 - pageSize;
  1132.             break;
  1133.  
  1134.         case kODPageDownArrowItem:
  1135.             limitCell = lastEntry;
  1136.             delta = pageSize;
  1137.             break;
  1138.  
  1139.         case kODHomeArrowItem:
  1140.             limitCell = 0;
  1141.             delta = 0 - lastEntry;
  1142.             break;
  1143.  
  1144.         case kODEndArrowItem:
  1145.             limitCell = lastEntry;
  1146.             delta = lastEntry;
  1147.             break;
  1148.  
  1149.         default:
  1150.             WARN( "unknown arrow key/item" );
  1151.             return;
  1152.     }
  1153.  
  1154.     Cell selectedCell = {0,0};
  1155.     if ( !LGetSelect( true, &selectedCell, listH ) 
  1156.             || (selectedCell.v == limitCell) ) 
  1157.         return;
  1158.     LSetSelect( false, selectedCell, listH );
  1159.     selectedCell.v += delta;
  1160.     if ( selectedCell.v < 0 )
  1161.         selectedCell.v = 0;
  1162.     else if ( limitCell > 0 && selectedCell.v > limitCell )
  1163.         selectedCell.v = limitCell;
  1164.     LSetSelect( true, selectedCell, listH );
  1165.     LAutoScroll(listH);
  1166. }
  1167.  
  1168. //------------------------------------------------------------------------------
  1169. // ReplaceIntoString
  1170. //------------------------------------------------------------------------------
  1171. // Substitutes str0 for all occurances of "^0", and str1 for "^1", in the string
  1172. // retrieved from the 'STR ' resource identified by the first parameter.  Either
  1173. // str0 or str1 may be null.  Uses the current resource chain to find the 'STR '
  1174. // resource.
  1175.  
  1176. void ReplaceIntoString(ODSShort strResourceID,
  1177.                         ConstStr255Param str0,
  1178.                         ConstStr255Param str1,
  1179.                         Str255 destString)
  1180. {
  1181.     StringHandle msgHandle = GetString(strResourceID);
  1182.     if ( msgHandle )
  1183.     {
  1184.         DetachResource((Handle) msgHandle);
  1185.  
  1186.         ODHandle textHandle;
  1187.  
  1188.         HLock((Handle) msgHandle);
  1189.         ODHandle templateText = PStrToText(*msgHandle);
  1190.         HUnlock((Handle) msgHandle);
  1191.  
  1192.         if ( str0 )
  1193.         {
  1194.             textHandle = PStrToText(str0);
  1195.             if ( textHandle )
  1196.             {
  1197.                 ReplaceText((Handle) templateText, (Handle) textHandle, "\p^0");
  1198.                 ODDisposeHandle(textHandle);
  1199.             }
  1200.         }
  1201.         
  1202.         if ( str1 )
  1203.         {
  1204.             textHandle = PStrToText(str1);
  1205.             if ( textHandle )
  1206.             {
  1207.                 ReplaceText((Handle) templateText, (Handle) textHandle, "\p^1");
  1208.                 ODDisposeHandle(textHandle);
  1209.             }
  1210.         }
  1211.  
  1212.         TextToPStr(templateText, destString);
  1213.  
  1214.         ODDisposeHandle(templateText);
  1215.         DisposeHandle((Handle) msgHandle);
  1216.     }
  1217.     else
  1218.         if( ResError() != memFullErr )
  1219.         {
  1220.             WARN("ReplaceIntoString didn't find STR %hd",strResourceID);
  1221.             destString[0] = 0;
  1222.         }
  1223. }
  1224.  
  1225.  
  1226. //--------------------------------------------------------------------
  1227. // GetODITextInd
  1228. // Gets string # (index) from the 'STR#' resource given by resID 
  1229. // into an IText* whose script and language codes are those of 
  1230. // the current system script.
  1231. //--------------------------------------------------------------------
  1232.  
  1233. ODIText* GetODITextInd(short resID, short index)
  1234. {
  1235.     Str255 pStr = "\p";
  1236.     GetIndString(pStr, resID, index);
  1237.     ODScriptCode script = FontToScript( GetSysFont() );
  1238.     return CreateITextPString(script,
  1239.                             GetScriptVariable(script, smScriptLang), 
  1240.                             pStr);
  1241. }
  1242.  
  1243.  
  1244. //--------------------------------------------------------------------
  1245. // GetODIText
  1246. // Turns an 'STR ' resource of the given resID into an ODIText* whose
  1247. // language and script codes are those of the current system script.
  1248. //--------------------------------------------------------------------
  1249.  
  1250. ODIText* GetODIText(short resID)
  1251. {
  1252.     Handle textHandle;
  1253.     ODIText* iText = kODNULL;
  1254.     
  1255.     textHandle = (Handle)GetString(resID);
  1256.     
  1257.     if ( textHandle != kODNULL )
  1258.     {
  1259.         // CreateIText copies the values passed into it, so we don't
  1260.         // have to worry about the resource handle moving outside of
  1261.         // the scope of this function.
  1262.  
  1263.         ODScriptCode script = GetScriptManagerVariable(smSysScript);
  1264.         ODLangCode lang = GetScriptVariable(script, smScriptLang);
  1265.         HLock(textHandle);
  1266.         iText = CreateIText( script, lang, (StringPtr)*textHandle );
  1267.             
  1268.         ReleaseResource(textHandle);
  1269.     }
  1270.     
  1271.     return iText;
  1272. }
  1273.  
  1274. //------------------------------------------------------------------------------
  1275. // SetDialogTextStyle
  1276. //------------------------------------------------------------------------------
  1277.  
  1278. void SetDialogTextStyle(DialogPtr dlg, short finfResourceID,
  1279.         ODScriptCode script)
  1280. {
  1281.     typedef struct {
  1282.         short count;
  1283.         short fontNumber;
  1284.         short fontStyl;
  1285.         short fontSize;
  1286.     } FontSpec;
  1287.  
  1288.     typedef FontSpec** FontSpecHandle;
  1289.     
  1290.     FontSpecHandle finfHandle = (FontSpecHandle) GetResource('finf', finfResourceID);
  1291.  
  1292.     if ( finfHandle )
  1293.     {
  1294.         SetPort(dlg);
  1295.         
  1296.         short font;
  1297.         if ( script != smCurrentScript )
  1298.             font = GetScriptVariable( script, smScriptAppFond );    // <eeh> smScriptSysFond better?
  1299.         else
  1300.             font = (**finfHandle).fontNumber;
  1301.         
  1302.         TextFont(font);
  1303.         TextFace((**finfHandle).fontStyl);
  1304.         TextSize((**finfHandle).fontSize);
  1305.         TEHandle te = ((DialogPeek)dlg)->textH;
  1306.         (**te).txFont = font;
  1307.         (**te).txSize = (**finfHandle).fontSize;
  1308.         (**te).txFace = (**finfHandle).fontStyl;
  1309.         TECalText(te);
  1310.         ReleaseResource((Handle) finfHandle);
  1311.     } else
  1312.         if( ResError() != memFullErr )
  1313.             WARN("SetDialogTextStyle didn't find 'finf' %hd",finfResourceID);
  1314. }
  1315.  
  1316. //-------------------------------------------------------------------------------------
  1317. // SetPopupItemScript
  1318. //-------------------------------------------------------------------------------------
  1319. // "scriptID" should be a true script code, not an implicit script code
  1320. //
  1321. // This routine assumes the popup is drawn using the font of the current port.
  1322. //
  1323. // Setting the script of a popup menu item has two bad consequences:
  1324. // The title and item appear in bold face, and the width of the
  1325. // menu is increased.  This is true even if the script specified
  1326. // is the same as the default script!  So only specify a script if its different.
  1327.  
  1328. void SetPopupItemScript(MenuHandle menu, short itemNum, short scriptID)
  1329. {
  1330.     const ODSShort kUseSpecificScript = 0x1c;
  1331.  
  1332.     ODSLong    savedSMFontForceFlag = GetScriptManagerVariable(smFontForce);
  1333.     SetScriptManagerVariable(smFontForce, false);
  1334.  
  1335.     // Since the popup is drawn using the window font, compare the argument
  1336.     // script to the script of the current graphics port.
  1337.     GrafPtr curPort;
  1338.     GetPort(&curPort);
  1339.  
  1340.     if ( scriptID == smSystemScript )
  1341.         scriptID = (short) GetScriptManagerVariable(smSysScript);
  1342.  
  1343.     if ( scriptID != FontToScript(curPort->txFont) )
  1344.     {
  1345.         SetItemCmd(menu, itemNum, kUseSpecificScript);
  1346.         SetItemIcon(menu, itemNum, scriptID);
  1347.     }
  1348.     
  1349.     SetScriptManagerVariable(smFontForce, savedSMFontForceFlag);
  1350. }
  1351.  
  1352.  
  1353. //-------------------------------------------------------------------------------------
  1354. // Implementation of DialogScriptData class
  1355. //-------------------------------------------------------------------------------------
  1356.  
  1357. DialogScriptData::DialogScriptData()
  1358. {
  1359.     fItemRedrawn = 0L;
  1360.     fMustUnlock = kODFalse;
  1361.     fScript = ksmUninited;
  1362. }
  1363.  
  1364. DialogScriptData::~DialogScriptData()
  1365. {
  1366.     if ( fMustUnlock )
  1367.         this->ReleaseLockout();
  1368. }
  1369.  
  1370. void DialogScriptData::SetScriptAndLockKeyboard()
  1371. {
  1372. //    this->SetScriptAndLockKeyboard( FontToScript( GetAppFont() ) );
  1373.     WASSERT( FontToScript( GetSysFont()) == FontToScript( GetAppFont() ));
  1374.     this->SetScriptAndLockKeyboard( FontToScript( GetSysFont() ) );
  1375. }
  1376.  
  1377. // There are two cases we need to be aware of here when the script passed
  1378. // in comes from an existing IText* and isn't Roman.  First, it's possible
  1379. // that the keyscript is not yet set to that script (that it's still Roman).
  1380. // Second, the dialog may not be in a state to properly display that text.
  1381.  
  1382. void DialogScriptData::SetScriptAndLockKeyboard( ODScriptCode script )
  1383. {
  1384.     if ( script != smRoman )    // lock all changes out: switch to Roman will
  1385.     {                            // result in non-Roman text being garbage
  1386.         if ( GetScriptManagerVariable(smKeyScript) != script )
  1387.             KeyScript( script );    // script may not yet have been set
  1388.  
  1389.         WASSERT(fDialog);
  1390.         TEHandle teh = ((DialogPeek)fDialog)->textH;
  1391.         if ( FontToScript( (*teh)->txFont ) != script )
  1392.         {
  1393.             (*teh)->txFont = GetScriptVariable( script, smScriptSysFond );            
  1394.         }
  1395.  
  1396. //        KeyScript( smKeyDisableKybdSwitch );    // <eeh> 1/6
  1397.         fMustUnlock = kODTrue;
  1398.     }
  1399.     fScript = script;
  1400. }
  1401.  
  1402. void DialogScriptData::ReleaseLockout()
  1403. {
  1404.     if ( fMustUnlock != kODFalse )
  1405.     {
  1406. //        KeyScript( smKeyEnableKybds );    // <eeh> 1/6
  1407.         fMustUnlock = kODFalse;
  1408.     }
  1409. }
  1410.  
  1411. ODBoolean DialogScriptData::ItemRedrawn( short item )
  1412. {
  1413.     WASSERT( item < kMaxNumItems );
  1414.     return (fItemRedrawn & 1L<<(item-1)) != 0;
  1415. }
  1416.  
  1417. void DialogScriptData::SetRedrawn( short item )
  1418. {
  1419.     WASSERT( item < kMaxNumItems );
  1420.     fItemRedrawn |= 1L<<(item-1);
  1421. }
  1422.