home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
-
-
- /*
- Features (not including the look/feel/behavior from inherited classes):
-
- (1) LMenu based. This allows flexible use of the class for both
- resource-based menus and menus built dynamically. Additionally,
- the benefits of attaching commands to menu items (using Mcmd and/or
- dynamically) is gained.
- (2) The "current item" can either be marked or not. If marking is specified,
- a mark character can be specified as well.
- (3) Popup or Popdown behavior.
- (4) A delay before popup value is supported. This gives rise to the "quick click"
- feature described below.
- (5) Quick clicks are supported (ala Greg's Browser and others). This allows a
- value or command to be specified such that if the button is released before
- the popup delay value, either the value will change to the specified value
- or the specified command will be sent. Note that if the quick click is
- command-based, the command does not have to coincide with a menu command
- for a menu item (it can be any arbitrary command). Quick click commands are
- supported even when there is no menu (as long as the quick click command
- is an enabled command).
- (6) Use of factory methods for menu management allows subclasses to add menu
- caching, etc.
- (7) Use of template methods (or hooks) for handling "quick clicks" and value
- changes allow subclasses to further customize the behavior. For example,
- a subclass may implement a "smart" button which will perform an action
- directly (instead of relying on broadcaster/listener delegation) by overriding
- HandleNewValue. For example, CGuideMenuPopup (which is a subclass of
- CPatternButtonPopup) can be inserted into a PPob window resource and
- It Will Just Work¬ without additional code to link broadcasters to listeners
- and additional ListenToMessage cases sprinkled about.
- (8) Fully configurable through Constructor PPobs and accessor methods.
-
-
-
- CAVEAT: Although we do correctly save and restore the system font, if Mercutio
- MDEF is being used in the app, then it must be used in all menus which
- change the system font in order to not mess up the system font. It is
- probably a wise idea to use Mercutio MDEF in *all* menus throughout the
- app to be safe.
- */
-
- #include "CPatternButtonPopup.h"
-
- #include <UMemoryMgr.h>
-
- #include "StSetBroadcasting.h"
- #include "CDrawingState.h"
- #include "CApplicationEventAttachment.h"
- #include "CTargetedUpdateMenuRegistry.h"
-
- // ---------------------------------------------------------------------------
- // Ñ CPatternButtonPopup
- // ---------------------------------------------------------------------------
- // Stream-based ctor
-
- CPatternButtonPopup::CPatternButtonPopup(
- LStream* inStream)
-
- : mMenu(nil),
-
- mPopupMenuID(0),
- mPopupTextTraitsID(0),
- mInitialCurrentItem(0),
- mTicksBeforeDisplayingPopup(9),
- mQuickClickValueOrCommand(0),
- mQuickClickIsCommandBased(false),
- mResourceBasedMenu(false),
- mPopdownBehavior(false),
- mMarkCurrentItem(false),
- mMarkCharacter(0),
- mDetachResource(false),
-
- mOwnsMenu(false),
- mPopUpMenuSelectWasCalled(true), // Start out true to ensure proper behavior
- // even if super::HandlePopupMenuSelect()
- // is called instead of our own
-
- super(inStream)
- {
- // Read in the data from the stream
-
- ThrowIfNil_(inStream);
-
- LStream& theStream = *inStream;
-
- theStream >> mPopupMenuID;
- theStream >> mPopupTextTraitsID;
- theStream >> mInitialCurrentItem;
- theStream >> mTicksBeforeDisplayingPopup;
- theStream >> mQuickClickValueOrCommand;
- theStream >> mQuickClickIsCommandBased;
- theStream >> mResourceBasedMenu;
- theStream >> mPopdownBehavior;
- theStream >> mMarkCurrentItem;
- theStream >> mMarkCharacter;
- theStream >> mDetachResource;
-
- // Ignore the ticks before displaying popup value specified in the resource.
- // That was a mistake.
-
- mTicksBeforeDisplayingPopup = GetDblTime();
- }
-
- // ---------------------------------------------------------------------------
- // Ñ ~CPatternButtonPopup
- // ---------------------------------------------------------------------------
- // dtor
-
- CPatternButtonPopup::~CPatternButtonPopup()
- {
- CPatternButtonPopup::EliminatePreviousMenu();
- }
-
- #pragma mark -
-
- // ---------------------------------------------------------------------------
- // Ñ FinishCreateSelf
- // ---------------------------------------------------------------------------
-
- void
- CPatternButtonPopup::FinishCreateSelf()
- {
- super::FinishCreateSelf();
-
- MakeNewMenu();
- }
-
-
- #pragma mark -
-
- // ---------------------------------------------------------------------------
- // Ñ GetMenu
- // ---------------------------------------------------------------------------
- // The menu factory methods (GetMenu, OwnsMenu, SetMenu, AdoptMenu,
- // MakeNewMenu, and EliminatePreviousMenu) *must* be overriden as a group.
- // The main reason for overriding this group of methods would be to
- // do some form of menu caching.
-
- LMenu*
- CPatternButtonPopup::GetMenu() const
- {
- return mMenu;
-
- }
-
- // ---------------------------------------------------------------------------
- // Ñ OwnsMenu
- // ---------------------------------------------------------------------------
- // The menu factory methods (GetMenu, OwnsMenu, SetMenu, AdoptMenu,
- // MakeNewMenu, and EliminatePreviousMenu) *must* be overriden as a group.
- // The main reason for overriding this group of methods would be to
- // do some form of menu caching.
-
- Boolean
- CPatternButtonPopup::OwnsMenu() const
- {
- return mOwnsMenu;
-
- }
-
- // ---------------------------------------------------------------------------
- // Ñ SetMenu
- // ---------------------------------------------------------------------------
- // The menu factory methods (GetMenu, OwnsMenu, SetMenu, AdoptMenu,
- // MakeNewMenu, and EliminatePreviousMenu) *must* be overriden as a group.
- // The main reason for overriding this group of methods would be to
- // do some form of menu caching.
-
- void
- CPatternButtonPopup::SetMenu(LMenu* inMenu)
- {
- EliminatePreviousMenu();
-
- mMenu = inMenu;
- mOwnsMenu = false;
- }
-
- // ---------------------------------------------------------------------------
- // Ñ AdoptMenu
- // ---------------------------------------------------------------------------
- // The menu factory methods (GetMenu, OwnsMenu, SetMenu, AdoptMenu,
- // MakeNewMenu, and EliminatePreviousMenu) *must* be overriden as a group.
- // The main reason for overriding this group of methods would be to
- // do some form of menu caching.
-
- void
- CPatternButtonPopup::AdoptMenu(
- LMenu* inMenuToAdopt)
- {
- EliminatePreviousMenu();
-
- mMenu = inMenuToAdopt;
- mOwnsMenu = true;
- }
-
- // ---------------------------------------------------------------------------
- // Ñ MakeNewMenu
- // ---------------------------------------------------------------------------
- // The menu factory methods (GetMenu, OwnsMenu, SetMenu, AdoptMenu,
- // MakeNewMenu, and EliminatePreviousMenu) *must* be overriden as a group.
- // The main reason for overriding this group of methods would be to
- // do some form of menu caching.
-
- void
- CPatternButtonPopup::MakeNewMenu()
- {
- // Create popup menu if appropriate
-
- if (mResourceBasedMenu)
- {
- if (mPopupMenuID)
- {
- // Resource-based menu (via ::GetMenu)
-
- AdoptMenu(new LMenu(mPopupMenuID));
- mValue = 0;
- SetPopupMinMaxValues();
-
- // Detach the resource as specified
-
- if (mDetachResource)
- {
- ::DetachResource((Handle) GetMenu()->GetMacMenuH());
- }
-
- // For resource-based menus, set the initial current item
-
- StSetBroadcasting setBroadcasting(this, false);
-
- try
- {
- SetValue(mInitialCurrentItem);
- }
- catch (const CValueRangeException&) { }
- catch (const CAttemptToSetDisabledValueException&) { }
- }
- }
- else
- {
- if (mPopupMenuID)
- {
- // Dynamic menu (via ::NewMenu)
-
- AdoptMenu(new LMenu(mPopupMenuID, "\p"));
- mValue = 0;
- SetPopupMinMaxValues();
- }
- }
- }
-
- // ---------------------------------------------------------------------------
- // Ñ EliminatePreviousMenu
- // ---------------------------------------------------------------------------
- // The menu factory methods (GetMenu, OwnsMenu, SetMenu, AdoptMenu,
- // MakeNewMenu, and EliminatePreviousMenu) *must* be overriden as a group.
- // The main reason for overriding this group of methods would be to
- // do some form of menu caching.
-
- void
- CPatternButtonPopup::EliminatePreviousMenu()
- {
- if (mMenu)
- {
- if (mOwnsMenu)
- {
- delete mMenu;
- }
-
- mMenu = nil;
- }
- }
-
- #pragma mark -
-
- // ---------------------------------------------------------------------------
- // Ñ TrackHotSpot
- // ---------------------------------------------------------------------------
-
- Boolean
- CPatternButtonPopup::TrackHotSpot(
- Int16 inHotSpot,
- Point inPoint,
- Int16 inModifiers)
- {
- Boolean pointInHotSpot;
- // The value we set mPopUpMenuSelectWasCalled
- // is not important. We just want to restore
- // the value when this function returns.
- StValueChanger<Boolean> theValueChanger(mPopUpMenuSelectWasCalled, true);
-
- // If no menu, then allow normal tracking and
- // perform a quick click if button is released
- // in the hot spot.
- if (!GetMenu() || !GetMenu()->GetMacMenuH())
- {
- pointInHotSpot = super::TrackHotSpot(inHotSpot, inPoint, inModifiers);
-
- if (pointInHotSpot)
- {
- if (mQuickClickIsCommandBased)
- {
- HandleQuickClick();
- }
- }
-
- return pointInHotSpot;
- }
-
- Point currPt = inPoint;
- UInt32 endTicks = sWhenLastMouseDown + mTicksBeforeDisplayingPopup;
-
- // For the initial mouse down, the
- // mouse is currently inside the HotSpot
- // when it was previously outside
- Boolean currInside = true;
- Boolean prevInside = false;
- HotSpotAction(inHotSpot, currInside, prevInside);
-
- // If the controlKey is down then we bypass quick click tracking in favor of
- // the popup menu. Additionally, we don't even bother tracking unless
- // mQuickClickValueOrCommand is non-zero
-
- if (!CApplicationEventAttachment::CurrentEventHasModifiers(controlKey) && mQuickClickValueOrCommand)
- {
- // Track the mouse while it is down
- Point currPt = inPoint;
- while (::StillDown() && ::TickCount() < endTicks)
- {
- ::GetMouse(&currPt); // Must keep track if mouse moves from
- prevInside = currInside; // In-to-Out or Out-To-In
- currInside = PointInHotSpot(currPt, inHotSpot);
-
- if (!currInside)
- {
- // Reset endTicks if mouse moves outside
- endTicks = ::TickCount() + mTicksBeforeDisplayingPopup;
- }
- else
- {
- // Quick Click tracking
- if (!::StillDown())
- {
- // Set button in "up" state
- HotSpotAction(inHotSpot, false, true);
-
- // Check if MouseUp occurred in HotSpot
- ::GetMouse(&currPt);
- pointInHotSpot = PointInHotSpot(currPt, inHotSpot);
-
- if (pointInHotSpot)
- {
- HandleQuickClick();
- }
-
- return pointInHotSpot;
- }
- }
-
- HotSpotAction(inHotSpot, currInside, prevInside);
- }
- }
-
- if (!::StillDown())
- {
- // Set button in "up" state
- HotSpotAction(inHotSpot, false, true);
-
- // Check if MouseUp occurred in HotSpot
- ::GetMouse(&currPt);
- pointInHotSpot = PointInHotSpot(currPt, inHotSpot);
-
- if (pointInHotSpot)
- {
- HandleQuickClick();
- }
-
- return pointInHotSpot;
- }
-
- // We tracked inside the button longer than
- // mTicksBeforeDisplayingPopup and the mouse is
- // still down, so we now skip normal tracking
- // to display the popup menu
- Int16 menuID = 0;
- Int16 menuItem = GetValue();
- Point popLocation;
-
- GetPopupMenuPosition(popLocation);
-
- // Handle user interaction with the menu
- HandlePopupMenuSelect(popLocation, mPopdownBehavior ? 1 : menuItem, menuID, menuItem);
-
- if (!mPopUpMenuSelectWasCalled && mQuickClickValueOrCommand)
- {
- // If the popup menu was not displayed,
- // then we will check once more if MouseUp
- // occurred in HotSpot so we can do
- // the quick click
- ::GetMouse(&currPt);
- pointInHotSpot = PointInHotSpot(currPt, inHotSpot);
-
- if (pointInHotSpot)
- {
- HandleQuickClick();
- }
- }
-
- Rect localFrame;
- Point mousePt;
-
- FocusDraw();
- CalcLocalFrameRect(localFrame);
- ::GetMouse(&mousePt);
-
- mMouseInFrame = ::PtInRect(mousePt, &localFrame);
-
- // Set the new item, if specified. NOTE: We set the
- // value here so that this control acts the same as
- // LStdControl and LGAPopup
- if (menuItem > 0)
- {
- try
- {
- SetValue(menuItem);
- }
- catch (const CValueRangeException&) { }
- catch (const CAttemptToSetDisabledValueException&) { }
- }
- else
- {
- // Set button in "up" state
- HotSpotAction(inHotSpot, false, true);
- }
-
- return (menuItem > 0);
- }
-
- // ---------------------------------------------------------------------------
- // Ñ HandlePopupMenuSelect
- // ---------------------------------------------------------------------------
- // Handle user interaction with the popup menu
-
- void
- CPatternButtonPopup::HandlePopupMenuSelect(
- Point inPopupLoc,
- Int16 inCurrentItem,
- Int16& outMenuID,
- Int16& outMenuItem)
- {
- ThrowIfNil_(GetMenu());
- ThrowIfNil_(GetMenu()->GetMacMenuH());
-
- mPopUpMenuSelectWasCalled = false;
-
- // Handle the actual insertion into the hierarchical menubar.
- //
- // From Apple Sample Code (PopupMenuWithCurFont.c):
- // "Believe it or not, it's important to insert
- // the menu before diddling the font characteristics."
- //
- // Note that this is also what LGAPopup.cp does. Unfortunately,
- // neither this nor the StMercutioMDEFTextState seems to help
- // with the font metrics problems we see with Mercurtio MDEF.
-
- ::InsertMenu(GetMenu()->GetMacMenuH(), hierMenu);
-
- Int16 saveFont = ::LMGetSysFontFam();
- Int16 saveSize = ::LMGetSysFontSize();
-
- StMercutioMDEFTextState theMercutioMDEFTextState;
-
- try
- {
- // Reconfigure the system font so that the menu will be drawn in our desired
- // font and size.
-
- if (mPopupTextTraitsID)
- {
- FocusDraw();
-
- TextTraitsH traitsH = UTextTraits::LoadTextTraits(mPopupTextTraitsID);
-
- if (traitsH)
- {
- // Bug #64133 kellys
- // If setting to application font, get the application font for current script
- if((**traitsH).fontNumber == 1)
- ::LMSetSysFontFam ( ::GetScriptVariable(::FontToScript(1), smScriptAppFond) );
- else
- ::LMSetSysFontFam ( (**traitsH).fontNumber );
- ::LMSetSysFontSize((**traitsH).size);
- ::LMSetLastSPExtra(-1L);
- }
- }
-
- // Adjust the contents of the menu
-
- AdjustMenuContents();
-
- // Setup the currently selected menu item
-
- SetupCurrentMenuItem(GetMenu()->GetMacMenuH(), GetValue());
-
- // Call PopupMenuSelect and wait for it to return
-
- Int32 result = 0;
-
- if (::StillDown())
- {
- mPopUpMenuSelectWasCalled = true;
-
- result = ::PopUpMenuSelect(
- GetMenu()->GetMacMenuH(),
- inPopupLoc.v,
- inPopupLoc.h,
- inCurrentItem);
- }
-
- // Extract the values from the returned result these are then passed
- // back out to the caller
-
- outMenuID = HiWord(result);
- outMenuItem = LoWord(result);
- }
- catch (...)
- {
- // Ignore errors
- }
-
- // Restore the system font
-
- ::LMSetSysFontFam(saveFont);
- ::LMSetSysFontSize(saveSize);
- ::LMSetLastSPExtra(-1L);
-
- // Finally get the menu removed
-
- ::DeleteMenu(mPopupMenuID);
- }
-
- // ---------------------------------------------------------------------------
- // Ñ HotSpotResult
- // ---------------------------------------------------------------------------
- // Note that actual hot spot result processing occurs in TrackHotSpot. This
- // is because the information necessary to perform the correct action is
- // only available while tracking.
-
- void
- CPatternButtonPopup::HotSpotResult(Int16 inHotSpot)
- {
- if (!IsBehaviourToggle())
- {
- // Make sure that non-toggle buttons return to the "up" state
-
- HotSpotAction(inHotSpot, false, true);
- }
- }
-
- #pragma mark -
-
- // ---------------------------------------------------------------------------
- // Ñ AdjustMenuContents
- // ---------------------------------------------------------------------------
- // Do stuff to the menu (add or remove menu items). The default implementation
- // is intentionally a noop. Override to add interesting behavior.
-
- void
- CPatternButtonPopup::AdjustMenuContents()
- {
- }
-
- // ---------------------------------------------------------------------------
- // Ñ SetupCurrentMenuItem
- // ---------------------------------------------------------------------------
- // Mark new item and unmark old item
-
- void
- CPatternButtonPopup::SetupCurrentMenuItem(MenuHandle inMenuH, Int16 inCurrentItem)
- {
- ThrowIfNil_(inMenuH);
-
- if (mMarkCurrentItem)
- {
- if (GetValue() != inCurrentItem)
- {
- Int16 oldItem = GetValue();
-
- if (oldItem > 0)
- {
- ::SetItemMark(inMenuH, oldItem, noMark);
- }
- }
-
- if (mMarkCharacter && (inCurrentItem > 0))
- {
- ::SetItemMark(inMenuH, inCurrentItem, mMarkCharacter);
- }
- else
- {
- ::SetItemMark(inMenuH, inCurrentItem, noMark);
- }
- }
- }
-
- // ---------------------------------------------------------------------------
- // Ñ GetPopupMenuPosition
- // ---------------------------------------------------------------------------
- // Get the position for displaying the popup menu in global coordinates
-
- void
- CPatternButtonPopup::GetPopupMenuPosition(Point &outPopupLoc)
- {
- Rect popupRect;
-
- CalcLocalFrameRect(popupRect);
-
- if (mPopdownBehavior)
- {
- outPopupLoc.v = popupRect.bottom + 1;
- outPopupLoc.h = popupRect.left + 2;
- }
- else
- {
- outPopupLoc.v = popupRect.top;
- outPopupLoc.h = popupRect.left;
- }
-
- LocalToPortPoint(outPopupLoc);
- PortToGlobalPoint(outPopupLoc);
- }
-
- #pragma mark -
-
- // ---------------------------------------------------------------------------
- // Ñ SetValue
- // ---------------------------------------------------------------------------
- // This is overridden to adjust the mark on the previous/new menu items and
- // to ensure that the value is always broadcast (even if it hasn't really
- // changed) and to call a "hook" for derived classes to perform some action
- // on value changes.
- //
- // Note that this implementation should be considered "final" (i.e. no further
- // overrides allowed) in order to preserve the semantics of this class.
- //
- // Exceptions thrown: CValueRangeException, CAttemptToSetDisabledValueException
-
- void
- CPatternButtonPopup::SetValue(Int32 inValue)
- {
- ThrowIfNil_(GetMenu());
- ThrowIfNil_(GetMenu()->GetMacMenuH());
-
- if (inValue < 0 || inValue > ::CountMItems(GetMenu()->GetMacMenuH()))
- {
- throw CValueRangeException();
- }
-
- if (!GetMenu()->ItemIsEnabled(inValue))
- {
- throw CAttemptToSetDisabledValueException();
- }
-
- // If mMarkCurrentItem is false, it is assumed that we want to
- // be able to select the same command several times in a row.
- // By hacking mValue to 0, we make sure that the menu command
- // will always be broadcast.
-
- if (!mMarkCurrentItem)
- {
- mValue = 0;
- }
-
- if (mValue != inValue)
- {
- // Setup the menu item
-
- SetupCurrentMenuItem(GetMenu()->GetMacMenuH(), inValue);
-
- // Set the new value. If the HandleNewValue hook indicates that
- // the value was handled, then we make sure that the call to
- // the base class SetValue does not broadcast the new value.
-
- if (HandleNewValue(inValue))
- {
- StSetBroadcasting setBroadcasting(this, false);
-
- super::SetValue(inValue);
- }
- else
- {
- super::SetValue(inValue);
- }
- }
- }
-
-
-
- // ---------------------------------------------------------------------------
- // Ñ SetPopupMinMaxValues
- // ---------------------------------------------------------------------------
- // Setup the minimum and maximum values for the control based on the
- // current menu state.
- //
- // NOTE: It is important for clients to call this method after inserting/removing
- // menu items dynamically.
-
- void
- CPatternButtonPopup::SetPopupMinMaxValues()
- {
- if (GetMenu() && GetMenu()->GetMacMenuH())
- {
- mMinValue = 0;
- mMaxValue = ::CountMItems(GetMenu()->GetMacMenuH());
- }
- else
- {
- mMaxValue = mMinValue = 0;
- }
- }
-
- #pragma mark -
-
- // ---------------------------------------------------------------------------
- // Ñ OKToSendCommand
- // ---------------------------------------------------------------------------
-
- Boolean
- CPatternButtonPopup::OKToSendCommand(
- Int32 inCommand)
- {
- LCommander* theTarget = LCommander::GetTarget();
- Boolean enabled = false;
- Boolean usesMark = false;
- Str255 outName;
- Char16 outMark;
-
- if (inCommand && theTarget)
- {
- theTarget->ProcessCommandStatus(inCommand, enabled, usesMark, outMark, outName);
- }
-
- return enabled;
- }
-
- // ---------------------------------------------------------------------------
- // Ñ BroadcastValueMessage
- // ---------------------------------------------------------------------------
- // Broadcast the menu command if there is one, otherwise broadcast the value
-
- void CPatternButtonPopup::BroadcastValueMessage()
- {
- ThrowIfNil_(GetMenu());
- ThrowIfNil_(GetMenu()->GetMacMenuH());
-
- if (mValueMessage != msg_Nothing)
- {
- CommandT theCommand = GetMenu()->CommandFromIndex(GetValue());
-
- if (theCommand != cmd_Nothing)
- {
- if (OKToSendCommand(theCommand))
- {
- BroadcastMessage(theCommand, nil);
- }
- }
- else
- {
- Int32 value = mValue;
-
- BroadcastMessage(mValueMessage, &value);
- }
- }
- }
-
- #pragma mark -
-
- // ---------------------------------------------------------------------------
- // Ñ HandleQuickClick
- // ---------------------------------------------------------------------------
- // Hook for handling quick clicks.
-
- void
- CPatternButtonPopup::HandleQuickClick()
- {
- if (mQuickClickValueOrCommand)
- {
- if (mQuickClickIsCommandBased)
- {
- if (OKToSendCommand(mQuickClickValueOrCommand))
- {
- BroadcastMessage(mQuickClickValueOrCommand, nil);
- }
- }
- else
- {
- try
- {
- SetValue(mQuickClickValueOrCommand);
- }
- catch (const CValueRangeException&) { }
- catch (const CAttemptToSetDisabledValueException&) { }
- }
- }
- }
-
- // ---------------------------------------------------------------------------
- // Ñ HandleNewValue
- // ---------------------------------------------------------------------------
- // Hook for handling value changes. Called by SetValue.
- //
- // Some CPatternButtonPopups may override this to perform an action rather
- // than using broadcaster/listener. Returns true if HandleNewValue handled the new
- // value (this will cause the new value to not be broadcast).
- //
- // Note that the setting of the new value is done by CPatternButtonPopup::SetValue.
- // Therefore, GetValue() will still return the old value here, so the old value is
- // still available in this method.
-
- Boolean
- CPatternButtonPopup::HandleNewValue(Int32 inNewValue)
- {
- #pragma unused(inNewValue)
-
- return false;
- }
-
- #pragma mark -
-
- // ---------------------------------------------------------------------------
- // Ñ HandleEnablingPolicy
- // ---------------------------------------------------------------------------
- // This is our required implementation of the MPaneEnablerPolicy interface.
- //
- // The enabling policy is as follows:
- //
- // - If all of the menu items associated with the menu items are disabled
- // then disable the button. Note that a menu item without a command
- // is automatically enabled and a menu item with a command is enabled
- // only if the command associated with it is enabled.
- // - If there is (no menu or no menu items in the menu) and
- // mQuickClickIsCommandBased is true and it is *not OK* to send the
- // mQuickClickValueOrCommand command then disable the button.
- // - Otherwise enable the buton.
-
- void
- CPatternButtonPopup::HandleEnablingPolicy()
- {
- LCommander* theTarget = LCommander::GetTarget();
- MenuHandle macMenuH = nil;
- MessageT buttonCommand = GetValueMessage();
- Boolean enabled = false;
- Boolean usesMark = false;
- Str255 outName;
- Char16 outMark;
-
- if (!CTargetedUpdateMenuRegistry::UseRegistryToUpdateMenus() ||
- CTargetedUpdateMenuRegistry::CommandInRegistry(buttonCommand))
- {
- if (!IsActive() || !IsVisible())
- return;
-
- if (!theTarget)
- return;
-
- if (GetMenu() && GetMenu()->GetMacMenuH() && ::CountMItems(GetMenu()->GetMacMenuH()))
- {
- macMenuH = GetMenu()->GetMacMenuH();
- }
-
- if (macMenuH)
- {
- // We have a menu
-
- CommandT theCommand;
- Boolean allDisabled = true;
- Int16 menuItem = 0;
-
- while (GetMenu()->FindNextCommand(menuItem, theCommand))
- {
- if (theCommand)
- {
- outName[0] = 0;
-
- // Call ProcessCommandStatus() to determine whether to enable the menu items.
- // If they are all disabled then disable the button itself.
-
- theTarget->ProcessCommandStatus(theCommand, enabled, usesMark, outMark, outName);
-
- if (outName[0] != 0)
- {
- ::SetMenuItemText(macMenuH, menuItem, outName);
- }
-
- if (enabled)
- {
- allDisabled = false;
- ::EnableItem(macMenuH, menuItem);
- }
- else
- {
- ::DisableItem(macMenuH, menuItem);
- }
-
- if (usesMark)
- {
- if ( outMark && mMarkCharacter )
- outMark = mMarkCharacter;
- ::SetItemMark(macMenuH, menuItem, outMark);
- }
- }
- else
- {
- allDisabled = false;
- ::EnableItem(macMenuH, menuItem);
- }
- }
-
- if (menuItem == 0)
- {
- // The menu does not have any commands, so we check the command attached to
- // the button itself.
-
- theTarget->ProcessCommandStatus(buttonCommand, enabled, usesMark, outMark, outName);
- allDisabled = (!enabled);
- }
-
- if (allDisabled)
- {
- Disable();
- }
- else
- {
- Enable();
- }
- }
- else
- {
- // We don't have a menu
-
- if (mQuickClickIsCommandBased && OKToSendCommand(mQuickClickValueOrCommand))
- {
- Enable();
- }
- else
- {
- Disable();
- }
- }
- }
- }
-