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
: public nsHTMLScrollFrame
,
50 public nsIFormControlFrame
,
51 public nsIListControlFrame
,
52 public nsISelectControlFrame
55 friend nsIFrame
* NS_NewListControlFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
);
58 NS_DECL_FRAMEARENA_HELPERS
61 NS_IMETHOD
HandleEvent(nsPresContext
* aPresContext
,
62 mozilla::WidgetGUIEvent
* aEvent
,
63 nsEventStatus
* aEventStatus
) MOZ_OVERRIDE
;
65 NS_IMETHOD
SetInitialChildList(ChildListID aListID
,
66 nsFrameList
& aChildList
) MOZ_OVERRIDE
;
68 virtual nscoord
GetPrefWidth(nsRenderingContext
*aRenderingContext
) MOZ_OVERRIDE
;
69 virtual nscoord
GetMinWidth(nsRenderingContext
*aRenderingContext
) MOZ_OVERRIDE
;
71 NS_IMETHOD
Reflow(nsPresContext
* aCX
,
72 nsHTMLReflowMetrics
& aDesiredSize
,
73 const nsHTMLReflowState
& aReflowState
,
74 nsReflowStatus
& aStatus
) MOZ_OVERRIDE
;
76 virtual void Init(nsIContent
* aContent
,
78 nsIFrame
* aPrevInFlow
) MOZ_OVERRIDE
;
80 NS_IMETHOD
DidReflow(nsPresContext
* aPresContext
,
81 const nsHTMLReflowState
* aReflowState
,
82 nsDidReflowStatus aStatus
) MOZ_OVERRIDE
;
83 virtual void DestroyFrom(nsIFrame
* aDestructRoot
) MOZ_OVERRIDE
;
85 virtual void BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
86 const nsRect
& aDirtyRect
,
87 const nsDisplayListSet
& aLists
) MOZ_OVERRIDE
;
89 virtual nsIFrame
* GetContentInsertionFrame() MOZ_OVERRIDE
;
92 * Get the "type" of the frame
94 * @see nsGkAtoms::scrollFrame
96 virtual nsIAtom
* GetType() const MOZ_OVERRIDE
;
98 virtual bool IsFrameOfType(uint32_t aFlags
) const MOZ_OVERRIDE
100 return nsHTMLScrollFrame::IsFrameOfType(aFlags
&
101 ~(nsIFrame::eReplaced
| nsIFrame::eReplacedContainsBlock
));
104 #ifdef DEBUG_FRAME_DUMP
105 NS_IMETHOD
GetFrameName(nsAString
& aResult
) const MOZ_OVERRIDE
;
108 // nsIFormControlFrame
109 virtual nsresult
SetFormProperty(nsIAtom
* aName
, const nsAString
& aValue
) MOZ_OVERRIDE
;
110 virtual void SetFocus(bool aOn
= true, bool aRepaint
= false) MOZ_OVERRIDE
;
112 virtual mozilla::ScrollbarStyles
GetScrollbarStyles() const MOZ_OVERRIDE
;
113 virtual bool ShouldPropagateComputedHeightToScrolledContent() const MOZ_OVERRIDE
;
115 // for accessibility purposes
117 virtual mozilla::a11y::AccType
AccessibleType() MOZ_OVERRIDE
;
120 // nsIListControlFrame
121 virtual void SetComboboxFrame(nsIFrame
* aComboboxFrame
) MOZ_OVERRIDE
;
122 virtual int32_t GetSelectedIndex() MOZ_OVERRIDE
;
123 virtual mozilla::dom::HTMLOptionElement
* GetCurrentOption() MOZ_OVERRIDE
;
126 * Gets the text of the currently selected item.
127 * If the there are zero items then an empty string is returned
128 * If there is nothing selected, then the 0th item's text is returned.
130 virtual void GetOptionText(uint32_t aIndex
, nsAString
& aStr
) MOZ_OVERRIDE
;
132 virtual void CaptureMouseEvents(bool aGrabMouseEvents
) MOZ_OVERRIDE
;
133 virtual nscoord
GetHeightOfARow() MOZ_OVERRIDE
;
134 virtual uint32_t GetNumberOfOptions() MOZ_OVERRIDE
;
135 virtual void AboutToDropDown() MOZ_OVERRIDE
;
138 * @note This method might destroy the frame, pres shell and other objects.
140 virtual void AboutToRollup() MOZ_OVERRIDE
;
143 * Dispatch a DOM onchange event synchroniously.
144 * @note This method might destroy the frame, pres shell and other objects.
146 virtual void FireOnChange() MOZ_OVERRIDE
;
149 * Makes aIndex the selected option of a combobox list.
150 * @note This method might destroy the frame, pres shell and other objects.
152 virtual void ComboboxFinish(int32_t aIndex
) MOZ_OVERRIDE
;
153 virtual void OnContentReset() MOZ_OVERRIDE
;
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
;
161 * Gets the content (an option) by index and then set it as
162 * being selected or not selected.
164 NS_IMETHOD
OnOptionSelected(int32_t aIndex
, bool aSelected
) MOZ_OVERRIDE
;
165 NS_IMETHOD
OnSetSelectedIndex(int32_t aOldIndex
, int32_t aNewIndex
) MOZ_OVERRIDE
;
168 * Mouse event listeners.
169 * @note These methods might destroy the frame, pres shell and other objects.
171 nsresult
MouseDown(nsIDOMEvent
* aMouseEvent
);
172 nsresult
MouseUp(nsIDOMEvent
* aMouseEvent
);
173 nsresult
MouseMove(nsIDOMEvent
* aMouseEvent
);
174 nsresult
DragMove(nsIDOMEvent
* aMouseEvent
);
175 nsresult
KeyDown(nsIDOMEvent
* aKeyEvent
);
176 nsresult
KeyPress(nsIDOMEvent
* aKeyEvent
);
179 * Returns the options collection for mContent, if any.
181 mozilla::dom::HTMLOptionsCollection
* GetOptions() const;
183 * Returns the HTMLOptionElement for a given index in mContent's collection.
185 mozilla::dom::HTMLOptionElement
* GetOption(uint32_t aIndex
) const;
187 static void ComboboxFocusSet();
190 bool IsFocused() { return this == mFocused
; }
193 * Function to paint the focus rect when our nsSelectsAreaFrame is painting.
194 * @param aPt the offset of this frame, relative to the rendering reference
197 void PaintFocus(nsRenderingContext
& aRC
, nsPoint aPt
);
199 * If this frame IsFocused(), invalidates an area that includes anything
200 * that PaintFocus will or could have painted --- basically the whole
201 * GetOptionsContainer, plus some extra stuff if there are no options. This
202 * must be called every time mEndSelectionIndex changes.
204 void InvalidateFocus();
207 * Function to calculate the height a row, for use with the "size" attribute.
208 * Can't be const because GetNumberOfOptions() isn't const.
210 nscoord
CalcHeightOfARow();
213 * Function to ask whether we're currently in what might be the
214 * first pass of a two-pass reflow.
216 bool MightNeedSecondPass() const {
217 return mMightNeedSecondPass
;
220 void SetSuppressScrollbarUpdate(bool aSuppress
) {
221 nsHTMLScrollFrame::SetSuppressScrollbarUpdate(aSuppress
);
225 * Return whether the list is in dropdown mode.
227 bool IsInDropDownMode() const;
230 * Return the number of displayed rows in the list.
232 uint32_t GetNumDisplayRows() const { return mNumDisplayRows
; }
235 * Return true if the drop-down list can display more rows.
236 * (always false if not in drop-down mode)
238 bool GetDropdownCanGrow() const { return mDropdownCanGrow
; }
241 * Dropdowns need views
243 virtual bool NeedsView() MOZ_OVERRIDE
{ return IsInDropDownMode(); }
246 * Frees statics owned by this class.
248 static void Shutdown();
252 * Post a custom DOM event for the change, so that accessibility can
253 * fire a native focus event for accessibility
254 * (Some 3rd party products need to track our focus)
256 void FireMenuItemActiveEvent(); // Inform assistive tech what got focused
261 * Updates the selected text in a combobox and then calls FireOnChange().
262 * @note This method might destroy the frame, pres shell and other objects.
263 * Returns false if calling it destroyed |this|.
265 bool UpdateSelection();
268 * Returns whether mContent supports multiple selection.
270 bool GetMultiple() const {
271 return mContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::multiple
);
276 * Toggles (show/hide) the combobox dropdown menu.
277 * @note This method might destroy the frame, pres shell and other objects.
279 void DropDownToggleKey(nsIDOMEvent
* aKeyEvent
);
281 nsresult
IsOptionDisabled(int32_t anIndex
, bool &aIsDisabled
);
283 * @note This method might destroy the frame, pres shell and other objects.
285 void ScrollToFrame(mozilla::dom::HTMLOptionElement
& aOptElement
);
287 * @note This method might destroy the frame, pres shell and other objects.
289 void ScrollToIndex(int32_t anIndex
);
292 * When the user clicks on the comboboxframe to show the dropdown
293 * listbox, they then have to move the mouse into the list. We don't
294 * want to process those mouse events as selection events (i.e., to
295 * scroll list items into view). So we ignore the events until
296 * the mouse moves below our border-inner-edge, when
297 * mItemSelectionStarted is set.
299 * @param aPoint relative to this frame
301 bool IgnoreMouseEventForSelection(nsIDOMEvent
* aEvent
);
304 * If the dropdown is showing and the mouse has moved below our
305 * border-inner-edge, then set mItemSelectionStarted.
307 void UpdateInListState(nsIDOMEvent
* aEvent
);
308 void AdjustIndexForDisabledOpt(int32_t aStartIndex
, int32_t &anNewIndex
,
309 int32_t aNumOptions
, int32_t aDoAdjustInc
, int32_t aDoAdjustIncNext
);
312 * Resets the select back to it's original default values;
313 * those values as determined by the original HTML
315 virtual void ResetList(bool aAllowScrolling
);
317 nsListControlFrame(nsIPresShell
* aShell
, nsIDocument
* aDocument
, nsStyleContext
* aContext
);
318 virtual ~nsListControlFrame();
321 * Sets the mSelectedIndex and mOldSelectedIndex from figuring out what
322 * item was selected using content
323 * @param aPoint the event point, in listcontrolframe coordinates
324 * @return NS_OK if it successfully found the selection
326 nsresult
GetIndexFromDOMEvent(nsIDOMEvent
* aMouseEvent
, int32_t& aCurIndex
);
328 bool CheckIfAllFramesHere();
329 bool IsLeftButton(nsIDOMEvent
* aMouseEvent
);
331 // guess at a row height based on our own style.
332 nscoord
CalcFallbackRowHeight(float aFontSizeInflation
);
334 // CalcIntrinsicHeight computes our intrinsic height (taking the "size"
335 // attribute into account). This should only be called in non-dropdown mode.
336 nscoord
CalcIntrinsicHeight(nscoord aHeightOfARow
, int32_t aNumberOfOptions
);
338 // Dropped down stuff
339 void SetComboboxItem(int32_t aIndex
);
342 * Method to reflow ourselves as a dropdown list. This differs from
343 * reflow as a listbox because the criteria for needing a second
344 * pass are different. This will be called from Reflow() as needed.
346 nsresult
ReflowAsDropdown(nsPresContext
* aPresContext
,
347 nsHTMLReflowMetrics
& aDesiredSize
,
348 const nsHTMLReflowState
& aReflowState
,
349 nsReflowStatus
& aStatus
);
352 bool SetOptionsSelectedFromFrame(int32_t aStartIndex
,
356 bool ToggleOptionSelectedFromFrame(int32_t aIndex
);
358 * @note This method might destroy the frame, pres shell and other objects.
360 bool SingleSelection(int32_t aClickedIndex
, bool aDoToggle
);
361 bool ExtendedSelection(int32_t aStartIndex
, int32_t aEndIndex
,
364 * @note This method might destroy the frame, pres shell and other objects.
366 bool PerformSelection(int32_t aClickedIndex
, bool aIsShift
,
369 * @note This method might destroy the frame, pres shell and other objects.
371 bool HandleListSelection(nsIDOMEvent
* aDOMEvent
, int32_t selectedIndex
);
372 void InitSelectionRange(int32_t aClickedIndex
);
373 void PostHandleKeyEvent(int32_t aNewIndex
, uint32_t aCharCode
,
374 bool aIsShift
, bool aIsControlOrMeta
);
377 nsSelectsAreaFrame
* GetOptionsContainer() const {
378 return static_cast<nsSelectsAreaFrame
*>(GetScrolledFrame());
382 nscoord
HeightOfARow() {
383 return GetOptionsContainer()->HeightOfARow();
387 * @return how many displayable options/optgroups this frame has.
389 uint32_t GetNumberOfRows();
392 int32_t mStartSelectionIndex
;
393 int32_t mEndSelectionIndex
;
395 nsIComboboxControlFrame
*mComboboxFrame
;
396 uint32_t mNumDisplayRows
;
397 bool mChangesSinceDragStart
:1;
399 // Has the user selected a visible item since we showed the
401 bool mItemSelectionStarted
:1;
403 bool mIsAllContentHere
:1;
404 bool mIsAllFramesHere
:1;
405 bool mHasBeenInitialized
:1;
407 bool mPostChildrenLoadedReset
:1;
409 //bool value for multiple discontiguous selection
410 bool mControlSelectMode
:1;
412 // True if we're in the middle of a reflow and might need a second
413 // pass. This only happens for auto heights.
414 bool mMightNeedSecondPass
:1;
417 * Set to aPresContext->HasPendingInterrupt() at the start of Reflow.
418 * Set to false at the end of DidReflow.
420 bool mHasPendingInterruptAtStartOfReflow
:1;
422 // True if the drop-down can show more rows. Always false if this list
423 // is not in drop-down mode.
424 bool mDropdownCanGrow
:1;
426 // The last computed height we reflowed at if we're a combobox dropdown.
427 // XXXbz should we be using a subclass here? Or just not worry
428 // about the extra member on listboxes?
429 nscoord mLastDropdownComputedHeight
;
431 // At the time of our last dropdown, the backstop color to draw in case we
433 nscolor mLastDropdownBackstopColor
;
435 nsRefPtr
<nsListEventListener
> mEventListener
;
437 static nsListControlFrame
* mFocused
;
438 static nsString
* sIncrementalString
;
440 #ifdef DO_REFLOW_COUNTER
445 // for incremental typing navigation
446 static nsAString
& GetIncrementalString ();
447 static DOMTimeStamp gLastKeyTime
;
450 #endif /* nsListControlFrame_h___ */