home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Snippets / PNL Libraries / MyMovableModal.p < prev    next >
Encoding:
Text File  |  1997-06-16  |  7.7 KB  |  301 lines  |  [TEXT/CWIE]

  1.  unit MyMovableModal;
  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 Marco Piovanelli <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. { Call DisableMenuBar after the modal dialog is shown }
  18. {
  19.     GetNewDialog
  20.     set up dialog
  21.     ShowWindow(dialog);
  22.     DisableMenuBar
  23.     while not finished
  24.         MovableModalDialog
  25.     end-while
  26.     ReEnableMenuBar
  27.     DisposeDialog
  28. }
  29.  
  30. implementation
  31.  
  32.     uses
  33.         Balloons, ToolUtils, Scrap, GestaltEqu, Memory, Menus, Dialogs, LowMem, Events, Windows, Menus, TextEdit, Quickdraw, 
  34.         MyTypes, MyDialogs, MyCursors, MySystemGlobals, MyMenus, MyUtils, MyEvents, MyMemory, MyAssertions;
  35.  
  36.     const
  37.         kSystemMenuThreshold = -16000;        { menu IDs <= than this are used by the system }
  38.         kMovableModalEventMask = mDownMask + mUpMask + keyDownMask + keyUpMask + autoKeyMask + updateMask + activMask + osMask;
  39.  
  40. {$PUSH}
  41. {$ALIGN MAC68K}
  42.  
  43.     type
  44.         MenuEntry = record
  45.                 hMenu: MenuHandle;
  46.                 leftEdge: Integer;
  47.             end;
  48.  
  49.         MenuList = record
  50.                 offsetToLastMenu: Integer;
  51.                 rightmostEdge: Integer;
  52.                 unused: Integer;
  53.                 theMenus: array[0..1000] of MenuEntry;
  54.             end;
  55.         MenuListPtr = ^MenuList;
  56.         MenuListHandle = ^MenuListPtr;
  57.  
  58. {$ALIGN RESET}
  59. {$POP}
  60.  
  61.     type
  62.         MenuBarState = record
  63.                 mbsBarEnable: LongInt;
  64.                 mbsEditEnable: LongInt;
  65.             end;
  66.         MenuBarStatePtr = ^MenuBarState;
  67.  
  68.     function HasHelpManager: Boolean;
  69.         var
  70.             response: LongInt;
  71.     begin
  72.         HasHelpManager := (Gestalt(gestaltHelpMgrAttr, response) = noErr) & btst(response, gestaltHelpMgrPresent);
  73.     end;
  74.  
  75.     procedure SetEditMenu( theDialog: DialogPtr );
  76.         var
  77.             item, start, fin: integer;
  78.     begin
  79.         if theDialog <> nil then begin
  80.             GetDialogTextSelection( theDialog, item, start, fin );
  81.             if item > 0 then begin
  82.                 SetIDItemEnable( M_Edit, EMcut, start < fin );
  83.                 SetIDItemEnable( M_Edit, EMcopy, start < fin );
  84.                 SetIDItemEnable( M_Edit, EMpaste, true );
  85.                 SetIDItemEnable( M_Edit, EMclear, start < fin );
  86.             end;
  87.         end;
  88.     end;
  89.     
  90.     procedure DisableMenuBar (var saved_state: univ Ptr; hmnuID: Integer);
  91.         var
  92.             menuList: MenuListHandle;
  93.             i, nMenus: Integer;
  94.             theMenu: MenuHandle;
  95.             menuID: Integer;
  96.             theDialog: DialogPtr;
  97.             hasBalloons, needEditMenu: Boolean;
  98.             junk: OSErr;
  99.             state: MenuBarStatePtr;
  100.     begin
  101.         hasBalloons := HasHelpManager;
  102.  
  103.         theDialog := FrontWindow;
  104.         needEditMenu := (theDialog <> nil) & (SelectedTextItem(theDialog) > 0);
  105.         menuList := MenuListHandle(LMGetMenuList);
  106.         nMenus := menuList^^.offsetToLastMenu div SizeOf(MenuEntry);
  107.  
  108.         junk := MNewPtr( saved_state, SizeOf(MenuBarState) );
  109.         state := MenuBarStatePtr(saved_state);
  110.  
  111.         state^.mbsBarEnable := 0;
  112.         for i := 0 to nMenus - 1 do begin
  113.             theMenu := menuList^^.theMenus[i].hMenu;
  114.             menuID := theMenu^^.menuID;
  115.  
  116.             if (menuID > kSystemMenuThreshold) then begin { do nothing if this is a system menu }
  117.  
  118.                 if (menuID = M_Edit) then begin
  119.                     state^.mbsEditEnable := theMenu^^.enableFlags;
  120.                     if needEditMenu then begin
  121.                         theMenu^^.enableFlags := 1 + BSL(1, EMcut) + BSL(1, EMcopy) + BSL(1, EMpaste);
  122.                     end else begin
  123.                         DisableItem(theMenu, 0);
  124.                     end;
  125.                 end else begin { if this menu is enabled, disable it and set the corresponding bit  }
  126.                     if (btst(theMenu^^.enableFlags, 0)) then begin
  127.                         BSET(state^.mbsBarEnable, i);
  128.                         DisableItem(theMenu, 0);
  129.                     end;
  130.  
  131.                     if (hasBalloons) then begin { remap the help strings for this menu }
  132.                         junk := HMSetMenuResID(menuID, hmnuID);
  133.                     end;
  134.                 end;
  135.             end;
  136.         end;
  137.  
  138.         HiliteMenu(0);
  139.         DrawMenuBar;
  140.         CursorSetProcessing(false);
  141.         CursorSetArrow;
  142.     end;
  143.  
  144.     procedure ReEnableMenuBar (var saved_state: univ Ptr);
  145.         var
  146.             menuList: MenuListHandle;
  147.             i, nMenus: Integer;
  148.             theMenu: MenuHandle;
  149.             menuID: Integer;
  150.             hasBalloons: Boolean;
  151.             err: OSErr;
  152.             state: MenuBarStatePtr;
  153.     begin
  154.         Assert( (saved_state <> nil) );
  155.         state := MenuBarStatePtr(saved_state);
  156.  
  157.         hasBalloons := HasHelpManager;
  158.  
  159.         menuList := MenuListHandle(LMGetMenuList);
  160.         nMenus := menuList^^.offsetToLastMenu div SizeOf(MenuEntry);
  161.  
  162.         for i := 0 to nMenus - 1 do begin
  163.             theMenu := menuList^^.theMenus[i].hMenu;
  164.             menuID := theMenu^^.menuID;
  165.  
  166.             if (menuID > kSystemMenuThreshold) then begin
  167.                 if (menuID = M_Edit) then begin
  168.                     theMenu^^.enableFlags := state^.mbsEditEnable;
  169.                 end else if (btst(state^.mbsBarEnable, i)) then begin
  170.                     EnableItem(theMenu, 0);
  171.                 end;
  172.                 if (hasBalloons) then begin
  173.                     err := HMSetMenuResID(menuID, -1);
  174.                 end;
  175.             end;
  176.         end;
  177.  
  178.         MDisposePtr( saved_state );
  179.         DrawMenuBar;
  180.     end;
  181.  
  182.     function DoMenuChoice (theDialog: DialogPtr; var theEvent: EventRecord; var itemHit: Integer; menuChoice: LongInt): Boolean;
  183.         var
  184.             menuID, menuitem: Integer;
  185.             currentEditField, itemType: Integer;
  186.             junk: OSErr;
  187.     begin
  188. {$unused(theEvent)}
  189.         DoMenuChoice := false;
  190.  
  191.         menuID := HiWord(menuChoice);
  192.         menuitem := LoWord(menuChoice);
  193.  
  194.         if (menuID = M_Edit) then begin
  195.             currentEditField := SelectedTextItem(theDialog);
  196.             GetDItemKind(theDialog, currentEditField, itemType);
  197.  
  198.             if (BAND(itemType, itemDisable) = 0) then begin { if the current edit field is an enabled item, exit from MovableModalDialog loop }
  199.                 DoMenuChoice := true;
  200.                 itemHit := currentEditField;
  201.             end;
  202.  
  203.             case menuitem of
  204.                 EMcut:  begin
  205.                     DialogCut(theDialog);
  206.                     junk := ZeroScrap;
  207.                     junk := TEToScrap;
  208.                 end;
  209.                 EMcopy: begin
  210.                     DialogCopy(theDialog);
  211.                     junk := ZeroScrap;
  212.                     junk := TEToScrap;
  213.                 end;
  214.                 EMpaste: begin
  215.                     junk := TEFromScrap;
  216.                     DialogPaste(theDialog);
  217.                 end;
  218.                 EMclear: begin
  219.                     DialogDelete(theDialog);
  220.                 end;
  221.                 otherwise begin
  222.                     { do nothing }
  223.                 end;
  224.             end;
  225.         end;
  226.  
  227.         HiliteMenu(0);
  228.     end;
  229.  
  230.     function HandleMouseDown (theDialog: DialogPtr; var theEvent: EventRecord; var itemHit: Integer): Boolean;
  231.         var
  232.             partCode: Integer;
  233.             wind: WindowPtr;
  234.             beeper: ProcPtr;
  235.             dragRect: Rect;
  236.     begin
  237.         HandleMouseDown := false;
  238.  
  239.         partCode := FindWindow(theEvent.where, wind);
  240.  
  241.         if (partCode = inMenuBar) then begin
  242.             SetEditMenu( theDialog );
  243.             HandleMouseDown := DoMenuChoice(theDialog, theEvent, itemHit, MenuSelect(theEvent.where));
  244.         end else if (not PtInRgn(theEvent.where, WindowPeek(theDialog)^.strucRgn)) then begin
  245.             beeper := LMGetDABeeper;
  246.             if (beeper <> nil) then begin
  247.                 CallSoundProc(1, beeper);
  248.             end;
  249.         end else if (partCode = inDrag) & (theDialog = wind) then begin { now, we have to Handle the only thing DialogSelect doesn't do for us: dragging }
  250.             dragRect := GetGrayRgn^^.rgnBBox;
  251.             DragWindow(wind, theEvent.where, dragRect);
  252.             theEvent.what := nullEvent;
  253.         end;
  254.     end;
  255.  
  256.     procedure MovableModalDialog (filterProc: ProcPtr; var itemHit: Integer);
  257.         var
  258.             dlg, junk_dialog: DialogPtr;
  259.             er: EventRecord;
  260.             dummy: Boolean;
  261.     begin
  262.         itemHit := 0;
  263.         dlg := FrontWindow;
  264.         if (dlg <> nil) then begin
  265.             SetPort(dlg);
  266.             SetEditMenu( dlg );
  267.             repeat
  268.                 dummy := WaitNextEvent(kMovableModalEventMask, er, 0, nil);
  269.                 SetPort(dlg);
  270.                 SetEditMenu( dlg );
  271.  
  272.                 if (filterProc <> nil) & CallModalFilterProc(dlg, er, itemHit, filterProc) then begin
  273.                     Leave;
  274.                 end;
  275.  
  276.                 if er.what = kOSEvent then begin
  277.                     if EventIsSuspendResume( er ) then begin
  278.                         SetInForeground( EventHasResume( er ) );
  279.                     end;
  280.                 end;
  281.  
  282.                 if (er.what = mouseDown) & HandleMouseDown(dlg, er, itemHit) then begin
  283.                     Leave;
  284.                 end;
  285.  
  286.                 if EventIsKeyDown( er ) & EventHasCommandKey( er ) then begin
  287.                     SetEditMenu( dlg );
  288.                     if DoMenuChoice(dlg, er, itemHit, MenuKey( EventChar( er ) ) ) then begin
  289.                         Leave;
  290.                     end;
  291.                 end;
  292.  
  293.                 if IsDialogEvent(er) & DialogSelect(er, junk_dialog, itemHit) then begin
  294.                     Leave;
  295.                 end;
  296.             until false;
  297.         end;
  298.  
  299.     end;
  300.  
  301. end.