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 #ifndef nsListControlFrame_h___
6 #define nsListControlFrame_h___
13 //#define DO_REFLOW_DEBUG
14 //#define DO_REFLOW_COUNTER
15 //#define DO_UNCONSTRAINED_CHECK
19 #include "mozilla/Attributes.h"
20 #include "nsGfxScrollFrame.h"
21 #include "nsIFormControlFrame.h"
22 #include "nsIListControlFrame.h"
23 #include "nsISelectControlFrame.h"
24 #include "nsAutoPtr.h"
25 #include "nsSelectsAreaFrame.h"
27 // X.h defines KeyPress
32 class nsIDOMHTMLSelectElement
;
33 class nsIDOMHTMLOptionsCollection
;
34 class nsIComboboxControlFrame
;
36 class nsListEventListener
;
40 class HTMLOptionElement
;
41 class HTMLOptionsCollection
;
43 } // namespace mozilla
46 * Frame-based listbox.
49 class nsListControlFrame MOZ_FINAL
: public nsHTMLScrollFrame
,
50 public nsIFormControlFrame
,
51 public nsIListControlFrame
,
52 public nsISelectControlFrame
55 friend nsContainerFrame
* NS_NewListControlFrame(nsIPresShell
* aPresShell
,
56 nsStyleContext
* aContext
);
59 NS_DECL_FRAMEARENA_HELPERS
62 virtual nsresult
HandleEvent(nsPresContext
* aPresContext
,
63 mozilla::WidgetGUIEvent
* aEvent
,
64 nsEventStatus
* aEventStatus
) MOZ_OVERRIDE
;
66 virtual void SetInitialChildList(ChildListID aListID
,
67 nsFrameList
& aChildList
) MOZ_OVERRIDE
;
69 virtual nscoord
GetPrefISize(nsRenderingContext
*aRenderingContext
) MOZ_OVERRIDE
;
70 virtual nscoord
GetMinISize(nsRenderingContext
*aRenderingContext
) MOZ_OVERRIDE
;
72 virtual void Reflow(nsPresContext
* aCX
,
73 nsHTMLReflowMetrics
& aDesiredSize
,
74 const nsHTMLReflowState
& aReflowState
,
75 nsReflowStatus
& aStatus
) MOZ_OVERRIDE
;
77 virtual void Init(nsIContent
* aContent
,
78 nsContainerFrame
* aParent
,
79 nsIFrame
* aPrevInFlow
) MOZ_OVERRIDE
;
81 virtual void DidReflow(nsPresContext
* aPresContext
,
82 const nsHTMLReflowState
* aReflowState
,
83 nsDidReflowStatus aStatus
) MOZ_OVERRIDE
;
84 virtual void DestroyFrom(nsIFrame
* aDestructRoot
) MOZ_OVERRIDE
;
86 virtual void BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
87 const nsRect
& aDirtyRect
,
88 const nsDisplayListSet
& aLists
) MOZ_OVERRIDE
;
90 virtual nsContainerFrame
* GetContentInsertionFrame() MOZ_OVERRIDE
;
93 * Get the "type" of the frame
95 * @see nsGkAtoms::scrollFrame
97 virtual nsIAtom
* GetType() const MOZ_OVERRIDE
;
99 virtual bool IsFrameOfType(uint32_t aFlags
) const MOZ_OVERRIDE
101 return nsHTMLScrollFrame::IsFrameOfType(aFlags
&
102 ~(nsIFrame::eReplaced
| nsIFrame::eReplacedContainsBlock
));
105 #ifdef DEBUG_FRAME_DUMP
106 virtual nsresult
GetFrameName(nsAString
& aResult
) const MOZ_OVERRIDE
;
109 // nsIFormControlFrame
110 virtual nsresult
SetFormProperty(nsIAtom
* aName
, const nsAString
& aValue
) MOZ_OVERRIDE
;
111 virtual void SetFocus(bool aOn
= true, bool aRepaint
= false) MOZ_OVERRIDE
;
113 virtual mozilla::ScrollbarStyles
GetScrollbarStyles() const MOZ_OVERRIDE
;
114 virtual bool ShouldPropagateComputedHeightToScrolledContent() const MOZ_OVERRIDE
;
116 // for accessibility purposes
118 virtual mozilla::a11y::AccType
AccessibleType() MOZ_OVERRIDE
;
121 // nsIListControlFrame
122 virtual void SetComboboxFrame(nsIFrame
* aComboboxFrame
) MOZ_OVERRIDE
;
123 virtual int32_t GetSelectedIndex() MOZ_OVERRIDE
;
124 virtual mozilla::dom::HTMLOptionElement
* GetCurrentOption() MOZ_OVERRIDE
;
127 * Gets the text of the currently selected item.
128 * If the there are zero items then an empty string is returned
129 * If there is nothing selected, then the 0th item's text is returned.
131 virtual void GetOptionText(uint32_t aIndex
, nsAString
& aStr
) MOZ_OVERRIDE
;
133 virtual void CaptureMouseEvents(bool aGrabMouseEvents
) MOZ_OVERRIDE
;
134 virtual nscoord
GetHeightOfARow() MOZ_OVERRIDE
;
135 virtual uint32_t GetNumberOfOptions() MOZ_OVERRIDE
;
136 virtual void AboutToDropDown() MOZ_OVERRIDE
;
139 * @note This method might destroy the frame, pres shell and other objects.
141 virtual void AboutToRollup() MOZ_OVERRIDE
;
144 * Dispatch a DOM onchange event synchroniously.
145 * @note This method might destroy the frame, pres shell and other objects.
147 virtual void FireOnChange() MOZ_OVERRIDE
;
150 * Makes aIndex the selected option of a combobox list.
151 * @note This method might destroy the frame, pres shell and other objects.
153 virtual void ComboboxFinish(int32_t aIndex
) MOZ_OVERRIDE
;
154 virtual void OnContentReset() MOZ_OVERRIDE
;
156 // nsISelectControlFrame
157 NS_IMETHOD
AddOption(int32_t index
) MOZ_OVERRIDE
;
158 NS_IMETHOD
RemoveOption(int32_t index
) MOZ_OVERRIDE
;
159 NS_IMETHOD
DoneAddingChildren(bool aIsDone
) MOZ_OVERRIDE
;
162 * Gets the content (an option) by index and then set it as
163 * being selected or not selected.
165 NS_IMETHOD
OnOptionSelected(int32_t aIndex
, bool aSelected
) MOZ_OVERRIDE
;
166 NS_IMETHOD
OnSetSelectedIndex(int32_t aOldIndex
, int32_t aNewIndex
) MOZ_OVERRIDE
;
169 * Mouse event listeners.
170 * @note These methods might destroy the frame, pres shell and other objects.
172 nsresult
MouseDown(nsIDOMEvent
* aMouseEvent
);
173 nsresult
MouseUp(nsIDOMEvent
* aMouseEvent
);
174 nsresult
MouseMove(nsIDOMEvent
* aMouseEvent
);
175 nsresult
DragMove(nsIDOMEvent
* aMouseEvent
);
176 nsresult
KeyDown(nsIDOMEvent
* aKeyEvent
);
177 nsresult
KeyPress(nsIDOMEvent
* aKeyEvent
);
180 * Returns the options collection for mContent, if any.
182 mozilla::dom::HTMLOptionsCollection
* GetOptions() const;
184 * Returns the HTMLOptionElement for a given index in mContent's collection.
186 mozilla::dom::HTMLOptionElement
* GetOption(uint32_t aIndex
) const;
188 static void ComboboxFocusSet();
191 bool IsFocused() { return this == mFocused
; }
194 * Function to paint the focus rect when our nsSelectsAreaFrame is painting.
195 * @param aPt the offset of this frame, relative to the rendering reference
198 void PaintFocus(nsRenderingContext
& aRC
, nsPoint aPt
);
200 * If this frame IsFocused(), invalidates an area that includes anything
201 * that PaintFocus will or could have painted --- basically the whole
202 * GetOptionsContainer, plus some extra stuff if there are no options. This
203 * must be called every time mEndSelectionIndex changes.
205 void InvalidateFocus();
208 * Function to calculate the height a row, for use with the "size" attribute.
209 * Can't be const because GetNumberOfOptions() isn't const.
211 nscoord
CalcHeightOfARow();
214 * Function to ask whether we're currently in what might be the
215 * first pass of a two-pass reflow.
217 bool MightNeedSecondPass() const {
218 return mMightNeedSecondPass
;
221 void SetSuppressScrollbarUpdate(bool aSuppress
) {
222 nsHTMLScrollFrame::SetSuppressScrollbarUpdate(aSuppress
);
226 * Return whether the list is in dropdown mode.
228 bool IsInDropDownMode() const;
231 * Return the number of displayed rows in the list.
233 uint32_t GetNumDisplayRows() const { return mNumDisplayRows
; }
236 * Return true if the drop-down list can display more rows.
237 * (always false if not in drop-down mode)
239 bool GetDropdownCanGrow() const { return mDropdownCanGrow
; }
242 * Dropdowns need views
244 virtual bool NeedsView() MOZ_OVERRIDE
{ return IsInDropDownMode(); }
247 * Frees statics owned by this class.
249 static void Shutdown();
253 * Post a custom DOM event for the change, so that accessibility can
254 * fire a native focus event for accessibility
255 * (Some 3rd party products need to track our focus)
257 void FireMenuItemActiveEvent(); // Inform assistive tech what got focused
262 * Updates the selected text in a combobox and then calls FireOnChange().
263 * @note This method might destroy the frame, pres shell and other objects.
264 * Returns false if calling it destroyed |this|.
266 bool UpdateSelection();
269 * Returns whether mContent supports multiple selection.
271 bool GetMultiple() const {
272 return mContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::multiple
);
277 * Toggles (show/hide) the combobox dropdown menu.
278 * @note This method might destroy the frame, pres shell and other objects.
280 void DropDownToggleKey(nsIDOMEvent
* aKeyEvent
);
282 nsresult
IsOptionDisabled(int32_t anIndex
, bool &aIsDisabled
);
284 * @note This method might destroy the frame, pres shell and other objects.
286 void ScrollToFrame(mozilla::dom::HTMLOptionElement
& aOptElement
);
288 * @note This method might destroy the frame, pres shell and other objects.
290 void ScrollToIndex(int32_t anIndex
);
293 * When the user clicks on the comboboxframe to show the dropdown
294 * listbox, they then have to move the mouse into the list. We don't
295 * want to process those mouse events as selection events (i.e., to
296 * scroll list items into view). So we ignore the events until
297 * the mouse moves below our border-inner-edge, when
298 * mItemSelectionStarted is set.
300 * @param aPoint relative to this frame
302 bool IgnoreMouseEventForSelection(nsIDOMEvent
* aEvent
);
305 * If the dropdown is showing and the mouse has moved below our
306 * border-inner-edge, then set mItemSelectionStarted.
308 void UpdateInListState(nsIDOMEvent
* aEvent
);
309 void AdjustIndexForDisabledOpt(int32_t aStartIndex
, int32_t &anNewIndex
,
310 int32_t aNumOptions
, int32_t aDoAdjustInc
, int32_t aDoAdjustIncNext
);
313 * Resets the select back to it's original default values;
314 * those values as determined by the original HTML
316 virtual void ResetList(bool aAllowScrolling
);
318 explicit nsListControlFrame(nsStyleContext
* aContext
);
319 virtual ~nsListControlFrame();
322 * Sets the mSelectedIndex and mOldSelectedIndex from figuring out what
323 * item was selected using content
324 * @param aPoint the event point, in listcontrolframe coordinates
325 * @return NS_OK if it successfully found the selection
327 nsresult
GetIndexFromDOMEvent(nsIDOMEvent
* aMouseEvent
, int32_t& aCurIndex
);
329 bool CheckIfAllFramesHere();
330 bool IsLeftButton(nsIDOMEvent
* aMouseEvent
);
332 // guess at a row height based on our own style.
333 nscoord
CalcFallbackRowHeight(float aFontSizeInflation
);
335 // CalcIntrinsicBSize computes our intrinsic height (taking the "size"
336 // attribute into account). This should only be called in non-dropdown mode.
337 nscoord
CalcIntrinsicBSize(nscoord aHeightOfARow
, int32_t aNumberOfOptions
);
339 // Dropped down stuff
340 void SetComboboxItem(int32_t aIndex
);
343 * Method to reflow ourselves as a dropdown list. This differs from
344 * reflow as a listbox because the criteria for needing a second
345 * pass are different. This will be called from Reflow() as needed.
347 void ReflowAsDropdown(nsPresContext
* aPresContext
,
348 nsHTMLReflowMetrics
& aDesiredSize
,
349 const nsHTMLReflowState
& aReflowState
,
350 nsReflowStatus
& aStatus
);
353 bool SetOptionsSelectedFromFrame(int32_t aStartIndex
,
357 bool ToggleOptionSelectedFromFrame(int32_t aIndex
);
359 * @note This method might destroy the frame, pres shell and other objects.
361 bool SingleSelection(int32_t aClickedIndex
, bool aDoToggle
);
362 bool ExtendedSelection(int32_t aStartIndex
, int32_t aEndIndex
,
365 * @note This method might destroy the frame, pres shell and other objects.
367 bool PerformSelection(int32_t aClickedIndex
, bool aIsShift
,
370 * @note This method might destroy the frame, pres shell and other objects.
372 bool HandleListSelection(nsIDOMEvent
* aDOMEvent
, int32_t selectedIndex
);
373 void InitSelectionRange(int32_t aClickedIndex
);
374 void PostHandleKeyEvent(int32_t aNewIndex
, uint32_t aCharCode
,
375 bool aIsShift
, bool aIsControlOrMeta
);
378 nsSelectsAreaFrame
* GetOptionsContainer() const {
379 return static_cast<nsSelectsAreaFrame
*>(GetScrolledFrame());
383 nscoord
HeightOfARow() {
384 return GetOptionsContainer()->HeightOfARow();
388 * @return how many displayable options/optgroups this frame has.
390 uint32_t GetNumberOfRows();
393 int32_t mStartSelectionIndex
;
394 int32_t mEndSelectionIndex
;
396 nsIComboboxControlFrame
*mComboboxFrame
;
397 uint32_t mNumDisplayRows
;
398 bool mChangesSinceDragStart
:1;
400 // Has the user selected a visible item since we showed the
402 bool mItemSelectionStarted
:1;
404 bool mIsAllContentHere
:1;
405 bool mIsAllFramesHere
:1;
406 bool mHasBeenInitialized
:1;
408 bool mPostChildrenLoadedReset
:1;
410 //bool value for multiple discontiguous selection
411 bool mControlSelectMode
:1;
413 // True if we're in the middle of a reflow and might need a second
414 // pass. This only happens for auto heights.
415 bool mMightNeedSecondPass
:1;
418 * Set to aPresContext->HasPendingInterrupt() at the start of Reflow.
419 * Set to false at the end of DidReflow.
421 bool mHasPendingInterruptAtStartOfReflow
:1;
423 // True if the drop-down can show more rows. Always false if this list
424 // is not in drop-down mode.
425 bool mDropdownCanGrow
:1;
427 // True if the selection can be set to nothing or disabled options.
428 bool mForceSelection
:1;
430 // The last computed height we reflowed at if we're a combobox dropdown.
431 // XXXbz should we be using a subclass here? Or just not worry
432 // about the extra member on listboxes?
433 nscoord mLastDropdownComputedHeight
;
435 // At the time of our last dropdown, the backstop color to draw in case we
437 nscolor mLastDropdownBackstopColor
;
439 nsRefPtr
<nsListEventListener
> mEventListener
;
441 static nsListControlFrame
* mFocused
;
442 static nsString
* sIncrementalString
;
444 #ifdef DO_REFLOW_COUNTER
449 // for incremental typing navigation
450 static nsAString
& GetIncrementalString ();
451 static DOMTimeStamp gLastKeyTime
;
453 class MOZ_STACK_CLASS AutoIncrementalSearchResetter
456 AutoIncrementalSearchResetter() :
460 ~AutoIncrementalSearchResetter()
463 nsListControlFrame::GetIncrementalString().Truncate();
475 #endif /* nsListControlFrame_h___ */