home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1996 March / macformat-035.iso / Shareware City / Developers / ICAppSourceKit1.2 / ICMovableModal.p < prev    next >
Encoding:
Text File  |  1995-11-07  |  7.1 KB  |  263 lines  |  [TEXT/CWIE]

  1. unit ICMovableModal;
  2.  
  3. { This unit implements a MovableModalDialog routine similar to }
  4. { the Toolbox routine ModalDialog, to be used for movable modal dialogs }
  5.  
  6. { Based on code by Merzwaren <piovanel@dsi.unimi.it> }
  7.  
  8. interface
  9.  
  10.     uses
  11.         Types;
  12.  
  13.     procedure DisableMenuBar (var saved_state: univ Ptr; hmnuID: Integer);
  14.     procedure ReEnableMenuBar (var saved_state: univ Ptr);
  15.     procedure MovableModalDialog (filterProc: ProcPtr; var itemHit: Integer);
  16.  
  17. implementation
  18.  
  19.     uses
  20.         GestaltEqu, ICTypes, ICDialogs, ICGlobals, Dialogs, ToolUtils, Scrap, ICMiscSubs;
  21.  
  22.     const
  23.         kSystemMenuThreshold = -16000;        { menu IDs <= than this are used by the system }
  24.         kMovableModalEventMask = mDownMask + mUpMask + keyDownMask + keyUpMask + autoKeyMask + updateMask + activMask + osMask;
  25.  
  26.     type
  27.         MenuEntry = record
  28.                 hMenu: MenuHandle;
  29.                 leftEdge: Integer;
  30.             end;
  31.  
  32.         MenuList = record
  33.                 offsetToLastMenu: Integer;
  34.                 rightmostEdge: Integer;
  35.                 unused: Integer;
  36.                 theMenus: array[0..1000] of MenuEntry;
  37.             end;
  38.         MenuListPtr = ^MenuList;
  39.         MenuListHandle = ^MenuListPtr;
  40.  
  41.         MenuBarState = record
  42.                 mbsBarEnable: LongInt;
  43.                 mbsEditEnable: LongInt;
  44.             end;
  45.         MenuBarStatePtr = ^MenuBarState;
  46.  
  47.     function HasHelpManager: Boolean;
  48.         var
  49.             response: LongInt;
  50.     begin
  51.         HasHelpManager := (Gestalt(gestaltHelpMgrAttr, response) = noErr) & TPbtst(response, gestaltHelpMgrPresent);
  52.     end;
  53.  
  54.     function LMGetMenuList: Handle;
  55.     inline
  56.         $2EB8, $0A1C;            { MOVE.L $0A1C,(SP) }
  57.  
  58.     function HMSetMenuResID (menuID: integer; resID: integer): OSErr;
  59.     inline
  60.         $303C, $020D, $A830;
  61.  
  62.     procedure DisableMenuBar (var saved_state: univ Ptr; hmnuID: Integer);
  63.         var
  64.             menuList: MenuListHandle;
  65.             i, nMenus: Integer;
  66.             theMenu: MenuHandle;
  67.             menuID: Integer;
  68.             theDialog: DialogPtr;
  69.             hasBalloons, needEditMenu: Boolean;
  70.             junk: OSErr;
  71.             state: MenuBarStatePtr;
  72.     begin
  73.         hasBalloons := HasHelpManager;
  74.  
  75.         theDialog := FrontWindow;
  76.         needEditMenu := (theDialog <> nil) & (SelectedTextItem(theDialog) > 0);
  77.  
  78.         menuList := MenuListHandle(LMGetMenuList);
  79.         nMenus := menuList^^.offsetToLastMenu div SizeOf(MenuEntry);
  80.  
  81.         saved_state := NewPtr(SizeOf(MenuBarState));
  82.         state := MenuBarStatePtr(saved_state);
  83.  
  84.         state^.mbsBarEnable := 0;
  85.         for i := 0 to nMenus - 1 do begin
  86.             theMenu := menuList^^.theMenus[i].hMenu;
  87.             menuID := theMenu^^.menuID;
  88.  
  89.             if (menuID > kSystemMenuThreshold) then begin { do nothing if this is a system menu }
  90.  
  91.                 if (menuID = M_Edit) then begin
  92.                     state^.mbsEditEnable := theMenu^^.enableFlags;
  93.                     if needEditMenu then begin
  94.                         theMenu^^.enableFlags := 1 + BSL(1, EM_Cut) + BSL(1, EM_Copy) + BSL(1, EM_Paste);
  95.                     end else begin
  96.                         DisableItem(theMenu, 0);
  97.                     end;
  98.                 end
  99.                 else begin { if this menu is enabled, disable it and set the corresponding bit  }
  100.                     if (TPbtst(theMenu^^.enableFlags, 0)) then begin
  101.                         BSET(state^.mbsBarEnable, i);
  102.                         DisableItem(theMenu, 0);
  103.                     end;
  104.  
  105.                     if (hasBalloons) then begin { remap the help strings for this menu }
  106.                         junk := HMSetMenuResID(menuID, hmnuID);
  107.                     end;
  108.                 end;
  109.             end;
  110.         end;
  111.  
  112.         HiliteMenu(0);
  113.         DrawMenuBar;
  114.     end;
  115.  
  116.     procedure ReEnableMenuBar (var saved_state: univ Ptr);
  117.         var
  118.             menuList: MenuListHandle;
  119.             i, nMenus: Integer;
  120.             theMenu: MenuHandle;
  121.             menuID: Integer;
  122.             hasBalloons: Boolean;
  123.             err: OSErr;
  124.             state: MenuBarStatePtr;
  125.     begin
  126.         state := MenuBarStatePtr(saved_state);
  127.  
  128.         hasBalloons := HasHelpManager;
  129.  
  130.         menuList := MenuListHandle(LMGetMenuList);
  131.         nMenus := menuList^^.offsetToLastMenu div SizeOf(MenuEntry);
  132.  
  133.         for i := 0 to nMenus - 1 do begin
  134.             theMenu := menuList^^.theMenus[i].hMenu;
  135.             menuID := theMenu^^.menuID;
  136.  
  137.             if (menuID > kSystemMenuThreshold) then begin
  138.                 if (menuID = M_Edit) then begin
  139.                     theMenu^^.enableFlags := state^.mbsEditEnable;
  140.                 end else if (TPbtst(state^.mbsBarEnable, i)) then begin
  141.                     EnableItem(theMenu, 0);
  142.                 end;
  143.                 if (hasBalloons) then begin
  144.                     err := HMSetMenuResID(menuID, -1);
  145.                 end;
  146.             end;
  147.         end;
  148.  
  149.         DisposePtr(saved_state);
  150.         saved_state := nil;
  151.         DrawMenuBar;
  152.     end;
  153.  
  154.     function CallFilter (dialog: DialogPtr; var event: EventRecord; var item: Integer; filterProc: ProcPtr): Boolean;
  155.     inline
  156.         $205F, $4E90;
  157.  
  158.     procedure CallBeeper (soundNo: Integer; beeperProc: ProcPtr);
  159.     inline
  160.         $205F, $4E90;
  161.  
  162.     function LMGetDABeeper: ProcPtr;
  163.     inline
  164.         $2EB8, $0A9C;            { MOVE.L $0A9C,(SP) }
  165.  
  166.     function DoMenuChoice (theDialog: DialogPtr; var theEvent: EventRecord; var itemHit: Integer; menuChoice: LongInt): Boolean;
  167.         var
  168.             menuID, menuItem: Integer;
  169.             currentEditField, itemType: Integer;
  170.             junk: OSErr;
  171.     begin
  172.         theEvent := theEvent; { Unused }
  173.         DoMenuChoice := false;
  174.  
  175.         menuID := HiWord(menuChoice);
  176.         menuItem := LoWord(menuChoice);
  177.  
  178.         if (menuID = M_Edit) & not system7 then begin
  179.             currentEditField := SelectedTextItem(theDialog);
  180.             GetDItemKind(theDialog, currentEditField, itemType);
  181.  
  182.             if (BAND(itemType, itemDisable) = 0) then begin { if the current edit field is an enabled item, exit from MovableModalDialog loop }
  183.                 DoMenuChoice := true;
  184.                 itemHit := currentEditField;
  185.             end;
  186.  
  187.             if (menuItem = EM_Cut) then begin
  188.                 DialogCut(theDialog);
  189.                 junk := ZeroScrap;
  190.                 junk := TEToScrap;
  191.             end else if (menuItem = EM_Copy) then begin
  192.                 DialogCopy(theDialog);
  193.                 junk := ZeroScrap;
  194.                 junk := TEToScrap;
  195.             end else if (menuItem = EM_Paste) then begin
  196.                 junk := TEFromScrap;
  197.                 DialogPaste(theDialog);
  198.             end;
  199.         end;
  200.  
  201.         HiliteMenu(0);
  202.     end;
  203.  
  204.     function HandleMouseDown (theDialog: DialogPtr; var theEvent: EventRecord; var itemHit: Integer): Boolean;
  205.         var
  206.             partCode: Integer;
  207.             wind: WindowPtr;
  208.             beeper: ProcPtr;
  209.             dragRect: Rect;
  210.     begin
  211.         HandleMouseDown := false;
  212.  
  213.         partCode := FindWindow(theEvent.where, wind);
  214.  
  215.         if (partCode = inMenuBar) then begin
  216.             HandleMouseDown := DoMenuChoice(theDialog, theEvent, itemHit, MenuSelect(theEvent.where));
  217.         end else if (not PtInRgn(theEvent.where, WindowPeek(theDialog)^.strucRgn)) then begin
  218.             beeper := LMGetDABeeper;
  219.             if (beeper <> nil) then begin
  220.                 CallBeeper(1, beeper);
  221.             end;
  222.         end else if (partCode = inDrag) & (theDialog = wind) then begin { now, we have to handle the only thing DialogSelect doesn't do for us: dragging }
  223.             dragRect := GetGrayRgn^^.rgnBBox;
  224.             DragWindow(wind, theEvent.where, dragRect);
  225.             theEvent.what := nullEvent;
  226.         end;
  227.     end;
  228.  
  229.     procedure MovableModalDialog (filterProc: ProcPtr; var itemHit: Integer);
  230.         var
  231.             theDialog, junk_dialog: DialogPtr;
  232.             theEvent: EventRecord;
  233.             gotEvent: Boolean;
  234.     begin
  235.         itemHit := 0;
  236.         theDialog := FrontWindow;
  237.         if (theDialog <> nil) then begin
  238.             SetPort(theDialog);
  239.             repeat
  240.                 gotEvent := WaitNextEvent(kMovableModalEventMask, theEvent, 0, nil);
  241.                 SetPort(theDialog);
  242.  
  243.                 if (filterProc <> nil) & CallFilter(theDialog, theEvent, itemHit, filterProc) then begin
  244.                     Leave;
  245.                 end;
  246.  
  247.                 if (theEvent.what = mouseDown) & HandleMouseDown(theDialog, theEvent, itemHit) then begin
  248.                     Leave;
  249.                 end;
  250.  
  251.                 if (theEvent.what = keyDown) & (BAND(theEvent.modifiers, cmdKey) <> 0) & DoMenuChoice(theDialog, theEvent, itemHit, MenuKey(CHR(BAND(theEvent.message, charCodeMask)))) then begin
  252.                     Leave;
  253.                 end;
  254.  
  255.                 if IsDialogEvent(theEvent) & DialogSelect(theEvent, junk_dialog, itemHit) then begin
  256.                     Leave;
  257.                 end;
  258.             until false;
  259.         end;
  260.  
  261.     end;
  262.  
  263. end.