зеркало из https://github.com/mozilla/gecko-dev.git
Родитель
61271d46ca
Коммит
f328cedeb9
|
@ -274,7 +274,7 @@ public:
|
|||
nsAttributeChangeType aType) = 0;
|
||||
|
||||
NS_IMETHOD PostReflowCallback(nsIReflowCallback* aCallback) = 0;
|
||||
|
||||
NS_IMETHOD CancelReflowCallback(nsIReflowCallback* aCallback) = 0;
|
||||
/**
|
||||
* Reflow batching
|
||||
*/
|
||||
|
|
|
@ -802,6 +802,7 @@ public:
|
|||
* Post a callback that should be handled after reflow has finished.
|
||||
*/
|
||||
NS_IMETHOD PostReflowCallback(nsIReflowCallback* aCallback);
|
||||
NS_IMETHOD CancelReflowCallback(nsIReflowCallback* aCallback);
|
||||
|
||||
/**
|
||||
* Reflow batching
|
||||
|
@ -3414,6 +3415,38 @@ PresShell::PostReflowCallback(nsIReflowCallback* aCallback)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresShell::CancelReflowCallback(nsIReflowCallback* aCallback)
|
||||
{
|
||||
nsCallbackEventRequest* before = nsnull;
|
||||
nsCallbackEventRequest* node = mFirstCallbackEventRequest;
|
||||
while(node)
|
||||
{
|
||||
nsIReflowCallback* callback = node->callback;
|
||||
|
||||
if (callback == aCallback)
|
||||
{
|
||||
nsCallbackEventRequest* toFree = node;
|
||||
if (node == mFirstCallbackEventRequest) {
|
||||
mFirstCallbackEventRequest = node->next;
|
||||
node = mFirstCallbackEventRequest;
|
||||
before = nsnull;
|
||||
} else {
|
||||
node = node->next;
|
||||
before->next = node;
|
||||
}
|
||||
|
||||
FreeFrame(sizeof(nsCallbackEventRequest), toFree);
|
||||
NS_RELEASE(callback);
|
||||
} else {
|
||||
before = node;
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post a request to handle a DOM event after Reflow has finished.
|
||||
* The event must have been created with the "new" operator.
|
||||
|
@ -3484,6 +3517,7 @@ PresShell::PostAttributeChange(nsIContent* aContent,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PresShell::HandlePostedReflowCallbacks()
|
||||
{
|
||||
|
|
|
@ -274,7 +274,7 @@ public:
|
|||
nsAttributeChangeType aType) = 0;
|
||||
|
||||
NS_IMETHOD PostReflowCallback(nsIReflowCallback* aCallback) = 0;
|
||||
|
||||
NS_IMETHOD CancelReflowCallback(nsIReflowCallback* aCallback) = 0;
|
||||
/**
|
||||
* Reflow batching
|
||||
*/
|
||||
|
|
|
@ -802,6 +802,7 @@ public:
|
|||
* Post a callback that should be handled after reflow has finished.
|
||||
*/
|
||||
NS_IMETHOD PostReflowCallback(nsIReflowCallback* aCallback);
|
||||
NS_IMETHOD CancelReflowCallback(nsIReflowCallback* aCallback);
|
||||
|
||||
/**
|
||||
* Reflow batching
|
||||
|
@ -3414,6 +3415,38 @@ PresShell::PostReflowCallback(nsIReflowCallback* aCallback)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresShell::CancelReflowCallback(nsIReflowCallback* aCallback)
|
||||
{
|
||||
nsCallbackEventRequest* before = nsnull;
|
||||
nsCallbackEventRequest* node = mFirstCallbackEventRequest;
|
||||
while(node)
|
||||
{
|
||||
nsIReflowCallback* callback = node->callback;
|
||||
|
||||
if (callback == aCallback)
|
||||
{
|
||||
nsCallbackEventRequest* toFree = node;
|
||||
if (node == mFirstCallbackEventRequest) {
|
||||
mFirstCallbackEventRequest = node->next;
|
||||
node = mFirstCallbackEventRequest;
|
||||
before = nsnull;
|
||||
} else {
|
||||
node = node->next;
|
||||
before->next = node;
|
||||
}
|
||||
|
||||
FreeFrame(sizeof(nsCallbackEventRequest), toFree);
|
||||
NS_RELEASE(callback);
|
||||
} else {
|
||||
before = node;
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post a request to handle a DOM event after Reflow has finished.
|
||||
* The event must have been created with the "new" operator.
|
||||
|
@ -3484,6 +3517,7 @@ PresShell::PostAttributeChange(nsIContent* aContent,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PresShell::HandlePostedReflowCallbacks()
|
||||
{
|
||||
|
|
|
@ -1089,6 +1089,9 @@ nsBox::Redraw(nsBoxLayoutState& aState,
|
|||
const nsRect* aDamageRect,
|
||||
PRBool aImmediate)
|
||||
{
|
||||
if (aState.GetDisablePainting())
|
||||
return NS_OK;
|
||||
|
||||
nsIPresContext* presContext = aState.GetPresContext();
|
||||
const nsHTMLReflowState* s = aState.GetReflowState();
|
||||
if (s) {
|
||||
|
|
|
@ -764,6 +764,20 @@ nsBoxFrame::Reflow(nsIPresContext* aPresContext,
|
|||
computedSize.height += m.top + m.bottom;
|
||||
}
|
||||
|
||||
// handle reflow state min and max sizes
|
||||
|
||||
if (computedSize.width > aReflowState.mComputedMaxWidth)
|
||||
computedSize.width = aReflowState.mComputedMaxWidth;
|
||||
|
||||
if (computedSize.height > aReflowState.mComputedMaxHeight)
|
||||
computedSize.height = aReflowState.mComputedMaxHeight;
|
||||
|
||||
if (computedSize.width < aReflowState.mComputedMinWidth)
|
||||
computedSize.width = aReflowState.mComputedMinWidth;
|
||||
|
||||
if (computedSize.height < aReflowState.mComputedMinHeight)
|
||||
computedSize.height = aReflowState.mComputedMinHeight;
|
||||
|
||||
nsRect r(mRect.x, mRect.y, computedSize.width, computedSize.height);
|
||||
|
||||
SetBounds(state, r);
|
||||
|
|
|
@ -43,7 +43,8 @@ nsBoxLayoutState::nsBoxLayoutState(nsIPresContext* aPresContext):mPresContext(aP
|
|||
mMaxElementSize(nsnull),
|
||||
mOverFlowSize(0,0),
|
||||
mIncludeOverFlow(PR_TRUE),
|
||||
mLayoutFlags(0)
|
||||
mLayoutFlags(0),
|
||||
mDisablePainting(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -55,6 +56,7 @@ nsBoxLayoutState::nsBoxLayoutState(const nsBoxLayoutState& aState)
|
|||
mMaxElementSize = aState.mMaxElementSize;
|
||||
mOverFlowSize = aState.mOverFlowSize;
|
||||
mLayoutFlags = aState.mLayoutFlags;
|
||||
mDisablePainting = aState.mDisablePainting;
|
||||
}
|
||||
|
||||
nsBoxLayoutState::nsBoxLayoutState(nsIPresShell* aShell):mReflowState(nsnull),
|
||||
|
@ -62,7 +64,8 @@ nsBoxLayoutState::nsBoxLayoutState(nsIPresShell* aShell):mReflowState(nsnull),
|
|||
mMaxElementSize(nsnull),
|
||||
mOverFlowSize(0,0),
|
||||
mIncludeOverFlow(PR_TRUE),
|
||||
mLayoutFlags(0)
|
||||
mLayoutFlags(0),
|
||||
mDisablePainting(PR_FALSE)
|
||||
{
|
||||
aShell->GetPresContext(getter_AddRefs(mPresContext));
|
||||
}
|
||||
|
@ -74,7 +77,8 @@ nsBoxLayoutState::nsBoxLayoutState(nsIPresContext* aPresContext,
|
|||
mType(Dirty),
|
||||
mOverFlowSize(0,0),
|
||||
mIncludeOverFlow(PR_TRUE),
|
||||
mLayoutFlags(0)
|
||||
mLayoutFlags(0),
|
||||
mDisablePainting(PR_FALSE)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -70,6 +70,10 @@ public:
|
|||
virtual void GetLayoutFlags(PRUint32& aFlags);
|
||||
virtual void SetLayoutFlags(const PRUint32& aFlags);
|
||||
|
||||
// if true no one under us will paint during reflow.
|
||||
virtual void SetDisablePainting(PRBool aDisable) { mDisablePainting = aDisable; }
|
||||
virtual PRBool GetDisablePainting() { return mDisablePainting; }
|
||||
|
||||
virtual eBoxLayoutReason GetLayoutReason() { return mType; }
|
||||
virtual void SetLayoutReason(eBoxLayoutReason aReason) { mType = aReason; }
|
||||
virtual const nsHTMLReflowState* GetReflowState() { return mReflowState; }
|
||||
|
@ -95,6 +99,7 @@ private:
|
|||
nsSize mOverFlowSize;
|
||||
PRBool mIncludeOverFlow;
|
||||
PRUint32 mLayoutFlags;
|
||||
PRBool mDisablePainting;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_ISCROLLBARLISTENER_IID; return iid; }
|
||||
|
||||
NS_IMETHOD PositionChanged(nsIPresContext* aPresContext, PRInt32 aOldIndex, PRInt32 aNewIndex) = 0;
|
||||
NS_IMETHOD PositionChanged(nsIPresContext* aPresContext, PRInt32 aOldIndex, PRInt32& aNewIndex) = 0;
|
||||
|
||||
NS_IMETHOD PagedUpDown() = 0;
|
||||
};
|
||||
|
|
|
@ -36,7 +36,7 @@ class nsIScrollbarMediator : public nsISupports {
|
|||
public:
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_ISCROLLBARMEDIATOR_IID; return iid; }
|
||||
|
||||
NS_IMETHOD PositionChanged(PRInt32 aOldIndex, PRInt32 aNewIndex) = 0;
|
||||
NS_IMETHOD PositionChanged(PRInt32 aOldIndex, PRInt32& aNewIndex) = 0;
|
||||
NS_IMETHOD ScrollbarButtonPressed(PRInt32 aOldIndex, PRInt32 aNewIndex) = 0;
|
||||
|
||||
NS_IMETHOD VisibilityChanged(PRBool aVisible) = 0;
|
||||
|
|
|
@ -38,6 +38,7 @@ public:
|
|||
NS_IMETHOD IsOutermostFrame(PRBool* aResult) = 0;
|
||||
NS_IMETHOD IsGroupFrame(PRBool* aResult) = 0;
|
||||
NS_IMETHOD IsRowFrame(PRBool* aResult) = 0;
|
||||
NS_IMETHOD GetOnScreenRowCount(PRInt32* aCount) = 0;
|
||||
|
||||
}; // class nsIXULTreeSlice
|
||||
|
||||
|
|
|
@ -201,6 +201,9 @@ nsSliderFrame::AttributeChanged(nsIPresContext* aPresContext,
|
|||
scrollbarFrame->GetScrollbarMediator(getter_AddRefs(mediator));
|
||||
if (mediator) {
|
||||
mediator->PositionChanged(GetCurrentPosition(scrollbar), current);
|
||||
char ch[100];
|
||||
sprintf(ch,"%d", current);
|
||||
scrollbar->SetAttribute(kNameSpaceID_None, nsXULAtoms::curpos, NS_ConvertASCIItoUCS2(ch), PR_FALSE);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
@ -692,12 +695,18 @@ nsSliderFrame::SetCurrentPosition(nsIContent* scrollbar, nsIFrame* aThumbFrame,
|
|||
|
||||
nsIBox* scrollbarBox = GetScrollbar();
|
||||
nsCOMPtr<nsIScrollbarFrame> scrollbarFrame(do_QueryInterface(scrollbarBox));
|
||||
|
||||
|
||||
if (scrollbarFrame) {
|
||||
// See if we have a mediator.
|
||||
nsCOMPtr<nsIScrollbarMediator> mediator;
|
||||
scrollbarFrame->GetScrollbarMediator(getter_AddRefs(mediator));
|
||||
if (mediator) {
|
||||
mediator->PositionChanged(GetCurrentPosition(scrollbar), newpos);
|
||||
char ch[100];
|
||||
sprintf(ch,"%d", newpos);
|
||||
scrollbar->SetAttribute(kNameSpaceID_None, nsXULAtoms::curpos, NS_ConvertASCIItoUCS2(ch), PR_FALSE);
|
||||
CurrentPositionChanged(mPresContext);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1087,10 +1087,8 @@ nsSplitterFrameInner::AdjustChildren(nsIPresContext* aPresContext)
|
|||
mParentBox->Layout(state);
|
||||
shell->ExitReflowLock(PR_TRUE);
|
||||
*/
|
||||
|
||||
shell->FlushPendingNotifications();
|
||||
|
||||
nsCOMPtr<nsIViewManager> viewManager;
|
||||
|
||||
nsCOMPtr<nsIViewManager> viewManager;
|
||||
nsIView* view = nsnull;
|
||||
frame->GetView(aPresContext, &view);
|
||||
|
||||
|
@ -1099,19 +1097,23 @@ nsSplitterFrameInner::AdjustChildren(nsIPresContext* aPresContext)
|
|||
|
||||
if (view) {
|
||||
view->GetViewManager(*getter_AddRefs(viewManager));
|
||||
viewManager->UpdateView(view, damageRect, NS_VMREFRESH_IMMEDIATE);
|
||||
|
||||
} else {
|
||||
nsRect rect(damageRect);
|
||||
nsPoint offset;
|
||||
|
||||
frame->GetOffsetFromView(aPresContext, offset, &view);
|
||||
NS_ASSERTION(nsnull != view, "no view");
|
||||
rect += offset;
|
||||
damageRect += offset;
|
||||
view->GetViewManager(*getter_AddRefs(viewManager));
|
||||
viewManager->UpdateView(view, rect, NS_VMREFRESH_IMMEDIATE);
|
||||
}
|
||||
|
||||
viewManager->DisableRefresh();
|
||||
shell->FlushPendingNotifications();
|
||||
viewManager->EnableRefresh(NS_VMREFRESH_NO_SYNC);
|
||||
|
||||
viewManager->UpdateView(view, damageRect, NS_VMREFRESH_IMMEDIATE);
|
||||
|
||||
|
||||
#else
|
||||
//mOuter->mState |= NS_FRAME_IS_DIRTY;
|
||||
//mOuter->mParent->ReflowDirtyChild(shell, mOuter->mParent);
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
#include "nsIBox.h"
|
||||
#include "nsIScrollableFrame.h"
|
||||
#include "nsBox.h"
|
||||
#include "nsIReflowCallback.h"
|
||||
#include "nsBoxLayoutState.h"
|
||||
|
||||
|
||||
// ------ nsTreeLayout ------
|
||||
|
||||
|
@ -141,17 +144,23 @@ nsTreeLayout::GetMaxSize(nsIBox* aBox, nsBoxLayoutState& aBoxLayoutState, nsSize
|
|||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called to layout our our children. Does no frame construction
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsTreeLayout::LayoutInternal(nsIBox* aBox, nsBoxLayoutState& aState)
|
||||
{
|
||||
PRInt32 redrawStart = -1;
|
||||
|
||||
// Get the start y position.
|
||||
nsXULTreeGroupFrame* frame = GetGroupFrame(aBox);
|
||||
if (!frame) {
|
||||
nsXULTreeGroupFrame* group = GetGroupFrame(aBox);
|
||||
if (!group) {
|
||||
NS_ERROR("Frame encountered that isn't a tree row group!\n");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsXULTreeOuterGroupFrame* outer = group->GetOuterFrame();
|
||||
|
||||
nsMargin margin;
|
||||
|
||||
// Get our client rect.
|
||||
|
@ -160,14 +169,16 @@ nsTreeLayout::LayoutInternal(nsIBox* aBox, nsBoxLayoutState& aState)
|
|||
|
||||
// Get the starting y position and the remaining available
|
||||
// height.
|
||||
nscoord availableHeight = frame->GetAvailableHeight();
|
||||
nscoord yOffset = frame->GetYPosition();
|
||||
nscoord availableHeight = group->GetAvailableHeight();
|
||||
nscoord yOffset = group->GetYPosition();
|
||||
|
||||
if (availableHeight <= 0)
|
||||
return NS_OK;
|
||||
|
||||
// Walk our frames, building them dynamically as needed.
|
||||
nsIBox* box = frame->GetFirstTreeBox();
|
||||
// run through all our currently created children
|
||||
nsIBox* box = nsnull;
|
||||
group->GetChildBox(&box);
|
||||
|
||||
while (box) {
|
||||
// If this box is dirty or if it has dirty children, we
|
||||
// call layout on it.
|
||||
|
@ -175,12 +186,7 @@ nsTreeLayout::LayoutInternal(nsIBox* aBox, nsBoxLayoutState& aState)
|
|||
PRBool dirtyChildren = PR_FALSE;
|
||||
box->IsDirty(dirty);
|
||||
box->HasDirtyChildren(dirtyChildren);
|
||||
|
||||
nsIFrame* childFrame;
|
||||
box->GetFrame(&childFrame);
|
||||
nsFrameState state;
|
||||
childFrame->GetFrameState(&state);
|
||||
|
||||
|
||||
PRBool isRow = PR_TRUE;
|
||||
nsXULTreeGroupFrame* childGroup = GetGroupFrame(box);
|
||||
if (childGroup) {
|
||||
|
@ -189,71 +195,154 @@ nsTreeLayout::LayoutInternal(nsIBox* aBox, nsBoxLayoutState& aState)
|
|||
isRow = PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool relayoutAll = (frame->GetOuterFrame()->GetTreeLayoutState() == eTreeLayoutDirtyAll);
|
||||
// if the reason is resize or initial we must relayout.
|
||||
PRBool relayout = (aState.GetLayoutReason() == nsBoxLayoutState::Resize || aState.GetLayoutReason() == nsBoxLayoutState::Initial);
|
||||
|
||||
nsRect childRect;
|
||||
PRBool sizeChanged = PR_FALSE;
|
||||
if (isRow) {
|
||||
nsSize size;
|
||||
box->GetPrefSize(aState, size);
|
||||
if (size.width != clientRect.width)
|
||||
sizeChanged = PR_TRUE;
|
||||
}
|
||||
|
||||
if (relayoutAll || childGroup || sizeChanged || dirty || dirtyChildren || aState.GetLayoutReason() == nsBoxLayoutState::Initial) {
|
||||
nsRect childRect;
|
||||
box->GetMargin(margin);
|
||||
|
||||
// relayout if we must or we are dirty or some of our children are
|
||||
// dirty
|
||||
if (relayout || dirty || dirtyChildren) {
|
||||
childRect.x = 0;
|
||||
childRect.y = yOffset;
|
||||
childRect.width = clientRect.width;
|
||||
|
||||
if (isRow)
|
||||
childRect.height = frame->GetOuterFrame()->GetRowHeightTwips();
|
||||
// of we can determine the height of the child be getting the number
|
||||
// of row inside it and multiplying it by the height of a row.
|
||||
// remember this is on screen rows not total row. We create things
|
||||
// lazily and we only worry about what is on screen during layout.
|
||||
nsCOMPtr<nsIXULTreeSlice> slice(do_QueryInterface(box));
|
||||
PRInt32 rowCount = 0;
|
||||
slice->GetOnScreenRowCount(&rowCount);
|
||||
|
||||
box->GetMargin(margin);
|
||||
// if we are a row then we could potential change the row size. We
|
||||
// don't know the height of a row until layout so tell the outer group
|
||||
// now. If the row height is greater than the current. We may have to
|
||||
// reflow everyone again!
|
||||
if (isRow) {
|
||||
nsSize size;
|
||||
box->GetPrefSize(aState, size);
|
||||
outer->SetRowHeight(size.height);
|
||||
}
|
||||
|
||||
// of now get the row height and figure out our child's total height.
|
||||
nscoord rowHeight = outer->GetRowHeightTwips();
|
||||
|
||||
childRect.height = rowHeight*rowCount;
|
||||
|
||||
childRect.Deflate(margin);
|
||||
box->SetBounds(aState, childRect);
|
||||
box->Layout(aState);
|
||||
} else {
|
||||
// if the child did not need to be relayed out. Then its easy.
|
||||
// Place the child by just grabbing its rect and adjusting the y.
|
||||
box->GetBounds(childRect);
|
||||
PRInt32 newPos = yOffset+margin.top;
|
||||
|
||||
nsSize size;
|
||||
if (!isRow) {
|
||||
// We are a row group that might have dynamically
|
||||
// constructed new rows. We need to clear out
|
||||
// and recompute our pref size and then adjust our
|
||||
// rect accordingly.
|
||||
box->NeedsRecalc();
|
||||
box->GetPrefSize(aState, size);
|
||||
childRect.height = size.height;
|
||||
box->SetBounds(aState, childRect);
|
||||
}
|
||||
else {// Check to see if the row height of the tree has changed.
|
||||
box->GetPrefSize(aState, size);
|
||||
frame->GetOuterFrame()->SetRowHeight(size.height);
|
||||
}
|
||||
// are we pushing down or pulling up any rows?
|
||||
// Then we may have to redraw everything below the the moved
|
||||
// rows.
|
||||
if (redrawStart == -1 && childRect.y != newPos)
|
||||
redrawStart = newPos;
|
||||
|
||||
childRect.y = newPos;
|
||||
box->SetBounds(aState, childRect);
|
||||
}
|
||||
|
||||
// Place the child by just grabbing its rect and adjusting the x,y.
|
||||
box->GetContentRect(childRect);
|
||||
childRect.x = 0;
|
||||
childRect.y = yOffset;
|
||||
yOffset += childRect.height;
|
||||
availableHeight -= childRect.height;
|
||||
box->GetMargin(margin);
|
||||
childRect.Deflate(margin);
|
||||
childRect.width = childRect.width < 0 ? 0 : childRect.width;
|
||||
childRect.height = childRect.height < 0 ? 0 : childRect.height;
|
||||
// Ok now the available size gets smaller and we move the
|
||||
// starting position of the next child down some.
|
||||
nscoord size = childRect.height + margin.top + margin.bottom;
|
||||
|
||||
yOffset += size;
|
||||
availableHeight -= size;
|
||||
|
||||
box->SetBounds(aState, childRect);
|
||||
box->GetNextBox(&box);
|
||||
}
|
||||
|
||||
if ((frame->GetOuterFrame()->GetTreeLayoutState() == eTreeLayoutAbort) ||
|
||||
(!frame->ContinueReflow(availableHeight)))
|
||||
break;
|
||||
if (availableHeight > outer->GetRowHeightTwips() || availableHeight < 0) {
|
||||
// of if we have enough available height left to add some more rows
|
||||
// or we have to much then we need to add or create some rows. We
|
||||
// can't do this durning layout but we can do it after. So post
|
||||
// a callback to do it after.
|
||||
outer->PostReflowCallback();
|
||||
}
|
||||
|
||||
box = frame->GetNextTreeBox(box);
|
||||
// if rows were pushed down or pulled up because some rows were added
|
||||
// before them then redraw everything under the inserted rows. The inserted
|
||||
// rows will automatically be redrawn because the were marked dirty on insertion.
|
||||
if (redrawStart > -1) {
|
||||
nsRect bounds;
|
||||
aBox->GetBounds(bounds);
|
||||
aBox->Redraw(aState, &nsRect(0,redrawStart,bounds.width, bounds.height - redrawStart));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates or removes rows lazily. This is done after layout because
|
||||
* It is illegal to add or remove frames during layout in the box system.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsTreeLayout::LazyRowCreator(nsBoxLayoutState& aState, nsXULTreeGroupFrame* aGroup)
|
||||
{
|
||||
nsXULTreeOuterGroupFrame* outer = aGroup->GetOuterFrame();
|
||||
|
||||
// Get our client rect.
|
||||
nsRect clientRect;
|
||||
aGroup->GetClientRect(clientRect);
|
||||
|
||||
// Get the starting y position and the remaining available
|
||||
// height.
|
||||
nscoord availableHeight = aGroup->GetAvailableHeight();
|
||||
|
||||
if (availableHeight <= 0)
|
||||
return NS_OK;
|
||||
|
||||
nsSize size;
|
||||
|
||||
// get the first tree box. If there isn't one create one.
|
||||
PRBool created = PR_FALSE;
|
||||
nsIBox* box = aGroup->GetFirstTreeBox(&created);
|
||||
while (box) {
|
||||
|
||||
// if its a group recursizely dive into it to build its rows.
|
||||
PRBool isRow = PR_TRUE;
|
||||
nsXULTreeGroupFrame* childGroup = GetGroupFrame(box);
|
||||
if (childGroup) {
|
||||
childGroup->SetAvailableHeight(availableHeight);
|
||||
LazyRowCreator(aState, childGroup);
|
||||
isRow = PR_FALSE;
|
||||
}
|
||||
|
||||
nscoord rowHeight = outer->GetRowHeightTwips();
|
||||
|
||||
// if the row height is 0 then fail. Wait until someone
|
||||
// laid out and sets the row height.
|
||||
if (rowHeight == 0)
|
||||
return NS_OK;
|
||||
|
||||
// figure out the child's height. Its the number of rows
|
||||
// the child contains * the row height. Remember this is
|
||||
// on screen rows not total rows.
|
||||
nsCOMPtr<nsIXULTreeSlice> slice(do_QueryInterface(box));
|
||||
|
||||
PRInt32 rowCount = 0;
|
||||
slice->GetOnScreenRowCount(&rowCount);
|
||||
|
||||
availableHeight -= rowHeight*rowCount;
|
||||
|
||||
// should we continue? Is the enought height?
|
||||
if (!aGroup->ContinueReflow(availableHeight))
|
||||
break;
|
||||
|
||||
// get the next tree box. Create one if needed.
|
||||
box = aGroup->GetNextTreeBox(box, &created);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -265,7 +354,6 @@ nsTreeLayout::Layout(nsIBox* aBox, nsBoxLayoutState& aState)
|
|||
|
||||
if (isOuterGroup) {
|
||||
nsXULTreeOuterGroupFrame* outer = (nsXULTreeOuterGroupFrame*) frame;
|
||||
nsTreeLayoutState state = outer->GetTreeLayoutState();
|
||||
|
||||
// Always ensure an accurate scrollview position
|
||||
// This is an edge case that was caused by the row height
|
||||
|
@ -283,12 +371,6 @@ nsTreeLayout::Layout(nsIBox* aBox, nsBoxLayoutState& aState)
|
|||
|
||||
nsresult rv = LayoutInternal(aBox, aState);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
state = outer->GetTreeLayoutState();
|
||||
if (state == eTreeLayoutDirtyAll)
|
||||
outer->SetTreeLayoutState(eTreeLayoutNormal);
|
||||
else if (state == eTreeLayoutAbort)
|
||||
outer->SetTreeLayoutState(eTreeLayoutDirtyAll);
|
||||
state = outer->GetTreeLayoutState();
|
||||
}
|
||||
else
|
||||
return LayoutInternal(aBox, aState);
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
#include "nsXULTreeOuterGroupFrame.h"
|
||||
#include "nsXULTreeSliceFrame.h"
|
||||
|
||||
class nsIBox;
|
||||
class nsBoxLayoutState;
|
||||
|
||||
class nsTreeLayout : public nsTempleLayout
|
||||
{
|
||||
public:
|
||||
|
@ -45,6 +48,8 @@ public:
|
|||
|
||||
NS_IMETHOD Layout(nsIBox* aBox, nsBoxLayoutState& aState);
|
||||
|
||||
NS_IMETHOD LazyRowCreator(nsBoxLayoutState& aState, nsXULTreeGroupFrame* aGroup);
|
||||
|
||||
protected:
|
||||
nsXULTreeOuterGroupFrame* GetOuterFrame(nsIBox* aBox);
|
||||
nsXULTreeGroupFrame* GetGroupFrame(nsIBox* aBox);
|
||||
|
|
|
@ -110,14 +110,8 @@ nsXULTreeFrame::DoLayout(nsBoxLayoutState& aBoxLayoutState)
|
|||
nsXULTreeOuterGroupFrame* treeOuterGroup = nsnull;
|
||||
GetTreeBody(&treeOuterGroup);
|
||||
|
||||
if (treeOuterGroup)
|
||||
treeOuterGroup->SetLayingOut(PR_TRUE);
|
||||
|
||||
nsresult rv = nsBoxFrame::DoLayout(aBoxLayoutState);
|
||||
|
||||
if (treeOuterGroup)
|
||||
treeOuterGroup->SetLayingOut(PR_FALSE);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
|
@ -90,7 +90,8 @@ NS_INTERFACE_MAP_END_INHERITING(nsBoxFrame)
|
|||
nsXULTreeGroupFrame::nsXULTreeGroupFrame(nsIPresShell* aPresShell, PRBool aIsRoot, nsIBoxLayout* aLayoutManager, PRBool aIsHorizontal)
|
||||
:nsBoxFrame(aPresShell, aIsRoot, aLayoutManager, aIsHorizontal), mFrameConstructor(nsnull), mPresContext(nsnull),
|
||||
mOuterFrame(nsnull), mAvailableHeight(10000), mTopFrame(nsnull), mBottomFrame(nsnull), mLinkupFrame(nsnull),
|
||||
mContentChain(nsnull), mYDropLoc(nsTreeItemDragCapturer::kNoDropLoc), mDropOnContainer(PR_FALSE)
|
||||
mContentChain(nsnull), mYDropLoc(nsTreeItemDragCapturer::kNoDropLoc), mDropOnContainer(PR_FALSE),
|
||||
mOnScreenRowCount(-1)
|
||||
{}
|
||||
|
||||
// Destructor
|
||||
|
@ -156,6 +157,34 @@ void nsXULTreeGroupFrame::LocateFrame(nsIFrame* aStartFrame, nsIFrame** aResult)
|
|||
else aStartFrame->GetNextSibling(aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTreeGroupFrame::NeedsRecalc()
|
||||
{
|
||||
mOnScreenRowCount = -1;
|
||||
return nsBoxFrame::NeedsRecalc();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTreeGroupFrame::GetOnScreenRowCount(PRInt32* aCount)
|
||||
{
|
||||
if (mOnScreenRowCount == -1)
|
||||
{
|
||||
mOnScreenRowCount = 0;
|
||||
nsIBox* box = nsnull;
|
||||
GetChildBox(&box);
|
||||
while(box) {
|
||||
PRInt32 count = 0;
|
||||
nsCOMPtr<nsIXULTreeSlice> slice(do_QueryInterface(box));
|
||||
slice->GetOnScreenRowCount(&count);
|
||||
mOnScreenRowCount += count;
|
||||
box->GetNextBox(&box);
|
||||
}
|
||||
}
|
||||
|
||||
*aCount = mOnScreenRowCount;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsXULTreeGroupFrame::GetFirstFrame()
|
||||
{
|
||||
|
@ -178,8 +207,12 @@ nsXULTreeGroupFrame::GetLastFrame()
|
|||
}
|
||||
|
||||
nsIBox*
|
||||
nsXULTreeGroupFrame::GetFirstTreeBox()
|
||||
nsXULTreeGroupFrame::GetFirstTreeBox(PRBool* aCreated)
|
||||
{
|
||||
|
||||
if (aCreated)
|
||||
*aCreated = PR_FALSE;
|
||||
|
||||
// Clear ourselves out.
|
||||
mLinkupFrame = nsnull;
|
||||
mBottomFrame = mTopFrame;
|
||||
|
@ -250,6 +283,10 @@ nsXULTreeGroupFrame::GetFirstTreeBox()
|
|||
mFrameConstructor->CreateTreeWidgetContent(mPresContext, this, nsnull, startContent,
|
||||
&mTopFrame, isAppend, PR_FALSE,
|
||||
nsnull);
|
||||
|
||||
if (aCreated)
|
||||
*aCreated = PR_TRUE;
|
||||
|
||||
//if (mTopFrame)
|
||||
// mOuterFrame->PostReflowCallback();
|
||||
|
||||
|
@ -267,8 +304,9 @@ nsXULTreeGroupFrame::GetFirstTreeBox()
|
|||
}
|
||||
|
||||
SetContentChain(nsnull);
|
||||
|
||||
|
||||
nsCOMPtr<nsIBox> box(do_QueryInterface(mTopFrame));
|
||||
|
||||
return box;
|
||||
}
|
||||
return nsnull;
|
||||
|
@ -276,8 +314,11 @@ nsXULTreeGroupFrame::GetFirstTreeBox()
|
|||
}
|
||||
|
||||
nsIBox*
|
||||
nsXULTreeGroupFrame::GetNextTreeBox(nsIBox* aBox)
|
||||
nsXULTreeGroupFrame::GetNextTreeBox(nsIBox* aBox, PRBool* aCreated)
|
||||
{
|
||||
if (aCreated)
|
||||
*aCreated = PR_FALSE;
|
||||
|
||||
// We're ultra-cool. We build our frames on the fly.
|
||||
nsIFrame* result;
|
||||
nsIFrame* frame;
|
||||
|
@ -329,6 +370,10 @@ nsXULTreeGroupFrame::GetNextTreeBox(nsIBox* aBox)
|
|||
mFrameConstructor->CreateTreeWidgetContent(mPresContext, this, prevFrame, nextContent,
|
||||
&result, isAppend, PR_FALSE,
|
||||
nsnull);
|
||||
|
||||
if (aCreated)
|
||||
*aCreated = PR_TRUE;
|
||||
|
||||
//if (result)
|
||||
// mOuterFrame->PostReflowCallback();
|
||||
}
|
||||
|
@ -346,8 +391,8 @@ nsXULTreeGroupFrame::TreeInsertFrames(nsIFrame* aPrevFrame, nsIFrame* aFrameList
|
|||
// insert the frames to our info list
|
||||
nsBoxLayoutState state(mPresContext);
|
||||
Insert(state, aPrevFrame, aFrameList);
|
||||
|
||||
mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList);
|
||||
MarkDirtyChildren(state);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -357,8 +402,9 @@ nsXULTreeGroupFrame::TreeAppendFrames(nsIFrame* aFrameList)
|
|||
// append them after
|
||||
nsBoxLayoutState state(mPresContext);
|
||||
Append(state,aFrameList);
|
||||
|
||||
mFrames.AppendFrames(nsnull, aFrameList);
|
||||
MarkDirtyChildren(state);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -392,8 +438,10 @@ nsXULTreeGroupFrame::OnContentInserted(nsIPresContext* aPresContext, nsIFrame* a
|
|||
mFrameConstructor->RemoveMappingsForFrameSubtree(aPresContext, currFrame, nsnull);
|
||||
|
||||
nsBoxLayoutState state(aPresContext);
|
||||
|
||||
Remove(state, currFrame);
|
||||
mFrames.DestroyFrame(aPresContext, currFrame);
|
||||
|
||||
currFrame = nextFrame;
|
||||
}
|
||||
nsBoxLayoutState state(aPresContext);
|
||||
|
@ -412,9 +460,11 @@ void nsXULTreeGroupFrame::OnContentRemoved(nsIPresContext* aPresContext,
|
|||
nsBoxLayoutState state(aPresContext);
|
||||
if (aChildFrame) {
|
||||
mFrameConstructor->RemoveMappingsForFrameSubtree(aPresContext, aChildFrame, nsnull);
|
||||
|
||||
Remove(state, aChildFrame);
|
||||
mFrames.DestroyFrame(aPresContext, aChildFrame);
|
||||
|
||||
MarkDirtyChildren(state);
|
||||
|
||||
// Get our old row count.
|
||||
PRInt32 rowCount = mOuterFrame->GetRowCount();
|
||||
|
||||
|
@ -460,18 +510,21 @@ PRBool nsXULTreeGroupFrame::ContinueReflow(nscoord height)
|
|||
// Nuke them.
|
||||
nsIFrame* currFrame;
|
||||
startingPoint->GetNextSibling(&currFrame);
|
||||
nsBoxLayoutState state(mPresContext);
|
||||
|
||||
while (currFrame) {
|
||||
nsIFrame* nextFrame;
|
||||
currFrame->GetNextSibling(&nextFrame);
|
||||
mFrameConstructor->RemoveMappingsForFrameSubtree(mPresContext, currFrame, nsnull);
|
||||
|
||||
nsBoxLayoutState state(mPresContext);
|
||||
Remove(state, currFrame);
|
||||
|
||||
mFrames.DestroyFrame(mPresContext, currFrame);
|
||||
|
||||
currFrame = nextFrame;
|
||||
}
|
||||
|
||||
MarkDirtyChildren(state);
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
@ -510,8 +563,11 @@ void nsXULTreeGroupFrame::DestroyRows(PRInt32& aRowsToLose)
|
|||
nsIFrame* nextFrame = GetNextFrame(childFrame);
|
||||
mFrameConstructor->RemoveMappingsForFrameSubtree(mPresContext, childFrame, nsnull);
|
||||
nsBoxLayoutState state(mPresContext);
|
||||
|
||||
Remove(state, childFrame);
|
||||
mFrames.DestroyFrame(mPresContext, childFrame);
|
||||
MarkDirtyChildren(state);
|
||||
|
||||
mTopFrame = childFrame = nextFrame;
|
||||
}
|
||||
}
|
||||
|
@ -547,8 +603,11 @@ void nsXULTreeGroupFrame::ReverseDestroyRows(PRInt32& aRowsToLose)
|
|||
prevFrame = mFrames.GetPrevSiblingFor(childFrame);
|
||||
mFrameConstructor->RemoveMappingsForFrameSubtree(mPresContext, childFrame, nsnull);
|
||||
nsBoxLayoutState state(mPresContext);
|
||||
|
||||
Remove(state, childFrame);
|
||||
mFrames.DestroyFrame(mPresContext, childFrame);
|
||||
MarkDirtyChildren(state);
|
||||
|
||||
mBottomFrame = childFrame = prevFrame;
|
||||
}
|
||||
}
|
||||
|
@ -914,7 +973,7 @@ nsXULTreeGroupFrame :: FindFirstChildTreeItemFrame ( nsIPresContext* inPresConte
|
|||
break;
|
||||
currChildFrame->GetNextSibling ( &currChildFrame );
|
||||
} // foreach child of the treeItem
|
||||
NS_ASSERTION ( currChildFrame, "Can't find <treechildren>" );
|
||||
//NS_ASSERTION ( currChildFrame, "Can't find <treechildren>" );
|
||||
|
||||
// |currChildFrame| now holds the correct frame if we found it
|
||||
if ( currChildFrame )
|
||||
|
|
|
@ -68,8 +68,8 @@ public:
|
|||
PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRInt32 aHint) ;
|
||||
|
||||
nsXULTreeOuterGroupFrame* GetOuterFrame() { return mOuterFrame; };
|
||||
nsIBox* GetFirstTreeBox();
|
||||
nsIBox* GetNextTreeBox(nsIBox* aBox);
|
||||
nsIBox* GetFirstTreeBox(PRBool* aCreated = nsnull);
|
||||
nsIBox* GetNextTreeBox(nsIBox* aBox, PRBool* aCreated = nsnull);
|
||||
|
||||
nsIFrame* GetFirstFrame();
|
||||
nsIFrame* GetNextFrame(nsIFrame* aCurrFrame);
|
||||
|
@ -92,7 +92,11 @@ public:
|
|||
NS_IMETHOD IsOutermostFrame(PRBool* aResult) { *aResult = PR_FALSE; return NS_OK; };
|
||||
NS_IMETHOD IsGroupFrame(PRBool* aResult) { *aResult = PR_TRUE; return NS_OK; };
|
||||
NS_IMETHOD IsRowFrame(PRBool* aResult) { *aResult = PR_FALSE; return NS_OK; };
|
||||
NS_IMETHOD GetOnScreenRowCount(PRInt32* aCount);
|
||||
|
||||
// nsIBox
|
||||
NS_IMETHOD NeedsRecalc();
|
||||
|
||||
virtual nscoord GetAvailableHeight() { return mAvailableHeight; };
|
||||
void SetAvailableHeight(nscoord aHeight) { mAvailableHeight = aHeight; };
|
||||
|
||||
|
@ -133,6 +137,7 @@ protected:
|
|||
nsIFrame* mBottomFrame;
|
||||
nsIFrame* mLinkupFrame;
|
||||
nsISupportsArray* mContentChain; // Our content chain
|
||||
PRInt32 mOnScreenRowCount;
|
||||
|
||||
// -- members for drag and drop --
|
||||
|
||||
|
|
|
@ -42,14 +42,27 @@
|
|||
#include "nsIScrollableView.h"
|
||||
#include "nsIMonument.h"
|
||||
#include "nsTempleLayout.h"
|
||||
#include "nsTreeLayout.h"
|
||||
#include "nsITimer.h"
|
||||
|
||||
#define TICK_FACTOR 50
|
||||
|
||||
// the longest amount of time that can go by before the use
|
||||
// notices it as a delay.
|
||||
#define USER_TIME_THRESHOLD 150000
|
||||
|
||||
// how long it takes to layout a single row inital value.
|
||||
// we will time this after we scroll a few rows.
|
||||
#define TIME_PER_ROW_INITAL 50000
|
||||
|
||||
// if we decide we can't layout the rows in the amount of time. How long
|
||||
// do we wait before checking again?
|
||||
#define SMOOTH_INTERVAL 100
|
||||
|
||||
static NS_DEFINE_IID(kIFrameIID, NS_IFRAME_IID);
|
||||
|
||||
nsresult NS_NewAutoScrollTimer(nsXULTreeOuterGroupFrame* aTree, nsDragAutoScrollTimer **aResult) ;
|
||||
|
||||
|
||||
//
|
||||
// nsDragOverListener
|
||||
//
|
||||
|
@ -114,6 +127,82 @@ nsDragOverListener :: DragOver(nsIDOMEvent* aDragEvent)
|
|||
#pragma mark -
|
||||
#endif
|
||||
|
||||
/* A mediator used to smooth out scrolling. It works by seeing if
|
||||
* we have time to scroll the amount of rows requested. This is determined
|
||||
* by measuring how long it takes to scroll a row. If we can scroll the
|
||||
* rows in time we do so. If not we start a timer and skip the request. We
|
||||
* do this until the timer finally first because the user has stopped moving
|
||||
* the mouse. Then do all the queued requests in on shot.
|
||||
*/
|
||||
class nsScrollSmoother : public nsITimerCallback
|
||||
{
|
||||
public:
|
||||
|
||||
NS_IMETHOD_(void) Notify(nsITimer *timer);
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
PRBool IsRunning();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
virtual ~nsScrollSmoother();
|
||||
|
||||
nsScrollSmoother(nsXULTreeOuterGroupFrame* aOuter);
|
||||
|
||||
nsCOMPtr<nsITimer> mRepeatTimer;
|
||||
PRBool mDelta;
|
||||
nsXULTreeOuterGroupFrame* mOuter;
|
||||
};
|
||||
|
||||
nsScrollSmoother::nsScrollSmoother(nsXULTreeOuterGroupFrame* aOuter)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
nsresult rv = NS_OK;
|
||||
mDelta = 0;
|
||||
mOuter = aOuter;
|
||||
}
|
||||
|
||||
nsScrollSmoother::~nsScrollSmoother()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
|
||||
PRBool nsScrollSmoother::IsRunning()
|
||||
{
|
||||
if (mRepeatTimer)
|
||||
return PR_TRUE;
|
||||
else
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
void nsScrollSmoother::Start()
|
||||
{
|
||||
Stop();
|
||||
mRepeatTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
mRepeatTimer->Init(this, SMOOTH_INTERVAL);
|
||||
}
|
||||
|
||||
void nsScrollSmoother::Stop()
|
||||
{
|
||||
if ( mRepeatTimer ) {
|
||||
mRepeatTimer->Cancel();
|
||||
mRepeatTimer = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void) nsScrollSmoother::Notify(nsITimer *timer)
|
||||
{
|
||||
//printf("Timer Callback!\n");
|
||||
|
||||
Stop();
|
||||
|
||||
// actually do some work.
|
||||
mOuter->InternalPositionChangedCallback();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsScrollSmoother, nsITimerCallback)
|
||||
|
||||
|
||||
//
|
||||
// NS_NewXULTreeOuterGroupFrame
|
||||
|
@ -143,14 +232,34 @@ nsXULTreeOuterGroupFrame::nsXULTreeOuterGroupFrame(nsIPresShell* aPresShell, PRB
|
|||
:nsXULTreeGroupFrame(aPresShell, aIsRoot, aLayoutManager, aIsHorizontal),
|
||||
mRowGroupInfo(nsnull), mRowHeight(0), mCurrentIndex(0),
|
||||
mTreeIsSorted(PR_FALSE), mDragOverListener(nsnull), mCanDropBetweenRows(PR_TRUE),
|
||||
mTreeLayoutState(eTreeLayoutNormal), mReflowCallbackPosted(PR_FALSE)
|
||||
mRowHeightWasSet(PR_FALSE), mReflowCallbackPosted(PR_FALSE), mYPosition(0), mScrolling(PR_FALSE),
|
||||
mScrollSmoother(nsnull), mTimePerRow(TIME_PER_ROW_INITAL), mAdjustScroll(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTreeOuterGroupFrame::Destroy(nsIPresContext* aPresContext)
|
||||
{
|
||||
|
||||
// make sure we cancel any posted callbacks.
|
||||
if (mReflowCallbackPosted) {
|
||||
nsCOMPtr<nsIPresShell> shell;
|
||||
aPresContext->GetShell(getter_AddRefs(shell));
|
||||
shell->CancelReflowCallback(this);
|
||||
}
|
||||
|
||||
|
||||
return nsXULTreeGroupFrame::Destroy(aPresContext);
|
||||
}
|
||||
|
||||
// Destructor
|
||||
nsXULTreeOuterGroupFrame::~nsXULTreeOuterGroupFrame()
|
||||
{
|
||||
NS_IF_RELEASE(mScrollSmoother);
|
||||
|
||||
// TODO cancel posted events.
|
||||
|
||||
nsCOMPtr<nsIContent> content;
|
||||
GetContent(getter_AddRefs(content));
|
||||
nsCOMPtr<nsIDOMEventReceiver> receiver(do_QueryInterface(content));
|
||||
|
@ -200,7 +309,7 @@ nsXULTreeOuterGroupFrame::Init(nsIPresContext* aPresContext, nsIContent* aConten
|
|||
{
|
||||
nsresult rv = nsXULTreeGroupFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
|
||||
|
||||
mLayingOut = PR_FALSE;
|
||||
// mLayingOut = PR_FALSE;
|
||||
|
||||
float p2t;
|
||||
aPresContext->GetScaledPixelsToTwips(&p2t);
|
||||
|
@ -257,7 +366,19 @@ nsXULTreeOuterGroupFrame::Init(nsIPresContext* aPresContext, nsIContent* aConten
|
|||
NS_IMETHODIMP
|
||||
nsXULTreeOuterGroupFrame::DoLayout(nsBoxLayoutState& aBoxLayoutState)
|
||||
{
|
||||
if (mScrolling)
|
||||
aBoxLayoutState.SetDisablePainting(PR_TRUE);
|
||||
|
||||
nsresult rv = nsXULTreeGroupFrame::DoLayout(aBoxLayoutState);
|
||||
|
||||
if (mScrolling)
|
||||
aBoxLayoutState.SetDisablePainting(PR_FALSE);
|
||||
|
||||
// if we are scrolled and the row height changed
|
||||
// make sure we are scrolled to a correct index.
|
||||
if (mAdjustScroll)
|
||||
PostReflowCallback();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -292,10 +413,11 @@ nsXULTreeOuterGroupFrame::SetRowHeight(nscoord aRowHeight)
|
|||
value.AppendInt(rowHeight*count);
|
||||
parent->SetAttribute(kNameSpaceID_None, nsHTMLAtoms::height, value, PR_FALSE);
|
||||
}
|
||||
nsBoxLayoutState state(mPresContext);
|
||||
MarkDirtyChildren(state);
|
||||
mTreeLayoutState = eTreeLayoutAbort;
|
||||
|
||||
|
||||
// signal we need to dirty everything
|
||||
// and we want to be notified after reflow
|
||||
// so we can create or destory rows as needed
|
||||
mRowHeightWasSet = PR_TRUE;
|
||||
PostReflowCallback();
|
||||
}
|
||||
}
|
||||
|
@ -303,22 +425,7 @@ nsXULTreeOuterGroupFrame::SetRowHeight(nscoord aRowHeight)
|
|||
nscoord
|
||||
nsXULTreeOuterGroupFrame::GetYPosition()
|
||||
{
|
||||
nsIBox* box;
|
||||
GetParentBox(&box);
|
||||
if (!box)
|
||||
return 0;
|
||||
|
||||
box->GetParentBox(&box);
|
||||
if (!box)
|
||||
return 0;
|
||||
|
||||
nsCOMPtr<nsIScrollableFrame> scrollFrame(do_QueryInterface(box));
|
||||
if (!scrollFrame)
|
||||
return 0;
|
||||
|
||||
nscoord x, y;
|
||||
scrollFrame->GetScrollPosition(mPresContext, x, y);
|
||||
return y;
|
||||
return mYPosition;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -341,6 +448,8 @@ nsXULTreeOuterGroupFrame::VerticalScroll(PRInt32 aPosition)
|
|||
scrollFrame->GetScrollPosition(mPresContext, x, y);
|
||||
|
||||
scrollFrame->ScrollTo(mPresContext, x, aPosition, NS_SCROLL_PROPERTY_ALWAYS_BLIT);
|
||||
|
||||
mYPosition = aPosition;
|
||||
}
|
||||
|
||||
nscoord
|
||||
|
@ -429,41 +538,105 @@ nsXULTreeOuterGroupFrame::ScrollbarButtonPressed(PRInt32 aOldIndex, PRInt32 aNew
|
|||
return NS_OK;
|
||||
}
|
||||
InternalPositionChanged(aNewIndex < aOldIndex, 1);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTreeOuterGroupFrame::PositionChanged(PRInt32 aOldIndex, PRInt32 aNewIndex)
|
||||
{
|
||||
if (aOldIndex == aNewIndex)
|
||||
return NS_OK;
|
||||
|
||||
nsXULTreeOuterGroupFrame::PositionChanged(PRInt32 aOldIndex, PRInt32& aNewIndex)
|
||||
{
|
||||
PRInt32 oldTwipIndex, newTwipIndex;
|
||||
oldTwipIndex = (aOldIndex*mOnePixel);
|
||||
oldTwipIndex = mCurrentIndex*mRowHeight;
|
||||
newTwipIndex = (aNewIndex*mOnePixel);
|
||||
|
||||
PRInt32 twipDelta = newTwipIndex > oldTwipIndex ? newTwipIndex - oldTwipIndex : oldTwipIndex - newTwipIndex;
|
||||
PRInt32 delta = twipDelta / mRowHeight;
|
||||
|
||||
PRInt32 rowDelta = twipDelta / mRowHeight;
|
||||
PRInt32 remainder = twipDelta % mRowHeight;
|
||||
if (remainder > (mRowHeight/2))
|
||||
delta++;
|
||||
rowDelta++;
|
||||
|
||||
if (delta == 0)
|
||||
if (rowDelta == 0)
|
||||
return NS_OK;
|
||||
|
||||
mCurrentIndex = newTwipIndex > oldTwipIndex ? mCurrentIndex + delta : mCurrentIndex - delta;
|
||||
// update the position to be row based.
|
||||
|
||||
PRInt32 newIndex = newTwipIndex > oldTwipIndex ? mCurrentIndex + rowDelta : mCurrentIndex - rowDelta;
|
||||
//aNewIndex = newIndex*mRowHeight/mOnePixel;
|
||||
|
||||
nsScrollSmoother* smoother = GetSmoother();
|
||||
|
||||
//printf("%d rows, %d per row, Estimated time needed %d, Threshhold %d (%s)\n", rowDelta, mTimePerRow, mTimePerRow * rowDelta, USER_TIME_THRESHOLD, (mTimePerRow * rowDelta > USER_TIME_THRESHOLD) ? "Nope" : "Yep");
|
||||
|
||||
// if we can't scroll the rows in time then start a timer. We will eat
|
||||
// events until the user stops moving and the timer stops.
|
||||
if (smoother->IsRunning() || rowDelta*mTimePerRow > USER_TIME_THRESHOLD) {
|
||||
|
||||
smoother->Stop();
|
||||
|
||||
nsCOMPtr<nsIPresShell> shell;
|
||||
mPresContext->GetShell(getter_AddRefs(shell));
|
||||
shell->FlushPendingNotifications();
|
||||
|
||||
smoother->mDelta = newTwipIndex > oldTwipIndex ? rowDelta : -rowDelta;
|
||||
|
||||
//printf("Eating scroll!\n");
|
||||
|
||||
smoother->Start();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
smoother->Stop();
|
||||
|
||||
mCurrentIndex = newIndex;
|
||||
smoother->mDelta = 0;
|
||||
|
||||
if (mCurrentIndex < 0) {
|
||||
mCurrentIndex = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return InternalPositionChanged(newTwipIndex < oldTwipIndex, delta);
|
||||
return InternalPositionChanged(newTwipIndex < oldTwipIndex, rowDelta);
|
||||
}
|
||||
|
||||
nsScrollSmoother*
|
||||
nsXULTreeOuterGroupFrame::GetSmoother()
|
||||
{
|
||||
if (!mScrollSmoother) {
|
||||
mScrollSmoother = new nsScrollSmoother(this);
|
||||
NS_ADDREF(mScrollSmoother);
|
||||
}
|
||||
|
||||
return mScrollSmoother;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTreeOuterGroupFrame::InternalPositionChangedCallback()
|
||||
{
|
||||
nsScrollSmoother* smoother = GetSmoother();
|
||||
|
||||
if (smoother->mDelta == 0)
|
||||
return NS_OK;
|
||||
|
||||
mCurrentIndex += smoother->mDelta;
|
||||
|
||||
if (mCurrentIndex < 0)
|
||||
mCurrentIndex = 0;
|
||||
|
||||
return InternalPositionChanged(smoother->mDelta < 0, smoother->mDelta < 0 ? -smoother->mDelta : smoother->mDelta);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTreeOuterGroupFrame::InternalPositionChanged(PRBool aUp, PRInt32 aDelta)
|
||||
{
|
||||
{
|
||||
if (aDelta == 0)
|
||||
return NS_OK;
|
||||
|
||||
// begin timing how long it takes to scroll a row
|
||||
PRTime start = PR_Now();
|
||||
|
||||
//printf("Actually doing scroll mCurrentIndex=%d, delta=%d!\n", mCurrentIndex, aDelta);
|
||||
|
||||
//if (mContentChain) {
|
||||
// XXX Eventually we need to make the code smart enough to look at a content chain
|
||||
// when building ANOTHER content chain.
|
||||
|
@ -534,16 +707,31 @@ nsXULTreeOuterGroupFrame::InternalPositionChanged(PRBool aUp, PRInt32 aDelta)
|
|||
}
|
||||
|
||||
mTopFrame = mBottomFrame = nsnull; // Make sure everything is cleared out.
|
||||
|
||||
VerticalScroll(mCurrentIndex*mRowHeight);
|
||||
|
||||
if (mLayingOut) {
|
||||
PostReflowCallback();
|
||||
}
|
||||
else {
|
||||
nsBoxLayoutState state(mPresContext);
|
||||
MarkDirtyChildren(state);
|
||||
}
|
||||
mYPosition = mCurrentIndex*mRowHeight;
|
||||
nsBoxLayoutState state(mPresContext);
|
||||
nsCOMPtr<nsIBoxLayout> layout;
|
||||
GetLayoutManager(getter_AddRefs(layout));
|
||||
nsTreeLayout* treeLayout = (nsTreeLayout*)layout.get();
|
||||
treeLayout->LazyRowCreator(state, this);
|
||||
mScrolling = PR_TRUE;
|
||||
shell->FlushPendingNotifications();
|
||||
mScrolling = PR_FALSE;
|
||||
VerticalScroll(mYPosition);
|
||||
|
||||
PRTime end = PR_Now();
|
||||
|
||||
PRTime difTime;
|
||||
LL_SUB(difTime, end, start);
|
||||
|
||||
PRInt32 newTime;
|
||||
LL_L2I(newTime, difTime);
|
||||
newTime /= aDelta;
|
||||
|
||||
// average old and new
|
||||
mTimePerRow = (newTime + mTimePerRow)/2;
|
||||
|
||||
//printf("time per row=%d\n", mTimePerRow);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -937,14 +1125,16 @@ nsXULTreeOuterGroupFrame::EnsureRowIsVisible(PRInt32 aRowIndex)
|
|||
|
||||
InternalPositionChanged(up, delta);
|
||||
|
||||
/*
|
||||
// This change has to happen immediately.
|
||||
if (mLayingOut) {
|
||||
PostReflowCallback();
|
||||
}
|
||||
else {
|
||||
nsBoxLayoutState state(mPresContext);
|
||||
MarkDirtyChildren(state);
|
||||
//nsBoxLayoutState state(mPresContext);
|
||||
//MarkDirtyChildren(state);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1047,10 +1237,33 @@ nsXULTreeOuterGroupFrame::ReflowFinished(nsIPresShell* aPresShell, PRBool* aFlus
|
|||
|
||||
nsCOMPtr<nsIBox> treeBox(do_QueryInterface(treeFrame));
|
||||
|
||||
mReflowCallbackPosted = PR_FALSE;
|
||||
nsBoxLayoutState state(mPresContext);
|
||||
//MarkDirtyChildren(state);
|
||||
treeBox->MarkStyleChange(state);
|
||||
|
||||
// now build or destroy any needed rows.
|
||||
nsCOMPtr<nsIBoxLayout> layout;
|
||||
GetLayoutManager(getter_AddRefs(layout));
|
||||
nsTreeLayout* treeLayout = (nsTreeLayout*)layout.get();
|
||||
treeLayout->LazyRowCreator(state, this);
|
||||
|
||||
if (mAdjustScroll) {
|
||||
PRInt32 pos = mCurrentIndex*mRowHeight;
|
||||
VerticalScroll(mYPosition);
|
||||
mAdjustScroll = PR_FALSE;
|
||||
}
|
||||
|
||||
// if the row height changed
|
||||
// then mark everything as a style change. That
|
||||
// will dirty the tree all the way to its leaves.
|
||||
if (mRowHeightWasSet) {
|
||||
treeBox->MarkStyleChange(state);
|
||||
PRInt32 pos = mCurrentIndex*mRowHeight;
|
||||
if (mYPosition != pos)
|
||||
mAdjustScroll = PR_TRUE;
|
||||
|
||||
mRowHeightWasSet = PR_FALSE;
|
||||
}
|
||||
|
||||
mReflowCallbackPosted = PR_FALSE;
|
||||
|
||||
*aFlushFlag = PR_TRUE;
|
||||
return NS_OK;
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
class nsCSSFrameConstructor;
|
||||
class nsDragOverListener;
|
||||
class nsDragAutoScrollTimer;
|
||||
class nsScrollSmoother;
|
||||
|
||||
|
||||
// I want to eventually use a delay so that the user has to hover over
|
||||
|
@ -50,13 +51,6 @@ class nsDragAutoScrollTimer;
|
|||
// good (pinkerton)
|
||||
#define USE_TIMER_TO_DELAY_SCROLLING 0
|
||||
|
||||
|
||||
enum nsTreeLayoutState {
|
||||
eTreeLayoutNormal,
|
||||
eTreeLayoutAbort,
|
||||
eTreeLayoutDirtyAll
|
||||
};
|
||||
|
||||
class nsXULTreeRowGroupInfo {
|
||||
public:
|
||||
PRInt32 mRowCount;
|
||||
|
@ -141,8 +135,6 @@ public:
|
|||
void SetRowHeight(PRInt32 aRowHeight);
|
||||
PRBool IsFixedRowSize();
|
||||
|
||||
void SetLayingOut(PRBool aLayingOut) { mLayingOut = aLayingOut; };
|
||||
|
||||
nscoord GetYPosition();
|
||||
nscoord GetAvailableHeight();
|
||||
NS_IMETHOD GetNumberOfVisibleRows(PRInt32 *aResult) {
|
||||
|
@ -155,7 +147,7 @@ public:
|
|||
|
||||
NS_IMETHOD GetRowCount(PRInt32* aResult) { *aResult = GetRowCount(); return NS_OK; }
|
||||
|
||||
NS_IMETHOD PositionChanged(PRInt32 aOldIndex, PRInt32 aNewIndex);
|
||||
NS_IMETHOD PositionChanged(PRInt32 aOldIndex, PRInt32& aNewIndex);
|
||||
NS_IMETHOD ScrollbarButtonPressed(PRInt32 aOldIndex, PRInt32 aNewIndex);
|
||||
NS_IMETHOD VisibilityChanged(PRBool aVisible);
|
||||
|
||||
|
@ -188,17 +180,20 @@ public:
|
|||
PRInt32 *aResult);
|
||||
|
||||
NS_IMETHOD InternalPositionChanged(PRBool aUp, PRInt32 aDelta);
|
||||
NS_IMETHOD InternalPositionChangedCallback();
|
||||
|
||||
NS_IMETHOD Destroy(nsIPresContext* aPresContext);
|
||||
|
||||
PRBool IsTreeSorted ( ) const { return mTreeIsSorted; }
|
||||
PRBool CanDropBetweenRows ( ) const { return mCanDropBetweenRows; }
|
||||
|
||||
nsTreeLayoutState GetTreeLayoutState() { return mTreeLayoutState; }
|
||||
void SetTreeLayoutState(nsTreeLayoutState aState) { mTreeLayoutState = aState; }
|
||||
|
||||
void PostReflowCallback();
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
nsScrollSmoother* GetSmoother();
|
||||
|
||||
void ComputeTotalRowCount(PRInt32& aRowCount, nsIContent* aParent);
|
||||
|
||||
// Drag Auto-scrolling
|
||||
|
@ -225,9 +220,13 @@ protected:
|
|||
// in Init() for why this is a weak ref.
|
||||
nsDragOverListener* mDragOverListener;
|
||||
|
||||
nsTreeLayoutState mTreeLayoutState;
|
||||
PRBool mReflowCallbackPosted;
|
||||
PRBool mLayingOut;
|
||||
PRPackedBool mRowHeightWasSet;
|
||||
PRPackedBool mReflowCallbackPosted;
|
||||
PRPackedBool mScrolling;
|
||||
PRPackedBool mAdjustScroll;
|
||||
PRInt32 mYPosition;
|
||||
nsScrollSmoother* mScrollSmoother;
|
||||
PRInt32 mTimePerRow;
|
||||
}; // class nsXULTreeOuterGroupFrame
|
||||
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ public:
|
|||
NS_IMETHOD IsOutermostFrame(PRBool* aResult) { *aResult = PR_FALSE; return NS_OK; };
|
||||
NS_IMETHOD IsGroupFrame(PRBool* aResult) { *aResult = PR_FALSE; return NS_OK; };
|
||||
NS_IMETHOD IsRowFrame(PRBool* aResult) { *aResult = PR_TRUE; return NS_OK; };
|
||||
NS_IMETHOD GetOnScreenRowCount(PRInt32* aCount) { *aCount = 1; return NS_OK; }
|
||||
|
||||
// nsIBox
|
||||
NS_IMETHOD GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize);
|
||||
|
|
Загрузка…
Ссылка в новой задаче