home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / mac / UserInterface / CContextMenuAttachment.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  9.4 KB  |  324 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "CContextMenuAttachment.h"
  20.  
  21. #include "CDrawingState.h"
  22. #include "CApplicationEventAttachment.h"
  23.  
  24. //-----------------------------------
  25. CContextMenuAttachment::CContextMenuAttachment(LStream* inStream)
  26. :    LAttachment(inStream)
  27. //-----------------------------------
  28. {
  29.     *inStream >> mMenuID >> mTextTraitsID;
  30.     mHostView = dynamic_cast<LView*>(LAttachable::GetDefaultAttachable());
  31.     mHostCommander = dynamic_cast<LCommander*>(LAttachable::GetDefaultAttachable());
  32.     Assert_(mHostView);
  33.     Assert_(mHostCommander);
  34. }
  35.  
  36. //-----------------------------------
  37. CContextMenuAttachment::~CContextMenuAttachment()
  38. //-----------------------------------
  39. {
  40. } // CContextMenuAttachment::CContextMenuAttachment
  41.  
  42. //-----------------------------------
  43. CContextMenuAttachment::EClickState CContextMenuAttachment::WaitMouseAction(
  44.     const Point&     inInitialPoint,
  45.     Int32            inWhen,
  46.     Int32            inDelay)
  47. //-----------------------------------
  48. {
  49.     //mHostView->FocusDraw();
  50.  
  51.     if (CApplicationEventAttachment::CurrentEventHasModifiers(controlKey))
  52.     {
  53.         return eMouseTimeout;
  54.     }
  55.  
  56.     while (::StillDown())
  57.     {
  58.         Point theCurrentPoint;
  59.         ::GetMouse(&theCurrentPoint);
  60.         if ((abs(theCurrentPoint.h - inInitialPoint.h) >= eMouseHysteresis) ||
  61.             (abs(theCurrentPoint.v - inInitialPoint.v) >= eMouseHysteresis))
  62.             return eMouseDragging;
  63.         Int32 now = ::TickCount();
  64.         if (abs( now - inWhen ) > inDelay)
  65.             return eMouseTimeout;
  66.     }
  67.     return eMouseUpEarly;
  68. } // CContextMenuAttachment::WaitMouseAction
  69.  
  70. //-----------------------------------
  71. UInt16 CContextMenuAttachment::PruneMenu(LMenu* inMenu)
  72. // Prune the menu.  Either enable each item, or remove it.  Returns the menu count.
  73. //-----------------------------------
  74. {
  75.  
  76. // Flag bits
  77. #define kKeepItemDisabled        1<<0 /* Don't remove this item, show it disabled */
  78. #define kSupercommanderCannotEnable    1<<1
  79. #define kWantsToBeDefault    1<<2
  80. // (NOTE: Bit 7 is not usable, because the icon ID must have this bit set!)
  81.     MenuHandle menuH = inMenu->GetMacMenuH();
  82.     Int16 index = 0; CommandT command;
  83.     Boolean previousItemWasSeparator = true; // true for first item
  84.     Boolean isSeparator = false;
  85.     Int16 itemCount = ::CountMItems(menuH);
  86.     UInt16 defaultItem = 0;
  87.     UInt16 firstEnabledItem = 0;
  88.     while (inMenu->FindNextCommand(index, command))
  89.     {
  90.         Boolean enabled = false;
  91.         Str255 commandText; // may be changed by host commander!
  92.         ::GetMenuItemText(menuH, index, commandText);
  93.         Int16 itemFlags; // icon ID used for flags
  94.         ::GetItemIcon(menuH, index, &itemFlags);
  95.         // Get rid of the icon ID (which we use for the flag hack)
  96.         if (itemFlags)
  97.             ::SetItemIcon(menuH, index, 0);
  98.         if (command > 0)
  99.         {
  100.             Boolean usesMark = false;
  101.             Char16 outMark;
  102.             Boolean statusKnown = false;
  103.             // If a command is not to be enabled by virtue of its super alone, check
  104.             // the super first.  If the super enables it, it's outta there.
  105.             if ((itemFlags & kSupercommanderCannotEnable) != 0)
  106.             {
  107.                 LCommander* super = mHostCommander->GetSuperCommander();
  108.                 if (super)
  109.                 {
  110.                     Boolean superEnabled = false;
  111.                     mHostCommander->ProcessCommandStatus(
  112.                         command, superEnabled, usesMark, outMark, commandText);
  113.                     if (superEnabled)
  114.                     {
  115.                         enabled = false;
  116.                         statusKnown = true;
  117.                     }
  118.                 }
  119.             }
  120.             // Normal case.  Ask the commander, let it use super if appropriate:
  121.             if (!statusKnown)
  122.                 mHostCommander->ProcessCommandStatus(
  123.                     command, enabled, usesMark, outMark, commandText);
  124.         }
  125.         if (enabled)
  126.         {
  127.             ::EnableItem(menuH, index);
  128.             ::SetMenuItemText(menuH, index, commandText);
  129.             // Allow a separator on the next line
  130.             previousItemWasSeparator = false;
  131.             // First item that says "I can be default" wins...
  132.             if (defaultItem == 0 && (itemFlags & kWantsToBeDefault))
  133.                 defaultItem = index;
  134.             if (firstEnabledItem == 0)
  135.                 firstEnabledItem = index;
  136.         }
  137.         else // disabled, including separators
  138.         {
  139.             isSeparator = commandText[1] == '-';
  140.             if (!isSeparator || previousItemWasSeparator)
  141.             {
  142.                 if (!isSeparator && (itemFlags & kKeepItemDisabled))
  143.                 {
  144.                     ::DisableItem(menuH, index);
  145.                     previousItemWasSeparator = false;
  146.                 }
  147.                 else
  148.                 {
  149.                     inMenu->RemoveItem(index);
  150.                     // decrement index so that we refind the next item
  151.                     index--;
  152.                     itemCount--;
  153.                     if (!itemCount) break;
  154.                     // Uh Oh, all items after the last separator were removed!
  155.                     if (index == itemCount && previousItemWasSeparator)
  156.                     {
  157.                         inMenu->RemoveItem(index);
  158.                         index--;
  159.                         itemCount--;
  160.                         break;
  161.                     }
  162.                 }
  163.             }
  164.             if (isSeparator)
  165.                 previousItemWasSeparator = true;
  166.         }
  167.     } // while
  168.     // The caller will only show the menu if we return a result > 0.  So handle the
  169.     // case when there are items, but all items are disabled.
  170.     if (defaultItem == 0 && itemCount > 0)
  171.         defaultItem = firstEnabledItem ? firstEnabledItem : 1;
  172.     return defaultItem;
  173. } // CContextMenuAttachment::PruneMenu
  174.  
  175. //-----------------------------------
  176. void CContextMenuAttachment::DoPopup(const SMouseDownEvent& inMouseDown, EClickState& outResult)
  177. //-----------------------------------
  178. {
  179.     Try_
  180.     {
  181.         LMenu* menu = BuildMenu();
  182.         MenuHandle menuH = menu->GetMacMenuH();
  183.         
  184.         CommandT command = 0;
  185.         // Call PruneMenu to strip out disabled commands.  Do nothing if no commands
  186.         // are available.
  187.         UInt16 defaultItem = PruneMenu(menu);
  188.         if (defaultItem > 0)
  189.         {
  190.             Int16 saveFont = ::LMGetSysFontFam();
  191.             Int16 saveSize = ::LMGetSysFontSize();
  192.             StMercutioMDEFTextState theMercutioMDEFTextState;
  193.             if (mTextTraitsID)
  194.             {                
  195.                 mHostView->FocusDraw();
  196.                 TextTraitsH traitsH = UTextTraits::LoadTextTraits(mTextTraitsID);
  197.                 if (traitsH)
  198.                 {
  199.                     mHostView->FocusDraw();
  200.                     ::LMSetSysFontFam((**traitsH).fontNumber);
  201.                     ::LMSetSysFontSize((**traitsH).size);
  202.                     ::LMSetLastSPExtra(-1L);
  203.                 }
  204.             }
  205.             // Handle the actual insertion into the hierarchical menubar
  206.             ::InsertMenu(menuH, hierMenu);
  207.             // Bring up the menu.
  208.             Point whereGlobal = inMouseDown.wherePort;
  209.             mHostView->PortToGlobalPoint(whereGlobal);
  210.             Int16 result = ::PopUpMenuSelect(
  211.                             menuH,
  212.                             whereGlobal.v - 5,
  213.                             whereGlobal.h - 5,
  214.                             defaultItem);
  215.             mExecuteHost = false;
  216.             outResult = eHandledByAttachment;
  217.             // Restore the system font
  218.             ::LMSetSysFontFam(saveFont);
  219.             ::LMSetSysFontSize(saveSize);
  220.             ::LMSetLastSPExtra(-1L);
  221.             if (result)
  222.                 command = menu->CommandFromIndex(result);
  223.         }
  224.         delete menu;
  225.         if (command)
  226.             mHostCommander->ObeyCommand(command, (void*)&inMouseDown);
  227.     }
  228.     Catch_(inError)
  229.     {
  230.     }
  231.     EndCatch_
  232. } // CContextMenuAttachment::DoPopup
  233.  
  234.  
  235. //
  236. // Execute
  237. //
  238. // Overridden to listen for multiple messages (context menu and context menu cursor)
  239. //
  240. Boolean
  241. CContextMenuAttachment :: Execute ( MessageT inMessage, void *ioParam )
  242. {
  243.     Boolean    executeHost = true;
  244.     
  245.     if ((inMessage == msg_ContextMenu) || (inMessage == msg_ContextMenuCursor)) {
  246.         ExecuteSelf(inMessage, ioParam);
  247.         executeHost = mExecuteHost;
  248.     }
  249.     
  250.     return executeHost;
  251. }
  252.  
  253.  
  254. //-----------------------------------
  255. void CContextMenuAttachment::ExecuteSelf(
  256.     MessageT    inMessage,
  257.     void*        ioParam)
  258. //-----------------------------------
  259. {
  260.     mExecuteHost = true;
  261.     if (!mHostView || !mHostCommander)
  262.         return;
  263.  
  264.     switch ( inMessage ) {
  265.         case msg_ContextMenu:
  266.             SExecuteParams& params = *(SExecuteParams*)ioParam;        
  267.             const SMouseDownEvent& mouseDown = *params.inMouseDown;
  268.             params.outResult = WaitMouseAction(
  269.                                         mouseDown.whereLocal,
  270.                                         mouseDown.macEvent.when,
  271.                                         2 * GetDblTime());
  272.             if (params.outResult == eMouseTimeout)
  273.                 DoPopup(mouseDown, params.outResult);
  274.             break;
  275.     
  276.         case msg_ContextMenuCursor:
  277.             Assert_(ioParam != NULL);
  278.             ChangeCursor ( (EventRecord*)ioParam );
  279.             break;
  280.             
  281.     } // case of which message
  282.     
  283. } // CContextMenuAttachment::ExecuteSelf
  284.  
  285. //
  286. // BuildMenu
  287. // THROWS int on error
  288. //
  289. // Reads in the menu with the id given in the PPob. This can be overridden to read the menu
  290. // from some other place, such as from the back-end.
  291. //
  292.  
  293. LMenu*
  294. CContextMenuAttachment :: BuildMenu ( )
  295. {
  296.     LMenu* menu = new LMenu(mMenuID);
  297.     MenuHandle menuH = menu->GetMacMenuH();
  298.     if (!menuH)
  299.         throw ResError();
  300.     ::DetachResource((Handle)menuH);
  301.     
  302.     return menu;
  303.  
  304. } // CContextMenuAttachment::BuildMenu
  305.  
  306.  
  307. //
  308. // ChangeCursor
  309. //
  310. // Makes the mouse the contextual menu cursor from OS8 if cmd key is down
  311. //
  312. void
  313. CContextMenuAttachment :: ChangeCursor ( const EventRecord* inEvent )
  314. {
  315.     if ( inEvent->modifiers & controlKey ) {
  316.         CursHandle contextCurs = ::GetCursor ( kContextualCursorID );
  317.         ::SetCursor ( *contextCurs );
  318.         mExecuteHost = false;
  319.     }
  320.     else
  321.         ::InitCursor();
  322.  
  323. } // ChangeCursor
  324.