nsSplitterFrameInner::State nsSplitterFrameInner::GetState() { static nsIContent::AttrValuesArray strings[] = {&nsGkAtoms::dragging, &nsGkAtoms::collapsed, nullptr}; static nsIContent::AttrValuesArray strings_substate[] = {&nsGkAtoms::before, &nsGkAtoms::after, nullptr}; switch (mOuter->GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::state, strings, eCaseMatters)) { case 0: return Dragging; case 1: switch (mOuter->GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::substate, strings_substate, eCaseMatters)) { case 0: return CollapsedBefore; case 1: return CollapsedAfter; default: if (SupportsCollapseDirection(After)) return CollapsedAfter; return CollapsedBefore; } } return Open; }
void nsSplitterFrameInner::UpdateState() { // State Transitions: // Open -> Dragging // Open -> CollapsedBefore // Open -> CollapsedAfter // CollapsedBefore -> Open // CollapsedBefore -> Dragging // CollapsedAfter -> Open // CollapsedAfter -> Dragging // Dragging -> Open // Dragging -> CollapsedBefore (auto collapse) // Dragging -> CollapsedAfter (auto collapse) State newState = GetState(); if (newState == mState) { // No change. return; } if ((SupportsCollapseDirection(Before) || SupportsCollapseDirection(After)) && mOuter->GetParent()->IsBoxFrame()) { // Find the splitter's immediate sibling. nsIFrame* splitterSibling; if (newState == CollapsedBefore || mState == CollapsedBefore) { splitterSibling = mOuter->GetPrevSibling(); } else { splitterSibling = mOuter->GetNextSibling(); } if (splitterSibling) { nsCOMPtr<nsIContent> sibling = splitterSibling->GetContent(); if (sibling) { if (mState == CollapsedBefore || mState == CollapsedAfter) { // CollapsedBefore -> Open // CollapsedBefore -> Dragging // CollapsedAfter -> Open // CollapsedAfter -> Dragging nsContentUtils::AddScriptRunner( new nsUnsetAttrRunnable(sibling, nsGkAtoms::collapsed)); } else if ((mState == Open || mState == Dragging) && (newState == CollapsedBefore || newState == CollapsedAfter)) { // Open -> CollapsedBefore / CollapsedAfter // Dragging -> CollapsedBefore / CollapsedAfter nsContentUtils::AddScriptRunner( new nsSetAttrRunnable(sibling, nsGkAtoms::collapsed, NS_LITERAL_STRING("true"))); } } } } mState = newState; }
void nsSplitterFrameInner::AddListener(nsPresContext* aPresContext) { mOuter->GetContent()-> AddEventListenerByIID(static_cast<nsIDOMMouseListener*>(this), NS_GET_IID(nsIDOMMouseListener)); mOuter->GetContent()-> AddEventListenerByIID(static_cast<nsIDOMMouseMotionListener*>(this), NS_GET_IID(nsIDOMMouseMotionListener)); }
void nsSplitterFrameInner::RemoveListener() { ENSURE_TRUE(mOuter); mOuter->GetContent()-> RemoveEventListenerByIID(static_cast<nsIDOMMouseListener*>(this), NS_GET_IID(nsIDOMMouseListener)); mOuter->GetContent()-> RemoveEventListenerByIID(static_cast<nsIDOMMouseMotionListener*>(this), NS_GET_IID(nsIDOMMouseMotionListener)); }
void nsSplitterFrameInner::AddListener(nsPresContext* aPresContext) { mOuter->GetContent()-> AddEventListener(NS_LITERAL_STRING("mouseup"), this, false, false); mOuter->GetContent()-> AddEventListener(NS_LITERAL_STRING("mousedown"), this, false, false); mOuter->GetContent()-> AddEventListener(NS_LITERAL_STRING("mousemove"), this, false, false); mOuter->GetContent()-> AddEventListener(NS_LITERAL_STRING("mouseout"), this, false, false); }
void nsSplitterFrameInner::RemoveListener() { ENSURE_TRUE(mOuter); mOuter->GetContent()-> RemoveEventListener(NS_LITERAL_STRING("mouseup"), this, false); mOuter->GetContent()-> RemoveEventListener(NS_LITERAL_STRING("mousedown"), this, false); mOuter->GetContent()-> RemoveEventListener(NS_LITERAL_STRING("mousemove"), this, false); mOuter->GetContent()-> RemoveEventListener(NS_LITERAL_STRING("mouseout"), this, false); }
void nsSplitterFrameInner::AdjustChildren(nsPresContext* aPresContext, nsSplitterInfo* aChildInfos, PRInt32 aCount, bool aIsHorizontal) { ///printf("------- AdjustChildren------\n"); nsBoxLayoutState state(aPresContext); nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); // first set all the widths. nsIFrame* child = mOuter->GetChildBox(); while(child) { SetPreferredSize(state, child, onePixel, aIsHorizontal, nullptr); child = child->GetNextBox(); } // now set our changed widths. for (int i=0; i < aCount; i++) { nscoord pref = aChildInfos[i].changed; nsIFrame* childBox = GetChildBoxForContent(mParentBox, aChildInfos[i].childElem); if (childBox) { SetPreferredSize(state, childBox, onePixel, aIsHorizontal, &pref); } } }
void nsSplitterFrameInner::MouseUp(nsPresContext* aPresContext, nsGUIEvent* aEvent) { if (mDragging && mOuter) { AdjustChildren(aPresContext); AddListener(aPresContext); nsIPresShell::SetCapturingContent(nullptr, 0); // XXXndeakin is this needed? mDragging = false; State newState = GetState(); // if the state is dragging then make it Open. if (newState == Dragging) mOuter->mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::state, EmptyString(), true); mPressed = false; // if we dragged then fire a command event. if (mDidDrag) { nsCOMPtr<nsIDOMXULElement> element = do_QueryInterface(mOuter->GetContent()); element->DoCommand(); } //printf("MouseUp\n"); } delete[] mChildInfosBefore; delete[] mChildInfosAfter; mChildInfosBefore = nullptr; mChildInfosAfter = nullptr; mChildInfosBeforeCount = 0; mChildInfosAfterCount = 0; }
void nsSplitterFrameInner::AdjustChildren(nsPresContext* aPresContext) { EnsureOrient(); bool isHorizontal = !mOuter->IsHorizontal(); AdjustChildren(aPresContext, mChildInfosBefore, mChildInfosBeforeCount, isHorizontal); AdjustChildren(aPresContext, mChildInfosAfter, mChildInfosAfterCount, isHorizontal); }
void nsSplitterFrameInner::AdjustChildren(nsPresContext* aPresContext) { EnsureOrient(); bool isHorizontal = !mOuter->IsHorizontal(); AdjustChildren(aPresContext, mChildInfosBefore, mChildInfosBeforeCount, isHorizontal); AdjustChildren(aPresContext, mChildInfosAfter, mChildInfosAfterCount, isHorizontal); // printf("----- Posting Dirty -----\n"); aPresContext->PresShell()->FlushPendingNotifications(Flush_Display); }
nsSplitterFrameInner::ResizeType nsSplitterFrameInner::GetResizeBefore() { static nsIContent::AttrValuesArray strings[] = {&nsGkAtoms::farthest, &nsGkAtoms::flex, nullptr}; switch (mOuter->GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::resizebefore, strings, eCaseMatters)) { case 0: return Farthest; case 1: return Flex; } return Closest; }
nsresult nsSplitterFrameInner::MouseDown(nsIDOMEvent* aMouseEvent) { NS_ENSURE_TRUE(mOuter, NS_OK); nsCOMPtr<nsIDOMMouseEvent> mouseEvent(do_QueryInterface(aMouseEvent)); if (!mouseEvent) return NS_OK; PRUint16 button = 0; mouseEvent->GetButton(&button); // only if left button if (button != 0) return NS_OK; if (mOuter->GetContent()-> AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true, eCaseMatters)) return NS_OK; mParentBox = mOuter->GetParentBox(); if (!mParentBox) return NS_OK; // get our index nsPresContext* outerPresContext = mOuter->PresContext(); const nsFrameList& siblingList(mParentBox->PrincipalChildList()); PRInt32 childIndex = siblingList.IndexOf(mOuter); // if it's 0 (or not found) then stop right here. // It might be not found if we're not in the parent's primary frame list. if (childIndex <= 0) return NS_OK; PRInt32 childCount = siblingList.GetLength(); // if it's the last index then we need to allow for resizeafter="grow" if (childIndex == childCount - 1 && GetResizeAfter() != Grow) return NS_OK; nsRefPtr<nsRenderingContext> rc = outerPresContext->PresShell()->GetReferenceRenderingContext(); NS_ENSURE_TRUE(rc, NS_ERROR_FAILURE); nsBoxLayoutState state(outerPresContext, rc); mCurrentPos = 0; mPressed = true; mDidDrag = false; EnsureOrient(); bool isHorizontal = !mOuter->IsHorizontal(); ResizeType resizeBefore = GetResizeBefore(); ResizeType resizeAfter = GetResizeAfter(); delete[] mChildInfosBefore; delete[] mChildInfosAfter; mChildInfosBefore = new nsSplitterInfo[childCount]; mChildInfosAfter = new nsSplitterInfo[childCount]; // create info 2 lists. One of the children before us and one after. PRInt32 count = 0; mChildInfosBeforeCount = 0; mChildInfosAfterCount = 0; nsIFrame* childBox = mParentBox->GetChildBox(); while (nullptr != childBox) { nsIContent* content = childBox->GetContent(); nsIDocument* doc = content->OwnerDoc(); PRInt32 dummy; nsIAtom* atom = doc->BindingManager()->ResolveTag(content, &dummy); // skip over any splitters if (atom != nsGkAtoms::splitter) { nsSize prefSize = childBox->GetPrefSize(state); nsSize minSize = childBox->GetMinSize(state); nsSize maxSize = nsBox::BoundsCheckMinMax(minSize, childBox->GetMaxSize(state)); prefSize = nsBox::BoundsCheck(minSize, prefSize, maxSize); mOuter->AddMargin(childBox, minSize); mOuter->AddMargin(childBox, prefSize); mOuter->AddMargin(childBox, maxSize); nscoord flex = childBox->GetFlex(state); nsMargin margin(0,0,0,0); childBox->GetMargin(margin); nsRect r(childBox->GetRect()); r.Inflate(margin); // We need to check for hidden attribute too, since treecols with // the hidden="true" attribute are not really hidden, just collapsed if (!content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::fixed, nsGkAtoms::_true, eCaseMatters) && !content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden, nsGkAtoms::_true, eCaseMatters)) { if (count < childIndex && (resizeBefore != Flex || flex > 0)) { mChildInfosBefore[mChildInfosBeforeCount].childElem = content; mChildInfosBefore[mChildInfosBeforeCount].min = isHorizontal ? minSize.width : minSize.height; mChildInfosBefore[mChildInfosBeforeCount].max = isHorizontal ? maxSize.width : maxSize.height; mChildInfosBefore[mChildInfosBeforeCount].current = isHorizontal ? r.width : r.height; mChildInfosBefore[mChildInfosBeforeCount].flex = flex; mChildInfosBefore[mChildInfosBeforeCount].index = count; mChildInfosBefore[mChildInfosBeforeCount].changed = mChildInfosBefore[mChildInfosBeforeCount].current; mChildInfosBeforeCount++; } else if (count > childIndex && (resizeAfter != Flex || flex > 0)) { mChildInfosAfter[mChildInfosAfterCount].childElem = content; mChildInfosAfter[mChildInfosAfterCount].min = isHorizontal ? minSize.width : minSize.height; mChildInfosAfter[mChildInfosAfterCount].max = isHorizontal ? maxSize.width : maxSize.height; mChildInfosAfter[mChildInfosAfterCount].current = isHorizontal ? r.width : r.height; mChildInfosAfter[mChildInfosAfterCount].flex = flex; mChildInfosAfter[mChildInfosAfterCount].index = count; mChildInfosAfter[mChildInfosAfterCount].changed = mChildInfosAfter[mChildInfosAfterCount].current; mChildInfosAfterCount++; } } } childBox = childBox->GetNextBox(); count++; } if (!mParentBox->IsNormalDirection()) { // The before array is really the after array, and the order needs to be reversed. // First reverse both arrays. Reverse(mChildInfosBefore, mChildInfosBeforeCount); Reverse(mChildInfosAfter, mChildInfosAfterCount); // Now swap the two arrays. nscoord newAfterCount = mChildInfosBeforeCount; mChildInfosBeforeCount = mChildInfosAfterCount; mChildInfosAfterCount = newAfterCount; nsSplitterInfo* temp = mChildInfosAfter; mChildInfosAfter = mChildInfosBefore; mChildInfosBefore = temp; } // 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 != Farthest) Reverse(mChildInfosBefore, mChildInfosBeforeCount); // 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 == Farthest) Reverse(mChildInfosAfter, mChildInfosAfterCount); // grow only applys to the children after. If grow is set then no space should be taken out of any children after // us. To do this we just set the size of that list to be 0. if (resizeAfter == Grow) mChildInfosAfterCount = 0; PRInt32 c; nsPoint pt = nsLayoutUtils::GetDOMEventCoordinatesRelativeTo(mouseEvent, mParentBox); if (isHorizontal) { c = pt.x; mSplitterPos = mOuter->mRect.x; } else { c = pt.y; mSplitterPos = mOuter->mRect.y; } mDragStart = c; //printf("Pressed mDragStart=%d\n",mDragStart); nsIPresShell::SetCapturingContent(mOuter->GetContent(), CAPTURE_IGNOREALLOWED); return NS_OK; }
void nsSplitterFrameInner::MouseDrag(nsPresContext* aPresContext, nsGUIEvent* aEvent) { if (mDragging && mOuter) { //printf("Dragging\n"); bool isHorizontal = !mOuter->IsHorizontal(); // convert coord to pixels nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, mParentBox); nscoord pos = isHorizontal ? pt.x : pt.y; // mDragStart is in frame coordinates nscoord start = mDragStart; // take our current position and subtract the start location pos -= start; //printf("Diff=%d\n", pos); ResizeType resizeAfter = GetResizeAfter(); bool bounded; if (resizeAfter == nsSplitterFrameInner::Grow) bounded = false; else bounded = true; int i; for (i=0; i < mChildInfosBeforeCount; i++) mChildInfosBefore[i].changed = mChildInfosBefore[i].current; for (i=0; i < mChildInfosAfterCount; i++) mChildInfosAfter[i].changed = mChildInfosAfter[i].current; nscoord oldPos = pos; ResizeChildTo(aPresContext, pos, mChildInfosBefore, mChildInfosAfter, mChildInfosBeforeCount, mChildInfosAfterCount, bounded); State currentState = GetState(); bool supportsBefore = SupportsCollapseDirection(Before); bool supportsAfter = SupportsCollapseDirection(After); const bool isRTL = mOuter->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL; bool pastEnd = oldPos > 0 && oldPos > pos; bool pastBegin = oldPos < 0 && oldPos < pos; if (isRTL) { // Swap the boundary checks in RTL mode bool tmp = pastEnd; pastEnd = pastBegin; pastBegin = tmp; } const bool isCollapsedBefore = pastBegin && supportsBefore; const bool isCollapsedAfter = pastEnd && supportsAfter; // if we are in a collapsed position if (isCollapsedBefore || isCollapsedAfter) { // and we are not collapsed then collapse if (currentState == Dragging) { if (pastEnd) { //printf("Collapse right\n"); if (supportsAfter) { nsCOMPtr<nsIContent> outer = mOuter->mContent; outer->SetAttr(kNameSpaceID_None, nsGkAtoms::substate, NS_LITERAL_STRING("after"), true); outer->SetAttr(kNameSpaceID_None, nsGkAtoms::state, NS_LITERAL_STRING("collapsed"), true); } } else if (pastBegin) { //printf("Collapse left\n"); if (supportsBefore) { nsCOMPtr<nsIContent> outer = mOuter->mContent; outer->SetAttr(kNameSpaceID_None, nsGkAtoms::substate, NS_LITERAL_STRING("before"), true); outer->SetAttr(kNameSpaceID_None, nsGkAtoms::state, NS_LITERAL_STRING("collapsed"), true); } } } } else { // if we are not in a collapsed position and we are not dragging make sure // we are dragging. if (currentState != Dragging) mOuter->mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::state, NS_LITERAL_STRING("dragging"), true); AdjustChildren(aPresContext); } mDidDrag = true; } }
void nsSplitterFrameInner::MouseDrag(nsPresContext* aPresContext, nsGUIEvent* aEvent) { if (mDragging && mOuter) { //printf("Dragging\n"); PRBool isHorizontal = !mOuter->IsHorizontal(); // convert coord to pixels nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, mParentBox); nscoord pos = isHorizontal ? pt.x : pt.y; // mDragStart is in frame coordinates nscoord start = mDragStart; // take our current position and subtract the start location pos -= start; //printf("Diff=%d\n", pos); ResizeType resizeAfter = GetResizeAfter(); PRBool bounded; if (resizeAfter == nsSplitterFrameInner::Grow) bounded = PR_FALSE; else bounded = PR_TRUE; int i; for (i=0; i < mChildInfosBeforeCount; i++) mChildInfosBefore[i].changed = mChildInfosBefore[i].current; for (i=0; i < mChildInfosAfterCount; i++) mChildInfosAfter[i].changed = mChildInfosAfter[i].current; nscoord oldPos = pos; ResizeChildTo(aPresContext, pos, mChildInfosBefore, mChildInfosAfter, mChildInfosBeforeCount, mChildInfosAfterCount, bounded); State currentState = GetState(); PRBool supportsBefore = SupportsCollapseDirection(Before); PRBool supportsAfter = SupportsCollapseDirection(After); // if we are in a collapsed position if ((oldPos > 0 && oldPos > pos && supportsAfter) || (oldPos < 0 && oldPos < pos && supportsBefore)) { // and we are not collapsed then collapse if (currentState == Dragging) { if (oldPos > 0 && oldPos > pos) { //printf("Collapse right\n"); if (supportsAfter) { nsCOMPtr<nsIContent> outer = mOuter->mContent; outer->SetAttr(kNameSpaceID_None, nsGkAtoms::substate, NS_LITERAL_STRING("after"), PR_TRUE); outer->SetAttr(kNameSpaceID_None, nsGkAtoms::state, NS_LITERAL_STRING("collapsed"), PR_TRUE); } } else if (oldPos < 0 && oldPos < pos) { //printf("Collapse left\n"); if (supportsBefore) { nsCOMPtr<nsIContent> outer = mOuter->mContent; outer->SetAttr(kNameSpaceID_None, nsGkAtoms::substate, NS_LITERAL_STRING("before"), PR_TRUE); outer->SetAttr(kNameSpaceID_None, nsGkAtoms::state, NS_LITERAL_STRING("collapsed"), PR_TRUE); } } } } else { // if we are not in a collapsed position and we are not dragging make sure // we are dragging. if (currentState != Dragging) mOuter->mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::state, NS_LITERAL_STRING("dragging"), PR_TRUE); AdjustChildren(aPresContext); } mDidDrag = PR_TRUE; } }