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/. */
9 // Netscape Communications
11 // See documentation in associated header file
14 #include "nsDeckFrame.h"
15 #include "mozilla/ComputedStyle.h"
16 #include "mozilla/PresShell.h"
17 #include "nsPresContext.h"
18 #include "nsIContent.h"
20 #include "nsNameSpaceManager.h"
21 #include "nsGkAtoms.h"
22 #include "nsHTMLParts.h"
23 #include "nsCSSRendering.h"
24 #include "nsViewManager.h"
25 #include "nsBoxLayoutState.h"
26 #include "nsStackLayout.h"
27 #include "nsDisplayList.h"
28 #include "nsContainerFrame.h"
29 #include "nsContentUtils.h"
30 #include "nsXULPopupManager.h"
31 #include "nsImageBoxFrame.h"
32 #include "nsImageFrame.h"
35 # include "nsAccessibilityService.h"
38 using namespace mozilla
;
40 nsIFrame
* NS_NewDeckFrame(PresShell
* aPresShell
, ComputedStyle
* aStyle
) {
41 return new (aPresShell
) nsDeckFrame(aStyle
, aPresShell
->GetPresContext());
44 NS_IMPL_FRAMEARENA_HELPERS(nsDeckFrame
)
46 NS_QUERYFRAME_HEAD(nsDeckFrame
)
47 NS_QUERYFRAME_ENTRY(nsDeckFrame
)
48 NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame
)
50 nsDeckFrame::nsDeckFrame(ComputedStyle
* aStyle
, nsPresContext
* aPresContext
)
51 : nsBoxFrame(aStyle
, aPresContext
, kClassID
), mIndex(0) {
52 nsCOMPtr
<nsBoxLayout
> layout
;
53 NS_NewStackLayout(layout
);
54 SetXULLayoutManager(layout
);
57 nsresult
nsDeckFrame::AttributeChanged(int32_t aNameSpaceID
, nsAtom
* aAttribute
,
60 nsBoxFrame::AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
62 // if the index changed hide the old element and make the new element visible
63 if (aAttribute
== nsGkAtoms::selectedIndex
) {
70 void nsDeckFrame::Init(nsIContent
* aContent
, nsContainerFrame
* aParent
,
71 nsIFrame
* aPrevInFlow
) {
72 nsBoxFrame::Init(aContent
, aParent
, aPrevInFlow
);
74 mIndex
= GetSelectedIndex();
77 void nsDeckFrame::ShowBox(nsIFrame
* aBox
) { Animate(aBox
, true); }
79 void nsDeckFrame::HideBox(nsIFrame
* aBox
) {
80 mozilla::PresShell::ClearMouseCapture(aBox
);
84 void nsDeckFrame::IndexChanged() {
85 // did the index change?
86 int32_t index
= GetSelectedIndex();
88 if (index
== mIndex
) return;
93 // hide the currently showing box
94 nsIFrame
* currentBox
= GetSelectedBox();
95 if (currentBox
) // only hide if it exists
100 ShowBox(GetSelectedBox());
103 nsAccessibilityService
* accService
= GetAccService();
105 accService
->DeckPanelSwitched(PresContext()->GetPresShell(), mContent
,
106 currentBox
, GetSelectedBox());
110 // Force any popups that might be anchored on elements within hidden
112 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
113 if (pm
&& currentBox
) {
114 pm
->UpdatePopupPositions(currentBox
->PresContext()->RefreshDriver());
118 int32_t nsDeckFrame::GetSelectedIndex() {
119 // default index is 0
122 // get the index attribute
124 if (mContent
->AsElement()->GetAttr(kNameSpaceID_None
,
125 nsGkAtoms::selectedIndex
, value
)) {
128 // convert it to an integer
129 index
= value
.ToInteger(&error
);
135 nsIFrame
* nsDeckFrame::GetSelectedBox() {
136 return (mIndex
>= 0) ? mFrames
.FrameAt(mIndex
) : nullptr;
139 void nsDeckFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
140 const nsDisplayListSet
& aLists
) {
141 // if a tab is hidden all its children are too.
142 if (!StyleVisibility()->mVisible
) return;
144 nsBoxFrame::BuildDisplayList(aBuilder
, aLists
);
147 void nsDeckFrame::RemoveFrame(ChildListID aListID
, nsIFrame
* aOldFrame
) {
148 nsIFrame
* currentFrame
= GetSelectedBox();
149 if (currentFrame
&& aOldFrame
&& currentFrame
!= aOldFrame
) {
150 // If the frame we're removing is at an index that's less
151 // than mIndex, that means we're going to be shifting indexes
154 // We attempt to keep the same child displayed by automatically
155 // updating our internal notion of the current index.
156 int32_t removedIndex
= mFrames
.IndexOf(aOldFrame
);
157 MOZ_ASSERT(removedIndex
>= 0,
158 "A deck child was removed that was not in mFrames.");
159 if (removedIndex
< mIndex
) {
161 // This is going to cause us to handle the index change in IndexedChanged,
162 // but since the new index will match mIndex, it's essentially a noop.
163 nsContentUtils::AddScriptRunner(new nsSetAttrRunnable(
164 mContent
->AsElement(), nsGkAtoms::selectedIndex
, mIndex
));
167 nsBoxFrame::RemoveFrame(aListID
, aOldFrame
);
170 void nsDeckFrame::BuildDisplayListForChildren(nsDisplayListBuilder
* aBuilder
,
171 const nsDisplayListSet
& aLists
) {
172 // only paint the selected box
173 nsIFrame
* box
= GetSelectedBox();
176 // Putting the child in the background list. This is a little weird but
177 // it matches what we were doing before.
178 nsDisplayListSet
set(aLists
, aLists
.BlockBorderBackgrounds());
179 BuildDisplayListForChild(aBuilder
, box
, set
);
182 void nsDeckFrame::Animate(nsIFrame
* aParentBox
, bool start
) {
183 if (!aParentBox
) return;
185 nsImageBoxFrame
* imgBoxFrame
= do_QueryFrame(aParentBox
);
186 nsImageFrame
* imgFrame
= do_QueryFrame(aParentBox
);
190 imgBoxFrame
->RestartAnimation();
192 imgBoxFrame
->StopAnimation();
197 imgFrame
->RestartAnimation();
199 imgFrame
->StopAnimation();
202 for (nsIFrame::ChildListIterator
childLists(aParentBox
); !childLists
.IsDone();
204 for (nsIFrame
* child
: childLists
.CurrentList()) {
205 Animate(child
, start
);
211 nsDeckFrame::DoXULLayout(nsBoxLayoutState
& aState
) {
212 // Make sure we tweak the state so it does not resize our children.
214 ReflowChildFlags oldFlags
= aState
.LayoutFlags();
215 aState
.SetLayoutFlags(ReflowChildFlags::NoSizeView
|
216 ReflowChildFlags::NoVisibility
);
218 // do a normal layout
219 nsresult rv
= nsBoxFrame::DoXULLayout(aState
);
221 // run though each child. Hide all but the selected one
222 nsIFrame
* box
= nsBox::GetChildXULBox(this);
226 // make collapsed children not show up
227 if (count
!= mIndex
) {
232 box
= GetNextXULBox(box
);
236 aState
.SetLayoutFlags(oldFlags
);