/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */
// // Eric Vaughan // Netscape Communications // // See documentation in associated header file //
enumclass ResizeType { // Resize the closest sibling in a given direction.
Closest, // Resize the farthest sibling in a given direction.
Farthest, // Resize only flexible siblings in a given direction.
Flex, // No space should be taken out of any children in that direction. // FIXME(emilio): This is a rather odd name...
Grow, // Only resize adjacent siblings.
Sibling, // Don't resize anything in a given direction.
None,
}; static ResizeType ResizeTypeFromAttribute(const Element& aElement,
nsAtom* aAttribute) { static Element::AttrValuesArray strings[] = {
nsGkAtoms::farthest, nsGkAtoms::flex, nsGkAtoms::grow,
nsGkAtoms::sibling, nsGkAtoms::none, nullptr}; switch (aElement.FindAttrValueIn(kNameSpaceID_None, aAttribute, strings,
eCaseMatters)) { case 0: return ResizeType::Farthest; case 1: return ResizeType::Flex; case 2: // Grow only applies to resizeAfter. if (aAttribute == nsGkAtoms::resizeafter) { return ResizeType::Grow;
} break; case 3: return ResizeType::Sibling; case 4: return ResizeType::None; default: break;
} return ResizeType::Closest;
}
class nsSplitterFrameInner final : public nsIDOMEventListener { protected: virtual ~nsSplitterFrameInner();
/** * Initialize us. If we are in a box get our alignment so we know what direction * we are
*/ void nsSplitterFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) {
MOZ_ASSERT(!mInner);
mInner = new nsSplitterFrameInner(this);
staticbool SplitterIsHorizontal(const nsIFrame* aParentBox) { // If our parent is horizontal, the splitter is vertical and vice-versa.
MOZ_ASSERT(aParentBox->IsFlexContainerFrame()); const FlexboxAxisInfo info(aParentBox); return !info.mIsRowOriented;
}
// if the mouse is captured always return us as the frame. if (mInner->mDragging && aBuilder->IsForEventDelivery()) { // XXX It's probably better not to check visibility here, right?
aLists.Outlines()->AppendNewToTop<nsDisplayEventReceiver>(aBuilder, this); return;
}
}
void nsSplitterFrameInner::MouseUp(nsPresContext* aPresContext,
WidgetGUIEvent* aEvent) { if (mDragging && mOuter) {
AdjustChildren(aPresContext);
AddListener();
PresShell::ReleaseCapturingContent(); // XXXndeakin is this needed?
mDragging = false;
State newState = GetState(); // if the state is dragging then make it Open. if (newState == State::Dragging) {
mOuter->mContent->AsElement()->SetAttr(kNameSpaceID_None,
nsGkAtoms::state, u""_ns, true);
}
mPressed = false;
// if we dragged then fire a command event. if (mDidDrag) {
RefPtr<nsXULElement> element =
nsXULElement::FromNode(mOuter->GetContent());
element->DoCommand();
}
// if we are in a collapsed position if (isCollapsedBefore || isCollapsedAfter) { // and we are not collapsed then collapse if (currentState == State::Dragging) { if (pastEnd) { // printf("Collapse right\n"); if (supportsAfter) {
RefPtr<Element> outer = mOuter->mContent->AsElement();
outer->SetAttr(kNameSpaceID_None, nsGkAtoms::substate, u"after"_ns, true);
outer->SetAttr(kNameSpaceID_None, nsGkAtoms::state, u"collapsed"_ns, true);
}
} elseif (pastBegin) { // printf("Collapse left\n"); if (supportsBefore) {
RefPtr<Element> outer = mOuter->mContent->AsElement();
outer->SetAttr(kNameSpaceID_None, nsGkAtoms::substate, u"before"_ns, true);
outer->SetAttr(kNameSpaceID_None, nsGkAtoms::state, u"collapsed"_ns, true);
}
}
}
} else { // if we are not in a collapsed position and we are not dragging make sure // we are dragging. if (currentState != State::Dragging) {
mOuter->mContent->AsElement()->SetAttr(
kNameSpaceID_None, nsGkAtoms::state, u"dragging"_ns, true);
}
AdjustChildren(aPresContext);
}
bool foundOuter = false;
CSSOrderAwareFrameIterator iter(
mParentBox, FrameChildListID::Principal,
CSSOrderAwareFrameIterator::ChildFilter::IncludeAll,
CSSOrderAwareFrameIterator::OrderState::Unknown,
CSSOrderAwareFrameIterator::OrderingProperty::Order); for (; !iter.AtEnd(); iter.Next()) {
nsIFrame* childBox = iter.get(); if (childBox == mOuter) {
foundOuter = true; if (!count) { // We're at the beginning, nothing to do. return NS_OK;
} if (count == childCount - 1 && resizeAfter != ResizeType::Grow) { // If it's the last index then we need to allow for resizeafter="grow" return NS_OK;
}
}
count++;
nsIContent* content = childBox->GetContent(); // XXX flex seems untested, as it uses mBoxFlex rather than actual flexbox // flex. const nscoord flex = childBox->StyleXUL()->mBoxFlex; constbool isBefore = !foundOuter; constbool isResizable = [&] { if (auto* element = nsXULElement::FromNode(content)) { if (element->NodeInfo()->NameAtom() == nsGkAtoms::splitter) { // skip over any splitters returnfalse;
}
// We need to check for hidden attribute too, since treecols with // the hidden="true" attribute are not really hidden, just collapsed if (element->GetXULBoolAttr(nsGkAtoms::fixed) ||
element->GetXULBoolAttr(nsGkAtoms::hidden)) { returnfalse;
}
}
// We need to check this here rather than in the switch before because we // want `sibling` to work in the DOM order, not frame tree order. if (resizeBefore == ResizeType::Sibling &&
content->GetNextElementSibling() == outerContent) { returntrue;
} if (resizeAfter == ResizeType::Sibling &&
content->GetPreviousElementSibling() == outerContent) { returntrue;
}
const ResizeType resizeType = isBefore ? resizeBefore : resizeAfter; switch (resizeType) { case ResizeType::Grow: case ResizeType::None: case ResizeType::Sibling: returnfalse; case ResizeType::Flex: return flex > 0; case ResizeType::Closest: case ResizeType::Farthest: break;
} returntrue;
}();
if (reverseDirection) { // The before array is really the after array, and the order needs to be // reversed. First reverse both arrays.
mChildInfosBefore.Reverse();
mChildInfosAfter.Reverse();
// Now swap the two arrays.
std::swap(mChildInfosBefore, mChildInfosAfter);
}
// if resizebefore is not Farthest, reverse the list because the first child // in the list is the farthest, and we want the first child to be the closest. if (resizeBefore != ResizeType::Farthest) {
mChildInfosBefore.Reverse();
}
// if the resizeafter is the Farthest we must reverse the list because the // first child in the list is the closest we want the first child to be the // Farthest. if (resizeAfter == ResizeType::Farthest) {
mChildInfosAfter.Reverse();
}
int32_t c;
nsPoint pt =
nsLayoutUtils::GetDOMEventCoordinatesRelativeTo(mouseEvent, mParentBox); if (isHorizontal) {
c = pt.x;
mSplitterPos = mOuter->mRect.x;
} else {
c = pt.y;
mSplitterPos = mOuter->mRect.y;
}
for (auto& info : aChildInfos) {
nscoord min = info.min;
nscoord max = info.max;
nscoord& c = info.changed;
// figure our how much space to add or remove if (c + aDiff < min) {
aDiff += (c - min);
c = min;
} elseif (c + aDiff > max) {
aDiff -= (max - c);
c = max;
} else {
c += aDiff;
aDiff = 0;
}
// there is not space left? We are done if (aDiff == 0) { break;
}
}
aSpaceLeft = aDiff;
}
/** * Ok if we want to resize a child we will know the actual size in pixels we * want it to be. This is not the preferred size. But the only way we can change * a child is by manipulating its preferred size. So give the actual pixel size * this method will figure out the preferred size and set it.
*/
if (!mChildInfosBefore.IsEmpty()) {
AddRemoveSpace(aDiff, mChildInfosBefore, spaceLeft); // If there is any space left over remove it from the diff we were // originally given.
aDiff -= spaceLeft;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.