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/. */
8 // Netscape Communications
10 // See documentation in associated header file
13 #include "nsScrollbarButtonFrame.h"
14 #include "nsPresContext.h"
15 #include "nsIContent.h"
17 #include "nsNameSpaceManager.h"
18 #include "nsGkAtoms.h"
19 #include "nsSliderFrame.h"
20 #include "nsScrollbarFrame.h"
21 #include "nsIScrollbarMediator.h"
22 #include "nsRepeatService.h"
23 #include "mozilla/LookAndFeel.h"
24 #include "mozilla/MouseEvents.h"
26 using namespace mozilla
;
31 // Creates a new Toolbar frame and returns it
34 NS_NewScrollbarButtonFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
36 return new (aPresShell
) nsScrollbarButtonFrame(aContext
);
39 NS_IMPL_FRAMEARENA_HELPERS(nsScrollbarButtonFrame
)
42 nsScrollbarButtonFrame::HandleEvent(nsPresContext
* aPresContext
,
43 WidgetGUIEvent
* aEvent
,
44 nsEventStatus
* aEventStatus
)
46 NS_ENSURE_ARG_POINTER(aEventStatus
);
48 // If a web page calls event.preventDefault() we still want to
49 // scroll when scroll arrow is clicked. See bug 511075.
50 if (!mContent
->IsInNativeAnonymousSubtree() &&
51 nsEventStatus_eConsumeNoDefault
== *aEventStatus
) {
55 switch (aEvent
->message
) {
56 case NS_MOUSE_BUTTON_DOWN
:
58 // if we didn't handle the press ourselves, pass it on to the superclass
59 if (HandleButtonPress(aPresContext
, aEvent
, aEventStatus
)) {
63 case NS_MOUSE_BUTTON_UP
:
64 HandleRelease(aPresContext
, aEvent
, aEventStatus
);
66 case NS_MOUSE_EXIT_SYNTH
:
67 mCursorOnThis
= false;
71 nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent
, this);
72 nsRect
frameRect(nsPoint(0, 0), GetSize());
73 mCursorOnThis
= frameRect
.Contains(cursor
);
78 return nsButtonBoxFrame::HandleEvent(aPresContext
, aEvent
, aEventStatus
);
82 nsScrollbarButtonFrame::HandleButtonPress(nsPresContext
* aPresContext
,
83 WidgetGUIEvent
* aEvent
,
84 nsEventStatus
* aEventStatus
)
86 // Get the desired action for the scrollbar button.
87 LookAndFeel::IntID tmpAction
;
88 uint16_t button
= aEvent
->AsMouseEvent()->button
;
89 if (button
== WidgetMouseEvent::eLeftButton
) {
90 tmpAction
= LookAndFeel::eIntID_ScrollButtonLeftMouseButtonAction
;
91 } else if (button
== WidgetMouseEvent::eMiddleButton
) {
92 tmpAction
= LookAndFeel::eIntID_ScrollButtonMiddleMouseButtonAction
;
93 } else if (button
== WidgetMouseEvent::eRightButton
) {
94 tmpAction
= LookAndFeel::eIntID_ScrollButtonRightMouseButtonAction
;
99 // Get the button action metric from the pres. shell.
100 int32_t pressedButtonAction
;
101 if (NS_FAILED(LookAndFeel::GetInt(tmpAction
, &pressedButtonAction
))) {
105 // get the scrollbar control
107 GetParentWithTag(nsGkAtoms::scrollbar
, this, scrollbar
);
109 if (scrollbar
== nullptr)
112 static nsIContent::AttrValuesArray strings
[] = { &nsGkAtoms::increment
,
113 &nsGkAtoms::decrement
,
115 int32_t index
= mContent
->FindAttrValueIn(kNameSpaceID_None
,
117 strings
, eCaseMatters
);
126 bool repeat
= pressedButtonAction
!= 2;
127 // set this attribute so we can style it later
128 nsWeakFrame
weakFrame(this);
129 mContent
->SetAttr(kNameSpaceID_None
, nsGkAtoms::active
, NS_LITERAL_STRING("true"), true);
131 nsIPresShell::SetCapturingContent(mContent
, CAPTURE_IGNOREALLOWED
);
133 if (!weakFrame
.IsAlive()) {
137 nsScrollbarFrame
* sb
= do_QueryFrame(scrollbar
);
139 nsIScrollbarMediator
* m
= sb
->GetScrollbarMediator();
140 switch (pressedButtonAction
) {
142 sb
->SetIncrementToLine(direction
);
144 m
->ScrollByLine(sb
, direction
);
148 sb
->SetIncrementToPage(direction
);
150 m
->ScrollByPage(sb
, direction
);
154 sb
->SetIncrementToWhole(direction
);
156 m
->ScrollByWhole(sb
, direction
);
161 // We were told to ignore this click, or someone assigned a non-standard
162 // value to the button's action.
165 if (!weakFrame
.IsAlive()) {
169 sb
->MoveToNewPosition();
170 if (!weakFrame
.IsAlive()) {
182 nsScrollbarButtonFrame::HandleRelease(nsPresContext
* aPresContext
,
183 WidgetGUIEvent
* aEvent
,
184 nsEventStatus
* aEventStatus
)
186 nsIPresShell::SetCapturingContent(nullptr, 0);
187 // we're not active anymore
188 mContent
->UnsetAttr(kNameSpaceID_None
, nsGkAtoms::active
, true);
193 void nsScrollbarButtonFrame::Notify()
197 LookAndFeel::eIntID_ScrollbarButtonAutoRepeatBehavior
, 0)) {
198 // get the scrollbar control
200 GetParentWithTag(nsGkAtoms::scrollbar
, this, scrollbar
);
201 nsScrollbarFrame
* sb
= do_QueryFrame(scrollbar
);
203 nsIScrollbarMediator
* m
= sb
->GetScrollbarMediator();
205 m
->RepeatButtonScroll(sb
);
207 sb
->MoveToNewPosition();
214 nsScrollbarButtonFrame::MouseClicked(nsPresContext
* aPresContext
,
215 WidgetGUIEvent
* aEvent
)
217 nsButtonBoxFrame::MouseClicked(aPresContext
, aEvent
);
222 nsScrollbarButtonFrame::GetChildWithTag(nsPresContext
* aPresContext
,
223 nsIAtom
* atom
, nsIFrame
* start
,
226 // recursively search our children
227 nsIFrame
* childFrame
= start
->GetFirstPrincipalChild();
228 while (nullptr != childFrame
)
230 // get the content node
231 nsIContent
* child
= childFrame
->GetContent();
234 // see if it is the child
235 if (child
->Tag() == atom
)
243 // recursive search the child
244 GetChildWithTag(aPresContext
, atom
, childFrame
, result
);
245 if (result
!= nullptr)
248 childFrame
= childFrame
->GetNextSibling();
256 nsScrollbarButtonFrame::GetParentWithTag(nsIAtom
* toFind
, nsIFrame
* start
,
261 start
= start
->GetParent();
264 // get the content node
265 nsIContent
* child
= start
->GetContent();
267 if (child
&& child
->Tag() == toFind
) {
279 nsScrollbarButtonFrame::DestroyFrom(nsIFrame
* aDestructRoot
)
281 // Ensure our repeat service isn't going... it's possible that a scrollbar can disappear out
282 // from under you while you're in the process of scrolling.
284 nsButtonBoxFrame::DestroyFrom(aDestructRoot
);