michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // michael@0: // Eric Vaughan michael@0: // Netscape Communications michael@0: // michael@0: // See documentation in associated header file michael@0: // michael@0: michael@0: #include "nsDeckFrame.h" michael@0: #include "nsStyleContext.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsIContent.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsNameSpaceManager.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsHTMLParts.h" michael@0: #include "nsIPresShell.h" michael@0: #include "nsCSSRendering.h" michael@0: #include "nsViewManager.h" michael@0: #include "nsBoxLayoutState.h" michael@0: #include "nsStackLayout.h" michael@0: #include "nsDisplayList.h" michael@0: #include "nsContainerFrame.h" michael@0: michael@0: #ifdef ACCESSIBILITY michael@0: #include "nsAccessibilityService.h" michael@0: #endif michael@0: michael@0: nsIFrame* michael@0: NS_NewDeckFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) michael@0: { michael@0: return new (aPresShell) nsDeckFrame(aPresShell, aContext); michael@0: } michael@0: michael@0: NS_IMPL_FRAMEARENA_HELPERS(nsDeckFrame) michael@0: michael@0: NS_QUERYFRAME_HEAD(nsDeckFrame) michael@0: NS_QUERYFRAME_ENTRY(nsDeckFrame) michael@0: NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame) michael@0: michael@0: michael@0: nsDeckFrame::nsDeckFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) michael@0: : nsBoxFrame(aPresShell, aContext), mIndex(0) michael@0: { michael@0: nsCOMPtr layout; michael@0: NS_NewStackLayout(aPresShell, layout); michael@0: SetLayoutManager(layout); michael@0: } michael@0: michael@0: nsIAtom* michael@0: nsDeckFrame::GetType() const michael@0: { michael@0: return nsGkAtoms::deckFrame; michael@0: } michael@0: michael@0: nsresult michael@0: nsDeckFrame::AttributeChanged(int32_t aNameSpaceID, michael@0: nsIAtom* aAttribute, michael@0: int32_t aModType) michael@0: { michael@0: nsresult rv = nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute, michael@0: aModType); michael@0: michael@0: michael@0: // if the index changed hide the old element and make the new element visible michael@0: if (aAttribute == nsGkAtoms::selectedIndex) { michael@0: IndexChanged(); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: void michael@0: nsDeckFrame::Init(nsIContent* aContent, michael@0: nsIFrame* aParent, michael@0: nsIFrame* aPrevInFlow) michael@0: { michael@0: nsBoxFrame::Init(aContent, aParent, aPrevInFlow); michael@0: michael@0: mIndex = GetSelectedIndex(); michael@0: } michael@0: michael@0: void michael@0: nsDeckFrame::HideBox(nsIFrame* aBox) michael@0: { michael@0: nsIPresShell::ClearMouseCapture(aBox); michael@0: } michael@0: michael@0: void michael@0: nsDeckFrame::IndexChanged() michael@0: { michael@0: //did the index change? michael@0: int32_t index = GetSelectedIndex(); michael@0: if (index == mIndex) michael@0: return; michael@0: michael@0: // redraw michael@0: InvalidateFrame(); michael@0: michael@0: // hide the currently showing box michael@0: nsIFrame* currentBox = GetSelectedBox(); michael@0: if (currentBox) // only hide if it exists michael@0: HideBox(currentBox); michael@0: michael@0: mIndex = index; michael@0: michael@0: #ifdef ACCESSIBILITY michael@0: nsAccessibilityService* accService = GetAccService(); michael@0: if (accService) { michael@0: accService->DeckPanelSwitched(PresContext()->GetPresShell(), mContent, michael@0: currentBox, GetSelectedBox()); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: int32_t michael@0: nsDeckFrame::GetSelectedIndex() michael@0: { michael@0: // default index is 0 michael@0: int32_t index = 0; michael@0: michael@0: // get the index attribute michael@0: nsAutoString value; michael@0: if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::selectedIndex, value)) michael@0: { michael@0: nsresult error; michael@0: michael@0: // convert it to an integer michael@0: index = value.ToInteger(&error); michael@0: } michael@0: michael@0: return index; michael@0: } michael@0: michael@0: nsIFrame* michael@0: nsDeckFrame::GetSelectedBox() michael@0: { michael@0: return (mIndex >= 0) ? mFrames.FrameAt(mIndex) : nullptr; michael@0: } michael@0: michael@0: void michael@0: nsDeckFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, michael@0: const nsRect& aDirtyRect, michael@0: const nsDisplayListSet& aLists) michael@0: { michael@0: // if a tab is hidden all its children are too. michael@0: if (!StyleVisibility()->mVisible) michael@0: return; michael@0: michael@0: nsBoxFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists); michael@0: } michael@0: michael@0: void michael@0: nsDeckFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder, michael@0: const nsRect& aDirtyRect, michael@0: const nsDisplayListSet& aLists) michael@0: { michael@0: // only paint the selected box michael@0: nsIFrame* box = GetSelectedBox(); michael@0: if (!box) michael@0: return; michael@0: michael@0: // Putting the child in the background list. This is a little weird but michael@0: // it matches what we were doing before. michael@0: nsDisplayListSet set(aLists, aLists.BlockBorderBackgrounds()); michael@0: BuildDisplayListForChild(aBuilder, box, aDirtyRect, set); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDeckFrame::DoLayout(nsBoxLayoutState& aState) michael@0: { michael@0: // Make sure we tweak the state so it does not resize our children. michael@0: // We will do that. michael@0: uint32_t oldFlags = aState.LayoutFlags(); michael@0: aState.SetLayoutFlags(NS_FRAME_NO_SIZE_VIEW | NS_FRAME_NO_VISIBILITY); michael@0: michael@0: // do a normal layout michael@0: nsresult rv = nsBoxFrame::DoLayout(aState); michael@0: michael@0: // run though each child. Hide all but the selected one michael@0: nsIFrame* box = GetChildBox(); michael@0: michael@0: nscoord count = 0; michael@0: while (box) michael@0: { michael@0: // make collapsed children not show up michael@0: if (count != mIndex) michael@0: HideBox(box); michael@0: michael@0: box = box->GetNextBox(); michael@0: count++; michael@0: } michael@0: michael@0: aState.SetLayoutFlags(oldFlags); michael@0: michael@0: return rv; michael@0: } michael@0: