Back to index

lightning-sunbird  0.9+nobinonly
nsSplitterFrame.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Blake Ross <blakeross@telocity.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 //
00040 // Eric Vaughan
00041 // Netscape Communications
00042 //
00043 // See documentation in associated header file
00044 //
00045 
00046 #include "nsSplitterFrame.h"
00047 #include "nsXULAtoms.h"
00048 #include "nsHTMLAtoms.h"
00049 #include "nsISupportsArray.h"
00050 #include "nsIDOMElement.h"
00051 #include "nsIDOMXULElement.h"
00052 #include "nsIDOMDocument.h"
00053 #include "nsPresContext.h"
00054 #include "nsIDocument.h"
00055 #include "nsINameSpaceManager.h"
00056 #include "nsScrollbarButtonFrame.h"
00057 #include "nsIDOMMouseListener.h"
00058 #include "nsIDOMMouseMotionListener.h"
00059 #include "nsIDOMEventReceiver.h"
00060 #include "nsIView.h"
00061 #include "nsIViewManager.h"
00062 #include "nsIScrollableView.h"
00063 #include "nsIDOMMouseEvent.h"
00064 #include "nsIPresShell.h"
00065 #include "nsFrameNavigator.h"
00066 #include "nsHTMLParts.h"
00067 #include "nsILookAndFeel.h"
00068 #include "nsStyleContext.h"
00069 #include "nsWidgetsCID.h"
00070 #include "nsBoxLayoutState.h"
00071 #include "nsIXBLService.h"
00072 #include "nsIServiceManager.h"
00073 #include "nsHTMLContainerFrame.h"
00074 #include "nsINodeInfo.h"
00075 #include "nsGUIEvent.h"
00076 #include "nsAutoPtr.h"
00077 #include "nsContentCID.h"
00078 #include "nsStyleSet.h"
00079 
00080 // was used in nsSplitterFrame::Init but now commented out
00081 //static NS_DEFINE_IID(kLookAndFeelCID,  NS_LOOKANDFEEL_CID);
00082 PRInt32 realTimeDrag;
00083 
00084 class nsSplitterInfo {
00085 public:
00086   nscoord min;
00087   nscoord max;
00088   nscoord current;
00089   nscoord changed;
00090   nsCOMPtr<nsIContent> childElem;
00091   PRInt32 flex;
00092   PRInt32 index;
00093 };
00094 
00095 class nsSplitterFrameInner : public nsIDOMMouseListener, public nsIDOMMouseMotionListener {
00096 
00097 public:
00098 
00099   NS_DECL_ISUPPORTS
00100 
00101   nsSplitterFrameInner(nsSplitterFrame* aSplitter)
00102   {
00103     mOuter = aSplitter;
00104     mPressed = PR_FALSE;
00105   }
00106   virtual ~nsSplitterFrameInner();
00107 
00108   // mouse listener
00109   NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
00110   NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent);
00111   NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent) { return NS_OK; }
00112   NS_IMETHOD MouseDblClick(nsIDOMEvent* aMouseEvent) { return NS_OK; }
00113   NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent) { return NS_OK; }
00114   NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent) { return MouseMove(aMouseEvent); }
00115   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; }
00116 
00117   // mouse motion listener
00118   NS_IMETHOD MouseMove(nsIDOMEvent* aMouseEvent);
00119   NS_IMETHOD DragMove(nsIDOMEvent* aMouseEvent) { return NS_OK; }
00120 
00121   void MouseDrag(nsPresContext* aPresContext, nsGUIEvent* aEvent);
00122   void MouseUp(nsPresContext* aPresContext, nsGUIEvent* aEvent);
00123 
00124   void AdjustChildren(nsPresContext* aPresContext);
00125   void AdjustChildren(nsPresContext* aPresContext, nsSplitterInfo* aChildInfos, PRInt32 aCount, PRBool aIsHorizontal);
00126 
00127   void AddRemoveSpace(nscoord aDiff,
00128                     nsSplitterInfo* aChildInfos,
00129                     PRInt32 aCount,
00130                     PRInt32& aSpaceLeft);
00131 
00132   void ResizeChildTo(nsPresContext* aPresContext,
00133                    nscoord& aDiff, 
00134                    nsSplitterInfo* aChildrenBeforeInfos, 
00135                    nsSplitterInfo* aChildrenAfterInfos, 
00136                    PRInt32 aChildrenBeforeCount, 
00137                    PRInt32 aChildrenAfterCount, 
00138                    PRBool aBounded);
00139 
00140   void UpdateState();
00141 
00142   void AddListener(nsPresContext* aPresContext);
00143   void RemoveListener();
00144 
00145   enum ResizeType { Closest, Farthest, Grow };
00146   enum State { Open, Collapsed, Dragging };
00147   enum CollapseDirection { Before, After, None };
00148 
00149   ResizeType GetResizeBefore();
00150   ResizeType GetResizeAfter();
00151   State GetState();
00152 
00153   //nsresult CaptureMouse(nsPresContext* aPresContext, PRBool aGrabMouseEvents);
00154   //PRBool IsMouseCaptured(nsPresContext* aPresContext);
00155   void Reverse(nsSplitterInfo*& aIndexes, PRInt32 aCount);
00156   CollapseDirection GetCollapseDirection();
00157 
00158   void MoveSplitterBy(nsPresContext* aPresContext, nscoord aDiff);
00159   void EnsureOrient();
00160   void SetPreferredSize(nsBoxLayoutState& aState, nsIBox* aChildBox, nscoord aOnePixel, PRBool aIsHorizontal, nscoord* aSize);
00161 
00162   nsSplitterFrame* mOuter;
00163   PRBool mDidDrag;
00164   PRInt32 mDragStartPx;
00165   nscoord mCurrentPos;
00166   nsIBox* mParentBox;
00167   PRBool mPressed;
00168   nsSplitterInfo* mChildInfosBefore;
00169   nsSplitterInfo* mChildInfosAfter;
00170   PRInt32 mChildInfosBeforeCount;
00171   PRInt32 mChildInfosAfterCount;
00172   State mState;
00173   nscoord mSplitterPos;
00174   nscoord mSplitterViewPos;
00175   PRBool mDragging;
00176 
00177 };
00178 
00179 
00180 NS_IMPL_ISUPPORTS2(nsSplitterFrameInner, nsIDOMMouseListener, nsIDOMMouseMotionListener)
00181 
00182 nsSplitterFrameInner::ResizeType
00183 nsSplitterFrameInner::GetResizeBefore()
00184 {
00185   nsString value;
00186   mOuter->GetContent()->GetAttr(kNameSpaceID_None,
00187                                 nsXULAtoms::resizebefore, value);
00188   if (value.EqualsLiteral("farthest"))
00189     return Farthest;
00190   return Closest;
00191 }
00192 
00193 nsSplitterFrameInner::~nsSplitterFrameInner() 
00194 {
00195   delete[] mChildInfosBefore;
00196   delete[] mChildInfosAfter;
00197 }
00198 
00199 nsSplitterFrameInner::ResizeType
00200 nsSplitterFrameInner::GetResizeAfter()
00201 {
00202   nsString value;
00203   mOuter->GetContent()->GetAttr(kNameSpaceID_None,
00204                                 nsXULAtoms::resizeafter, value);
00205   if (value.EqualsLiteral("farthest"))
00206     return Farthest;
00207   if (value.EqualsLiteral("grow"))
00208     return Grow;
00209   return Closest;
00210 }
00211 
00212 nsSplitterFrameInner::State
00213 nsSplitterFrameInner::GetState()
00214 {
00215   nsString value;
00216   mOuter->GetContent()->GetAttr(kNameSpaceID_None,
00217                                 nsXULAtoms::state, value);
00218   if (value.EqualsLiteral("dragging"))
00219     return Dragging;
00220   if (value.EqualsLiteral("collapsed"))
00221     return Collapsed;
00222   return Open;
00223 }
00224 
00225 //
00226 // NS_NewSplitterFrame
00227 //
00228 // Creates a new Toolbar frame and returns it in |aNewFrame|
00229 //
00230 nsresult
00231 NS_NewSplitterFrame ( nsIPresShell* aPresShell, nsIFrame** aNewFrame )
00232 {
00233   NS_PRECONDITION(aNewFrame, "null OUT ptr");
00234   if (nsnull == aNewFrame) {
00235     return NS_ERROR_NULL_POINTER;
00236   }
00237   nsSplitterFrame* it = new (aPresShell) nsSplitterFrame(aPresShell);
00238   if (nsnull == it)
00239     return NS_ERROR_OUT_OF_MEMORY;
00240 
00241   *aNewFrame = it;
00242   return NS_OK;
00243   
00244 } // NS_NewSplitterFrame
00245 
00246 nsSplitterFrame::nsSplitterFrame(nsIPresShell* aPresShell)
00247 : nsBoxFrame(aPresShell),
00248   mInner(0)
00249 {
00250 }
00251 
00252 nsSplitterFrame::~nsSplitterFrame()
00253 {
00254   if (mInner) {
00255     mInner->RemoveListener();
00256     mInner->Release();
00257   }
00258 }
00259 
00260 
00261 //
00262 // QueryInterface
00263 //
00264 NS_INTERFACE_MAP_BEGIN(nsSplitterFrame)
00265 NS_INTERFACE_MAP_END_INHERITING(nsBoxFrame)
00266 
00267 
00268 NS_IMETHODIMP
00269 nsSplitterFrame::GetCursor(const nsPoint&    aPoint,
00270                            nsIFrame::Cursor& aCursor)
00271 {
00272   return nsBoxFrame::GetCursor(aPoint, aCursor);
00273 
00274   /*
00275     if (IsHorizontal())
00276       aCursor = NS_STYLE_CURSOR_N_RESIZE;
00277     else
00278       aCursor = NS_STYLE_CURSOR_W_RESIZE;
00279 
00280     return NS_OK;
00281   */
00282 }
00283 
00284 NS_IMETHODIMP
00285 nsSplitterFrame::AttributeChanged(nsIContent* aChild,
00286                                   PRInt32 aNameSpaceID,
00287                                   nsIAtom* aAttribute,
00288                                   PRInt32 aModType)
00289 {
00290   nsresult rv = nsBoxFrame::AttributeChanged(aChild, aNameSpaceID,
00291                                              aAttribute, aModType);
00292   // if the alignment changed. Let the grippy know
00293   if (aAttribute == nsHTMLAtoms::align) {
00294     // tell the slider its attribute changed so it can 
00295     // update itself
00296     nsIFrame* grippy = nsnull;
00297     nsScrollbarButtonFrame::GetChildWithTag(GetPresContext(), nsXULAtoms::grippy, this, grippy);
00298     if (grippy)
00299       grippy->AttributeChanged(aChild, aNameSpaceID, aAttribute, aModType);
00300   } else if (aAttribute == nsXULAtoms::state) {
00301     mInner->UpdateState();
00302   }
00303 
00304   return rv;
00305 }
00306 
00310 NS_IMETHODIMP
00311 nsSplitterFrame::Init(nsPresContext*  aPresContext,
00312               nsIContent*      aContent,
00313               nsIFrame*        aParent,
00314               nsStyleContext*  aContext,
00315               nsIFrame*        aPrevInFlow)
00316 {
00317   NS_ENSURE_FALSE(mInner, NS_ERROR_ALREADY_INITIALIZED);
00318   mInner = new nsSplitterFrameInner(this);
00319   if (!mInner)
00320     return NS_ERROR_OUT_OF_MEMORY;
00321 
00322   mInner->AddRef();
00323   mInner->mChildInfosAfter = nsnull;
00324   mInner->mChildInfosBefore = nsnull;
00325   mInner->mState = nsSplitterFrameInner::Open;
00326   mInner->mDragging = PR_FALSE;
00327 
00328   {
00329 #if 0
00330     // make it real time drag for now due to problems
00331     nsCOMPtr<nsILookAndFeel> lookAndFeel = do_GetService(kLookAndFeelCID);
00332     if (lookAndFeel) {
00333       lookAndFeel->GetMetric(nsILookAndFeel::eMetric_DragFullWindow, realTimeDrag);
00334     }
00335     else
00336 #endif
00337       realTimeDrag = 1;
00338   }
00339 
00340   // determine orientation of parent, and if vertical, set orient to vertical
00341   // on splitter content, then re-resolve style
00342   // |newContext| to Release the reference after the call to nsBoxFrame::Init
00343   nsRefPtr<nsStyleContext> newContext;
00344   if (aParent && aParent->IsBoxFrame()) {
00345     PRBool isHorizontal;
00346     aParent->GetOrientation(isHorizontal);
00347     if (!isHorizontal) {
00348       nsAutoString str;
00349       aContent->GetAttr(kNameSpaceID_None, nsXULAtoms::orient, str);
00350       if (str.IsEmpty()) {
00351         aContent->SetAttr(kNameSpaceID_None, nsXULAtoms::orient,
00352                           NS_LITERAL_STRING("vertical"), PR_FALSE);
00353         nsStyleContext* parent = aContext->GetParent();
00354         newContext = aPresContext->StyleSet()->
00355           ResolveStyleFor(aContent, parent);
00356         aContext = newContext;
00357       }
00358     }
00359   }
00360 
00361   nsresult  rv = nsBoxFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
00362   NS_ENSURE_SUCCESS(rv, rv);
00363 
00364   // XXX Hack because we need the pres context in some of the event handling functions...
00365   mPresContext = aPresContext; 
00366 
00367   nsHTMLContainerFrame::CreateViewForFrame(this, nsnull, PR_TRUE);
00368   NS_ENSURE_SUCCESS(rv, rv);
00369 
00370   nsIView* view = GetView();
00371   nsIViewManager* viewManager = view->GetViewManager();
00372   viewManager->SetViewContentTransparency(view, PR_TRUE);
00373 
00374   if (!realTimeDrag) {
00375     // currently this only works on win32 and mac
00376     static NS_DEFINE_CID(kCChildCID, NS_CHILD_CID);
00377 
00378     // Need to have a widget to appear on top of other widgets.
00379     NS_ASSERTION(!view->HasWidget(), "have an unwanted widget");
00380     if (!view->HasWidget()) {
00381       view->CreateWidget(kCChildCID);
00382     }
00383   }
00384 
00385   mInner->mState = nsSplitterFrameInner::Open;
00386   mInner->AddListener(aPresContext);
00387   mInner->mParentBox = nsnull;
00388   return rv;
00389 }
00390 
00391 NS_IMETHODIMP
00392 nsSplitterFrame::DoLayout(nsBoxLayoutState& aState)
00393 {
00394   if (GetStateBits() & NS_FRAME_FIRST_REFLOW) 
00395   {
00396     GetParentBox(&mInner->mParentBox);
00397     mInner->UpdateState();
00398   }
00399 
00400   return nsBoxFrame::DoLayout(aState);
00401 }
00402 
00403 
00404 void
00405 nsSplitterFrame::GetInitialOrientation(PRBool& aIsHorizontal)
00406 {
00407   nsIBox* box;
00408   GetParentBox(&box);
00409   if (box) {
00410     PRBool horizontal;
00411     box->GetOrientation(horizontal);
00412     aIsHorizontal = !horizontal;
00413   }
00414   else
00415     nsBoxFrame::GetInitialOrientation(aIsHorizontal);
00416 }
00417 
00418 NS_IMETHODIMP
00419 nsSplitterFrame::HandlePress(nsPresContext* aPresContext,
00420                          nsGUIEvent *    aEvent,
00421                          nsEventStatus*  aEventStatus)
00422 {
00423   return NS_OK;
00424 }
00425 
00426 NS_IMETHODIMP
00427 nsSplitterFrame::HandleMultiplePress(nsPresContext* aPresContext,
00428                          nsGUIEvent *    aEvent,
00429                          nsEventStatus*  aEventStatus)
00430 {
00431   return NS_OK;
00432 }
00433 
00434 NS_IMETHODIMP
00435 nsSplitterFrame::HandleDrag(nsPresContext* aPresContext,
00436                         nsGUIEvent *    aEvent,
00437                         nsEventStatus*  aEventStatus)
00438 {
00439   return NS_OK;
00440 }
00441 
00442 NS_IMETHODIMP
00443 nsSplitterFrame::HandleRelease(nsPresContext* aPresContext,
00444                            nsGUIEvent *    aEvent,
00445                            nsEventStatus*  aEventStatus)
00446 {
00447   return NS_OK;
00448 }
00449 
00450 NS_IMETHODIMP  nsSplitterFrame::GetFrameForPoint(const nsPoint& aPoint, 
00451                                              nsFramePaintLayer aWhichLayer,    
00452                                              nsIFrame**     aFrame)
00453 {   
00454   // if the mouse is captured always return us as the frame.
00455   if (mInner->mDragging)
00456   {
00457     // XXX It's probably better not to check visibility here, right?
00458     *aFrame = this;
00459     return NS_OK;
00460   }
00461 
00462   nsresult rv = nsBoxFrame::GetFrameForPoint(aPoint, aWhichLayer, aFrame);
00463 
00464   if (NS_FAILED(rv) &&
00465       aWhichLayer == NS_FRAME_PAINT_LAYER_FOREGROUND &&
00466       mRect.Contains(aPoint)) {
00467     *aFrame = this;
00468     rv = NS_OK;
00469   } 
00470 
00471   return rv;
00472 }
00473 
00474 NS_IMETHODIMP
00475 nsSplitterFrame::HandleEvent(nsPresContext* aPresContext, 
00476                                       nsGUIEvent* aEvent,
00477                                       nsEventStatus* aEventStatus)
00478 {
00479   nsWeakFrame weakFrame(this);
00480   nsRefPtr<nsSplitterFrameInner> kungFuDeathGrip(mInner);
00481   switch (aEvent->message) {
00482     case NS_MOUSE_MOVE: 
00483       mInner->MouseDrag(aPresContext, aEvent);
00484     break;
00485   
00486     case NS_MOUSE_LEFT_BUTTON_UP:
00487       mInner->MouseUp(aPresContext, aEvent);     
00488     break;
00489   }
00490 
00491   NS_ENSURE_STATE(weakFrame.IsAlive());
00492   return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
00493 }
00494 
00495 void
00496 nsSplitterFrameInner::MouseUp(nsPresContext* aPresContext, nsGUIEvent* aEvent)
00497 {
00498   if (mDragging) {
00499     AdjustChildren(aPresContext);
00500     AddListener(aPresContext);
00501     mOuter->CaptureMouse(aPresContext, PR_FALSE);
00502     mDragging = PR_FALSE;
00503     State newState = GetState(); 
00504     // if the state is dragging then make it Open.
00505     if (newState == Dragging)
00506       mOuter->mContent->SetAttr(kNameSpaceID_None, nsXULAtoms::state, EmptyString(), PR_TRUE);
00507 
00508     mPressed = PR_FALSE;
00509 
00510     // if we dragged then fire a command event.
00511     if (mDidDrag) {
00512       nsCOMPtr<nsIDOMXULElement> element = do_QueryInterface(mOuter->GetContent());
00513       element->DoCommand();
00514     }
00515 
00516     //printf("MouseUp\n");
00517   }
00518 
00519   delete[] mChildInfosBefore;
00520   delete[] mChildInfosAfter;
00521   mChildInfosBefore = nsnull;
00522   mChildInfosAfter = nsnull;
00523 }
00524 
00525 void
00526 nsSplitterFrameInner::MouseDrag(nsPresContext* aPresContext, nsGUIEvent* aEvent)
00527 {
00528   if (mDragging) {
00529 
00530     //printf("Dragging\n");
00531 
00532     PRBool isHorizontal = !mOuter->IsHorizontal();
00533     // convert coord to pixels
00534     nscoord pos = isHorizontal ? aEvent->point.x : aEvent->point.y;
00535 
00536     // mDragStartPx is in pixels and is in our client area's coordinate system.
00537     // so we need to first convert it so twips and then get it into our
00538     // coordinate system.
00539 
00540     // convert start to twips
00541     nscoord start = aPresContext->IntScaledPixelsToTwips(mDragStartPx);
00542 
00543     // get it into our coordinate system (that is, the coordinate
00544     // system that aEvent->point is in)
00545     nsIView* eventCoordView;
00546     nsPoint offsetFromView;
00547     mOuter->GetOffsetFromView(offsetFromView, &eventCoordView);
00548     NS_ASSERTION(eventCoordView, "No view?");
00549 
00550     nsIView* rootView;
00551     aPresContext->GetViewManager()->GetRootView(rootView);
00552     NS_ASSERTION(rootView, "No root view?");
00553     
00554     nsPoint eventCoordViewOffset = eventCoordView->GetOffsetTo(rootView);
00555     
00556     start -= (isHorizontal ? eventCoordViewOffset.x : eventCoordViewOffset.y);
00557     
00558     // take our current position and substract the start location
00559     pos -= start;
00560 
00561     //printf("Diff=%d\n", pos);
00562 
00563     ResizeType resizeAfter  = GetResizeAfter();
00564 
00565     PRBool bounded;
00566 
00567     if (resizeAfter == nsSplitterFrameInner::Grow)
00568       bounded = PR_FALSE;
00569     else 
00570       bounded = PR_TRUE;
00571 
00572     int i;
00573     for (i=0; i < mChildInfosBeforeCount; i++) 
00574       mChildInfosBefore[i].changed = mChildInfosBefore[i].current;
00575 
00576     for (i=0; i < mChildInfosAfterCount; i++) 
00577       mChildInfosAfter[i].changed = mChildInfosAfter[i].current;
00578 
00579     nscoord oldPos = pos;
00580 
00581     ResizeChildTo(aPresContext, pos, mChildInfosBefore, mChildInfosAfter, mChildInfosBeforeCount, mChildInfosAfterCount, bounded);
00582 
00583     State currentState = GetState();
00584     CollapseDirection dir = GetCollapseDirection();
00585 
00586     // if we are in a collapsed position
00587     if (realTimeDrag && ((oldPos > 0 && oldPos > pos && dir == After) || (oldPos < 0 && oldPos < pos && dir == Before)))
00588     {
00589       // and we are not collapsed then collapse
00590       if (currentState == Dragging) {
00591         if (oldPos > 0 && oldPos > pos)
00592         {
00593           //printf("Collapse right\n");
00594           if (GetCollapseDirection() == After) 
00595           {
00596             mOuter->mContent->SetAttr(kNameSpaceID_None, nsXULAtoms::state, NS_LITERAL_STRING("collapsed"), PR_TRUE);
00597           }
00598 
00599         } else if (oldPos < 0 && oldPos < pos)
00600         {
00601           //printf("Collapse left\n");
00602           if (GetCollapseDirection() == Before) 
00603           {
00604             mOuter->mContent->SetAttr(kNameSpaceID_None, nsXULAtoms::state, NS_LITERAL_STRING("collapsed"), PR_TRUE);
00605           }
00606         }
00607       }
00608     } else {
00609       // if we are not in a collapsed position and we are not dragging make sure
00610       // we are dragging.
00611       if (currentState != Dragging)
00612         mOuter->mContent->SetAttr(kNameSpaceID_None, nsXULAtoms::state, NS_LITERAL_STRING("dragging"), PR_TRUE);
00613       if (realTimeDrag)
00614         AdjustChildren(aPresContext);
00615       else
00616         MoveSplitterBy(aPresContext, pos);
00617     }
00618 
00619     // printf("----- resize ----- ");
00620     /*
00621       for (i=0; i < mChildInfosBeforeCount; i++) 
00622         printf("before, index=%d, current=%d, changed=%d\n", mChildInfosBefore[i].index, mChildInfosBefore[i].current, mChildInfosBefore[i].changed);
00623       for (i=0; i < mChildInfosAfterCount; i++) 
00624         printf("after, index=%d, current=%d, changed=%d\n", mChildInfosAfter[i].index, mChildInfosAfter[i].current, mChildInfosAfter[i].changed);
00625     */
00626 
00627     /*
00628       nsIPresShell *shell = aPresContext->PresShell();
00629 
00630       shell->AppendReflowCommand(mOuter->mParent, eReflowType_StyleChanged,
00631                                  nsnull);
00632      
00633       mOuter->mState |= NS_FRAME_IS_DIRTY;
00634       mOuter->mParent->ReflowDirtyChild(shell, mOuter);
00635     */
00636     mDidDrag = PR_TRUE;
00637   }
00638 }
00639 
00640 void
00641 nsSplitterFrameInner::AddListener(nsPresContext* aPresContext)
00642 {
00643   nsCOMPtr<nsIDOMEventReceiver>
00644     receiver(do_QueryInterface(mOuter->GetContent()));
00645 
00646   receiver->AddEventListenerByIID(NS_STATIC_CAST(nsIDOMMouseListener*,this), NS_GET_IID(nsIDOMMouseListener));
00647   receiver->AddEventListenerByIID(NS_STATIC_CAST(nsIDOMMouseMotionListener*,this), NS_GET_IID(nsIDOMMouseMotionListener));
00648 }
00649 
00650 void
00651 nsSplitterFrameInner::RemoveListener()
00652 {
00653   nsCOMPtr<nsIDOMEventReceiver>
00654     receiver(do_QueryInterface(mOuter->GetContent()));
00655 
00656   receiver->RemoveEventListenerByIID(NS_STATIC_CAST(nsIDOMMouseListener*,this),NS_GET_IID(nsIDOMMouseListener));
00657   receiver->RemoveEventListenerByIID(NS_STATIC_CAST(nsIDOMMouseMotionListener*,this),NS_GET_IID(nsIDOMMouseMotionListener));
00658 }
00659 
00660 /*
00661 nsresult
00662 nsSplitterFrameInner :: CaptureMouse(nsPresContext* aPresContext, PRBool aGrabMouseEvents)
00663 {
00664   // get its view
00665   nsIView* view = mOuter->GetView();
00666   PRBool result;
00667 
00668   if (view) {
00669     nsIViewManager* viewMan = view->GetViewManager();
00670     if (viewMan) {
00671       // nsIWidget* widget = view->GetWidget();
00672       if (aGrabMouseEvents) {
00673         viewMan->GrabMouseEvents(view,result);
00674         //  if (widget)
00675         //   widget->CaptureMouse(PR_TRUE);
00676       } else {
00677         viewMan->GrabMouseEvents(nsnull,result);
00678        // if (widget)
00679          //  widget->CaptureMouse(PR_FALSE);
00680       }
00681     }
00682   }
00683 
00684   return NS_OK;
00685 }
00686 
00687 
00688 PRBool
00689 nsSplitterFrameInner :: IsMouseCaptured(nsPresContext* aPresContext)
00690 {
00691     // get its view
00692   nsIView* view = mOuter->GetView();
00693   
00694   if (view) {
00695     nsIViewManager* viewMan = view->GetViewManager();
00696 
00697     if (viewMan) {
00698         nsIView* grabbingView;
00699         viewMan->GetMouseEventGrabber(grabbingView);
00700         if (grabbingView == view)
00701           return PR_TRUE;
00702     }
00703   }
00704 
00705   return PR_FALSE;
00706 }
00707 */
00708 
00709 nsresult
00710 nsSplitterFrameInner::MouseUp(nsIDOMEvent* aMouseEvent)
00711 {  
00712   mPressed = PR_FALSE;
00713 
00714   mOuter->CaptureMouse(mOuter->mPresContext, PR_FALSE);
00715 
00716   return NS_OK;
00717 }
00718 
00719 nsresult
00720 nsSplitterFrameInner::MouseDown(nsIDOMEvent* aMouseEvent)
00721 {  
00722   nsCOMPtr<nsIDOMMouseEvent> mouseEvent(do_QueryInterface(aMouseEvent));
00723 
00724   PRUint16 button = 0;
00725   mouseEvent->GetButton(&button);
00726 
00727   // only if left button
00728   if (button != 0)
00729      return NS_OK;
00730 
00731   nsAutoString disabled;
00732   mOuter->GetContent()->GetAttr(kNameSpaceID_None,
00733                                 nsHTMLAtoms::disabled, disabled);
00734   if (disabled.EqualsLiteral("true"))
00735     return NS_OK;
00736 
00737   nsBoxLayoutState state(mOuter->mPresContext);
00738   mCurrentPos = 0;
00739   mPressed = PR_TRUE;
00740 
00741   mDidDrag = PR_FALSE;
00742 
00743   mOuter->GetParentBox(&mParentBox);
00744   
00745   // get our index
00746   nscoord childIndex = nsFrameNavigator::IndexOf(mOuter->mPresContext, mParentBox, mOuter);
00747   PRInt32 childCount = nsFrameNavigator::CountFrames(mOuter->mPresContext, mParentBox);
00748 
00749   // if its 0 or the last index then stop right here.
00750   if (childIndex == 0 || childIndex == childCount-1) {
00751     mPressed = PR_FALSE;
00752     return NS_OK;
00753   }
00754 
00755   EnsureOrient();
00756   PRBool isHorizontal = !mOuter->IsHorizontal();
00757   
00758   ResizeType resizeBefore = GetResizeBefore();
00759   ResizeType resizeAfter  = GetResizeAfter();
00760 
00761   delete[] mChildInfosBefore;
00762   delete[] mChildInfosAfter;
00763   mChildInfosBefore = new nsSplitterInfo[childCount];
00764   mChildInfosAfter  = new nsSplitterInfo[childCount];
00765 
00766   // create info 2 lists. One of the children before us and one after.
00767   PRInt32 count = 0;
00768   mChildInfosBeforeCount = 0;
00769   mChildInfosAfterCount = 0;
00770 
00771   nsIBox* childBox = nsnull;
00772   mParentBox->GetChildBox(&childBox); 
00773 
00774   while (nsnull != childBox) 
00775   { 
00776     nsIContent* content = childBox->GetContent();
00777     nsCOMPtr<nsIAtom> atom;
00778     nsresult rv;
00779     nsCOMPtr<nsIXBLService> xblService = 
00780              do_GetService("@mozilla.org/xbl;1", &rv);
00781 
00782     if (NS_SUCCEEDED(rv) && xblService) {
00783       PRInt32 dummy;
00784       xblService->ResolveTag(content, &dummy, getter_AddRefs(atom));
00785     } else
00786       atom = content->Tag();
00787 
00788     // skip over any splitters
00789     if (atom != nsXULAtoms::splitter) { 
00790         nsSize prefSize(0,0);
00791         nsSize minSize(0,0);
00792         nsSize maxSize(0,0);
00793         nscoord flex = 0;
00794 
00795         childBox->GetPrefSize(state, prefSize);
00796         childBox->GetMinSize(state, minSize);
00797         childBox->GetMaxSize(state, maxSize);
00798         nsBox::BoundsCheck(minSize, prefSize, maxSize);
00799 
00800         mOuter->AddMargin(childBox, minSize);
00801         mOuter->AddMargin(childBox, prefSize);
00802         mOuter->AddMargin(childBox, maxSize);
00803 
00804         childBox->GetFlex(state, flex);
00805 
00806         nsMargin margin(0,0,0,0);
00807         childBox->GetMargin(margin);
00808         nsRect r(childBox->GetRect());
00809         r.Inflate(margin);
00810 
00811         nsAutoString fixed, hidden;
00812         content->GetAttr(kNameSpaceID_None, nsXULAtoms::fixed, fixed);
00813         // We need to check for hidden attribute too, since treecols with
00814         // the hidden="true" attribute are not really hidden, just collapsed
00815         content->GetAttr(kNameSpaceID_None, nsHTMLAtoms::hidden, hidden);
00816 
00817         NS_NAMED_LITERAL_STRING(attrTrue, "true");
00818         if (!attrTrue.Equals(fixed) && !attrTrue.Equals(hidden)) {
00819             if (count < childIndex) {
00820                 mChildInfosBefore[mChildInfosBeforeCount].childElem = content;
00821                 mChildInfosBefore[mChildInfosBeforeCount].min     = isHorizontal ? minSize.width : minSize.height;
00822                 mChildInfosBefore[mChildInfosBeforeCount].max     = isHorizontal ? maxSize.width : maxSize.height;
00823                 mChildInfosBefore[mChildInfosBeforeCount].current = isHorizontal ? r.width : r.height;
00824                 mChildInfosBefore[mChildInfosBeforeCount].flex    = flex;
00825                 mChildInfosBefore[mChildInfosBeforeCount].index   = count;
00826                 mChildInfosBefore[mChildInfosBeforeCount].changed = mChildInfosBefore[mChildInfosBeforeCount].current;
00827                 mChildInfosBeforeCount++;
00828             } else if (count > childIndex) {
00829                 mChildInfosAfter[mChildInfosAfterCount].childElem = content;
00830                 mChildInfosAfter[mChildInfosAfterCount].min     = isHorizontal ? minSize.width : minSize.height;
00831                 mChildInfosAfter[mChildInfosAfterCount].max     = isHorizontal ? maxSize.width : maxSize.height;
00832                 mChildInfosAfter[mChildInfosAfterCount].current = isHorizontal ? r.width : r.height;
00833                 mChildInfosAfter[mChildInfosAfterCount].flex    = flex;
00834                 mChildInfosAfter[mChildInfosAfterCount].index   = count;
00835                 mChildInfosAfter[mChildInfosAfterCount].changed = mChildInfosAfter[mChildInfosAfterCount].current;
00836                 mChildInfosAfterCount++;
00837             }
00838         } 
00839     }
00840     
00841     rv = childBox->GetNextBox(&childBox);
00842     NS_ASSERTION(rv == NS_OK,"failed to get next child");
00843     count++;
00844   }
00845 
00846   PRBool isNormalDirection = PR_TRUE;
00847   mParentBox->GetDirection(isNormalDirection);
00848   if (!isNormalDirection) {
00849     // The before array is really the after array, and the order needs to be reversed.
00850     // First reverse both arrays.
00851     Reverse(mChildInfosBefore, mChildInfosBeforeCount);
00852     Reverse(mChildInfosAfter, mChildInfosAfterCount);
00853 
00854     // Now swap the two arrays.
00855     nscoord newAfterCount = mChildInfosBeforeCount;
00856     mChildInfosBeforeCount = mChildInfosAfterCount;
00857     mChildInfosAfterCount = newAfterCount;
00858     nsSplitterInfo* temp = mChildInfosAfter;
00859     mChildInfosAfter = mChildInfosBefore;
00860     mChildInfosBefore = temp;
00861   }
00862 
00863   // if the resizebefore is closest we must reverse the list because the first child in the list
00864   // is the Farthest we want the first child to be the closest.
00865   if (resizeBefore == Closest)
00866      Reverse(mChildInfosBefore, mChildInfosBeforeCount);
00867 
00868   // if the resizeafter is the Farthest we must reverse the list because the first child in the list
00869   // is the closest we want the first child to be the Farthest.
00870   if (resizeAfter == Farthest)
00871      Reverse(mChildInfosAfter, mChildInfosAfterCount);
00872 
00873   // grow only applys to the children after. If grow is set then no space should be taken out of any children after
00874   // us. To do this we just set the size of that list to be 0.
00875   if (resizeAfter == Grow)
00876      mChildInfosAfterCount = 0;
00877 
00878   nsRect vr = mOuter->GetView()->GetBounds();
00879 
00880   PRInt32 c = 0;
00881   if (isHorizontal) {
00882      mouseEvent->GetClientX(&c);
00883      mSplitterPos = mOuter->mRect.x;
00884      mSplitterViewPos = vr.x;
00885   } else {
00886      mouseEvent->GetClientY(&c);
00887      mSplitterPos = mOuter->mRect.y;
00888      mSplitterViewPos = vr.y;
00889   }
00890 
00891   mDragStartPx = c;
00892     
00893   //printf("Pressed mDragStartPx=%d\n",mDragStartPx);
00894 
00895   mOuter->CaptureMouse(mOuter->mPresContext, PR_TRUE);
00896 
00897   return NS_OK;
00898 }
00899 
00900 nsresult
00901 nsSplitterFrameInner::MouseMove(nsIDOMEvent* aMouseEvent)
00902 {  
00903   //printf("Mouse move\n");
00904 
00905   if (!mPressed)
00906       return NS_OK;
00907   
00908   if (mDragging)
00909     return NS_OK;
00910 
00911   mOuter->mContent->SetAttr(kNameSpaceID_None, nsXULAtoms::state, NS_LITERAL_STRING("dragging"), PR_TRUE);
00912 
00913   RemoveListener();
00914   mDragging = PR_TRUE;
00915 
00916   return NS_OK;
00917 }
00918 
00919 void
00920 nsSplitterFrameInner::Reverse(nsSplitterInfo*& aChildInfos, PRInt32 aCount)
00921 {
00922     nsSplitterInfo* infos = new nsSplitterInfo[aCount];
00923 
00924     for (int i=0; i < aCount; i++)
00925        infos[i] = aChildInfos[aCount - 1 - i];
00926 
00927     delete[] aChildInfos;
00928     aChildInfos = infos;
00929 }
00930 
00931 nsSplitterFrameInner::CollapseDirection
00932 nsSplitterFrameInner::GetCollapseDirection()
00933 {
00934     nsString value;
00935     if (NS_CONTENT_ATTR_HAS_VALUE == mOuter->mContent->GetAttr(kNameSpaceID_None, nsXULAtoms::collapse, value))
00936     {
00937      if (value.EqualsLiteral("before"))
00938          return Before;
00939      else if (value.EqualsLiteral("after"))
00940          return After;
00941      else 
00942        return None;
00943     } else {
00944         return None;
00945     }
00946 }
00947 
00948 void
00949 nsSplitterFrameInner::UpdateState()
00950 {
00951   // State Transitions:
00952   //   Open      -> Dragging
00953   //   Open      -> Collapsed
00954   //   Collapsed -> Open
00955   //   Collapsed -> Dragging
00956   //   Dragging  -> Open
00957   //   Dragging  -> Collapsed (auto collapse)
00958 
00959   State newState = GetState(); 
00960 
00961   if (newState == mState) {
00962     // No change.
00963     return;
00964   }
00965 
00966   CollapseDirection direction = GetCollapseDirection();
00967   if (direction != None) {
00968     nsIBox* splitter = mOuter;
00969     // Find the splitter's immediate sibling.
00970     nsIBox* splitterSibling =
00971       nsFrameNavigator::GetChildBeforeAfter(mOuter->mPresContext, splitter,
00972                                             (direction == Before));
00973     if (splitterSibling) {
00974       nsIContent* sibling = splitterSibling->GetContent();
00975       if (sibling) {
00976         if (mState == Collapsed) {
00977           // Collapsed -> Open
00978           // Collapsed -> Dragging
00979           sibling->UnsetAttr(kNameSpaceID_None, nsXULAtoms::collapsed,
00980                              PR_TRUE);
00981         } else if ((mState == Open || mState == Dragging) 
00982                    && newState == Collapsed) {
00983           // Open -> Collapsed
00984           // Dragging -> Collapsed
00985           sibling->SetAttr(kNameSpaceID_None, nsXULAtoms::collapsed,
00986                            NS_LITERAL_STRING("true"), PR_TRUE);
00987         }
00988       }
00989     }
00990   }
00991   mState = newState;
00992 }
00993 
00994 void
00995 nsSplitterFrameInner::EnsureOrient()
00996 {
00997   PRBool isHorizontal = !(mParentBox->GetStateBits() & NS_STATE_IS_HORIZONTAL);
00998   if (isHorizontal)
00999     mOuter->mState |= NS_STATE_IS_HORIZONTAL;
01000   else
01001     mOuter->mState &= ~NS_STATE_IS_HORIZONTAL;
01002 }
01003 
01004 void
01005 nsSplitterFrameInner::AdjustChildren(nsPresContext* aPresContext)
01006 {
01007   EnsureOrient();
01008   PRBool isHorizontal = !mOuter->IsHorizontal();
01009 
01010   AdjustChildren(aPresContext, mChildInfosBefore, mChildInfosBeforeCount, isHorizontal);
01011   AdjustChildren(aPresContext, mChildInfosAfter, mChildInfosAfterCount, isHorizontal);
01012    
01013   
01014    // printf("----- Posting Dirty -----\n");
01015 
01016    
01017   if (realTimeDrag) {
01018     nsIView* view = mParentBox->GetView();
01019 
01020     if (!view) {
01021         nsPoint   offset;
01022         mParentBox->GetOffsetFromView(offset, &view);
01023         NS_ASSERTION(nsnull != view, "no view");
01024     }
01025     aPresContext->PresShell()->FlushPendingNotifications(Flush_Display);
01026   }
01027   else {
01028     nsBoxLayoutState state(aPresContext);
01029     mOuter->MarkDirty(state);
01030   }
01031 }
01032 
01033 static nsIBox* GetChildBoxForContent(nsIBox* aParentBox, nsIContent* aContent)
01034 {
01035   nsIBox* childBox = nsnull;
01036   aParentBox->GetChildBox(&childBox); 
01037 
01038   while (nsnull != childBox) {
01039     if (childBox->GetContent() == aContent) {
01040       return childBox;
01041     }
01042     childBox->GetNextBox(&childBox);
01043   }
01044   return nsnull;
01045 }
01046 
01047 void
01048 nsSplitterFrameInner::AdjustChildren(nsPresContext* aPresContext, nsSplitterInfo* aChildInfos, PRInt32 aCount, PRBool aIsHorizontal)
01049 {
01051 
01052   nsBoxLayoutState state(aPresContext);
01053 
01054   nscoord onePixel = aPresContext->IntScaledPixelsToTwips(1);
01055 
01056   // first set all the widths.
01057   nsIBox* child = nsnull;
01058   mOuter->GetChildBox(&child);
01059   while(child)
01060   {
01061     SetPreferredSize(state, child, onePixel, aIsHorizontal, nsnull);
01062     child->GetNextBox(&child);
01063   }
01064 
01065   // now set our changed widths.
01066   for (int i=0; i < aCount; i++) 
01067   {
01068     nscoord   pref       = aChildInfos[i].changed;
01069     nsIBox* childBox     = GetChildBoxForContent(mParentBox, aChildInfos[i].childElem);
01070 
01071     if (childBox) {
01072       SetPreferredSize(state, childBox, onePixel, aIsHorizontal, &pref);
01073     }
01074   }
01075 }
01076 
01077 void
01078 nsSplitterFrameInner::SetPreferredSize(nsBoxLayoutState& aState, nsIBox* aChildBox, nscoord aOnePixel, PRBool aIsHorizontal, nscoord* aSize)
01079 {
01080   //printf("current=%d, pref=%d", current/onePixel, pref/onePixel);
01081  
01082   nscoord current = 0;
01083 
01084   nsRect rect(aChildBox->GetRect());
01085   if (aIsHorizontal) 
01086     current = rect.width;
01087   else
01088     current = rect.height;
01089 
01090   nscoord pref = 0;
01091 
01092   if (!aSize)
01093   {
01094     if (aIsHorizontal) 
01095       pref = rect.width;
01096     else
01097       pref = rect.height;
01098   } else {
01099     pref = *aSize;
01100   }
01101 
01102   nsMargin margin(0,0,0,0);
01103   aChildBox->GetMargin(margin);
01104 
01105   nsCOMPtr<nsIAtom> attribute;
01106 
01107   if (aIsHorizontal) {
01108     pref -= (margin.left + margin.right);
01109     attribute = nsHTMLAtoms::width;
01110   } else {
01111     pref -= (margin.top + margin.bottom);
01112     attribute = nsHTMLAtoms::height;
01113   }
01114 
01115   nsIContent* content = aChildBox->GetContent();
01116 
01117   // set its preferred size.
01118   nsAutoString prefValue;
01119   prefValue.AppendInt(pref/aOnePixel);
01120   nsAutoString oldValue;
01121   content->GetAttr(kNameSpaceID_None, attribute, oldValue);
01122   if (oldValue.Equals(prefValue))
01123      return;
01124 
01125   nsWeakFrame weakBox(aChildBox);
01126   content->SetAttr(kNameSpaceID_None, attribute, prefValue, PR_TRUE);
01127   ENSURE_TRUE(weakBox.IsAlive());
01128   aChildBox->MarkDirty(aState);
01129 }
01130 
01131 
01132 void 
01133 nsSplitterFrameInner::AddRemoveSpace(nscoord aDiff,
01134                                     nsSplitterInfo* aChildInfos,
01135                                     PRInt32 aCount,
01136                                     PRInt32& aSpaceLeft)
01137 {
01138   aSpaceLeft = 0;
01139 
01140   for (int i=0; i < aCount; i++) {   
01141     nscoord min    = aChildInfos[i].min;
01142     nscoord max    = aChildInfos[i].max;
01143     nscoord& c     = aChildInfos[i].changed;
01144 
01145     // figure our how much space to add or remove
01146     if (c + aDiff < min) {
01147       aDiff += (c - min);
01148       c = min;
01149     } else if (c + aDiff > max) {
01150       aDiff -= (max - c);
01151       c = max;
01152     } else {
01153       c += aDiff;
01154       aDiff = 0;
01155     }
01156 
01157     // there is not space left? We are done
01158     if (aDiff == 0)
01159       break;
01160   }
01161 
01162   aSpaceLeft = aDiff;
01163 }
01164 
01172 void
01173 nsSplitterFrameInner::ResizeChildTo(nsPresContext* aPresContext,
01174                                    nscoord& aDiff, 
01175                                    nsSplitterInfo* aChildrenBeforeInfos, 
01176                                    nsSplitterInfo* aChildrenAfterInfos, 
01177                                    PRInt32 aChildrenBeforeCount, 
01178                                    PRInt32 aChildrenAfterCount, 
01179                                    PRBool aBounded)
01180 { 
01181   nscoord spaceLeft;
01182   AddRemoveSpace(aDiff, aChildrenBeforeInfos,aChildrenBeforeCount,spaceLeft);
01183 
01184   // if there is any space left over remove it from the dif we were originally given
01185   aDiff -= spaceLeft;
01186   AddRemoveSpace(-aDiff, aChildrenAfterInfos,aChildrenAfterCount,spaceLeft);
01187 
01188   if (spaceLeft != 0) {
01189     if (aBounded) {
01190        aDiff += spaceLeft;
01191        AddRemoveSpace(spaceLeft, aChildrenBeforeInfos,aChildrenBeforeCount,spaceLeft);
01192     } else {
01193       spaceLeft = 0;
01194     }
01195   }
01196 }
01197 
01198 
01199 void
01200 nsSplitterFrameInner::MoveSplitterBy(nsPresContext* aPresContext, nscoord aDiff)
01201 {
01202   const nsRect& r = mOuter->mRect;
01203   nsIView *v = mOuter->GetView();
01204   nsIViewManager* vm = v->GetViewManager();
01205   nsRect vr = v->GetBounds();
01206   nsRect invalid;
01207   EnsureOrient();
01208   PRBool isHorizontal = !mOuter->IsHorizontal();
01209   if (isHorizontal) {
01210     mOuter->SetPosition(nsPoint(mSplitterPos + aDiff, r.y));
01211     vm->MoveViewTo(v, mSplitterViewPos + aDiff, vr.y);
01212     invalid.UnionRect(r,mOuter->mRect);
01213   } else {
01214     mOuter->SetPosition(nsPoint(r.x, mSplitterPos + aDiff));
01215     vm->MoveViewTo(v, vr.x, mSplitterViewPos + aDiff);
01216     invalid.UnionRect(r,mOuter->mRect);
01217   }
01218 
01219   // redraw immediately only what changed. This is animation so 
01220   // it must be immediate.
01221   nsBoxLayoutState state(aPresContext);
01222   mParentBox->Redraw(state, &invalid, PR_TRUE);
01223 }