layout/xul/nsMenuPopupFrame.h

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 //
     7 // nsMenuPopupFrame
     8 //
    10 #ifndef nsMenuPopupFrame_h__
    11 #define nsMenuPopupFrame_h__
    13 #include "mozilla/Attributes.h"
    14 #include "nsIAtom.h"
    15 #include "nsGkAtoms.h"
    16 #include "nsCOMPtr.h"
    17 #include "nsMenuFrame.h"
    19 #include "nsBoxFrame.h"
    20 #include "nsMenuParent.h"
    22 #include "nsITimer.h"
    24 class nsIWidget;
    26 // XUL popups can be in several different states. When opening a popup, the
    27 // state changes as follows:
    28 //   ePopupClosed - initial state
    29 //   ePopupShowing - during the period when the popupshowing event fires
    30 //   ePopupOpen - between the popupshowing event and being visible. Creation
    31 //                of the child frames, layout and reflow occurs in this state.
    32 //   ePopupOpenAndVisible - layout is done and the popup's view and widget are
    33 //                          made visible. The popupshown event fires.
    34 // When closing a popup:
    35 //   ePopupHidden - during the period when the popuphiding event fires and
    36 //                  the popup is removed.
    37 //   ePopupClosed - the popup's widget is made invisible.
    38 enum nsPopupState {
    39   // state when a popup is not open
    40   ePopupClosed,
    41   // state from when a popup is requested to be shown to after the
    42   // popupshowing event has been fired.
    43   ePopupShowing,
    44   // state while a popup is open but the widget is not yet visible
    45   ePopupOpen,
    46   // state while a popup is open and visible on screen
    47   ePopupOpenAndVisible,
    48   // state from when a popup is requested to be hidden to when it is closed.
    49   ePopupHiding,
    50   // state which indicates that the popup was hidden without firing the
    51   // popuphiding or popuphidden events. It is used when executing a menu
    52   // command because the menu needs to be hidden before the command event
    53   // fires, yet the popuphiding and popuphidden events are fired after. This
    54   // state can also occur when the popup is removed because the document is
    55   // unloaded.
    56   ePopupInvisible
    57 };
    59 // How a popup may be flipped. Flipping to the outside edge is like how
    60 // a submenu would work. The entire popup is flipped to the opposite side
    61 // of the anchor.
    62 enum FlipStyle {
    63   FlipStyle_None = 0,
    64   FlipStyle_Outside = 1,
    65   FlipStyle_Inside = 2
    66 };
    68 // Values for the flip attribute
    69 enum FlipType {
    70   FlipType_Default = 0,
    71   FlipType_None = 1,    // don't try to flip or translate to stay onscreen
    72   FlipType_Both = 2,    // flip in both directions
    73   FlipType_Slide = 3    // allow the arrow to "slide" instead of resizing
    74 };
    76 // values are selected so that the direction can be flipped just by
    77 // changing the sign
    78 #define POPUPALIGNMENT_NONE 0
    79 #define POPUPALIGNMENT_TOPLEFT 1
    80 #define POPUPALIGNMENT_TOPRIGHT -1
    81 #define POPUPALIGNMENT_BOTTOMLEFT 2
    82 #define POPUPALIGNMENT_BOTTOMRIGHT -2
    84 #define POPUPALIGNMENT_LEFTCENTER 16
    85 #define POPUPALIGNMENT_RIGHTCENTER -16
    86 #define POPUPALIGNMENT_TOPCENTER 17
    87 #define POPUPALIGNMENT_BOTTOMCENTER 18
    89 // The constants here are selected so that horizontally and vertically flipping
    90 // can be easily handled using the two flip macros below.
    91 #define POPUPPOSITION_UNKNOWN -1
    92 #define POPUPPOSITION_BEFORESTART 0
    93 #define POPUPPOSITION_BEFOREEND 1
    94 #define POPUPPOSITION_AFTERSTART 2
    95 #define POPUPPOSITION_AFTEREND 3
    96 #define POPUPPOSITION_STARTBEFORE 4
    97 #define POPUPPOSITION_ENDBEFORE 5
    98 #define POPUPPOSITION_STARTAFTER 6
    99 #define POPUPPOSITION_ENDAFTER 7
   100 #define POPUPPOSITION_OVERLAP 8
   101 #define POPUPPOSITION_AFTERPOINTER 9
   103 #define POPUPPOSITION_HFLIP(v) (v ^ 1)
   104 #define POPUPPOSITION_VFLIP(v) (v ^ 2)
   106 #define INC_TYP_INTERVAL  1000  // 1s. If the interval between two keypresses is shorter than this, 
   107                                 //   treat as a continue typing
   108 // XXX, kyle.yuan@sun.com, there are 4 definitions for the same purpose:
   109 //  nsMenuPopupFrame.h, nsListControlFrame.cpp, listbox.xml, tree.xml
   110 //  need to find a good place to put them together.
   111 //  if someone changes one, please also change the other.
   113 #define CONTEXT_MENU_OFFSET_PIXELS 2
   115 nsIFrame* NS_NewMenuPopupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   117 class nsViewManager;
   118 class nsView;
   119 class nsMenuPopupFrame;
   121 class nsMenuPopupFrame : public nsBoxFrame, public nsMenuParent
   122 {
   123 public:
   124   NS_DECL_QUERYFRAME_TARGET(nsMenuPopupFrame)
   125   NS_DECL_QUERYFRAME
   126   NS_DECL_FRAMEARENA_HELPERS
   128   nsMenuPopupFrame(nsIPresShell* aShell, nsStyleContext* aContext);
   130   // nsMenuParent interface
   131   virtual nsMenuFrame* GetCurrentMenuItem() MOZ_OVERRIDE;
   132   NS_IMETHOD SetCurrentMenuItem(nsMenuFrame* aMenuItem) MOZ_OVERRIDE;
   133   virtual void CurrentMenuIsBeingDestroyed() MOZ_OVERRIDE;
   134   NS_IMETHOD ChangeMenuItem(nsMenuFrame* aMenuItem, bool aSelectFirstItem) MOZ_OVERRIDE;
   136   // as popups are opened asynchronously, the popup pending state is used to
   137   // prevent multiple requests from attempting to open the same popup twice
   138   nsPopupState PopupState() { return mPopupState; }
   139   void SetPopupState(nsPopupState aPopupState) { mPopupState = aPopupState; }
   141   NS_IMETHOD SetActive(bool aActiveFlag) MOZ_OVERRIDE { return NS_OK; } // We don't care.
   142   virtual bool IsActive() MOZ_OVERRIDE { return false; }
   143   virtual bool IsMenuBar() MOZ_OVERRIDE { return false; }
   145   /*
   146    * When this popup is open, should clicks outside of it be consumed?
   147    * Return true if the popup should rollup on an outside click, 
   148    * but consume that click so it can't be used for anything else.
   149    * Return false to allow clicks outside the popup to activate content 
   150    * even when the popup is open.
   151    * ---------------------------------------------------------------------
   152    * 
   153    * Should clicks outside of a popup be eaten?
   154    *
   155    *       Menus     Autocomplete     Comboboxes
   156    * Mac     Eat           No              Eat
   157    * Win     No            No              Eat     
   158    * Unix    Eat           No              Eat
   159    *
   160    */
   161   bool ConsumeOutsideClicks();
   163   virtual bool IsContextMenu() MOZ_OVERRIDE { return mIsContextMenu; }
   165   virtual bool MenuClosed() MOZ_OVERRIDE { return true; }
   167   virtual void LockMenuUntilClosed(bool aLock) MOZ_OVERRIDE;
   168   virtual bool IsMenuLocked() MOZ_OVERRIDE { return mIsMenuLocked; }
   170   nsIWidget* GetWidget();
   172   // The dismissal listener gets created and attached to the window.
   173   void AttachedDismissalListener();
   175   // Overridden methods
   176   virtual void Init(nsIContent*      aContent,
   177                     nsIFrame*        aParent,
   178                     nsIFrame*        aPrevInFlow) MOZ_OVERRIDE;
   180   virtual nsresult AttributeChanged(int32_t aNameSpaceID,
   181                                     nsIAtom* aAttribute,
   182                                     int32_t aModType) MOZ_OVERRIDE;
   184   virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
   186   // returns true if the popup is a panel with the noautohide attribute set to
   187   // true. These panels do not roll up automatically.
   188   bool IsNoAutoHide() const;
   190   nsPopupLevel PopupLevel() const
   191   {
   192     return PopupLevel(IsNoAutoHide()); 
   193   }
   195   void EnsureWidget();
   197   nsresult CreateWidgetForView(nsView* aView);
   198   uint8_t GetShadowStyle();
   200   virtual nsresult SetInitialChildList(ChildListID  aListID,
   201                                        nsFrameList& aChildList) MOZ_OVERRIDE;
   203   virtual bool IsLeaf() const MOZ_OVERRIDE;
   205   // layout, position and display the popup as needed
   206   void LayoutPopup(nsBoxLayoutState& aState, nsIFrame* aParentMenu,
   207                    nsIFrame* aAnchor, bool aSizedToPopup);
   209   nsView* GetRootViewForPopup(nsIFrame* aStartFrame);
   211   // set the position of the popup either relative to the anchor aAnchorFrame
   212   // (or the frame for mAnchorContent if aAnchorFrame is null) or at a specific
   213   // point if a screen position (mScreenXPos and mScreenYPos) are set. The popup
   214   // will be adjusted so that it is on screen. If aIsMove is true, then the popup
   215   // is being moved, and should not be flipped.
   216   nsresult SetPopupPosition(nsIFrame* aAnchorFrame, bool aIsMove, bool aSizedToPopup);
   218   bool HasGeneratedChildren() { return mGeneratedChildren; }
   219   void SetGeneratedChildren() { mGeneratedChildren = true; }
   221   // called when the Enter key is pressed while the popup is open. This will
   222   // just pass the call down to the current menu, if any. If a current menu
   223   // should be opened as a result, this method should return the frame for
   224   // that menu, or null if no menu should be opened. Also, calling Enter will
   225   // reset the current incremental search string, calculated in
   226   // FindMenuWithShortcut.
   227   nsMenuFrame* Enter(mozilla::WidgetGUIEvent* aEvent);
   229   nsPopupType PopupType() const { return mPopupType; }
   230   bool IsMenu() MOZ_OVERRIDE { return mPopupType == ePopupTypeMenu; }
   231   bool IsOpen() MOZ_OVERRIDE { return mPopupState == ePopupOpen || mPopupState == ePopupOpenAndVisible; }
   233   bool IsMouseTransparent() { return mMouseTransparent; }
   235   static nsIContent* GetTriggerContent(nsMenuPopupFrame* aMenuPopupFrame);
   236   void ClearTriggerContent() { mTriggerContent = nullptr; }
   238   // returns true if the popup is in a content shell, or false for a popup in
   239   // a chrome shell
   240   bool IsInContentShell() { return mInContentShell; }
   242   // the Initialize methods are used to set the anchor position for
   243   // each way of opening a popup.
   244   void InitializePopup(nsIContent* aAnchorContent,
   245                        nsIContent* aTriggerContent,
   246                        const nsAString& aPosition,
   247                        int32_t aXPos, int32_t aYPos,
   248                        bool aAttributesOverride);
   250   /**
   251    * @param aIsContextMenu if true, then the popup is
   252    * positioned at a slight offset from aXPos/aYPos to ensure the
   253    * (presumed) mouse position is not over the menu.
   254    */
   255   void InitializePopupAtScreen(nsIContent* aTriggerContent,
   256                                int32_t aXPos, int32_t aYPos,
   257                                bool aIsContextMenu);
   259   void InitializePopupWithAnchorAlign(nsIContent* aAnchorContent,
   260                                       nsAString& aAnchor,
   261                                       nsAString& aAlign,
   262                                       int32_t aXPos, int32_t aYPos);
   264   // indicate that the popup should be opened
   265   void ShowPopup(bool aIsContextMenu, bool aSelectFirstItem);
   266   // indicate that the popup should be hidden. The new state should either be
   267   // ePopupClosed or ePopupInvisible.
   268   void HidePopup(bool aDeselectMenu, nsPopupState aNewState);
   270   // locate and return the menu frame that should be activated for the
   271   // supplied key event. If doAction is set to true by this method,
   272   // then the menu's action should be carried out, as if the user had pressed
   273   // the Enter key. If doAction is false, the menu should just be highlighted.
   274   // This method also handles incremental searching in menus so the user can
   275   // type the first few letters of an item/s name to select it.
   276   nsMenuFrame* FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent, bool& doAction);
   278   void ClearIncrementalString() { mIncrementalString.Truncate(); }
   280   virtual nsIAtom* GetType() const MOZ_OVERRIDE { return nsGkAtoms::menuPopupFrame; }
   282 #ifdef DEBUG_FRAME_DUMP
   283   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE
   284   {
   285       return MakeFrameName(NS_LITERAL_STRING("MenuPopup"), aResult);
   286   }
   287 #endif
   289   void EnsureMenuItemIsVisible(nsMenuFrame* aMenuFrame);
   291   // Move the popup to the screen coordinate (aLeft, aTop) in CSS pixels.
   292   // If aUpdateAttrs is true, and the popup already has left or top attributes,
   293   // then those attributes are updated to the new location.
   294   // The frame may be destroyed by this method.
   295   void MoveTo(int32_t aLeft, int32_t aTop, bool aUpdateAttrs);
   297   void MoveToAnchor(nsIContent* aAnchorContent,
   298                     const nsAString& aPosition,
   299                     int32_t aXPos, int32_t aYPos,
   300                     bool aAttributesOverride);
   302   bool GetAutoPosition();
   303   void SetAutoPosition(bool aShouldAutoPosition);
   304   void SetConsumeRollupEvent(uint32_t aConsumeMode);
   306   nsIScrollableFrame* GetScrollFrame(nsIFrame* aStart);
   308   // For a popup that should appear anchored at the given rect, determine
   309   // the screen area that it is constrained by. This will be the available
   310   // area of the screen the popup should be displayed on. Content popups,
   311   // however, will also be constrained by the content area, given by
   312   // aRootScreenRect. All coordinates are in app units.
   313   // For non-toplevel popups (which will always be panels), we will also
   314   // constrain them to the available screen rect, ie they will not fall
   315   // underneath the taskbar, dock or other fixed OS elements.
   316   nsRect GetConstraintRect(const nsRect& aAnchorRect, const nsRect& aRootScreenRect,
   317                            nsPopupLevel aPopupLevel);
   319   // Determines whether the given edges of the popup may be moved, where
   320   // aHorizontalSide and aVerticalSide are one of the NS_SIDE_* constants, or
   321   // 0 for no movement in that direction. aChange is the distance to move on
   322   // those sides. If will be reset to 0 if the side cannot be adjusted at all
   323   // in that direction. For example, a popup cannot be moved if it is anchored
   324   // on a particular side.
   325   //
   326   // Later, when bug 357725 is implemented, we can make this adjust aChange by
   327   // the amount that the side can be resized, so that minimums and maximums
   328   // can be taken into account.
   329   void CanAdjustEdges(int8_t aHorizontalSide, int8_t aVerticalSide, nsIntPoint& aChange);
   331   // Return true if the popup is positioned relative to an anchor.
   332   bool IsAnchored() const { return mScreenXPos == -1 && mScreenYPos == -1; }
   334   // Return the anchor if there is one.
   335   nsIContent* GetAnchor() const { return mAnchorContent; }
   337   // Return the screen coordinates of the popup, or (-1, -1) if anchored.
   338   // This position is in CSS pixels.
   339   nsIntPoint ScreenPosition() const { return nsIntPoint(mScreenXPos, mScreenYPos); }
   341   nsIntPoint GetLastClientOffset() const { return mLastClientOffset; }
   343   // Return the alignment of the popup
   344   int8_t GetAlignmentPosition() const;
   346   // Return the offset applied to the alignment of the popup
   347   nscoord GetAlignmentOffset() const { return mAlignmentOffset; }
   348 protected:
   350   // returns the popup's level.
   351   nsPopupLevel PopupLevel(bool aIsNoAutoHide) const;
   353   // redefine to tell the box system not to move the views.
   354   virtual void GetLayoutFlags(uint32_t& aFlags) MOZ_OVERRIDE;
   356   void InitPositionFromAnchorAlign(const nsAString& aAnchor,
   357                                    const nsAString& aAlign);
   359   // return the position where the popup should be, when it should be
   360   // anchored at anchorRect. aHFlip and aVFlip will be set if the popup may be
   361   // flipped in that direction if there is not enough space available.
   362   nsPoint AdjustPositionForAnchorAlign(nsRect& anchorRect,
   363                                        FlipStyle& aHFlip, FlipStyle& aVFlip);
   365   // check if the popup will fit into the available space and resize it. This
   366   // method handles only one axis at a time so is called twice, once for
   367   // horizontal and once for vertical. All arguments are specified for this
   368   // one axis. All coordinates are in app units relative to the screen.
   369   //   aScreenPoint - the point where the popup should appear
   370   //   aSize - the size of the popup
   371   //   aScreenBegin - the left or top edge of the screen
   372   //   aScreenEnd - the right or bottom edge of the screen
   373   //   aAnchorBegin - the left or top edge of the anchor rectangle
   374   //   aAnchorEnd - the right or bottom edge of the anchor rectangle
   375   //   aMarginBegin - the left or top margin of the popup
   376   //   aMarginEnd - the right or bottom margin of the popup
   377   //   aOffsetForContextMenu - the additional offset to add for context menus
   378   //   aFlip - how to flip or resize the popup when there isn't space
   379   //   aFlipSide - pointer to where current flip mode is stored
   380   nscoord FlipOrResize(nscoord& aScreenPoint, nscoord aSize, 
   381                        nscoord aScreenBegin, nscoord aScreenEnd,
   382                        nscoord aAnchorBegin, nscoord aAnchorEnd,
   383                        nscoord aMarginBegin, nscoord aMarginEnd,
   384                        nscoord aOffsetForContextMenu, FlipStyle aFlip,
   385                        bool* aFlipSide);
   387   // check if the popup can fit into the available space by "sliding" (i.e.,
   388   // by having the anchor arrow slide along one axis and only resizing if that
   389   // can't provide the requested size). Only one axis can be slid - the other
   390   // axis is "flipped" as normal. This method can handle either axis, but is
   391   // only called for the sliding axis. All coordinates are in app units
   392   // relative to the screen.
   393   //   aScreenPoint - the point where the popup should appear
   394   //   aSize - the size of the popup
   395   //   aScreenBegin - the left or top edge of the screen
   396   //   aScreenEnd - the right or bottom edge of the screen
   397   //   aOffset - the amount by which the arrow must be slid such that it is
   398   //             still aligned with the anchor.
   399   // Result is the new size of the popup, which will typically be the same
   400   // as aSize, unless aSize is greater than the screen width/height.
   401   nscoord SlideOrResize(nscoord& aScreenPoint, nscoord aSize,
   402                         nscoord aScreenBegin, nscoord aScreenEnd,
   403                         nscoord *aOffset);
   405   // Move the popup to the position specified in its |left| and |top| attributes.
   406   void MoveToAttributePosition();
   408   /**
   409    * Return whether the popup direction should be RTL.
   410    * If the popup has an anchor, its direction is the anchor direction.
   411    * Otherwise, its the general direction of the UI.
   412    *
   413    * Return whether the popup direction should be RTL.
   414    */
   415   bool IsDirectionRTL() const {
   416     return mAnchorContent && mAnchorContent->GetPrimaryFrame()
   417       ? mAnchorContent->GetPrimaryFrame()->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL
   418       : StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
   419   }
   421   // Create a popup view for this frame. The view is added a child of the root
   422   // view, and is initially hidden.
   423   void CreatePopupView();
   425   nsString     mIncrementalString;  // for incremental typing navigation
   427   // the content that the popup is anchored to, if any, which may be in a
   428   // different document than the popup.
   429   nsCOMPtr<nsIContent> mAnchorContent;
   431   // the content that triggered the popup, typically the node where the mouse
   432   // was clicked. It will be cleared when the popup is hidden.
   433   nsCOMPtr<nsIContent> mTriggerContent;
   435   nsMenuFrame* mCurrentMenu; // The current menu that is active.
   437   // A popup's preferred size may be different than its actual size stored in
   438   // mRect in the case where the popup was resized because it was too large
   439   // for the screen. The preferred size mPrefSize holds the full size the popup
   440   // would be before resizing. Computations are performed using this size.
   441   nsSize mPrefSize;
   443   // The position of the popup, in CSS pixels.
   444   // The screen coordinates, if set to values other than -1,
   445   // override mXPos and mYPos.
   446   int32_t mXPos;
   447   int32_t mYPos;
   448   int32_t mScreenXPos;
   449   int32_t mScreenYPos;
   451   // If the panel prefers to "slide" rather than resize, then the arrow gets
   452   // positioned at this offset (along either the x or y axis, depending on
   453   // mPosition)
   454   nscoord mAlignmentOffset;
   456   // The value of the client offset of our widget the last time we positioned
   457   // ourselves. We store this so that we can detect when it changes but the
   458   // position of our widget didn't change.
   459   nsIntPoint mLastClientOffset;
   461   nsPopupType mPopupType; // type of popup
   462   nsPopupState mPopupState; // open state of the popup
   464   // popup alignment relative to the anchor node
   465   int8_t mPopupAlignment;
   466   int8_t mPopupAnchor;
   467   int8_t mPosition;
   469   // One of nsIPopupBoxObject::ROLLUP_DEFAULT/ROLLUP_CONSUME/ROLLUP_NO_CONSUME
   470   int8_t mConsumeRollupEvent;
   471   FlipType mFlip; // Whether to flip
   473   bool mIsOpenChanged; // true if the open state changed since the last layout
   474   bool mIsContextMenu; // true for context menus
   475   // true if we need to offset the popup to ensure it's not under the mouse
   476   bool mAdjustOffsetForContextMenu;
   477   bool mGeneratedChildren; // true if the contents have been created
   479   bool mMenuCanOverlapOSBar;    // can we appear over the taskbar/menubar?
   480   bool mShouldAutoPosition; // Should SetPopupPosition be allowed to auto position popup?
   481   bool mInContentShell; // True if the popup is in a content shell
   482   bool mIsMenuLocked; // Should events inside this menu be ignored?
   483   bool mMouseTransparent; // True if this is a popup is transparent to mouse events
   485   // the flip modes that were used when the popup was opened
   486   bool mHFlip;
   487   bool mVFlip;
   489   static int8_t sDefaultLevelIsTop;
   490 }; // class nsMenuPopupFrame
   492 #endif

mercurial