Back to index

lightning-sunbird  0.9+nobinonly
nsGridRowLeafLayout.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  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 //
00039 // Eric Vaughan
00040 // Netscape Communications
00041 //
00042 // See documentation in associated header file
00043 //
00044 
00045 #include "nsGridRowLeafLayout.h"
00046 #include "nsGridRowGroupLayout.h"
00047 #include "nsGridRow.h"
00048 #include "nsBoxLayoutState.h"
00049 #include "nsBox.h"
00050 #include "nsIScrollableFrame.h"
00051 #include "nsBoxFrame.h"
00052 #include "nsGridLayout2.h"
00053 
00054 nsresult
00055 NS_NewGridRowLeafLayout( nsIPresShell* aPresShell, nsIBoxLayout** aNewLayout)
00056 {
00057   *aNewLayout = new nsGridRowLeafLayout(aPresShell);
00058   NS_IF_ADDREF(*aNewLayout);
00059 
00060   return NS_OK;
00061   
00062 } 
00063 
00064 nsGridRowLeafLayout::nsGridRowLeafLayout(nsIPresShell* aPresShell):nsGridRowLayout(aPresShell)
00065 {
00066 }
00067 
00068 nsGridRowLeafLayout::~nsGridRowLeafLayout()
00069 {
00070 }
00071 
00072 NS_IMETHODIMP
00073 nsGridRowLeafLayout::CastToGridRowLeaf(nsGridRowLeafLayout** aGridRowLeaf)
00074 {
00075   *aGridRowLeaf = this;
00076   return NS_OK;
00077 }
00078 
00079 NS_IMETHODIMP
00080 nsGridRowLeafLayout::GetPrefSize(nsIBox* aBox, nsBoxLayoutState& aState, nsSize& aSize)
00081 {
00082   nsGrid* grid = nsnull;
00083   PRInt32 index = 0;
00084   GetGrid(aBox, &grid, &index);
00085   PRInt32 isHorizontal = IsHorizontal(aBox);
00086 
00087   // If we are not in a grid. Then we just work like a box. But if we are in a grid
00088   // ask the grid for our size.
00089   if (!grid)
00090     return nsGridRowLayout::GetPrefSize(aBox, aState, aSize); 
00091   else {
00092     nsresult rv = grid->GetPrefRowSize(aState, index, aSize, isHorizontal);
00093     //AddBorderAndPadding(aBox, aSize);
00094     //AddInset(aBox, aSize);
00095     return rv;
00096   }
00097 }
00098 
00099 NS_IMETHODIMP
00100 nsGridRowLeafLayout::GetMinSize(nsIBox* aBox, nsBoxLayoutState& aState, nsSize& aSize)
00101 {
00102   nsGrid* grid = nsnull;
00103   PRInt32 index = 0;
00104   GetGrid(aBox, &grid, &index);
00105   PRInt32 isHorizontal = IsHorizontal(aBox);
00106 
00107   if (!grid)
00108     return nsGridRowLayout::GetMinSize(aBox, aState, aSize); 
00109   else {
00110     nsresult rv = grid->GetMinRowSize(aState, index, aSize, isHorizontal);
00111     AddBorderAndPadding(aBox, aSize);
00112     AddInset(aBox, aSize);
00113     return rv;
00114   }
00115 }
00116 
00117 NS_IMETHODIMP
00118 nsGridRowLeafLayout::GetMaxSize(nsIBox* aBox, nsBoxLayoutState& aState, nsSize& aSize)
00119 {
00120   nsGrid* grid = nsnull;
00121   PRInt32 index = 0;
00122   GetGrid(aBox, &grid, &index);
00123   PRInt32 isHorizontal = IsHorizontal(aBox);
00124 
00125   if (!grid)
00126     return nsGridRowLayout::GetMaxSize(aBox, aState, aSize); 
00127   else {
00128     nsresult rv = grid->GetMaxRowSize(aState, index, aSize, isHorizontal);
00129     AddBorderAndPadding(aBox, aSize);
00130     AddInset(aBox, aSize);
00131     return rv;
00132   }
00133 }
00134 
00135 NS_IMETHODIMP
00136 nsGridRowLeafLayout::ChildBecameDirty(nsIBox* aBox, nsBoxLayoutState& aState, nsIBox* aChild)
00137 {
00138   nsGrid* grid = nsnull;
00139   PRInt32 index = 0;
00140   GetGrid(aBox, &grid, &index);
00141   PRInt32 isHorizontal = IsHorizontal(aBox);
00142 
00143   if (grid) {
00144     PRInt32 columnIndex = -1;
00145     aBox->GetIndexOf(aChild, &columnIndex);
00146     grid->RowChildIsDirty(aState, index, columnIndex, isHorizontal);
00147   }
00148 
00149   return NS_OK;
00150 }
00151 
00152 NS_IMETHODIMP
00153 nsGridRowLeafLayout::BecameDirty(nsIBox* aBox, nsBoxLayoutState& aState)
00154 {
00155   nsGrid* grid = nsnull;
00156   PRInt32 index = 0;
00157   GetGrid(aBox, &grid, &index);
00158   PRInt32 isHorizontal = IsHorizontal(aBox);
00159 
00160   if (grid)
00161     grid->RowIsDirty(aState, index, isHorizontal);
00162 
00163   return NS_OK;
00164 }
00165 
00168 NS_IMETHODIMP
00169 nsGridRowLeafLayout::ChildAddedOrRemoved(nsIBox* aBox, nsBoxLayoutState& aState)
00170 {
00171   nsGrid* grid = nsnull;
00172   PRInt32 index = 0;
00173   GetGrid(aBox, &grid, &index);
00174   PRInt32 isHorizontal = IsHorizontal(aBox);
00175 
00176   if (grid)
00177     grid->CellAddedOrRemoved(aState, index, isHorizontal);
00178 
00179   return NS_OK;
00180 }
00181 
00182 void
00183 nsGridRowLeafLayout::PopulateBoxSizes(nsIBox* aBox, nsBoxLayoutState& aState, nsBoxSize*& aBoxSizes, nsComputedBoxSize*& aComputedBoxSizes, nscoord& aMinSize, nscoord& aMaxSize, PRInt32& aFlexes)
00184 {
00185   nsGrid* grid = nsnull;
00186   PRInt32 index = 0;
00187   GetGrid(aBox, &grid, &index);
00188   PRInt32 isHorizontal = IsHorizontal(aBox);
00189 
00190   // Our base class SprocketLayout is giving us a chance to change the box sizes before layout
00191   // If we are a row lets change the sizes to match our columns. If we are a column then do the opposite
00192   // and make them match or rows.
00193   if (grid) {
00194    nsGridRow* column;
00195    PRInt32 count = grid->GetColumnCount(isHorizontal); 
00196    nsBoxSize* start = nsnull;
00197    nsBoxSize* last = nsnull;
00198    nsBoxSize* current = nsnull;
00199    nsIBox* child = nsnull;
00200    aBox->GetChildBox(&child);
00201    for (int i=0; i < count; i++)
00202    {
00203      column = grid->GetColumnAt(i,isHorizontal); 
00204 
00205      // make sure the value was computed before we use it.
00206      nscoord pref = 0;
00207      nscoord min  = 0;
00208      nscoord max  = 0;
00209      nscoord flex  = 0;
00210      nscoord left  = 0;
00211      nscoord right  = 0;
00212 
00213      current = new (aState) nsBoxSize();
00214 
00215      // !isHorizontal is passed in to invert the behavor of these methods.
00216      grid->GetPrefRowHeight(aState, i, pref, !isHorizontal); // GetPrefColumnWidth
00217      grid->GetMinRowHeight(aState, i, min, !isHorizontal);   // GetMinColumnWidth
00218      grid->GetMaxRowHeight(aState, i, max, !isHorizontal);   // GetMaxColumnWidth
00219      grid->GetRowFlex(aState, i, flex, !isHorizontal);       // GetColumnFlex
00220      grid->GetRowOffsets(aState, i, left, right, !isHorizontal); // GetColumnOffsets
00221      nsIBox* box = column->GetBox();
00222      nscoord collapsed = PR_FALSE;
00223      nscoord topMargin = column->mTopMargin;
00224      nscoord bottomMargin = column->mBottomMargin;
00225 
00226      if (box) 
00227        box->IsCollapsed(aState, collapsed);
00228 
00229      pref = pref - (left + right);
00230      if (pref < 0)
00231        pref = 0;
00232 
00233      // if this is the first or last column. Take into account that
00234      // our row could have a border that could affect our left or right
00235      // padding from our columns. If the row has padding subtract it.
00236      // would should always be able to garentee that our margin is smaller
00237      // or equal to our left or right
00238       PRInt32 firstIndex = 0;
00239       PRInt32 lastIndex = 0;
00240       nsGridRow* firstRow = nsnull;
00241       nsGridRow* lastRow = nsnull;
00242       grid->GetFirstAndLastRow(aState, firstIndex, lastIndex, firstRow, lastRow, !isHorizontal);
00243 
00244       if (i == firstIndex || i == lastIndex) {
00245         nsMargin offset(0,0,0,0);
00246         GetTotalMargin(aBox, offset, isHorizontal);
00247 
00248         nsMargin border(0,0,0,0);
00249         // can't call GetBorderPadding we will get into recursion
00250         aBox->GetBorder(border);
00251         offset += border;
00252         aBox->GetPadding(border);
00253         offset += border;
00254 
00255         // subtract from out left and right
00256         if (i == firstIndex) 
00257         {
00258           if (isHorizontal)
00259            left -= offset.left;
00260           else
00261            left -= offset.top;
00262         }
00263 
00264         if (i == lastIndex)
00265         {
00266           if (isHorizontal)
00267            right -= offset.right;
00268           else
00269            right -= offset.bottom;
00270         }
00271       }
00272     
00273      // initialize the box size here 
00274      nsBox::BoundsCheck(min, pref, max);
00275    
00276 
00277      current->pref = pref;
00278      current->min = min;
00279      current->max = max;
00280      current->flex = flex;
00281      current->bogus = column->mIsBogus;
00282      current->left = left + topMargin;
00283      current->right = right + bottomMargin;
00284      current->collapsed = collapsed;
00285 
00286      if (!start) {
00287         start = current;
00288         last = start;
00289      } else {
00290         last->next = current;
00291         last = current;
00292      }
00293 
00294      if (child)
00295        child->GetNextBox(&child);
00296 
00297    }
00298    aBoxSizes = start;
00299   }
00300 
00301   nsSprocketLayout::PopulateBoxSizes(aBox, aState, aBoxSizes, aComputedBoxSizes, aMinSize, aMaxSize, aFlexes);
00302 }
00303 
00304 void
00305 nsGridRowLeafLayout::ComputeChildSizes(nsIBox* aBox,
00306                            nsBoxLayoutState& aState, 
00307                            nscoord& aGivenSize, 
00308                            nsBoxSize* aBoxSizes, 
00309                            nsComputedBoxSize*& aComputedBoxSizes)
00310 { 
00311   // see if we are in a scrollable frame. If we are then there could be scrollbars present
00312   // if so we need to subtract them out to make sure our columns line up.
00313   if (aBox) {
00314 
00315      // go up the parent chain looking for scrollframes
00316      PRBool isHorizontal = PR_FALSE;
00317      aBox->GetOrientation(isHorizontal);
00318 
00319      nsIBox* scrollbox = nsnull;
00320      aBox->GetParentBox(&aBox);
00321      scrollbox = nsGrid::GetScrollBox(aBox);
00322        
00323        nsCOMPtr<nsIScrollableFrame> scrollable = do_QueryInterface(scrollbox);
00324        if (scrollable) {
00325           nsMargin scrollbarSizes = scrollable->GetActualScrollbarSizes();
00326 
00327           nsRect ourRect(scrollbox->GetRect());
00328           nsMargin padding(0,0,0,0);
00329           scrollbox->GetBorderAndPadding(padding);
00330           ourRect.Deflate(padding);
00331           scrollbox->GetInset(padding);
00332           ourRect.Deflate(padding);
00333 
00334           nscoord diff;
00335           if (isHorizontal) {
00336             diff = scrollbarSizes.left + scrollbarSizes.right;
00337           } else {
00338             diff = scrollbarSizes.top + scrollbarSizes.bottom;
00339           }
00340 
00341           if (diff > 0) {
00342             aGivenSize += diff;
00343 
00344             nsSprocketLayout::ComputeChildSizes(aBox, aState, aGivenSize, aBoxSizes, aComputedBoxSizes);
00345 
00346             aGivenSize -= diff;
00347 
00348             nsComputedBoxSize* s    = aComputedBoxSizes;
00349             nsComputedBoxSize* last = aComputedBoxSizes;
00350             while(s)
00351             {
00352               last = s;
00353               s = s->next;
00354             }
00355   
00356             if (last) 
00357                 last->size -= diff;                         
00358           }
00359        }
00360   }
00361       
00362   nsSprocketLayout::ComputeChildSizes(aBox, aState, aGivenSize, aBoxSizes, aComputedBoxSizes);
00363 
00364 }
00365 
00366 NS_IMETHODIMP
00367 nsGridRowLeafLayout::Layout(nsIBox* aBox, nsBoxLayoutState& aBoxLayoutState)
00368 {
00369   return nsGridRowLayout::Layout(aBox, aBoxLayoutState);
00370 }
00371 
00372 NS_IMETHODIMP
00373 nsGridRowLeafLayout::DirtyRows(nsIBox* aBox, nsBoxLayoutState& aState)
00374 {
00375   if (aBox) {
00376     // mark us dirty
00377     aBox->MarkDirty(aState);
00378   }
00379 
00380   return NS_OK;
00381 }
00382 
00383 NS_IMETHODIMP
00384 nsGridRowLeafLayout::CountRowsColumns(nsIBox* aBox, PRInt32& aRowCount, PRInt32& aComputedColumnCount)
00385 {
00386   if (aBox) {
00387     nsIBox* child = nsnull;
00388     aBox->GetChildBox(&child);
00389 
00390     // count the children
00391     PRInt32 columnCount = 0;
00392     while(child) {
00393       child->GetNextBox(&child);
00394       columnCount++;
00395     }
00396 
00397     // if our count is greater than the current column count
00398     if (columnCount > aComputedColumnCount) 
00399       aComputedColumnCount = columnCount;
00400 
00401     aRowCount++;
00402   }
00403 
00404   return NS_OK;
00405 }
00406 
00407 NS_IMETHODIMP
00408 nsGridRowLeafLayout::BuildRows(nsIBox* aBox, nsGridRow* aRows, PRInt32* aCount)
00409 { 
00410   if (aBox) {
00411       aRows[0].Init(aBox, PR_FALSE);
00412       *aCount = 1;
00413       return NS_OK;
00414   }
00415 
00416   *aCount = 0;
00417 
00418   return NS_OK;
00419 }
00420 
00421 NS_IMETHODIMP
00422 nsGridRowLeafLayout::GetRowCount(PRInt32& aRowCount)
00423 {
00424   aRowCount = 1;
00425   return NS_OK;
00426 }
00427