nsDeckFrame.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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 "nsDeckFrame.h"
  12. #include "nsStyleContext.h"
  13. #include "nsPresContext.h"
  14. #include "nsIContent.h"
  15. #include "nsCOMPtr.h"
  16. #include "nsNameSpaceManager.h"
  17. #include "nsGkAtoms.h"
  18. #include "nsHTMLParts.h"
  19. #include "nsIPresShell.h"
  20. #include "nsCSSRendering.h"
  21. #include "nsViewManager.h"
  22. #include "nsBoxLayoutState.h"
  23. #include "nsStackLayout.h"
  24. #include "nsDisplayList.h"
  25. #include "nsContainerFrame.h"
  26. #include "nsContentUtils.h"
  27. #ifdef ACCESSIBILITY
  28. #include "nsAccessibilityService.h"
  29. #endif
  30. nsIFrame*
  31. NS_NewDeckFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
  32. {
  33. return new (aPresShell) nsDeckFrame(aContext);
  34. }
  35. NS_IMPL_FRAMEARENA_HELPERS(nsDeckFrame)
  36. NS_QUERYFRAME_HEAD(nsDeckFrame)
  37. NS_QUERYFRAME_ENTRY(nsDeckFrame)
  38. NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
  39. nsDeckFrame::nsDeckFrame(nsStyleContext* aContext)
  40. : nsBoxFrame(aContext), mIndex(0)
  41. {
  42. nsCOMPtr<nsBoxLayout> layout;
  43. NS_NewStackLayout(layout);
  44. SetXULLayoutManager(layout);
  45. }
  46. nsIAtom*
  47. nsDeckFrame::GetType() const
  48. {
  49. return nsGkAtoms::deckFrame;
  50. }
  51. nsresult
  52. nsDeckFrame::AttributeChanged(int32_t aNameSpaceID,
  53. nsIAtom* aAttribute,
  54. int32_t aModType)
  55. {
  56. nsresult rv = nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute,
  57. aModType);
  58. // if the index changed hide the old element and make the new element visible
  59. if (aAttribute == nsGkAtoms::selectedIndex) {
  60. IndexChanged();
  61. }
  62. return rv;
  63. }
  64. void
  65. nsDeckFrame::Init(nsIContent* aContent,
  66. nsContainerFrame* aParent,
  67. nsIFrame* aPrevInFlow)
  68. {
  69. nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
  70. mIndex = GetSelectedIndex();
  71. }
  72. void
  73. nsDeckFrame::HideBox(nsIFrame* aBox)
  74. {
  75. nsIPresShell::ClearMouseCapture(aBox);
  76. }
  77. void
  78. nsDeckFrame::IndexChanged()
  79. {
  80. //did the index change?
  81. int32_t index = GetSelectedIndex();
  82. if (index == mIndex)
  83. return;
  84. // redraw
  85. InvalidateFrame();
  86. // hide the currently showing box
  87. nsIFrame* currentBox = GetSelectedBox();
  88. if (currentBox) // only hide if it exists
  89. HideBox(currentBox);
  90. mIndex = index;
  91. #ifdef ACCESSIBILITY
  92. nsAccessibilityService* accService = GetAccService();
  93. if (accService) {
  94. accService->DeckPanelSwitched(PresContext()->GetPresShell(), mContent,
  95. currentBox, GetSelectedBox());
  96. }
  97. #endif
  98. }
  99. int32_t
  100. nsDeckFrame::GetSelectedIndex()
  101. {
  102. // default index is 0
  103. int32_t index = 0;
  104. // get the index attribute
  105. nsAutoString value;
  106. if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::selectedIndex, value))
  107. {
  108. nsresult error;
  109. // convert it to an integer
  110. index = value.ToInteger(&error);
  111. }
  112. return index;
  113. }
  114. nsIFrame*
  115. nsDeckFrame::GetSelectedBox()
  116. {
  117. return (mIndex >= 0) ? mFrames.FrameAt(mIndex) : nullptr;
  118. }
  119. void
  120. nsDeckFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
  121. const nsDisplayListSet& aLists)
  122. {
  123. // if a tab is hidden all its children are too.
  124. if (!StyleVisibility()->mVisible)
  125. return;
  126. nsBoxFrame::BuildDisplayList(aBuilder, aLists);
  127. }
  128. void
  129. nsDeckFrame::RemoveFrame(ChildListID aListID,
  130. nsIFrame* aOldFrame)
  131. {
  132. nsIFrame* currentFrame = GetSelectedBox();
  133. if (currentFrame &&
  134. aOldFrame &&
  135. currentFrame != aOldFrame) {
  136. // If the frame we're removing is at an index that's less
  137. // than mIndex, that means we're going to be shifting indexes
  138. // by 1.
  139. //
  140. // We attempt to keep the same child displayed by automatically
  141. // updating our internal notion of the current index.
  142. int32_t removedIndex = mFrames.IndexOf(aOldFrame);
  143. MOZ_ASSERT(removedIndex >= 0,
  144. "A deck child was removed that was not in mFrames.");
  145. if (removedIndex < mIndex) {
  146. mIndex--;
  147. // This is going to cause us to handle the index change in IndexedChanged,
  148. // but since the new index will match mIndex, it's essentially a noop.
  149. nsContentUtils::AddScriptRunner(new nsSetAttrRunnable(
  150. mContent, nsGkAtoms::selectedIndex, mIndex));
  151. }
  152. }
  153. nsBoxFrame::RemoveFrame(aListID, aOldFrame);
  154. }
  155. void
  156. nsDeckFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
  157. const nsDisplayListSet& aLists)
  158. {
  159. // only paint the selected box
  160. nsIFrame* box = GetSelectedBox();
  161. if (!box)
  162. return;
  163. // Putting the child in the background list. This is a little weird but
  164. // it matches what we were doing before.
  165. nsDisplayListSet set(aLists, aLists.BlockBorderBackgrounds());
  166. BuildDisplayListForChild(aBuilder, box, set);
  167. }
  168. NS_IMETHODIMP
  169. nsDeckFrame::DoXULLayout(nsBoxLayoutState& aState)
  170. {
  171. // Make sure we tweak the state so it does not resize our children.
  172. // We will do that.
  173. uint32_t oldFlags = aState.LayoutFlags();
  174. aState.SetLayoutFlags(NS_FRAME_NO_SIZE_VIEW | NS_FRAME_NO_VISIBILITY);
  175. // do a normal layout
  176. nsresult rv = nsBoxFrame::DoXULLayout(aState);
  177. // run though each child. Hide all but the selected one
  178. nsIFrame* box = nsBox::GetChildXULBox(this);
  179. nscoord count = 0;
  180. while (box)
  181. {
  182. // make collapsed children not show up
  183. if (count != mIndex)
  184. HideBox(box);
  185. box = GetNextXULBox(box);
  186. count++;
  187. }
  188. aState.SetLayoutFlags(oldFlags);
  189. return rv;
  190. }