|
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/. */ |
|
5 |
|
6 #ifndef nsComboboxControlFrame_h___ |
|
7 #define nsComboboxControlFrame_h___ |
|
8 |
|
9 #ifdef DEBUG_evaughan |
|
10 //#define DEBUG_rods |
|
11 #endif |
|
12 |
|
13 #ifdef DEBUG_rods |
|
14 //#define DO_REFLOW_DEBUG |
|
15 //#define DO_REFLOW_COUNTER |
|
16 //#define DO_UNCONSTRAINED_CHECK |
|
17 //#define DO_PIXELS |
|
18 //#define DO_NEW_REFLOW |
|
19 #endif |
|
20 |
|
21 //Mark used to indicate when onchange has been fired for current combobox item |
|
22 #define NS_SKIP_NOTIFY_INDEX -2 |
|
23 |
|
24 #include "mozilla/Attributes.h" |
|
25 #include "nsBlockFrame.h" |
|
26 #include "nsIFormControlFrame.h" |
|
27 #include "nsIComboboxControlFrame.h" |
|
28 #include "nsIAnonymousContentCreator.h" |
|
29 #include "nsISelectControlFrame.h" |
|
30 #include "nsIRollupListener.h" |
|
31 #include "nsIStatefulFrame.h" |
|
32 #include "nsThreadUtils.h" |
|
33 |
|
34 class nsStyleContext; |
|
35 class nsIListControlFrame; |
|
36 class nsComboboxDisplayFrame; |
|
37 class nsIDOMEventListener; |
|
38 class nsIScrollableFrame; |
|
39 |
|
40 class nsComboboxControlFrame : public nsBlockFrame, |
|
41 public nsIFormControlFrame, |
|
42 public nsIComboboxControlFrame, |
|
43 public nsIAnonymousContentCreator, |
|
44 public nsISelectControlFrame, |
|
45 public nsIRollupListener, |
|
46 public nsIStatefulFrame |
|
47 { |
|
48 public: |
|
49 friend nsIFrame* NS_NewComboboxControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, nsFrameState aFlags); |
|
50 friend class nsComboboxDisplayFrame; |
|
51 |
|
52 nsComboboxControlFrame(nsStyleContext* aContext); |
|
53 ~nsComboboxControlFrame(); |
|
54 |
|
55 NS_DECL_QUERYFRAME |
|
56 NS_DECL_FRAMEARENA_HELPERS |
|
57 |
|
58 // nsIAnonymousContentCreator |
|
59 virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) MOZ_OVERRIDE; |
|
60 virtual void AppendAnonymousContentTo(nsBaseContentList& aElements, |
|
61 uint32_t aFilter) MOZ_OVERRIDE; |
|
62 virtual nsIFrame* CreateFrameFor(nsIContent* aContent) MOZ_OVERRIDE; |
|
63 |
|
64 #ifdef ACCESSIBILITY |
|
65 virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE; |
|
66 #endif |
|
67 |
|
68 virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; |
|
69 |
|
70 virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; |
|
71 |
|
72 virtual nsresult Reflow(nsPresContext* aCX, |
|
73 nsHTMLReflowMetrics& aDesiredSize, |
|
74 const nsHTMLReflowState& aReflowState, |
|
75 nsReflowStatus& aStatus) MOZ_OVERRIDE; |
|
76 |
|
77 virtual nsresult HandleEvent(nsPresContext* aPresContext, |
|
78 mozilla::WidgetGUIEvent* aEvent, |
|
79 nsEventStatus* aEventStatus) MOZ_OVERRIDE; |
|
80 |
|
81 virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, |
|
82 const nsRect& aDirtyRect, |
|
83 const nsDisplayListSet& aLists) MOZ_OVERRIDE; |
|
84 |
|
85 void PaintFocus(nsRenderingContext& aRenderingContext, nsPoint aPt); |
|
86 |
|
87 // XXXbz this is only needed to prevent the quirk percent height stuff from |
|
88 // leaking out of the combobox. We may be able to get rid of this as more |
|
89 // things move to IsFrameOfType. |
|
90 virtual nsIAtom* GetType() const MOZ_OVERRIDE; |
|
91 |
|
92 virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE |
|
93 { |
|
94 return nsBlockFrame::IsFrameOfType(aFlags & |
|
95 ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock)); |
|
96 } |
|
97 |
|
98 virtual nsIScrollableFrame* GetScrollTargetFrame() MOZ_OVERRIDE { |
|
99 return do_QueryFrame(mDropdownFrame); |
|
100 } |
|
101 |
|
102 #ifdef DEBUG_FRAME_DUMP |
|
103 virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE; |
|
104 #endif |
|
105 virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; |
|
106 virtual nsresult SetInitialChildList(ChildListID aListID, |
|
107 nsFrameList& aChildList) MOZ_OVERRIDE; |
|
108 virtual const nsFrameList& GetChildList(ChildListID aListID) const MOZ_OVERRIDE; |
|
109 virtual void GetChildLists(nsTArray<ChildList>* aLists) const MOZ_OVERRIDE; |
|
110 |
|
111 virtual nsIFrame* GetContentInsertionFrame() MOZ_OVERRIDE; |
|
112 |
|
113 // nsIFormControlFrame |
|
114 virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue) MOZ_OVERRIDE; |
|
115 /** |
|
116 * Inform the control that it got (or lost) focus. |
|
117 * If it lost focus, the dropdown menu will be rolled up if needed, |
|
118 * and FireOnChange() will be called. |
|
119 * @param aOn true if got focus, false if lost focus. |
|
120 * @param aRepaint if true then force repaint (NOTE: we always force repaint currently) |
|
121 * @note This method might destroy |this|. |
|
122 */ |
|
123 virtual void SetFocus(bool aOn, bool aRepaint) MOZ_OVERRIDE; |
|
124 |
|
125 //nsIComboboxControlFrame |
|
126 virtual bool IsDroppedDown() MOZ_OVERRIDE { return mDroppedDown; } |
|
127 /** |
|
128 * @note This method might destroy |this|. |
|
129 */ |
|
130 virtual void ShowDropDown(bool aDoDropDown) MOZ_OVERRIDE; |
|
131 virtual nsIFrame* GetDropDown() MOZ_OVERRIDE; |
|
132 virtual void SetDropDown(nsIFrame* aDropDownFrame) MOZ_OVERRIDE; |
|
133 /** |
|
134 * @note This method might destroy |this|. |
|
135 */ |
|
136 virtual void RollupFromList() MOZ_OVERRIDE; |
|
137 |
|
138 /** |
|
139 * Return the available space above and below this frame for |
|
140 * placing the drop-down list, and the current 2D translation. |
|
141 * Note that either or both can be less than or equal to zero, |
|
142 * if both are then the drop-down should be closed. |
|
143 */ |
|
144 void GetAvailableDropdownSpace(nscoord* aAbove, |
|
145 nscoord* aBelow, |
|
146 nsPoint* aTranslation); |
|
147 virtual int32_t GetIndexOfDisplayArea() MOZ_OVERRIDE; |
|
148 /** |
|
149 * @note This method might destroy |this|. |
|
150 */ |
|
151 NS_IMETHOD RedisplaySelectedText() MOZ_OVERRIDE; |
|
152 virtual int32_t UpdateRecentIndex(int32_t aIndex) MOZ_OVERRIDE; |
|
153 virtual void OnContentReset() MOZ_OVERRIDE; |
|
154 |
|
155 // nsISelectControlFrame |
|
156 NS_IMETHOD AddOption(int32_t index) MOZ_OVERRIDE; |
|
157 NS_IMETHOD RemoveOption(int32_t index) MOZ_OVERRIDE; |
|
158 NS_IMETHOD DoneAddingChildren(bool aIsDone) MOZ_OVERRIDE; |
|
159 NS_IMETHOD OnOptionSelected(int32_t aIndex, bool aSelected) MOZ_OVERRIDE; |
|
160 NS_IMETHOD OnSetSelectedIndex(int32_t aOldIndex, int32_t aNewIndex) MOZ_OVERRIDE; |
|
161 |
|
162 //nsIRollupListener |
|
163 /** |
|
164 * Hide the dropdown menu and stop capturing mouse events. |
|
165 * @note This method might destroy |this|. |
|
166 */ |
|
167 virtual bool Rollup(uint32_t aCount, const nsIntPoint* pos, nsIContent** aLastRolledUp) MOZ_OVERRIDE; |
|
168 virtual void NotifyGeometryChange() MOZ_OVERRIDE; |
|
169 |
|
170 /** |
|
171 * A combobox should roll up if a mousewheel event happens outside of |
|
172 * the popup area. |
|
173 */ |
|
174 virtual bool ShouldRollupOnMouseWheelEvent() MOZ_OVERRIDE |
|
175 { return true; } |
|
176 |
|
177 virtual bool ShouldConsumeOnMouseWheelEvent() MOZ_OVERRIDE |
|
178 { return false; } |
|
179 |
|
180 /** |
|
181 * A combobox should not roll up if activated by a mouse activate message |
|
182 * (eg. X-mouse). |
|
183 */ |
|
184 virtual bool ShouldRollupOnMouseActivate() MOZ_OVERRIDE |
|
185 { return false; } |
|
186 |
|
187 virtual uint32_t GetSubmenuWidgetChain(nsTArray<nsIWidget*> *aWidgetChain) MOZ_OVERRIDE |
|
188 { return 0; } |
|
189 |
|
190 virtual nsIWidget* GetRollupWidget() MOZ_OVERRIDE; |
|
191 |
|
192 //nsIStatefulFrame |
|
193 NS_IMETHOD SaveState(nsPresState** aState) MOZ_OVERRIDE; |
|
194 NS_IMETHOD RestoreState(nsPresState* aState) MOZ_OVERRIDE; |
|
195 |
|
196 static bool ToolkitHasNativePopup(); |
|
197 |
|
198 protected: |
|
199 friend class RedisplayTextEvent; |
|
200 friend class nsAsyncResize; |
|
201 friend class nsResizeDropdownAtFinalPosition; |
|
202 |
|
203 // Utilities |
|
204 nsresult ReflowDropdown(nsPresContext* aPresContext, |
|
205 const nsHTMLReflowState& aReflowState); |
|
206 |
|
207 enum DropDownPositionState { |
|
208 // can't show the dropdown at its current position |
|
209 eDropDownPositionSuppressed, |
|
210 // a resize reflow is pending, don't show it yet |
|
211 eDropDownPositionPendingResize, |
|
212 // the dropdown has its final size and position and can be displayed here |
|
213 eDropDownPositionFinal |
|
214 }; |
|
215 DropDownPositionState AbsolutelyPositionDropDown(); |
|
216 |
|
217 // Helper for GetMinWidth/GetPrefWidth |
|
218 nscoord GetIntrinsicWidth(nsRenderingContext* aRenderingContext, |
|
219 nsLayoutUtils::IntrinsicWidthType aType); |
|
220 |
|
221 class RedisplayTextEvent : public nsRunnable { |
|
222 public: |
|
223 NS_DECL_NSIRUNNABLE |
|
224 RedisplayTextEvent(nsComboboxControlFrame *c) : mControlFrame(c) {} |
|
225 void Revoke() { mControlFrame = nullptr; } |
|
226 private: |
|
227 nsComboboxControlFrame *mControlFrame; |
|
228 }; |
|
229 |
|
230 /** |
|
231 * Show or hide the dropdown list. |
|
232 * @note This method might destroy |this|. |
|
233 */ |
|
234 void ShowPopup(bool aShowPopup); |
|
235 |
|
236 /** |
|
237 * Show or hide the dropdown list. |
|
238 * @param aShowList true to show, false to hide the dropdown. |
|
239 * @note This method might destroy |this|. |
|
240 * @return false if this frame is destroyed, true if still alive. |
|
241 */ |
|
242 bool ShowList(bool aShowList); |
|
243 void CheckFireOnChange(); |
|
244 void FireValueChangeEvent(); |
|
245 nsresult RedisplayText(int32_t aIndex); |
|
246 void HandleRedisplayTextEvent(); |
|
247 void ActuallyDisplayText(bool aNotify); |
|
248 |
|
249 private: |
|
250 // If our total transform to the root frame of the root document is only a 2d |
|
251 // translation then return that translation, otherwise returns (0,0). |
|
252 nsPoint GetCSSTransformTranslation(); |
|
253 |
|
254 protected: |
|
255 nsFrameList mPopupFrames; // additional named child list |
|
256 nsCOMPtr<nsIContent> mDisplayContent; // Anonymous content used to display the current selection |
|
257 nsCOMPtr<nsIContent> mButtonContent; // Anonymous content for the button |
|
258 nsIFrame* mDisplayFrame; // frame to display selection |
|
259 nsIFrame* mButtonFrame; // button frame |
|
260 nsIFrame* mDropdownFrame; // dropdown list frame |
|
261 nsIListControlFrame * mListControlFrame; // ListControl Interface for the dropdown frame |
|
262 |
|
263 // The width of our display area. Used by that frame's reflow to |
|
264 // size to the full width except the drop-marker. |
|
265 nscoord mDisplayWidth; |
|
266 |
|
267 nsRevocableEventPtr<RedisplayTextEvent> mRedisplayTextEvent; |
|
268 |
|
269 int32_t mRecentSelectedIndex; |
|
270 int32_t mDisplayedIndex; |
|
271 nsString mDisplayedOptionText; |
|
272 |
|
273 // make someone to listen to the button. If its programmatically pressed by someone like Accessibility |
|
274 // then open or close the combo box. |
|
275 nsCOMPtr<nsIDOMEventListener> mButtonListener; |
|
276 |
|
277 // The last y-positions used for estimating available space above and |
|
278 // below for the dropdown list in GetAvailableDropdownSpace. These are |
|
279 // reset to nscoord_MIN in AbsolutelyPositionDropDown when placing the |
|
280 // dropdown at its actual position. The GetAvailableDropdownSpace call |
|
281 // from nsListControlFrame::ReflowAsDropdown use the last position. |
|
282 nscoord mLastDropDownAboveScreenY; |
|
283 nscoord mLastDropDownBelowScreenY; |
|
284 // Current state of the dropdown list, true is dropped down. |
|
285 bool mDroppedDown; |
|
286 // See comment in HandleRedisplayTextEvent(). |
|
287 bool mInRedisplayText; |
|
288 // Acting on ShowDropDown(true) is delayed until we're focused. |
|
289 bool mDelayedShowDropDown; |
|
290 |
|
291 // static class data member for Bug 32920 |
|
292 // only one control can be focused at a time |
|
293 static nsComboboxControlFrame* sFocused; |
|
294 |
|
295 #ifdef DO_REFLOW_COUNTER |
|
296 int32_t mReflowId; |
|
297 #endif |
|
298 }; |
|
299 |
|
300 #endif |