1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Original Author: David W. Hyatt (hyatt@netscape.com)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : //
40 : // nsMenuFrame
41 : //
42 :
43 : #ifndef nsMenuFrame_h__
44 : #define nsMenuFrame_h__
45 :
46 : #include "prtypes.h"
47 : #include "nsIAtom.h"
48 : #include "nsCOMPtr.h"
49 :
50 : #include "nsBoxFrame.h"
51 : #include "nsFrameList.h"
52 : #include "nsGkAtoms.h"
53 : #include "nsMenuParent.h"
54 : #include "nsXULPopupManager.h"
55 : #include "nsITimer.h"
56 : #include "nsIContent.h"
57 :
58 : nsIFrame* NS_NewMenuFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
59 : nsIFrame* NS_NewMenuItemFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
60 :
61 : class nsMenuBarFrame;
62 :
63 : #define NS_STATE_ACCELTEXT_IS_DERIVED NS_STATE_BOX_CHILD_RESERVED
64 :
65 : // the type of menuitem
66 : enum nsMenuType {
67 : // a normal menuitem where a command is carried out when activated
68 : eMenuType_Normal = 0,
69 : // a menuitem with a checkmark that toggles when activated
70 : eMenuType_Checkbox = 1,
71 : // a radio menuitem where only one of it and its siblings with the same
72 : // name attribute can be checked at a time
73 : eMenuType_Radio = 2
74 : };
75 :
76 : enum nsMenuListType {
77 : eNotMenuList, // not a menulist
78 : eReadonlyMenuList, // <menulist/>
79 : eEditableMenuList // <menulist editable="true"/>
80 : };
81 :
82 : class nsMenuFrame;
83 :
84 : /**
85 : * nsMenuTimerMediator is a wrapper around an nsMenuFrame which can be safely
86 : * passed to timers. The class is reference counted unlike the underlying
87 : * nsMenuFrame, so that it will exist as long as the timer holds a reference
88 : * to it. The callback is delegated to the contained nsMenuFrame as long as
89 : * the contained nsMenuFrame has not been destroyed.
90 : */
91 : class nsMenuTimerMediator : public nsITimerCallback
92 : {
93 : public:
94 : nsMenuTimerMediator(nsMenuFrame* aFrame);
95 : ~nsMenuTimerMediator();
96 :
97 : NS_DECL_ISUPPORTS
98 : NS_DECL_NSITIMERCALLBACK
99 :
100 : void ClearFrame();
101 :
102 : private:
103 :
104 : // Pointer to the wrapped frame.
105 : nsMenuFrame* mFrame;
106 : };
107 :
108 : class nsMenuFrame : public nsBoxFrame
109 : {
110 : public:
111 : nsMenuFrame(nsIPresShell* aShell, nsStyleContext* aContext);
112 :
113 : NS_DECL_QUERYFRAME_TARGET(nsMenuFrame)
114 : NS_DECL_QUERYFRAME
115 : NS_DECL_FRAMEARENA_HELPERS
116 :
117 : // nsIBox
118 : NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState);
119 : virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState);
120 : virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState);
121 :
122 : NS_IMETHOD Init(nsIContent* aContent,
123 : nsIFrame* aParent,
124 : nsIFrame* aPrevInFlow);
125 :
126 : #ifdef DEBUG_LAYOUT
127 : NS_IMETHOD SetDebug(nsBoxLayoutState& aState, bool aDebug);
128 : #endif
129 :
130 : // The following methods are all overridden so that the menupopup
131 : // can be stored in a separate list, so that it doesn't impact reflow of the
132 : // actual menu item at all.
133 : virtual const nsFrameList& GetChildList(ChildListID aList) const;
134 : virtual void GetChildLists(nsTArray<ChildList>* aLists) const;
135 : NS_IMETHOD SetInitialChildList(ChildListID aListID,
136 : nsFrameList& aChildList);
137 : virtual void DestroyFrom(nsIFrame* aDestructRoot);
138 :
139 : // Overridden to prevent events from going to children of the menu.
140 : NS_IMETHOD BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
141 : const nsRect& aDirtyRect,
142 : const nsDisplayListSet& aLists);
143 :
144 : // this method can destroy the frame
145 : NS_IMETHOD HandleEvent(nsPresContext* aPresContext,
146 : nsGUIEvent* aEvent,
147 : nsEventStatus* aEventStatus);
148 :
149 : NS_IMETHOD AppendFrames(ChildListID aListID,
150 : nsFrameList& aFrameList);
151 :
152 : NS_IMETHOD InsertFrames(ChildListID aListID,
153 : nsIFrame* aPrevFrame,
154 : nsFrameList& aFrameList);
155 :
156 : NS_IMETHOD RemoveFrame(ChildListID aListID,
157 : nsIFrame* aOldFrame);
158 :
159 0 : virtual nsIAtom* GetType() const { return nsGkAtoms::menuFrame; }
160 :
161 : NS_IMETHOD SelectMenu(bool aActivateFlag);
162 :
163 : virtual nsIScrollableFrame* GetScrollTargetFrame();
164 :
165 : /**
166 : * NOTE: OpenMenu will open the menu asynchronously.
167 : */
168 : void OpenMenu(bool aSelectFirstItem);
169 : // CloseMenu closes the menu asynchronously
170 : void CloseMenu(bool aDeselectMenu);
171 :
172 0 : bool IsChecked() { return mChecked; }
173 :
174 : NS_IMETHOD GetActiveChild(nsIDOMElement** aResult);
175 : NS_IMETHOD SetActiveChild(nsIDOMElement* aChild);
176 :
177 : // called when the Enter key is pressed while the menuitem is the current
178 : // one in its parent popup. This will carry out the command attached to
179 : // the menuitem. If the menu should be opened, this frame will be returned,
180 : // otherwise null will be returned.
181 : nsMenuFrame* Enter(nsGUIEvent* aEvent);
182 :
183 : virtual void SetParent(nsIFrame* aParent);
184 :
185 0 : virtual nsMenuParent *GetMenuParent() { return mMenuParent; }
186 0 : const nsAString& GetRadioGroupName() { return mGroupName; }
187 0 : nsMenuType GetMenuType() { return mType; }
188 : nsMenuPopupFrame* GetPopup();
189 :
190 : /**
191 : * @return true if this frame has a popup child frame.
192 : */
193 0 : bool HasPopup() const
194 : {
195 0 : return (GetStateBits() & NS_STATE_MENU_HAS_POPUP_LIST) != 0;
196 : }
197 :
198 :
199 : // nsMenuFrame methods
200 :
201 0 : bool IsOnMenuBar() { return mMenuParent && mMenuParent->IsMenuBar(); }
202 : bool IsOnActiveMenuBar() { return IsOnMenuBar() && mMenuParent->IsActive(); }
203 : virtual bool IsOpen();
204 : virtual bool IsMenu();
205 : nsMenuListType GetParentMenuListType();
206 : bool IsDisabled();
207 : void ToggleMenuState();
208 :
209 : // indiciate that the menu's popup has just been opened, so that the menu
210 : // can update its open state. This method modifies the open attribute on
211 : // the menu, so the frames could be gone after this call.
212 : void PopupOpened();
213 : // indiciate that the menu's popup has just been closed, so that the menu
214 : // can update its open state. The menu should be unhighlighted if
215 : // aDeselectedMenu is true. This method modifies the open attribute on
216 : // the menu, so the frames could be gone after this call.
217 : void PopupClosed(bool aDeselectMenu);
218 :
219 : // returns true if this is a menu on another menu popup. A menu is a submenu
220 : // if it has a parent popup or menupopup.
221 0 : bool IsOnMenu() { return mMenuParent && mMenuParent->IsMenu(); }
222 0 : void SetIsMenu(bool aIsMenu) { mIsMenu = aIsMenu; }
223 :
224 : #ifdef DEBUG
225 0 : NS_IMETHOD GetFrameName(nsAString& aResult) const
226 : {
227 0 : return MakeFrameName(NS_LITERAL_STRING("Menu"), aResult);
228 : }
229 : #endif
230 :
231 : static bool IsSizedToPopup(nsIContent* aContent, bool aRequireAlways);
232 :
233 : protected:
234 : friend class nsMenuTimerMediator;
235 : friend class nsASyncMenuInitialization;
236 : friend class nsMenuAttributeChangedEvent;
237 :
238 : /**
239 : * Initialize the popup list to the first popup frame within
240 : * aChildList. Removes the popup, if any, from aChildList.
241 : */
242 : void SetPopupFrame(nsFrameList& aChildList);
243 :
244 : /**
245 : * Get the popup frame list from the frame property.
246 : * @return the property value if it exists, nsnull otherwise.
247 : */
248 : nsFrameList* GetPopupList() const;
249 :
250 : /**
251 : * Destroy the popup list property. The list must exist and be empty.
252 : */
253 : void DestroyPopupList();
254 :
255 : // set mMenuParent to the nearest enclosing menu bar or menupopup frame of
256 : // aParent (or aParent itself). This is called when initializing the frame,
257 : // so aParent should be the expected parent of this frame.
258 : void InitMenuParent(nsIFrame* aParent);
259 :
260 : // Update the menu's type (normal, checkbox, radio).
261 : // This method can destroy the frame.
262 : void UpdateMenuType(nsPresContext* aPresContext);
263 : // Update the checked state of the menu, and for radios, clear any other
264 : // checked items. This method can destroy the frame.
265 : void UpdateMenuSpecialState(nsPresContext* aPresContext);
266 :
267 : // Examines the key node and builds the accelerator.
268 : void BuildAcceleratorText(bool aNotify);
269 :
270 : // Called to execute our command handler. This method can destroy the frame.
271 : void Execute(nsGUIEvent *aEvent);
272 :
273 : // This method can destroy the frame
274 : NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
275 : nsIAtom* aAttribute,
276 : PRInt32 aModType);
277 0 : virtual ~nsMenuFrame() { };
278 :
279 : bool SizeToPopup(nsBoxLayoutState& aState, nsSize& aSize);
280 :
281 : bool ShouldBlink();
282 : void StartBlinking(nsGUIEvent *aEvent, bool aFlipChecked);
283 : void StopBlinking();
284 : void CreateMenuCommandEvent(nsGUIEvent *aEvent, bool aFlipChecked);
285 : void PassMenuCommandEventToPopupManager();
286 :
287 : protected:
288 : #ifdef DEBUG_LAYOUT
289 : nsresult SetDebug(nsBoxLayoutState& aState, nsIFrame* aList, bool aDebug);
290 : #endif
291 : NS_HIDDEN_(nsresult) Notify(nsITimer* aTimer);
292 :
293 : bool mIsMenu; // Whether or not we can even have children or not.
294 : bool mChecked; // are we checked?
295 : bool mIgnoreAccelTextChange; // temporarily set while determining the accelerator key
296 : nsMenuType mType;
297 :
298 : nsMenuParent* mMenuParent; // Our parent menu.
299 :
300 : // Reference to the mediator which wraps this frame.
301 : nsRefPtr<nsMenuTimerMediator> mTimerMediator;
302 :
303 : nsCOMPtr<nsITimer> mOpenTimer;
304 : nsCOMPtr<nsITimer> mBlinkTimer;
305 :
306 : PRUint8 mBlinkState; // 0: not blinking, 1: off, 2: on
307 : nsRefPtr<nsXULMenuCommandEvent> mDelayedMenuCommandEvent;
308 :
309 : nsString mGroupName;
310 :
311 : }; // class nsMenuFrame
312 :
313 : #endif
|