2017-10-27 20:33:53 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
1999-04-22 02:46:15 +04:00
|
|
|
|
|
|
|
//
|
|
|
|
// Eric Vaughan
|
|
|
|
// Netscape Communications
|
|
|
|
//
|
|
|
|
// See documentation in associated header file
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "nsDeckFrame.h"
|
2018-03-22 21:20:41 +03:00
|
|
|
#include "mozilla/ComputedStyle.h"
|
2019-04-03 15:40:26 +03:00
|
|
|
#include "mozilla/PresShell.h"
|
2004-08-01 03:15:21 +04:00
|
|
|
#include "nsPresContext.h"
|
1999-04-22 02:46:15 +04:00
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsCOMPtr.h"
|
2014-02-28 03:04:46 +04:00
|
|
|
#include "nsNameSpaceManager.h"
|
2006-12-26 20:47:52 +03:00
|
|
|
#include "nsGkAtoms.h"
|
1999-05-20 02:14:11 +04:00
|
|
|
#include "nsHTMLParts.h"
|
|
|
|
#include "nsCSSRendering.h"
|
2013-01-05 07:12:24 +04:00
|
|
|
#include "nsViewManager.h"
|
2000-03-31 11:02:06 +04:00
|
|
|
#include "nsBoxLayoutState.h"
|
|
|
|
#include "nsStackLayout.h"
|
2006-01-26 05:29:17 +03:00
|
|
|
#include "nsDisplayList.h"
|
2011-12-28 00:18:48 +04:00
|
|
|
#include "nsContainerFrame.h"
|
2014-08-02 16:22:06 +04:00
|
|
|
#include "nsContentUtils.h"
|
2018-07-31 22:30:17 +03:00
|
|
|
#include "nsXULPopupManager.h"
|
2019-03-25 22:11:22 +03:00
|
|
|
#include "nsImageBoxFrame.h"
|
|
|
|
#include "nsImageFrame.h"
|
1999-05-10 01:46:24 +04:00
|
|
|
|
2012-12-28 12:15:02 +04:00
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
# include "nsAccessibilityService.h"
|
|
|
|
#endif
|
|
|
|
|
2018-11-13 01:20:52 +03:00
|
|
|
using namespace mozilla;
|
|
|
|
|
2019-04-16 10:24:49 +03:00
|
|
|
nsIFrame* NS_NewDeckFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
|
2019-02-05 19:45:54 +03:00
|
|
|
return new (aPresShell) nsDeckFrame(aStyle, aPresShell->GetPresContext());
|
2009-09-12 20:49:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(nsDeckFrame)
|
1999-04-22 02:46:15 +04:00
|
|
|
|
2011-10-27 03:57:55 +04:00
|
|
|
NS_QUERYFRAME_HEAD(nsDeckFrame)
|
2018-12-07 23:00:18 +03:00
|
|
|
NS_QUERYFRAME_ENTRY(nsDeckFrame)
|
2011-10-27 03:57:55 +04:00
|
|
|
NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
|
|
|
|
|
2019-02-05 19:45:54 +03:00
|
|
|
nsDeckFrame::nsDeckFrame(ComputedStyle* aStyle, nsPresContext* aPresContext)
|
|
|
|
: nsBoxFrame(aStyle, aPresContext, kClassID), mIndex(0) {
|
2011-07-11 18:05:10 +04:00
|
|
|
nsCOMPtr<nsBoxLayout> layout;
|
2015-12-08 02:27:01 +03:00
|
|
|
NS_NewStackLayout(layout);
|
2016-04-21 07:28:33 +03:00
|
|
|
SetXULLayoutManager(layout);
|
1999-04-22 02:46:15 +04:00
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
nsresult nsDeckFrame::AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
|
|
|
|
int32_t aModType) {
|
2005-09-07 20:49:21 +04:00
|
|
|
nsresult rv =
|
|
|
|
nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
|
1999-04-22 02:46:15 +04:00
|
|
|
|
2006-12-10 21:13:48 +03:00
|
|
|
// if the index changed hide the old element and make the new element visible
|
2006-12-26 20:47:52 +03:00
|
|
|
if (aAttribute == nsGkAtoms::selectedIndex) {
|
2011-10-27 03:57:55 +04:00
|
|
|
IndexChanged();
|
1999-04-22 02:46:15 +04:00
|
|
|
}
|
|
|
|
|
2000-04-25 11:10:48 +04:00
|
|
|
return rv;
|
1999-04-22 02:46:15 +04:00
|
|
|
}
|
|
|
|
|
2014-05-25 02:20:40 +04:00
|
|
|
void nsDeckFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
|
|
|
|
nsIFrame* aPrevInFlow) {
|
2013-03-20 05:47:48 +04:00
|
|
|
nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
|
2000-06-22 04:48:49 +04:00
|
|
|
|
|
|
|
mIndex = GetSelectedIndex();
|
|
|
|
}
|
|
|
|
|
2019-03-25 22:11:22 +03:00
|
|
|
void nsDeckFrame::ShowBox(nsIFrame* aBox) { Animate(aBox, true); }
|
|
|
|
|
2012-08-06 07:00:57 +04:00
|
|
|
void nsDeckFrame::HideBox(nsIFrame* aBox) {
|
2019-04-30 03:26:57 +03:00
|
|
|
mozilla::PresShell::ClearMouseCapture(aBox);
|
2019-03-25 22:11:22 +03:00
|
|
|
Animate(aBox, false);
|
2000-06-22 04:48:49 +04:00
|
|
|
}
|
|
|
|
|
2011-10-27 03:57:55 +04:00
|
|
|
void nsDeckFrame::IndexChanged() {
|
2000-06-22 04:48:49 +04:00
|
|
|
// did the index change?
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t index = GetSelectedIndex();
|
2019-03-25 22:11:22 +03:00
|
|
|
|
2000-06-22 04:48:49 +04:00
|
|
|
if (index == mIndex) return;
|
|
|
|
|
|
|
|
// redraw
|
2012-08-29 09:39:31 +04:00
|
|
|
InvalidateFrame();
|
2000-06-22 04:48:49 +04:00
|
|
|
|
|
|
|
// hide the currently showing box
|
2012-08-06 07:00:57 +04:00
|
|
|
nsIFrame* currentBox = GetSelectedBox();
|
2001-01-11 04:56:27 +03:00
|
|
|
if (currentBox) // only hide if it exists
|
2011-10-27 03:57:55 +04:00
|
|
|
HideBox(currentBox);
|
2000-06-22 04:48:49 +04:00
|
|
|
|
2006-12-10 21:13:48 +03:00
|
|
|
mIndex = index;
|
2012-12-28 12:15:02 +04:00
|
|
|
|
2019-03-25 22:11:22 +03:00
|
|
|
ShowBox(GetSelectedBox());
|
|
|
|
|
2012-12-28 12:15:02 +04:00
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
nsAccessibilityService* accService = GetAccService();
|
|
|
|
if (accService) {
|
|
|
|
accService->DeckPanelSwitched(PresContext()->GetPresShell(), mContent,
|
|
|
|
currentBox, GetSelectedBox());
|
|
|
|
}
|
|
|
|
#endif
|
2017-06-13 11:03:27 +03:00
|
|
|
|
|
|
|
// Force any popups that might be anchored on elements within hidden
|
|
|
|
// box to update.
|
|
|
|
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
|
|
|
if (pm && currentBox) {
|
|
|
|
pm->UpdatePopupPositions(currentBox->PresContext()->RefreshDriver());
|
|
|
|
}
|
2000-06-22 04:48:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int32_t nsDeckFrame::GetSelectedIndex() {
|
2003-05-24 06:35:08 +04:00
|
|
|
// default index is 0
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t index = 0;
|
1999-04-22 02:46:15 +04:00
|
|
|
|
|
|
|
// get the index attribute
|
|
|
|
nsAutoString value;
|
2017-12-07 21:13:50 +03:00
|
|
|
if (mContent->AsElement()->GetAttr(kNameSpaceID_None,
|
|
|
|
nsGkAtoms::selectedIndex, value)) {
|
2012-07-27 17:59:29 +04:00
|
|
|
nsresult error;
|
1999-04-22 02:46:15 +04:00
|
|
|
|
|
|
|
// convert it to an integer
|
|
|
|
index = value.ToInteger(&error);
|
|
|
|
}
|
|
|
|
|
2000-06-22 04:48:49 +04:00
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIFrame* nsDeckFrame::GetSelectedBox() {
|
2017-07-06 15:00:35 +03:00
|
|
|
return (mIndex >= 0) ? mFrames.FrameAt(mIndex) : nullptr;
|
1999-04-22 02:46:15 +04:00
|
|
|
}
|
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
void nsDeckFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsDisplayListSet& aLists) {
|
1999-05-20 02:14:11 +04:00
|
|
|
// if a tab is hidden all its children are too.
|
2013-02-17 01:51:02 +04:00
|
|
|
if (!StyleVisibility()->mVisible) return;
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2017-08-07 05:23:35 +03:00
|
|
|
nsBoxFrame::BuildDisplayList(aBuilder, aLists);
|
1999-04-22 02:46:15 +04:00
|
|
|
}
|
|
|
|
|
2014-08-02 16:22:06 +04:00
|
|
|
void nsDeckFrame::RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) {
|
|
|
|
nsIFrame* currentFrame = GetSelectedBox();
|
|
|
|
if (currentFrame && aOldFrame && currentFrame != aOldFrame) {
|
|
|
|
// If the frame we're removing is at an index that's less
|
|
|
|
// than mIndex, that means we're going to be shifting indexes
|
|
|
|
// by 1.
|
|
|
|
//
|
|
|
|
// We attempt to keep the same child displayed by automatically
|
|
|
|
// updating our internal notion of the current index.
|
|
|
|
int32_t removedIndex = mFrames.IndexOf(aOldFrame);
|
|
|
|
MOZ_ASSERT(removedIndex >= 0,
|
|
|
|
"A deck child was removed that was not in mFrames.");
|
|
|
|
if (removedIndex < mIndex) {
|
|
|
|
mIndex--;
|
|
|
|
// This is going to cause us to handle the index change in IndexedChanged,
|
|
|
|
// but since the new index will match mIndex, it's essentially a noop.
|
|
|
|
nsContentUtils::AddScriptRunner(new nsSetAttrRunnable(
|
2017-12-05 20:05:51 +03:00
|
|
|
mContent->AsElement(), nsGkAtoms::selectedIndex, mIndex));
|
2014-08-02 16:22:06 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
nsBoxFrame::RemoveFrame(aListID, aOldFrame);
|
|
|
|
}
|
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
void nsDeckFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsDisplayListSet& aLists) {
|
|
|
|
// only paint the selected box
|
2012-08-06 07:00:57 +04:00
|
|
|
nsIFrame* box = GetSelectedBox();
|
2006-01-26 05:29:17 +03:00
|
|
|
if (!box) return;
|
2003-11-15 03:47:43 +03:00
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
// Putting the child in the background list. This is a little weird but
|
|
|
|
// it matches what we were doing before.
|
|
|
|
nsDisplayListSet set(aLists, aLists.BlockBorderBackgrounds());
|
2017-08-07 05:23:35 +03:00
|
|
|
BuildDisplayListForChild(aBuilder, box, set);
|
1999-04-22 02:46:15 +04:00
|
|
|
}
|
|
|
|
|
2019-03-25 22:11:22 +03:00
|
|
|
void nsDeckFrame::Animate(nsIFrame* aParentBox, bool start) {
|
|
|
|
if (!aParentBox) return;
|
|
|
|
|
|
|
|
nsImageBoxFrame* imgBoxFrame = do_QueryFrame(aParentBox);
|
|
|
|
nsImageFrame* imgFrame = do_QueryFrame(aParentBox);
|
|
|
|
|
|
|
|
if (imgBoxFrame) {
|
|
|
|
if (start)
|
|
|
|
imgBoxFrame->RestartAnimation();
|
|
|
|
else
|
|
|
|
imgBoxFrame->StopAnimation();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (imgFrame) {
|
|
|
|
if (start)
|
|
|
|
imgFrame->RestartAnimation();
|
|
|
|
else
|
|
|
|
imgFrame->StopAnimation();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (nsIFrame::ChildListIterator childLists(aParentBox); !childLists.IsDone();
|
|
|
|
childLists.Next()) {
|
|
|
|
for (nsIFrame* child : childLists.CurrentList()) {
|
|
|
|
Animate(child, start);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-10-30 02:13:57 +04:00
|
|
|
NS_IMETHODIMP
|
2016-04-21 07:28:35 +03:00
|
|
|
nsDeckFrame::DoXULLayout(nsBoxLayoutState& aState) {
|
2004-06-22 06:55:04 +04:00
|
|
|
// Make sure we tweak the state so it does not resize our children.
|
2003-05-24 06:35:08 +04:00
|
|
|
// We will do that.
|
2019-08-08 22:48:19 +03:00
|
|
|
ReflowChildFlags oldFlags = aState.LayoutFlags();
|
|
|
|
aState.SetLayoutFlags(ReflowChildFlags::NoSizeView |
|
|
|
|
ReflowChildFlags::NoVisibility);
|
1999-05-10 01:46:24 +04:00
|
|
|
|
2000-06-22 04:48:49 +04:00
|
|
|
// do a normal layout
|
2016-04-21 07:28:35 +03:00
|
|
|
nsresult rv = nsBoxFrame::DoXULLayout(aState);
|
1999-05-20 02:14:11 +04:00
|
|
|
|
2000-06-22 04:48:49 +04:00
|
|
|
// run though each child. Hide all but the selected one
|
2016-04-21 07:28:32 +03:00
|
|
|
nsIFrame* box = nsBox::GetChildXULBox(this);
|
1999-10-30 02:13:57 +04:00
|
|
|
|
1999-07-23 04:11:21 +04:00
|
|
|
nscoord count = 0;
|
2017-07-06 15:00:35 +03:00
|
|
|
while (box) {
|
2000-03-31 11:02:06 +04:00
|
|
|
// make collapsed children not show up
|
2019-06-11 17:19:43 +03:00
|
|
|
if (count != mIndex) {
|
|
|
|
HideBox(box);
|
|
|
|
} else {
|
|
|
|
ShowBox(box);
|
|
|
|
}
|
2016-04-21 07:28:32 +03:00
|
|
|
box = GetNextXULBox(box);
|
2000-03-31 11:02:06 +04:00
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
2000-06-22 04:48:49 +04:00
|
|
|
aState.SetLayoutFlags(oldFlags);
|
1999-07-23 04:11:21 +04:00
|
|
|
|
1999-10-30 02:13:57 +04:00
|
|
|
return rv;
|
1999-07-23 04:11:21 +04:00
|
|
|
}
|