nsScrollbarFrame.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  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/. */
  5. //
  6. // Eric Vaughan
  7. // Netscape Communications
  8. //
  9. // See documentation in associated header file
  10. //
  11. #include "nsScrollbarFrame.h"
  12. #include "nsSliderFrame.h"
  13. #include "nsScrollbarButtonFrame.h"
  14. #include "nsGkAtoms.h"
  15. #include "nsIScrollableFrame.h"
  16. #include "nsIScrollbarMediator.h"
  17. #include "mozilla/LookAndFeel.h"
  18. #include "nsThemeConstants.h"
  19. #include "nsIContent.h"
  20. #include "nsIDOMMutationEvent.h"
  21. using namespace mozilla;
  22. //
  23. // NS_NewScrollbarFrame
  24. //
  25. // Creates a new scrollbar frame and returns it
  26. //
  27. nsIFrame*
  28. NS_NewScrollbarFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
  29. {
  30. return new (aPresShell) nsScrollbarFrame(aContext);
  31. }
  32. NS_IMPL_FRAMEARENA_HELPERS(nsScrollbarFrame)
  33. NS_QUERYFRAME_HEAD(nsScrollbarFrame)
  34. NS_QUERYFRAME_ENTRY(nsScrollbarFrame)
  35. NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
  36. void
  37. nsScrollbarFrame::Init(nsIContent* aContent,
  38. nsContainerFrame* aParent,
  39. nsIFrame* aPrevInFlow)
  40. {
  41. nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
  42. // We want to be a reflow root since we use reflows to move the
  43. // slider. Any reflow inside the scrollbar frame will be a reflow to
  44. // move the slider and will thus not change anything outside of the
  45. // scrollbar or change the size of the scrollbar frame.
  46. mState |= NS_FRAME_REFLOW_ROOT;
  47. }
  48. void
  49. nsScrollbarFrame::Reflow(nsPresContext* aPresContext,
  50. ReflowOutput& aDesiredSize,
  51. const ReflowInput& aReflowInput,
  52. nsReflowStatus& aStatus)
  53. {
  54. nsBoxFrame::Reflow(aPresContext, aDesiredSize, aReflowInput, aStatus);
  55. // nsGfxScrollFrame may have told us to shrink to nothing. If so, make sure our
  56. // desired size agrees.
  57. if (aReflowInput.AvailableWidth() == 0) {
  58. aDesiredSize.Width() = 0;
  59. }
  60. if (aReflowInput.AvailableHeight() == 0) {
  61. aDesiredSize.Height() = 0;
  62. }
  63. }
  64. nsIAtom*
  65. nsScrollbarFrame::GetType() const
  66. {
  67. return nsGkAtoms::scrollbarFrame;
  68. }
  69. nsresult
  70. nsScrollbarFrame::AttributeChanged(int32_t aNameSpaceID,
  71. nsIAtom* aAttribute,
  72. int32_t aModType)
  73. {
  74. nsresult rv = nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute,
  75. aModType);
  76. // if the current position changes, notify any nsGfxScrollFrame
  77. // parent we may have
  78. if (aAttribute != nsGkAtoms::curpos)
  79. return rv;
  80. nsIScrollableFrame* scrollable = do_QueryFrame(GetParent());
  81. if (!scrollable)
  82. return rv;
  83. nsCOMPtr<nsIContent> content(mContent);
  84. scrollable->CurPosAttributeChanged(content);
  85. return rv;
  86. }
  87. NS_IMETHODIMP
  88. nsScrollbarFrame::HandlePress(nsPresContext* aPresContext,
  89. WidgetGUIEvent* aEvent,
  90. nsEventStatus* aEventStatus)
  91. {
  92. return NS_OK;
  93. }
  94. NS_IMETHODIMP
  95. nsScrollbarFrame::HandleMultiplePress(nsPresContext* aPresContext,
  96. WidgetGUIEvent* aEvent,
  97. nsEventStatus* aEventStatus,
  98. bool aControlHeld)
  99. {
  100. return NS_OK;
  101. }
  102. NS_IMETHODIMP
  103. nsScrollbarFrame::HandleDrag(nsPresContext* aPresContext,
  104. WidgetGUIEvent* aEvent,
  105. nsEventStatus* aEventStatus)
  106. {
  107. return NS_OK;
  108. }
  109. NS_IMETHODIMP
  110. nsScrollbarFrame::HandleRelease(nsPresContext* aPresContext,
  111. WidgetGUIEvent* aEvent,
  112. nsEventStatus* aEventStatus)
  113. {
  114. return NS_OK;
  115. }
  116. void
  117. nsScrollbarFrame::SetScrollbarMediatorContent(nsIContent* aMediator)
  118. {
  119. mScrollbarMediator = aMediator;
  120. }
  121. nsIScrollbarMediator*
  122. nsScrollbarFrame::GetScrollbarMediator()
  123. {
  124. if (!mScrollbarMediator) {
  125. return nullptr;
  126. }
  127. nsIFrame* f = mScrollbarMediator->GetPrimaryFrame();
  128. nsIScrollableFrame* scrollFrame = do_QueryFrame(f);
  129. nsIScrollbarMediator* sbm;
  130. if (scrollFrame) {
  131. nsIFrame* scrolledFrame = scrollFrame->GetScrolledFrame();
  132. sbm = do_QueryFrame(scrolledFrame);
  133. if (sbm) {
  134. return sbm;
  135. }
  136. }
  137. sbm = do_QueryFrame(f);
  138. if (f && !sbm) {
  139. f = f->PresContext()->PresShell()->GetRootScrollFrame();
  140. if (f && f->GetContent() == mScrollbarMediator) {
  141. return do_QueryFrame(f);
  142. }
  143. }
  144. return sbm;
  145. }
  146. nsresult
  147. nsScrollbarFrame::GetXULMargin(nsMargin& aMargin)
  148. {
  149. nsresult rv = NS_ERROR_FAILURE;
  150. aMargin.SizeTo(0,0,0,0);
  151. if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) {
  152. nsPresContext* presContext = PresContext();
  153. nsITheme* theme = presContext->GetTheme();
  154. if (theme) {
  155. LayoutDeviceIntSize size;
  156. bool isOverridable;
  157. theme->GetMinimumWidgetSize(presContext, this, NS_THEME_SCROLLBAR, &size,
  158. &isOverridable);
  159. if (IsXULHorizontal()) {
  160. aMargin.top = -presContext->DevPixelsToAppUnits(size.height);
  161. }
  162. else {
  163. aMargin.left = -presContext->DevPixelsToAppUnits(size.width);
  164. }
  165. rv = NS_OK;
  166. }
  167. }
  168. if (NS_FAILED(rv)) {
  169. rv = nsBox::GetXULMargin(aMargin);
  170. }
  171. if (NS_SUCCEEDED(rv) && !IsXULHorizontal()) {
  172. nsIScrollbarMediator* scrollFrame = GetScrollbarMediator();
  173. if (scrollFrame && !scrollFrame->IsScrollbarOnRight()) {
  174. Swap(aMargin.left, aMargin.right);
  175. }
  176. }
  177. return rv;
  178. }
  179. void
  180. nsScrollbarFrame::SetIncrementToLine(int32_t aDirection)
  181. {
  182. // get the scrollbar's content node
  183. nsIContent* content = GetContent();
  184. mSmoothScroll = true;
  185. mIncrement = aDirection * nsSliderFrame::GetIncrement(content);
  186. }
  187. void
  188. nsScrollbarFrame::SetIncrementToPage(int32_t aDirection)
  189. {
  190. // get the scrollbar's content node
  191. nsIContent* content = GetContent();
  192. mSmoothScroll = true;
  193. mIncrement = aDirection * nsSliderFrame::GetPageIncrement(content);
  194. }
  195. void
  196. nsScrollbarFrame::SetIncrementToWhole(int32_t aDirection)
  197. {
  198. // get the scrollbar's content node
  199. nsIContent* content = GetContent();
  200. if (aDirection == -1)
  201. mIncrement = -nsSliderFrame::GetCurrentPosition(content);
  202. else
  203. mIncrement = nsSliderFrame::GetMaxPosition(content) -
  204. nsSliderFrame::GetCurrentPosition(content);
  205. // Don't repeat or use smooth scrolling if scrolling to beginning or end
  206. // of a page.
  207. mSmoothScroll = false;
  208. }
  209. int32_t
  210. nsScrollbarFrame::MoveToNewPosition()
  211. {
  212. // get the scrollbar's content node
  213. nsCOMPtr<nsIContent> content = GetContent();
  214. // get the current pos
  215. int32_t curpos = nsSliderFrame::GetCurrentPosition(content);
  216. // get the max pos
  217. int32_t maxpos = nsSliderFrame::GetMaxPosition(content);
  218. // save the old curpos
  219. int32_t oldCurpos = curpos;
  220. // increment the given amount
  221. if (mIncrement) {
  222. curpos += mIncrement;
  223. }
  224. // make sure the current position is between the current and max positions
  225. if (curpos < 0) {
  226. curpos = 0;
  227. } else if (curpos > maxpos) {
  228. curpos = maxpos;
  229. }
  230. // set the current position of the slider.
  231. nsAutoString curposStr;
  232. curposStr.AppendInt(curpos);
  233. nsWeakFrame weakFrame(this);
  234. if (mSmoothScroll) {
  235. content->SetAttr(kNameSpaceID_None, nsGkAtoms::smooth, NS_LITERAL_STRING("true"), false);
  236. }
  237. content->SetAttr(kNameSpaceID_None, nsGkAtoms::curpos, curposStr, false);
  238. // notify the nsScrollbarFrame of the change
  239. AttributeChanged(kNameSpaceID_None, nsGkAtoms::curpos, nsIDOMMutationEvent::MODIFICATION);
  240. if (!weakFrame.IsAlive()) {
  241. return curpos;
  242. }
  243. // notify all nsSliderFrames of the change
  244. nsIFrame::ChildListIterator childLists(this);
  245. for (; !childLists.IsDone(); childLists.Next()) {
  246. nsFrameList::Enumerator childFrames(childLists.CurrentList());
  247. for (; !childFrames.AtEnd(); childFrames.Next()) {
  248. nsIFrame* f = childFrames.get();
  249. nsSliderFrame* sliderFrame = do_QueryFrame(f);
  250. if (sliderFrame) {
  251. sliderFrame->AttributeChanged(kNameSpaceID_None, nsGkAtoms::curpos, nsIDOMMutationEvent::MODIFICATION);
  252. if (!weakFrame.IsAlive()) {
  253. return curpos;
  254. }
  255. }
  256. }
  257. }
  258. // See if we have appearance information for a theme.
  259. const nsStyleDisplay* disp = StyleDisplay();
  260. nsPresContext* presContext = PresContext();
  261. if (disp->mAppearance) {
  262. nsITheme *theme = presContext->GetTheme();
  263. if (theme && theme->ThemeSupportsWidget(presContext, this, disp->mAppearance)) {
  264. bool repaint;
  265. nsAttrValue oldValue;
  266. oldValue.SetTo(oldCurpos);
  267. theme->WidgetStateChanged(this, disp->mAppearance, nsGkAtoms::curpos,
  268. &repaint, &oldValue);
  269. }
  270. }
  271. content->UnsetAttr(kNameSpaceID_None, nsGkAtoms::smooth, false);
  272. return curpos;
  273. }