layout/xul/nsScrollbarButtonFrame.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/xul/nsScrollbarButtonFrame.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,316 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +//
    1.10 +// Eric Vaughan
    1.11 +// Netscape Communications
    1.12 +//
    1.13 +// See documentation in associated header file
    1.14 +//
    1.15 +
    1.16 +#include "nsScrollbarButtonFrame.h"
    1.17 +#include "nsPresContext.h"
    1.18 +#include "nsIContent.h"
    1.19 +#include "nsCOMPtr.h"
    1.20 +#include "nsNameSpaceManager.h"
    1.21 +#include "nsGkAtoms.h"
    1.22 +#include "nsSliderFrame.h"
    1.23 +#include "nsScrollbarFrame.h"
    1.24 +#include "nsIScrollbarMediator.h"
    1.25 +#include "nsRepeatService.h"
    1.26 +#include "mozilla/LookAndFeel.h"
    1.27 +#include "mozilla/MouseEvents.h"
    1.28 +
    1.29 +using namespace mozilla;
    1.30 +
    1.31 +//
    1.32 +// NS_NewToolbarFrame
    1.33 +//
    1.34 +// Creates a new Toolbar frame and returns it
    1.35 +//
    1.36 +nsIFrame*
    1.37 +NS_NewScrollbarButtonFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
    1.38 +{
    1.39 +  return new (aPresShell) nsScrollbarButtonFrame(aPresShell, aContext);
    1.40 +}
    1.41 +
    1.42 +NS_IMPL_FRAMEARENA_HELPERS(nsScrollbarButtonFrame)
    1.43 +
    1.44 +nsresult
    1.45 +nsScrollbarButtonFrame::HandleEvent(nsPresContext* aPresContext,
    1.46 +                                    WidgetGUIEvent* aEvent,
    1.47 +                                    nsEventStatus* aEventStatus)
    1.48 +{  
    1.49 +  NS_ENSURE_ARG_POINTER(aEventStatus);
    1.50 +
    1.51 +  // If a web page calls event.preventDefault() we still want to
    1.52 +  // scroll when scroll arrow is clicked. See bug 511075.
    1.53 +  if (!mContent->IsInNativeAnonymousSubtree() &&
    1.54 +      nsEventStatus_eConsumeNoDefault == *aEventStatus) {
    1.55 +    return NS_OK;
    1.56 +  }
    1.57 +
    1.58 +  switch (aEvent->message) {
    1.59 +    case NS_MOUSE_BUTTON_DOWN:
    1.60 +      mCursorOnThis = true;
    1.61 +      // if we didn't handle the press ourselves, pass it on to the superclass
    1.62 +      if (HandleButtonPress(aPresContext, aEvent, aEventStatus)) {
    1.63 +        return NS_OK;
    1.64 +      }
    1.65 +      break;
    1.66 +    case NS_MOUSE_BUTTON_UP:
    1.67 +      HandleRelease(aPresContext, aEvent, aEventStatus);
    1.68 +      break;
    1.69 +    case NS_MOUSE_EXIT_SYNTH:
    1.70 +      mCursorOnThis = false;
    1.71 +      break;
    1.72 +    case NS_MOUSE_MOVE: {
    1.73 +      nsPoint cursor =
    1.74 +        nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
    1.75 +      nsRect frameRect(nsPoint(0, 0), GetSize());
    1.76 +      mCursorOnThis = frameRect.Contains(cursor);
    1.77 +      break;
    1.78 +    }
    1.79 +  }
    1.80 +
    1.81 +  return nsButtonBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
    1.82 +}
    1.83 +
    1.84 +
    1.85 +bool
    1.86 +nsScrollbarButtonFrame::HandleButtonPress(nsPresContext* aPresContext,
    1.87 +                                          WidgetGUIEvent* aEvent,
    1.88 +                                          nsEventStatus* aEventStatus)
    1.89 +{
    1.90 +  // Get the desired action for the scrollbar button.
    1.91 +  LookAndFeel::IntID tmpAction;
    1.92 +  uint16_t button = aEvent->AsMouseEvent()->button;
    1.93 +  if (button == WidgetMouseEvent::eLeftButton) {
    1.94 +    tmpAction = LookAndFeel::eIntID_ScrollButtonLeftMouseButtonAction;
    1.95 +  } else if (button == WidgetMouseEvent::eMiddleButton) {
    1.96 +    tmpAction = LookAndFeel::eIntID_ScrollButtonMiddleMouseButtonAction;
    1.97 +  } else if (button == WidgetMouseEvent::eRightButton) {
    1.98 +    tmpAction = LookAndFeel::eIntID_ScrollButtonRightMouseButtonAction;
    1.99 +  } else {
   1.100 +    return false;
   1.101 +  }
   1.102 +
   1.103 +  // Get the button action metric from the pres. shell.
   1.104 +  int32_t pressedButtonAction;
   1.105 +  if (NS_FAILED(LookAndFeel::GetInt(tmpAction, &pressedButtonAction))) {
   1.106 +    return false;
   1.107 +  }
   1.108 +
   1.109 +  // get the scrollbar control
   1.110 +  nsIFrame* scrollbar;
   1.111 +  GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar);
   1.112 +
   1.113 +  if (scrollbar == nullptr)
   1.114 +    return false;
   1.115 +
   1.116 +  // get the scrollbars content node
   1.117 +  nsIContent* content = scrollbar->GetContent();
   1.118 +
   1.119 +  static nsIContent::AttrValuesArray strings[] = { &nsGkAtoms::increment,
   1.120 +                                                   &nsGkAtoms::decrement,
   1.121 +                                                   nullptr };
   1.122 +  int32_t index = mContent->FindAttrValueIn(kNameSpaceID_None,
   1.123 +                                            nsGkAtoms::type,
   1.124 +                                            strings, eCaseMatters);
   1.125 +  int32_t direction;
   1.126 +  if (index == 0) 
   1.127 +    direction = 1;
   1.128 +  else if (index == 1)
   1.129 +    direction = -1;
   1.130 +  else
   1.131 +    return false;
   1.132 +
   1.133 +  // Whether or not to repeat the click action.
   1.134 +  bool repeat = true;
   1.135 +  // Use smooth scrolling by default.
   1.136 +  bool smoothScroll = true;
   1.137 +  switch (pressedButtonAction) {
   1.138 +    case 0:
   1.139 +      mIncrement = direction * nsSliderFrame::GetIncrement(content);
   1.140 +      break;
   1.141 +    case 1:
   1.142 +      mIncrement = direction * nsSliderFrame::GetPageIncrement(content);
   1.143 +      break;
   1.144 +    case 2:
   1.145 +      if (direction == -1)
   1.146 +        mIncrement = -nsSliderFrame::GetCurrentPosition(content);
   1.147 +      else
   1.148 +        mIncrement = nsSliderFrame::GetMaxPosition(content) - 
   1.149 +                     nsSliderFrame::GetCurrentPosition(content);
   1.150 +      // Don't repeat or use smooth scrolling if scrolling to beginning or end
   1.151 +      // of a page.
   1.152 +      repeat = smoothScroll = false;
   1.153 +      break;
   1.154 +    case 3:
   1.155 +    default:
   1.156 +      // We were told to ignore this click, or someone assigned a non-standard
   1.157 +      // value to the button's action.
   1.158 +      return false;
   1.159 +  }
   1.160 +  // set this attribute so we can style it later
   1.161 +  nsWeakFrame weakFrame(this);
   1.162 +  mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::active, NS_LITERAL_STRING("true"), true);
   1.163 +
   1.164 +  nsIPresShell::SetCapturingContent(mContent, CAPTURE_IGNOREALLOWED);
   1.165 +
   1.166 +  if (weakFrame.IsAlive()) {
   1.167 +    DoButtonAction(smoothScroll);
   1.168 +  }
   1.169 +  if (repeat)
   1.170 +    StartRepeat();
   1.171 +  return true;
   1.172 +}
   1.173 +
   1.174 +NS_IMETHODIMP 
   1.175 +nsScrollbarButtonFrame::HandleRelease(nsPresContext* aPresContext,
   1.176 +                                      WidgetGUIEvent* aEvent,
   1.177 +                                      nsEventStatus* aEventStatus)
   1.178 +{
   1.179 +  nsIPresShell::SetCapturingContent(nullptr, 0);
   1.180 +  // we're not active anymore
   1.181 +  mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::active, true);
   1.182 +  StopRepeat();
   1.183 +  return NS_OK;
   1.184 +}
   1.185 +
   1.186 +void nsScrollbarButtonFrame::Notify()
   1.187 +{
   1.188 +  // Since this is only going to get called if we're scrolling a page length
   1.189 +  // or a line increment, we will always use smooth scrolling.
   1.190 +  if (mCursorOnThis ||
   1.191 +      LookAndFeel::GetInt(
   1.192 +        LookAndFeel::eIntID_ScrollbarButtonAutoRepeatBehavior, 0)) {
   1.193 +    DoButtonAction(true);
   1.194 +  }
   1.195 +}
   1.196 +
   1.197 +void
   1.198 +nsScrollbarButtonFrame::MouseClicked(nsPresContext* aPresContext,
   1.199 +                                     WidgetGUIEvent* aEvent) 
   1.200 +{
   1.201 +  nsButtonBoxFrame::MouseClicked(aPresContext, aEvent);
   1.202 +  //MouseClicked();
   1.203 +}
   1.204 +
   1.205 +void
   1.206 +nsScrollbarButtonFrame::DoButtonAction(bool aSmoothScroll) 
   1.207 +{
   1.208 +  // get the scrollbar control
   1.209 +  nsIFrame* scrollbar;
   1.210 +  GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar);
   1.211 +
   1.212 +  if (scrollbar == nullptr)
   1.213 +    return;
   1.214 +
   1.215 +  // get the scrollbars content node
   1.216 +  nsCOMPtr<nsIContent> content = scrollbar->GetContent();
   1.217 +
   1.218 +  // get the current pos
   1.219 +  int32_t curpos = nsSliderFrame::GetCurrentPosition(content);
   1.220 +  int32_t oldpos = curpos;
   1.221 +
   1.222 +  // get the max pos
   1.223 +  int32_t maxpos = nsSliderFrame::GetMaxPosition(content);
   1.224 +
   1.225 +  // increment the given amount
   1.226 +  if (mIncrement)
   1.227 +    curpos += mIncrement;
   1.228 +
   1.229 +  // make sure the current position is between the current and max positions
   1.230 +  if (curpos < 0)
   1.231 +    curpos = 0;
   1.232 +  else if (curpos > maxpos)
   1.233 +    curpos = maxpos;
   1.234 +
   1.235 +  nsScrollbarFrame* sb = do_QueryFrame(scrollbar);
   1.236 +  if (sb) {
   1.237 +    nsIScrollbarMediator* m = sb->GetScrollbarMediator();
   1.238 +    if (m) {
   1.239 +      m->ScrollbarButtonPressed(sb, oldpos, curpos);
   1.240 +      return;
   1.241 +    }
   1.242 +  }
   1.243 +
   1.244 +  // set the current position of the slider.
   1.245 +  nsAutoString curposStr;
   1.246 +  curposStr.AppendInt(curpos);
   1.247 +
   1.248 +  if (aSmoothScroll)
   1.249 +    content->SetAttr(kNameSpaceID_None, nsGkAtoms::smooth, NS_LITERAL_STRING("true"), false);
   1.250 +  content->SetAttr(kNameSpaceID_None, nsGkAtoms::curpos, curposStr, true);
   1.251 +  if (aSmoothScroll)
   1.252 +    content->UnsetAttr(kNameSpaceID_None, nsGkAtoms::smooth, false);
   1.253 +}
   1.254 +
   1.255 +nsresult
   1.256 +nsScrollbarButtonFrame::GetChildWithTag(nsPresContext* aPresContext,
   1.257 +                                        nsIAtom* atom, nsIFrame* start,
   1.258 +                                        nsIFrame*& result)
   1.259 +{
   1.260 +  // recursively search our children
   1.261 +  nsIFrame* childFrame = start->GetFirstPrincipalChild();
   1.262 +  while (nullptr != childFrame) 
   1.263 +  {    
   1.264 +    // get the content node
   1.265 +    nsIContent* child = childFrame->GetContent();
   1.266 +
   1.267 +    if (child) {
   1.268 +      // see if it is the child
   1.269 +       if (child->Tag() == atom)
   1.270 +       {
   1.271 +         result = childFrame;
   1.272 +
   1.273 +         return NS_OK;
   1.274 +       }
   1.275 +    }
   1.276 +
   1.277 +     // recursive search the child
   1.278 +     GetChildWithTag(aPresContext, atom, childFrame, result);
   1.279 +     if (result != nullptr) 
   1.280 +       return NS_OK;
   1.281 +
   1.282 +    childFrame = childFrame->GetNextSibling();
   1.283 +  }
   1.284 +
   1.285 +  result = nullptr;
   1.286 +  return NS_OK;
   1.287 +}
   1.288 +
   1.289 +nsresult
   1.290 +nsScrollbarButtonFrame::GetParentWithTag(nsIAtom* toFind, nsIFrame* start,
   1.291 +                                         nsIFrame*& result)
   1.292 +{
   1.293 +   while (start)
   1.294 +   {
   1.295 +      start = start->GetParent();
   1.296 +
   1.297 +      if (start) {
   1.298 +        // get the content node
   1.299 +        nsIContent* child = start->GetContent();
   1.300 +
   1.301 +        if (child && child->Tag() == toFind) {
   1.302 +          result = start;
   1.303 +          return NS_OK;
   1.304 +        }
   1.305 +      }
   1.306 +   }
   1.307 +
   1.308 +   result = nullptr;
   1.309 +   return NS_OK;
   1.310 +}
   1.311 +
   1.312 +void
   1.313 +nsScrollbarButtonFrame::DestroyFrom(nsIFrame* aDestructRoot)
   1.314 +{
   1.315 +  // Ensure our repeat service isn't going... it's possible that a scrollbar can disappear out
   1.316 +  // from under you while you're in the process of scrolling.
   1.317 +  StopRepeat();
   1.318 +  nsButtonBoxFrame::DestroyFrom(aDestructRoot);
   1.319 +}

mercurial