1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef nsListControlFrame_h___
7 #define nsListControlFrame_h___
14 //#define DO_REFLOW_DEBUG
15 //#define DO_REFLOW_COUNTER
16 //#define DO_UNCONSTRAINED_CHECK
20 #include "mozilla/Attributes.h"
21 #include "mozilla/StaticPtr.h"
22 #include "nsGfxScrollFrame.h"
23 #include "nsIFormControlFrame.h"
24 #include "nsISelectControlFrame.h"
25 #include "nsSelectsAreaFrame.h"
27 class nsComboboxControlFrame
;
32 class HTMLSelectEventListener
;
36 class HTMLOptionElement
;
37 class HTMLSelectElement
;
38 class HTMLOptionsCollection
;
40 } // namespace mozilla
43 * Frame-based listbox.
46 class nsListControlFrame final
: public nsHTMLScrollFrame
,
47 public nsIFormControlFrame
,
48 public nsISelectControlFrame
{
50 typedef mozilla::dom::HTMLOptionElement HTMLOptionElement
;
52 friend nsListControlFrame
* NS_NewListControlFrame(
53 mozilla::PresShell
* aPresShell
, ComputedStyle
* aStyle
);
56 NS_DECL_FRAMEARENA_HELPERS(nsListControlFrame
)
59 nsresult
HandleEvent(nsPresContext
* aPresContext
,
60 mozilla::WidgetGUIEvent
* aEvent
,
61 nsEventStatus
* aEventStatus
) final
;
63 void SetInitialChildList(ChildListID aListID
, nsFrameList
& aChildList
) final
;
65 nscoord
GetPrefISize(gfxContext
* aRenderingContext
) final
;
66 nscoord
GetMinISize(gfxContext
* aRenderingContext
) final
;
68 void Reflow(nsPresContext
* aCX
, ReflowOutput
& aDesiredSize
,
69 const ReflowInput
& aReflowInput
, nsReflowStatus
& aStatus
) final
;
71 void Init(nsIContent
* aContent
, nsContainerFrame
* aParent
,
72 nsIFrame
* aPrevInFlow
) final
;
74 MOZ_CAN_RUN_SCRIPT_BOUNDARY
75 void DidReflow(nsPresContext
* aPresContext
,
76 const ReflowInput
* aReflowInput
) final
;
77 void DestroyFrom(nsIFrame
* aDestructRoot
,
78 PostDestroyData
& aPostDestroyData
) final
;
80 void BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
81 const nsDisplayListSet
& aLists
) final
;
83 nsContainerFrame
* GetContentInsertionFrame() final
;
85 int32_t GetEndSelectionIndex() const { return mEndSelectionIndex
; }
87 mozilla::dom::HTMLOptionElement
* GetCurrentOption() const;
89 bool IsFrameOfType(uint32_t aFlags
) const final
{
90 return nsHTMLScrollFrame::IsFrameOfType(
91 aFlags
& ~(nsIFrame::eReplaced
| nsIFrame::eReplacedContainsBlock
));
94 #ifdef DEBUG_FRAME_DUMP
95 nsresult
GetFrameName(nsAString
& aResult
) const final
;
98 // nsIFormControlFrame
99 nsresult
SetFormProperty(nsAtom
* aName
, const nsAString
& aValue
) final
;
100 MOZ_CAN_RUN_SCRIPT_BOUNDARY
101 void SetFocus(bool aOn
= true, bool aRepaint
= false) final
;
103 mozilla::ScrollStyles
GetScrollStyles() const final
;
104 bool ShouldPropagateComputedBSizeToScrolledContent() const final
;
106 // for accessibility purposes
108 mozilla::a11y::AccType
AccessibleType() final
;
111 int32_t GetSelectedIndex();
114 * Gets the text of the currently selected item.
115 * If the there are zero items then an empty string is returned
116 * If there is nothing selected, then the 0th item's text is returned.
118 void GetOptionText(uint32_t aIndex
, nsAString
& aStr
);
120 void CaptureMouseEvents(bool aGrabMouseEvents
);
121 nscoord
GetBSizeOfARow();
122 uint32_t GetNumberOfOptions();
124 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void OnContentReset();
126 // nsISelectControlFrame
127 NS_IMETHOD
AddOption(int32_t index
) final
;
128 NS_IMETHOD
RemoveOption(int32_t index
) final
;
129 MOZ_CAN_RUN_SCRIPT_BOUNDARY
130 NS_IMETHOD
DoneAddingChildren(bool aIsDone
) final
;
133 * Gets the content (an option) by index and then set it as
134 * being selected or not selected.
136 MOZ_CAN_RUN_SCRIPT_BOUNDARY
137 NS_IMETHOD
OnOptionSelected(int32_t aIndex
, bool aSelected
) final
;
138 MOZ_CAN_RUN_SCRIPT_BOUNDARY
140 OnSetSelectedIndex(int32_t aOldIndex
, int32_t aNewIndex
) final
;
143 * Mouse event listeners.
144 * @note These methods might destroy the frame, pres shell and other objects.
147 nsresult
HandleLeftButtonMouseDown(mozilla::dom::Event
* aMouseEvent
);
149 nsresult
HandleLeftButtonMouseUp(mozilla::dom::Event
* aMouseEvent
);
151 nsresult
DragMove(mozilla::dom::Event
* aMouseEvent
);
155 bool PerformSelection(int32_t aClickedIndex
, bool aIsShift
, bool aIsControl
);
157 void UpdateSelectionAfterKeyEvent(int32_t aNewIndex
, uint32_t aCharCode
,
158 bool aIsShift
, bool aIsControlOrMeta
,
159 bool aIsControlSelectMode
);
162 * Returns the options collection for mContent, if any.
164 mozilla::dom::HTMLOptionsCollection
* GetOptions() const;
166 * Returns the HTMLOptionElement for a given index in mContent's collection.
168 HTMLOptionElement
* GetOption(uint32_t aIndex
) const;
171 bool IsFocused() { return this == mFocused
; }
174 * Function to paint the focus rect when our nsSelectsAreaFrame is painting.
175 * @param aPt the offset of this frame, relative to the rendering reference
178 void PaintFocus(mozilla::gfx::DrawTarget
* aDrawTarget
, nsPoint aPt
);
181 * If this frame IsFocused(), invalidates an area that includes anything
182 * that PaintFocus will or could have painted --- basically the whole
183 * GetOptionsContainer, plus some extra stuff if there are no options. This
184 * must be called every time mEndSelectionIndex changes.
186 void InvalidateFocus();
189 * Function to calculate the block size of a row, for use with the
191 * Can't be const because GetNumberOfOptions() isn't const.
193 nscoord
CalcBSizeOfARow();
196 * Function to ask whether we're currently in what might be the
197 * first pass of a two-pass reflow.
199 bool MightNeedSecondPass() const { return mMightNeedSecondPass
; }
201 void SetSuppressScrollbarUpdate(bool aSuppress
) {
202 nsHTMLScrollFrame::SetSuppressScrollbarUpdate(aSuppress
);
206 * Return the number of displayed rows in the list.
208 uint32_t GetNumDisplayRows() const { return mNumDisplayRows
; }
212 * Post a custom DOM event for the change, so that accessibility can
213 * fire a native focus event for accessibility
214 * (Some 3rd party products need to track our focus)
216 void FireMenuItemActiveEvent(
217 nsIContent
* aPreviousOption
); // Inform assistive tech what got focused
222 * Updates the selected text in a combobox and then calls FireOnChange().
223 * @note This method might destroy the frame, pres shell and other objects.
224 * Returns false if calling it destroyed |this|.
227 bool UpdateSelection();
230 * Returns whether mContent supports multiple selection.
232 bool GetMultiple() const {
233 return mContent
->AsElement()->HasAttr(kNameSpaceID_None
,
234 nsGkAtoms::multiple
);
237 mozilla::dom::HTMLSelectElement
& Select() const;
240 * @return true if the <option> at aIndex is selectable by the user.
242 bool IsOptionInteractivelySelectable(int32_t aIndex
) const;
244 * @return true if aOption in aSelect is selectable by the user.
246 static bool IsOptionInteractivelySelectable(
247 mozilla::dom::HTMLSelectElement
* aSelect
,
248 mozilla::dom::HTMLOptionElement
* aOption
);
250 MOZ_CAN_RUN_SCRIPT
void ScrollToFrame(HTMLOptionElement
& aOptElement
);
252 MOZ_CAN_RUN_SCRIPT
void ScrollToIndex(int32_t anIndex
);
255 * Resets the select back to it's original default values;
256 * those values as determined by the original HTML
258 MOZ_CAN_RUN_SCRIPT
void ResetList(bool aAllowScrolling
);
260 explicit nsListControlFrame(ComputedStyle
* aStyle
,
261 nsPresContext
* aPresContext
);
262 virtual ~nsListControlFrame();
265 * Sets the mSelectedIndex and mOldSelectedIndex from figuring out what
266 * item was selected using content
267 * @param aPoint the event point, in listcontrolframe coordinates
268 * @return NS_OK if it successfully found the selection
270 nsresult
GetIndexFromDOMEvent(mozilla::dom::Event
* aMouseEvent
,
273 bool CheckIfAllFramesHere();
275 // guess at a row block size based on our own style.
276 nscoord
CalcFallbackRowBSize(float aFontSizeInflation
);
278 // CalcIntrinsicBSize computes our intrinsic block size (taking the
279 // "size" attribute into account). This should only be called in
280 // non-dropdown mode.
281 nscoord
CalcIntrinsicBSize(nscoord aBSizeOfARow
, int32_t aNumberOfOptions
);
283 // Dropped down stuff
284 void SetComboboxItem(int32_t aIndex
);
287 bool SetOptionsSelectedFromFrame(int32_t aStartIndex
, int32_t aEndIndex
,
288 bool aValue
, bool aClearAll
);
289 bool ToggleOptionSelectedFromFrame(int32_t aIndex
);
292 bool SingleSelection(int32_t aClickedIndex
, bool aDoToggle
);
293 bool ExtendedSelection(int32_t aStartIndex
, int32_t aEndIndex
,
296 bool HandleListSelection(mozilla::dom::Event
* aDOMEvent
,
297 int32_t selectedIndex
);
298 void InitSelectionRange(int32_t aClickedIndex
);
301 nsSelectsAreaFrame
* GetOptionsContainer() const {
302 return static_cast<nsSelectsAreaFrame
*>(GetScrolledFrame());
305 static constexpr int32_t kNothingSelected
= -1;
308 nscoord
BSizeOfARow() { return GetOptionsContainer()->BSizeOfARow(); }
311 * @return how many displayable options/optgroups this frame has.
313 uint32_t GetNumberOfRows();
316 int32_t mStartSelectionIndex
;
317 int32_t mEndSelectionIndex
;
319 uint32_t mNumDisplayRows
;
320 bool mChangesSinceDragStart
: 1;
322 // Has the user selected a visible item since we showed the dropdown?
323 bool mItemSelectionStarted
: 1;
325 bool mIsAllContentHere
: 1;
326 bool mIsAllFramesHere
: 1;
327 bool mHasBeenInitialized
: 1;
328 bool mNeedToReset
: 1;
329 bool mPostChildrenLoadedReset
: 1;
331 // True if we're in the middle of a reflow and might need a second
332 // pass. This only happens for auto heights.
333 bool mMightNeedSecondPass
: 1;
336 * Set to aPresContext->HasPendingInterrupt() at the start of Reflow.
337 * Set to false at the end of DidReflow.
339 bool mHasPendingInterruptAtStartOfReflow
: 1;
341 // True if the selection can be set to nothing or disabled options.
342 bool mForceSelection
: 1;
344 // The last computed block size we reflowed at if we're a combobox
346 // XXXbz should we be using a subclass here? Or just not worry
347 // about the extra member on listboxes?
348 nscoord mLastDropdownComputedBSize
;
350 // At the time of our last dropdown, the backstop color to draw in case we
352 nscolor mLastDropdownBackstopColor
;
354 RefPtr
<mozilla::HTMLSelectEventListener
> mEventListener
;
356 static nsListControlFrame
* mFocused
;
358 #ifdef DO_REFLOW_COUNTER
363 #endif /* nsListControlFrame_h___ */