nsScrollbarButtonFrame.cpp (6771B)
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 7 // 8 // Eric Vaughan 9 // Netscape Communications 10 // 11 // See documentation in associated header file 12 // 13 14 #include "nsScrollbarButtonFrame.h" 15 16 #include "mozilla/LookAndFeel.h" 17 #include "mozilla/MouseEvents.h" 18 #include "mozilla/PresShell.h" 19 #include "nsCOMPtr.h" 20 #include "nsGkAtoms.h" 21 #include "nsIContent.h" 22 #include "nsIScrollbarMediator.h" 23 #include "nsLayoutUtils.h" 24 #include "nsNameSpaceManager.h" 25 #include "nsPresContext.h" 26 #include "nsRepeatService.h" 27 #include "nsScrollbarFrame.h" 28 #include "nsSliderFrame.h" 29 30 using namespace mozilla; 31 32 // 33 // NS_NewToolbarFrame 34 // 35 // Creates a new Toolbar frame and returns it 36 // 37 nsIFrame* NS_NewScrollbarButtonFrame(PresShell* aPresShell, 38 ComputedStyle* aStyle) { 39 return new (aPresShell) 40 nsScrollbarButtonFrame(aStyle, aPresShell->GetPresContext()); 41 } 42 NS_IMPL_FRAMEARENA_HELPERS(nsScrollbarButtonFrame) 43 44 nsresult nsScrollbarButtonFrame::HandleEvent(nsPresContext* aPresContext, 45 WidgetGUIEvent* aEvent, 46 nsEventStatus* aEventStatus) { 47 NS_ENSURE_ARG_POINTER(aEventStatus); 48 49 // If a web page calls event.preventDefault() we still want to 50 // scroll when scroll arrow is clicked. See bug 511075. 51 if (!mContent->IsInNativeAnonymousSubtree() && 52 nsEventStatus_eConsumeNoDefault == *aEventStatus) { 53 return NS_OK; 54 } 55 56 switch (aEvent->mMessage) { 57 case eMouseDown: 58 mCursorOnThis = true; 59 // if we didn't handle the press ourselves, pass it on to the superclass 60 if (HandleButtonPress(aPresContext, aEvent, aEventStatus)) { 61 return NS_OK; 62 } 63 break; 64 case eMouseUp: 65 HandleRelease(aPresContext, aEvent, aEventStatus); 66 break; 67 case eMouseOut: 68 mCursorOnThis = false; 69 break; 70 case eMouseMove: { 71 nsPoint cursor = nsLayoutUtils::GetEventCoordinatesRelativeTo( 72 aEvent, RelativeTo{this}); 73 nsRect frameRect(nsPoint(0, 0), GetSize()); 74 mCursorOnThis = frameRect.Contains(cursor); 75 break; 76 } 77 default: 78 break; 79 } 80 81 return SimpleXULLeafFrame::HandleEvent(aPresContext, aEvent, aEventStatus); 82 } 83 84 bool nsScrollbarButtonFrame::HandleButtonPress(nsPresContext* aPresContext, 85 WidgetGUIEvent* aEvent, 86 nsEventStatus* aEventStatus) { 87 // Get the desired action for the scrollbar button. 88 LookAndFeel::IntID tmpAction; 89 uint16_t button = aEvent->AsMouseEvent()->mButton; 90 if (button == MouseButton::ePrimary) { 91 tmpAction = LookAndFeel::IntID::ScrollButtonLeftMouseButtonAction; 92 } else if (button == MouseButton::eMiddle) { 93 tmpAction = LookAndFeel::IntID::ScrollButtonMiddleMouseButtonAction; 94 } else if (button == MouseButton::eSecondary) { 95 tmpAction = LookAndFeel::IntID::ScrollButtonRightMouseButtonAction; 96 } else { 97 return false; 98 } 99 100 // Get the button action metric from the pres. shell. 101 int32_t pressedButtonAction; 102 if (NS_FAILED(LookAndFeel::GetInt(tmpAction, &pressedButtonAction))) { 103 return false; 104 } 105 106 // get the scrollbar control 107 nsScrollbarFrame* scrollbar = GetScrollbar(); 108 if (!scrollbar) { 109 return false; 110 } 111 112 static dom::Element::AttrValuesArray strings[] = { 113 nsGkAtoms::increment, nsGkAtoms::decrement, nullptr}; 114 int32_t index = mContent->AsElement()->FindAttrValueIn( 115 kNameSpaceID_None, nsGkAtoms::type, strings, eCaseMatters); 116 int32_t direction; 117 if (index == 0) { 118 direction = 1; 119 } else if (index == 1) { 120 direction = -1; 121 } else { 122 return false; 123 } 124 125 const bool repeat = pressedButtonAction != 2; 126 127 PresShell::SetCapturingContent(mContent, CaptureFlags::IgnoreAllowedState); 128 129 AutoWeakFrame weakFrame(this); 130 131 nsIScrollbarMediator* m = scrollbar->GetScrollbarMediator(); 132 switch (pressedButtonAction) { 133 case 0: 134 scrollbar->SetButtonScrollDirectionAndUnit(direction, ScrollUnit::LINES); 135 if (m) { 136 m->ScrollByLine(scrollbar, direction, 137 ScrollSnapFlags::IntendedDirection); 138 } 139 break; 140 case 1: 141 scrollbar->SetButtonScrollDirectionAndUnit(direction, ScrollUnit::PAGES); 142 if (m) { 143 m->ScrollByPage(scrollbar, direction, 144 ScrollSnapFlags::IntendedDirection | 145 ScrollSnapFlags::IntendedEndPosition); 146 } 147 break; 148 case 2: 149 scrollbar->SetButtonScrollDirectionAndUnit(direction, ScrollUnit::WHOLE); 150 if (m) { 151 m->ScrollByWhole(scrollbar, direction, 152 ScrollSnapFlags::IntendedEndPosition); 153 } 154 break; 155 case 3: 156 default: 157 // We were told to ignore this click, or someone assigned a non-standard 158 // value to the button's action. 159 return false; 160 } 161 if (!weakFrame.IsAlive()) { 162 return false; 163 } 164 if (repeat) { 165 StartRepeat(); 166 } 167 return true; 168 } 169 170 NS_IMETHODIMP 171 nsScrollbarButtonFrame::HandleRelease(nsPresContext* aPresContext, 172 WidgetGUIEvent* aEvent, 173 nsEventStatus* aEventStatus) { 174 PresShell::ReleaseCapturingContent(); 175 StopRepeat(); 176 if (nsScrollbarFrame* scrollbar = GetScrollbar()) { 177 if (nsIScrollbarMediator* m = scrollbar->GetScrollbarMediator()) { 178 m->ScrollbarReleased(scrollbar); 179 } 180 } 181 return NS_OK; 182 } 183 184 void nsScrollbarButtonFrame::Notify() { 185 if (mCursorOnThis || 186 LookAndFeel::GetInt(LookAndFeel::IntID::ScrollbarButtonAutoRepeatBehavior, 187 0)) { 188 // get the scrollbar control 189 if (nsScrollbarFrame* sb = GetScrollbar()) { 190 if (nsIScrollbarMediator* m = sb->GetScrollbarMediator()) { 191 m->RepeatButtonScroll(sb); 192 } 193 } 194 } 195 } 196 197 nsIScrollbarMediator* nsScrollbarButtonFrame::GetMediator() { 198 if (auto* sb = GetScrollbar()) { 199 return sb->GetScrollbarMediator(); 200 } 201 return nullptr; 202 } 203 204 nsScrollbarFrame* nsScrollbarButtonFrame::GetScrollbar() { 205 for (nsIFrame* cur = GetParent(); cur; cur = cur->GetParent()) { 206 if (cur->IsScrollbarFrame()) { 207 return static_cast<nsScrollbarFrame*>(cur); 208 } 209 } 210 return nullptr; 211 } 212 213 void nsScrollbarButtonFrame::Destroy(DestroyContext& aContext) { 214 // Ensure our repeat service isn't going... it's possible that a scrollbar can 215 // disappear out from under you while you're in the process of scrolling. 216 StopRepeat(); 217 SimpleXULLeafFrame::Destroy(aContext); 218 }