From 1a3893097faf9e95e463cb8fe79c8abdfdc5d50c Mon Sep 17 00:00:00 2001 From: "pinkerton%netscape.com" Date: Tue, 15 Aug 2000 18:23:34 +0000 Subject: [PATCH] fix for 47105, retooling of tree d&d to not be so confusing, to use the style system a little more, and to handle the case where a tree won't let you drop anything between rows. --- content/shared/public/nsXULAtomList.h | 2 + .../xul/base/src/nsTreeItemDragCapturer.cpp | 141 +++++++++++------- layout/xul/base/src/nsTreeItemDragCapturer.h | 13 +- layout/xul/base/src/nsXULTreeGroupFrame.cpp | 83 ++++------- .../xul/base/src/nsXULTreeOuterGroupFrame.cpp | 13 +- .../xul/base/src/nsXULTreeOuterGroupFrame.h | 2 + layout/xul/content/src/nsXULAtomList.h | 2 + 7 files changed, 148 insertions(+), 108 deletions(-) diff --git a/content/shared/public/nsXULAtomList.h b/content/shared/public/nsXULAtomList.h index 5153ef6a4b99..e9652ca5b23e 100644 --- a/content/shared/public/nsXULAtomList.h +++ b/content/shared/public/nsXULAtomList.h @@ -155,8 +155,10 @@ XUL_ATOM(ddDropOn, "dd-dropon") XUL_ATOM(ddTriggerRepaintSorted, "dd-triggerrepaintsorted") XUL_ATOM(ddTriggerRepaintRestore, "dd-triggerrepaintrestore") XUL_ATOM(ddTriggerRepaint, "dd-triggerrepaint") +XUL_ATOM(ddNoDropBetweenRows, "dd-nodropbetweenrows") XUL_ATOM(container, "container") XUL_ATOM(ddDragDropArea, "dragdroparea") +XUL_ATOM(ddDropMarker, ":-moz-drop-marker") XUL_ATOM(widget, "widget") XUL_ATOM(window, "window") diff --git a/layout/xul/base/src/nsTreeItemDragCapturer.cpp b/layout/xul/base/src/nsTreeItemDragCapturer.cpp index db3737a4e673..1a0f47f08abf 100644 --- a/layout/xul/base/src/nsTreeItemDragCapturer.cpp +++ b/layout/xul/base/src/nsTreeItemDragCapturer.cpp @@ -37,6 +37,9 @@ #include "nsIDOMEventTarget.h" #include "nsIView.h" #include "nsIFrame.h" +#include "nsXULTreeGroupFrame.h" +#include "nsXULTreeOuterGroupFrame.h" + NS_IMPL_ADDREF(nsTreeItemDragCapturer) NS_IMPL_RELEASE(nsTreeItemDragCapturer) @@ -49,7 +52,7 @@ NS_IMPL_QUERY_INTERFACE2(nsTreeItemDragCapturer, nsIDOMEventListener, nsIDOMDrag // Init member variables. We can't really do much of anything important here because // any subframes might not be totally intialized yet, or in the hash table // -nsTreeItemDragCapturer :: nsTreeItemDragCapturer ( nsIFrame* inTreeItem, nsIPresContext* inPresContext ) +nsTreeItemDragCapturer :: nsTreeItemDragCapturer ( nsXULTreeGroupFrame* inTreeItem, nsIPresContext* inPresContext ) : mTreeItem(inTreeItem), mPresContext(inPresContext), mCurrentDropLoc(kNoDropLoc) { NS_INIT_REFCNT(); @@ -110,18 +113,92 @@ void nsTreeItemDragCapturer :: ComputeDropPosition ( nsIDOMEvent* aDragEvent, nscoord* outYLoc, PRBool* outBefore, PRBool* outDropOnMe ) { - *outYLoc = 0; + *outYLoc = kNoDropLoc; *outBefore = PR_FALSE; *outDropOnMe = PR_FALSE; - // - // Get the mouse coordinates from the DOM event, but they will be in the - // window/widget coordinate system. We must first get them into the frame-relative - // coordinate system. Yuck. - // + float p2t; + mPresContext->GetScaledPixelsToTwips(&p2t); + nscoord onePixel = NSIntPixelsToTwips(1, p2t); + + // Gecko trickery to get mouse coordinates into the right coordinate system for + // comparison with the row. + nsPoint pnt(0,0); + nsRect rowRect; + ConvertEventCoordsToRowCoords ( aDragEvent, &pnt, &rowRect); + // check the outer group frame to see if the tree allows drops between rows. If it + // doesn't then basically the entire row is a drop zone for a container. + PRBool allowsDropsBetweenRows = PR_TRUE; + nsXULTreeOuterGroupFrame* outerGroup = mTreeItem->GetOuterFrame(); + if ( outerGroup ) + allowsDropsBetweenRows = outerGroup->CanDropBetweenRows(); + + // now check if item is a container + PRBool isContainer = PR_FALSE; + nsCOMPtr treeItemContent; + mTreeItem->GetContent ( getter_AddRefs(treeItemContent) ); + nsCOMPtr treeItemNode ( do_QueryInterface(treeItemContent) ); + if ( treeItemNode ) { + nsAutoString value; + treeItemNode->GetAttribute(NS_ConvertASCIItoUCS2("container"), value); // can't use an atom here =( + isContainer = value.EqualsWithConversion("true"); + } + else + NS_WARNING("Not a DOM element"); + + if ( allowsDropsBetweenRows ) { + // if we have a container, the area is broken up into 3 pieces (top, middle, bottom). If + // it isn't it's only broken up into two (top and bottom) + if ( isContainer ) { + if (pnt.y <= (rowRect.y + (rowRect.height / 4))) { + *outBefore = PR_TRUE; + *outYLoc = 0; + } + else if (pnt.y >= (rowRect.y + PRInt32(float(rowRect.height) *0.75))) { + *outBefore = PR_FALSE; + *outYLoc = rowRect.y + rowRect.height - onePixel; + } + else { + // we're on the container + *outDropOnMe = PR_TRUE; + *outYLoc = kContainerDropLoc; + } + } // if row is a container + else { + if (pnt.y <= (rowRect.y + (rowRect.height / 2))) { + *outBefore = PR_TRUE; + *outYLoc = 0; + } + else + *outYLoc = rowRect.y + rowRect.height - onePixel; + } // else is not a container + } // if can drop between rows + else { + // the tree doesn't allow drops between rows, therefore only drops on containers + // are valid. For this case, make the entire cell a dropzone for this row as there + // is no concept of above and below. + if ( isContainer ) { + *outYLoc = kContainerDropLoc; + *outDropOnMe = PR_TRUE; + } + } // else only allow drops on containers + +} // ComputeDropPosition + + +// +// ConvertEventCoordsToRowCoords +// +// Get the mouse coordinates from the DOM event, but they will be in the +// window/widget coordinate system. We must first get them into the frame-relative +// coordinate system of the row. Yuck. +// +void +nsTreeItemDragCapturer :: ConvertEventCoordsToRowCoords ( nsIDOMEvent* inDragEvent, nsPoint* outCoords, nsRect* outRowRect ) +{ // get mouse coordinates and translate them into twips - nsCOMPtr mouseEvent(do_QueryInterface(aDragEvent)); + nsCOMPtr mouseEvent(do_QueryInterface(inDragEvent)); PRInt32 x,y = 0; mouseEvent->GetClientX(&x); mouseEvent->GetClientY(&y); @@ -133,11 +210,10 @@ nsTreeItemDragCapturer :: ComputeDropPosition ( nsIDOMEvent* aDragEvent, nscoord // get the rect of the row (not the tree item) that the mouse is over. This is // where we need to start computing things from. - nsRect rowRect; nsIFrame* rowFrame; mTreeItem->FirstChild(mPresContext, nsnull, &rowFrame); NS_ASSERTION ( rowFrame, "couldn't get rowGroup's row frame" ); - rowFrame->GetRect(rowRect); + rowFrame->GetRect(*outRowRect); // compute the offset to top level in twips float t2p; @@ -167,47 +243,11 @@ nsTreeItemDragCapturer :: ComputeDropPosition ( nsIDOMEvent* aDragEvent, nscoord nscoord viewOffsetToParentX = 0, viewOffsetToParentY = 0; containingView->GetPosition ( &viewOffsetToParentX, &viewOffsetToParentY ); pnt.MoveBy ( -viewOffsetToParentX, -viewOffsetToParentY ); - - // now check if item is a container - PRBool isContainer = PR_FALSE; - nsCOMPtr treeItemContent; - mTreeItem->GetContent ( getter_AddRefs(treeItemContent) ); - nsCOMPtr treeItemNode ( do_QueryInterface(treeItemContent) ); - if ( treeItemNode ) { - nsAutoString value; - treeItemNode->GetAttribute(NS_ConvertASCIItoUCS2("container"), value); // can't use an atom here =( - isContainer = value.EqualsWithConversion("true"); - } - else - NS_WARNING("Not a DOM element"); - - // if we have a container, the area is broken up into 3 pieces (top, middle, bottom). If - // it isn't it's only broken up into two (top and bottom) - if ( isContainer ) { - if (pnt.y <= (rowRect.y + (rowRect.height / 4))) { - *outBefore = PR_TRUE; - *outYLoc = 0; - } - else if (pnt.y >= (rowRect.y + PRInt32(float(rowRect.height) *0.75))) { - *outBefore = PR_FALSE; - *outYLoc = rowRect.y + rowRect.height - onePixel; - } - else { - // we're on the container - *outDropOnMe = PR_TRUE; - *outYLoc = kContainerDropLoc; - } - } // if row is a container - else { - if (pnt.y <= (rowRect.y + (rowRect.height / 2))) { - *outBefore = PR_TRUE; - *outYLoc = 0; - } - else - *outYLoc = rowRect.y + rowRect.height - onePixel; - } // else is not a container -} // ComputeDropPosition + if ( outCoords ) + *outCoords = pnt; + +} // ConvertEventCoordsToRowCoords // @@ -240,7 +280,6 @@ nsTreeItemDragCapturer::DragOver(nsIDOMEvent* aDragEvent) if ( content ) { char buffer[10]; - // need the cast, because on some platforms, PR[U]int32 != long, but we're using "%ld" sprintf(buffer, "%d", yLoc); content->SetAttribute ( kNameSpaceID_None, nsXULAtoms::ddDropLocationCoord, NS_ConvertASCIItoUCS2(buffer), PR_TRUE ); content->SetAttribute ( kNameSpaceID_None, nsXULAtoms::ddDropLocation, NS_ConvertASCIItoUCS2(beforeMe ? "true" : "false"), PR_FALSE ); diff --git a/layout/xul/base/src/nsTreeItemDragCapturer.h b/layout/xul/base/src/nsTreeItemDragCapturer.h index f33dc98db39f..7a1d29270286 100644 --- a/layout/xul/base/src/nsTreeItemDragCapturer.h +++ b/layout/xul/base/src/nsTreeItemDragCapturer.h @@ -30,7 +30,9 @@ class nsIPresContext; class nsIDOMEvent; class nsIFrame; - +class nsXULTreeGroupFrame; +class nsPoint; +class nsRect; class nsTreeItemDragCapturer : public nsIDOMDragListener { @@ -43,7 +45,7 @@ public: } ; // default ctor and dtor - nsTreeItemDragCapturer ( nsIFrame* inTreeItem, nsIPresContext* inPresContext ); + nsTreeItemDragCapturer ( nsXULTreeGroupFrame* inTreeItem, nsIPresContext* inPresContext ); virtual ~nsTreeItemDragCapturer(); // interfaces for addref and release and queryinterface @@ -65,11 +67,16 @@ protected: // middle region of the row height. If this is the case, |outBefore| is meaningless. void ComputeDropPosition(nsIDOMEvent* aDragEvent, nscoord* outYLoc, PRBool* outBefore, PRBool* outDropOnMe); + // Take the mouse coordinates from the DOM event and convert them into frame-relative + // coordinates. + void ConvertEventCoordsToRowCoords ( nsIDOMEvent* inDragEvent, nsPoint* outCoords, + nsRect* outRowRect ) ; + // Since there are so many nested tree items, we have to weed out when the event is not // really for us. PRBool IsEventTargetMyTreeItem ( nsIDOMEvent* inEvent ) ; - nsIFrame* mTreeItem; // rowGroup owns me, don't be circular + nsXULTreeGroupFrame* mTreeItem; // rowGroup owns me, don't be circular nsIPresContext* mPresContext; // weak reference PRInt32 mCurrentDropLoc; diff --git a/layout/xul/base/src/nsXULTreeGroupFrame.cpp b/layout/xul/base/src/nsXULTreeGroupFrame.cpp index 6390dda39321..38caeb5508ee 100644 --- a/layout/xul/base/src/nsXULTreeGroupFrame.cpp +++ b/layout/xul/base/src/nsXULTreeGroupFrame.cpp @@ -714,8 +714,7 @@ nsXULTreeGroupFrame :: PaintDropFeedback ( nsIPresContext* aPresContext, nsIRend PRBool aPaintSorted ) { // lookup the drop marker color. default to black if not found. - nsCOMPtr atom ( getter_AddRefs(NS_NewAtom(":-moz-drop-marker")) ); - nscolor color = GetColorFromStyleContext ( aPresContext, atom, NS_RGB(0,0,0) ) ; + nscolor color = GetColorFromStyleContext ( aPresContext, nsXULAtoms::ddDropMarker, NS_RGB(0,0,0) ); // find the twips-to-pixels conversion. We have decided not to cache this for // space reasons. @@ -769,50 +768,25 @@ nsXULTreeGroupFrame :: PaintSortedDropFeedback ( nscolor inColor, nsIRenderingCo // // PaintOnContainerDropFeedback // -// Draws the drop feedback for when the tree is sorted, so line-item drop feedback is -// not appliable. +// Draws the drop feedback for when the row is a container and it is open. We let +// CSS handle the operation of painting the row bg so it's skinnable. // void nsXULTreeGroupFrame :: PaintOnContainerDropFeedback ( nscolor inColor, nsIRenderingContext& inRenderingContext, nsIPresContext* inPresContext, float & inPixelsToTwips ) { - // lookup the color for the bg of the selected cell. default to gray if not found. - nsCOMPtr atom ( getter_AddRefs(NS_NewAtom(":-moz-drop-container-bg")) ); - nscolor bgColor = GetColorFromStyleContext ( inPresContext, atom, NS_RGB(0xDD, 0xDD, 0xDD) ) ; - - // paint the cell's bg...we really want to muck with the titled buttons, but a) there - // isn't any support for that yet, and b) we don't really know what's going - // to be there in the cell as far as anonymous content goes... - nsRect cellBounds; - nsIFrame* treeRow; - FirstChild ( inPresContext, nsnull, &treeRow ); - if ( !treeRow ) return; - nsIFrame* treeCell; - treeRow->FirstChild ( inPresContext, nsnull, &treeCell ); - if ( !treeCell ) return; - treeCell->GetRect ( cellBounds ); - inRenderingContext.SetColor ( bgColor ); - inRenderingContext.FillRect ( cellBounds ); - - PRInt32 horizIndent = 0; if ( IsOpenContainer() ) { + PRInt32 horizIndent = 0; nsIFrame* firstChild = nsnull; FindFirstChildTreeItemFrame ( inPresContext, &firstChild ); if ( firstChild ) horizIndent = FindIndentation(inPresContext, firstChild); + + inRenderingContext.SetColor(inColor); + nsRect dividingLine ( horizIndent, mRect.height - NSToIntRound(2 * inPixelsToTwips), + NSToIntRound(50 * inPixelsToTwips), NSToIntRound(2 * inPixelsToTwips) ); + inRenderingContext.DrawRect ( dividingLine ); } - else { - // for the case where the container is closed (it doesn't have any children) - // all we can do is get our own indentation and add the hardcoded indent level - // since we don't really know...The indent level is currently hardcoded in - // the treeIndentation frame to 16.. - horizIndent = FindIndentation(inPresContext, this) + NSToIntRound(16 * inPixelsToTwips); - } - - inRenderingContext.SetColor(inColor); - nsRect dividingLine ( horizIndent, mRect.height - NSToIntRound(2 * inPixelsToTwips), - NSToIntRound(50 * inPixelsToTwips), NSToIntRound(2 * inPixelsToTwips) ); - inRenderingContext.DrawRect ( dividingLine ); } // PaintOnContainerDropFeedback @@ -820,30 +794,33 @@ nsXULTreeGroupFrame :: PaintOnContainerDropFeedback ( nscolor inColor, nsIRender // // PaintInBetweenDropFeedback // -// Draw the feedback for when the drop is to go in between two nodes +// Draw the feedback for when the drop is to go in between two nodes, but only if the tree +// allows that. // void nsXULTreeGroupFrame :: PaintInBetweenDropFeedback ( nscolor inColor, nsIRenderingContext& inRenderingContext, nsIPresContext* inPresContext, float & inPixelsToTwips ) { - // the normal case is that we can just look at this frame to find the indentation we need. However, - // when we're an _open container_ and are being asked to draw the line _after_, we need to use the - // indentation of our first child instead. ick. - PRInt32 horizIndent = 0; - if ( IsOpenContainer() && mYDropLoc > 0 ) { - nsIFrame* firstChild = nsnull; - FindFirstChildTreeItemFrame ( inPresContext, &firstChild ); - if ( firstChild ) - horizIndent = FindIndentation(inPresContext, firstChild); - } // if open container and drop after - else - horizIndent = FindIndentation(inPresContext, this); + if ( mOuterFrame->CanDropBetweenRows() ) { + // the normal case is that we can just look at this frame to find the indentation we need. However, + // when we're an _open container_ and are being asked to draw the line _after_, we need to use the + // indentation of our first child instead. ick. + PRInt32 horizIndent = 0; + if ( IsOpenContainer() && mYDropLoc > 0 ) { + nsIFrame* firstChild = nsnull; + FindFirstChildTreeItemFrame ( inPresContext, &firstChild ); + if ( firstChild ) + horizIndent = FindIndentation(inPresContext, firstChild); + } // if open container and drop after + else + horizIndent = FindIndentation(inPresContext, this); + + inRenderingContext.SetColor(inColor); + nsRect dividingLine ( horizIndent, mYDropLoc, + NSToIntRound(50 * inPixelsToTwips), NSToIntRound(2 * inPixelsToTwips) ); + inRenderingContext.FillRect(dividingLine); + } - inRenderingContext.SetColor(inColor); - nsRect dividingLine ( horizIndent, mYDropLoc, - NSToIntRound(50 * inPixelsToTwips), NSToIntRound(2 * inPixelsToTwips) ); - inRenderingContext.FillRect(dividingLine); - } // PaintInBetweenDropFeedback diff --git a/layout/xul/base/src/nsXULTreeOuterGroupFrame.cpp b/layout/xul/base/src/nsXULTreeOuterGroupFrame.cpp index f06933a8549e..0634032e83e8 100644 --- a/layout/xul/base/src/nsXULTreeOuterGroupFrame.cpp +++ b/layout/xul/base/src/nsXULTreeOuterGroupFrame.cpp @@ -140,7 +140,7 @@ NS_NewXULTreeOuterGroupFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRB nsXULTreeOuterGroupFrame::nsXULTreeOuterGroupFrame(nsIPresShell* aPresShell, PRBool aIsRoot, nsIBoxLayout* aLayoutManager, PRBool aIsHorizontal) :nsXULTreeGroupFrame(aPresShell, aIsRoot, aLayoutManager, aIsHorizontal), mRowGroupInfo(nsnull), mRowHeight(0), mCurrentIndex(0), - mTreeIsSorted(PR_FALSE), mDragOverListener(nsnull), + mTreeIsSorted(PR_FALSE), mDragOverListener(nsnull), mCanDropBetweenRows(PR_TRUE), mTreeLayoutState(eTreeLayoutNormal), mReflowCallbackPosted(PR_FALSE) { } @@ -235,6 +235,17 @@ nsXULTreeOuterGroupFrame::Init(nsIPresContext* aPresContext, nsIContent* aConten receiver->AddEventListener(NS_ConvertASCIItoUCS2("dragover"), mDragOverListener, PR_FALSE); } + // our parent is the tag. check if it has an attribute denying the ability to + // drop between rows and cache it here for the benefit of the rows inside us. + nsCOMPtr parent; + mContent->GetParent ( *getter_AddRefs(parent) ); + if ( parent ) { + nsAutoString attr; + parent->GetAttribute ( kNameSpaceID_None, nsXULAtoms::ddNoDropBetweenRows, attr ); + if ( attr.Equals(NS_ConvertASCIItoUCS2("true")) ) + mCanDropBetweenRows = PR_FALSE; + } + return rv; } // Init diff --git a/layout/xul/base/src/nsXULTreeOuterGroupFrame.h b/layout/xul/base/src/nsXULTreeOuterGroupFrame.h index a2376b96a5fe..d2e01a7bdbc6 100644 --- a/layout/xul/base/src/nsXULTreeOuterGroupFrame.h +++ b/layout/xul/base/src/nsXULTreeOuterGroupFrame.h @@ -186,6 +186,7 @@ public: NS_IMETHOD InternalPositionChanged(PRBool aUp, PRInt32 aDelta); PRBool IsTreeSorted ( ) const { return mTreeIsSorted; } + PRBool CanDropBetweenRows ( ) const { return mCanDropBetweenRows; } nsTreeLayoutState GetTreeLayoutState() { return mTreeLayoutState; } void SetTreeLayoutState(nsTreeLayoutState aState) { mTreeLayoutState = aState; } @@ -208,6 +209,7 @@ protected: nscoord mOnePixel; PRInt32 mCurrentIndex; // Row-based PRPackedBool mTreeIsSorted; + PRPackedBool mCanDropBetweenRows; // is the user allowed to drop between rows #if USE_TIMER_TO_DELAY_SCROLLING PRPackedBool mAutoScrollTimerHasFired; diff --git a/layout/xul/content/src/nsXULAtomList.h b/layout/xul/content/src/nsXULAtomList.h index 5153ef6a4b99..e9652ca5b23e 100644 --- a/layout/xul/content/src/nsXULAtomList.h +++ b/layout/xul/content/src/nsXULAtomList.h @@ -155,8 +155,10 @@ XUL_ATOM(ddDropOn, "dd-dropon") XUL_ATOM(ddTriggerRepaintSorted, "dd-triggerrepaintsorted") XUL_ATOM(ddTriggerRepaintRestore, "dd-triggerrepaintrestore") XUL_ATOM(ddTriggerRepaint, "dd-triggerrepaint") +XUL_ATOM(ddNoDropBetweenRows, "dd-nodropbetweenrows") XUL_ATOM(container, "container") XUL_ATOM(ddDragDropArea, "dragdroparea") +XUL_ATOM(ddDropMarker, ":-moz-drop-marker") XUL_ATOM(widget, "widget") XUL_ATOM(window, "window")