1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsListControlFrame_h___
#define nsListControlFrame_h___
#include "mozilla/Attributes.h"
#include "mozilla/ScrollContainerFrame.h"
#include "mozilla/StaticPtr.h"
#include "nsISelectControlFrame.h"
#include "nsSelectsAreaFrame.h"
class nsComboboxControlFrame;
class nsPresContext;
namespace mozilla {
class PresShell;
class HTMLSelectEventListener;
namespace dom {
class Event;
class HTMLOptionElement;
class HTMLSelectElement;
class HTMLOptionsCollection;
} // namespace dom
} // namespace mozilla
/**
* Frame-based listbox.
*/
class nsListControlFrame final : public mozilla::ScrollContainerFrame,
public nsISelectControlFrame {
public:
using HTMLOptionElement = mozilla::dom::HTMLOptionElement;
friend nsListControlFrame* NS_NewListControlFrame(
mozilla::PresShell* aPresShell, ComputedStyle* aStyle);
NS_DECL_QUERYFRAME
NS_DECL_FRAMEARENA_HELPERS(nsListControlFrame)
Maybe<nscoord> GetNaturalBaselineBOffset(
mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup,
BaselineExportContext) const override;
// nsIFrame
nsresult HandleEvent(nsPresContext* aPresContext,
mozilla::WidgetGUIEvent* aEvent,
nsEventStatus* aEventStatus) final;
void SetInitialChildList(ChildListID aListID, nsFrameList&& aChildList) final;
nscoord IntrinsicISize(const mozilla::IntrinsicSizeInput& aInput,
mozilla::IntrinsicISizeType aType) final;
void Reflow(nsPresContext* aCX, ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput, nsReflowStatus& aStatus) final;
void Init(nsIContent* aContent, nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) final;
bool ReflowFinished() final;
void Destroy(DestroyContext&) override;
void BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) final;
nsContainerFrame* GetContentInsertionFrame() final;
int32_t GetEndSelectionIndex() const { return mEndSelectionIndex; }
mozilla::dom::HTMLOptionElement* GetCurrentOption() const;
#ifdef DEBUG_FRAME_DUMP
nsresult GetFrameName(nsAString& aResult) const final;
#endif
void ElementStateChanged(mozilla::dom::ElementState aStates) final;
bool ShouldPropagateComputedBSizeToScrolledContent() const final;
// for accessibility purposes
#ifdef ACCESSIBILITY
mozilla::a11y::AccType AccessibleType() final;
#endif
int32_t GetSelectedIndex();
/**
* Gets the text of the currently selected item.
* If the there are zero items then an empty string is returned
* If there is nothing selected, then the 0th item's text is returned.
*/
void GetOptionText(uint32_t aIndex, nsAString& aStr);
void CaptureMouseEvents(bool aGrabMouseEvents);
nscoord GetBSizeOfARow();
uint32_t GetNumberOfOptions();
MOZ_CAN_RUN_SCRIPT_BOUNDARY void OnContentReset();
// nsISelectControlFrame
NS_IMETHOD AddOption(int32_t index) final;
NS_IMETHOD RemoveOption(int32_t index) final;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
NS_IMETHOD DoneAddingChildren(bool aIsDone) final;
/**
* Gets the content (an option) by index and then set it as
* being selected or not selected.
*/
MOZ_CAN_RUN_SCRIPT_BOUNDARY
NS_IMETHOD OnOptionSelected(int32_t aIndex, bool aSelected) final;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
NS_IMETHOD_(void)
OnSetSelectedIndex(int32_t aOldIndex, int32_t aNewIndex) final;
/**
* Mouse event listeners.
* @note These methods might destroy the frame, pres shell and other objects.
*/
MOZ_CAN_RUN_SCRIPT
nsresult HandleLeftButtonMouseDown(mozilla::dom::Event* aMouseEvent);
MOZ_CAN_RUN_SCRIPT
nsresult HandleLeftButtonMouseUp(mozilla::dom::Event* aMouseEvent);
MOZ_CAN_RUN_SCRIPT
nsresult DragMove(mozilla::dom::Event* aMouseEvent);
MOZ_CAN_RUN_SCRIPT
MOZ_CAN_RUN_SCRIPT
bool PerformSelection(int32_t aClickedIndex, bool aIsShift, bool aIsControl);
MOZ_CAN_RUN_SCRIPT
void UpdateSelectionAfterKeyEvent(int32_t aNewIndex, uint32_t aCharCode,
bool aIsShift, bool aIsControlOrMeta,
bool aIsControlSelectMode);
/**
* Returns the options collection for mContent, if any.
*/
mozilla::dom::HTMLOptionsCollection* GetOptions() const;
/**
* Returns the HTMLOptionElement for a given index in mContent's collection.
*/
HTMLOptionElement* GetOption(uint32_t aIndex) const;
// Helper
bool IsFocused() const;
/**
* Function to paint the focus rect when our nsSelectsAreaFrame is painting.
* @param aPt the offset of this frame, relative to the rendering reference
* frame
*/
void PaintFocus(mozilla::gfx::DrawTarget* aDrawTarget, nsPoint aPt);
/**
* If this frame IsFocused(), invalidates an area that includes anything
* that PaintFocus will or could have painted --- basically the whole
* GetOptionsContainer, plus some extra stuff if there are no options. This
* must be called every time mEndSelectionIndex changes.
*/
void InvalidateFocus();
/**
* Function to calculate the block size of a row, for use with the
* "size" attribute.
* Can't be const because GetNumberOfOptions() isn't const.
*/
nscoord CalcBSizeOfARow();
/**
* Function to ask whether we're currently in what might be the
* first pass of a two-pass reflow.
*/
bool MightNeedSecondPass() const { return mMightNeedSecondPass; }
void SetSuppressScrollbarUpdate(bool aSuppress) {
ScrollContainerFrame::SetSuppressScrollbarUpdate(aSuppress);
}
/**
* Return the number of displayed rows in the list.
*/
uint32_t GetNumDisplayRows() const { return mNumDisplayRows; }
#ifdef ACCESSIBILITY
/**
* Post a custom DOM event for the change, so that accessibility can
* fire a native focus event for accessibility
* (Some 3rd party products need to track our focus)
*/
void FireMenuItemActiveEvent(
nsIContent* aPreviousOption); // Inform assistive tech what got focused
#endif
protected:
/**
* Updates the selected text in a combobox and then calls FireOnChange().
* @note This method might destroy the frame, pres shell and other objects.
* Returns false if calling it destroyed |this|.
*/
MOZ_CAN_RUN_SCRIPT
bool UpdateSelection();
/**
* Returns whether mContent supports multiple selection.
*/
bool GetMultiple() const;
mozilla::dom::HTMLSelectElement& Select() const;
/**
* @return true if the <option> at aIndex is selectable by the user.
*/
bool IsOptionInteractivelySelectable(int32_t aIndex) const;
/**
* @return true if aOption in aSelect is selectable by the user.
*/
static bool IsOptionInteractivelySelectable(
mozilla::dom::HTMLSelectElement* aSelect,
mozilla::dom::HTMLOptionElement* aOption);
MOZ_CAN_RUN_SCRIPT void ScrollToFrame(HTMLOptionElement& aOptElement);
MOZ_CAN_RUN_SCRIPT void ScrollToIndex(int32_t anIndex);
public:
/**
* Resets the select back to it's original default values;
* those values as determined by the original HTML
*/
MOZ_CAN_RUN_SCRIPT void ResetList(bool aAllowScrolling);
protected:
explicit nsListControlFrame(ComputedStyle* aStyle,
nsPresContext* aPresContext);
virtual ~nsListControlFrame();
/**
* Sets the mSelectedIndex and mOldSelectedIndex from figuring out what
* item was selected using content
* @param aPoint the event point, in listcontrolframe coordinates
* @return NS_OK if it successfully found the selection
*/
nsresult GetIndexFromDOMEvent(mozilla::dom::Event* aMouseEvent,
int32_t& aCurIndex);
bool CheckIfAllFramesHere();
// guess at a row block size based on our own style.
nscoord CalcFallbackRowBSize(float aFontSizeInflation);
// CalcIntrinsicBSize computes our intrinsic block size (taking the
// "size" attribute into account). This should only be called in
// non-dropdown mode.
nscoord CalcIntrinsicBSize(nscoord aBSizeOfARow, int32_t aNumberOfOptions);
// Dropped down stuff
void SetComboboxItem(int32_t aIndex);
// Selection
bool SetOptionsSelectedFromFrame(int32_t aStartIndex, int32_t aEndIndex,
bool aValue, bool aClearAll);
bool ToggleOptionSelectedFromFrame(int32_t aIndex);
MOZ_CAN_RUN_SCRIPT
bool SingleSelection(int32_t aClickedIndex, bool aDoToggle);
bool ExtendedSelection(int32_t aStartIndex, int32_t aEndIndex,
bool aClearAll);
MOZ_CAN_RUN_SCRIPT
bool HandleListSelection(mozilla::dom::Event* aDOMEvent,
int32_t selectedIndex);
void InitSelectionRange(int32_t aClickedIndex);
public:
nsSelectsAreaFrame* GetOptionsContainer() const {
return static_cast<nsSelectsAreaFrame*>(GetScrolledFrame());
}
static constexpr int32_t kNothingSelected = -1;
protected:
nscoord BSizeOfARow() { return GetOptionsContainer()->BSizeOfARow(); }
/**
* @return how many displayable options/optgroups this frame has.
*/
uint32_t GetNumberOfRows();
// Data Members
int32_t mStartSelectionIndex = 0;
int32_t mEndSelectionIndex = 0;
uint32_t mNumDisplayRows = 0;
bool mChangesSinceDragStart : 1;
// Has the user selected a visible item since we showed the dropdown?
bool mItemSelectionStarted : 1;
bool mIsAllContentHere : 1;
bool mIsAllFramesHere : 1;
bool mHasBeenInitialized : 1;
bool mNeedToReset : 1;
bool mPostChildrenLoadedReset : 1;
// True if we're in the middle of a reflow and might need a second
// pass. This only happens for auto heights.
bool mMightNeedSecondPass : 1;
// True if our reflow got interrupted.
bool mReflowWasInterrupted : 1;
RefPtr<mozilla::HTMLSelectEventListener> mEventListener;
static nsListControlFrame* sFocused;
};
#endif /* nsListControlFrame_h___ */
|