layout/xul/nsListBoxLayout.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/xul/nsListBoxLayout.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,212 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsListBoxLayout.h"
    1.10 +
    1.11 +#include "nsListBoxBodyFrame.h"
    1.12 +#include "nsBox.h"
    1.13 +#include "nsBoxLayoutState.h"
    1.14 +#include "nsIScrollableFrame.h"
    1.15 +#include "nsIReflowCallback.h"
    1.16 +#include "nsNameSpaceManager.h"
    1.17 +#include "nsGkAtoms.h"
    1.18 +#include "nsContentUtils.h"
    1.19 +
    1.20 +nsListBoxLayout::nsListBoxLayout() : nsGridRowGroupLayout()
    1.21 +{
    1.22 +}
    1.23 +
    1.24 +////////// nsBoxLayout //////////////
    1.25 +
    1.26 +nsSize
    1.27 +nsListBoxLayout::GetPrefSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState)
    1.28 +{
    1.29 +  nsSize pref = nsGridRowGroupLayout::GetPrefSize(aBox, aBoxLayoutState);
    1.30 +
    1.31 +  nsListBoxBodyFrame* frame = static_cast<nsListBoxBodyFrame*>(aBox);
    1.32 +  if (frame) {
    1.33 +    nscoord rowheight = frame->GetRowHeightAppUnits();
    1.34 +    pref.height = frame->GetRowCount() * rowheight;
    1.35 +    // Pad the height.
    1.36 +    nscoord y = frame->GetAvailableHeight();
    1.37 +    if (pref.height > y && y > 0 && rowheight > 0) {
    1.38 +      nscoord m = (pref.height-y)%rowheight;
    1.39 +      nscoord remainder = m == 0 ? 0 : rowheight - m;
    1.40 +      pref.height += remainder;
    1.41 +    }
    1.42 +    if (nsContentUtils::HasNonEmptyAttr(frame->GetContent(), kNameSpaceID_None,
    1.43 +                                        nsGkAtoms::sizemode)) {
    1.44 +      nscoord width = frame->ComputeIntrinsicWidth(aBoxLayoutState);
    1.45 +      if (width > pref.width)
    1.46 +        pref.width = width;
    1.47 +    }
    1.48 +  }
    1.49 +  return pref;
    1.50 +}
    1.51 +
    1.52 +nsSize
    1.53 +nsListBoxLayout::GetMinSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState)
    1.54 +{
    1.55 +  nsSize minSize = nsGridRowGroupLayout::GetMinSize(aBox, aBoxLayoutState);
    1.56 +
    1.57 +  nsListBoxBodyFrame* frame = static_cast<nsListBoxBodyFrame*>(aBox);
    1.58 +  if (frame) {
    1.59 +    nscoord rowheight = frame->GetRowHeightAppUnits();
    1.60 +    minSize.height = frame->GetRowCount() * rowheight;
    1.61 +    // Pad the height.
    1.62 +    nscoord y = frame->GetAvailableHeight();
    1.63 +    if (minSize.height > y && y > 0 && rowheight > 0) {
    1.64 +      nscoord m = (minSize.height-y)%rowheight;
    1.65 +      nscoord remainder = m == 0 ? 0 : rowheight - m;
    1.66 +      minSize.height += remainder;
    1.67 +    }
    1.68 +    if (nsContentUtils::HasNonEmptyAttr(frame->GetContent(), kNameSpaceID_None,
    1.69 +                                        nsGkAtoms::sizemode)) {
    1.70 +      nscoord width = frame->ComputeIntrinsicWidth(aBoxLayoutState);
    1.71 +      if (width > minSize.width)
    1.72 +        minSize.width = width;
    1.73 +    }
    1.74 +  }
    1.75 +  return minSize;
    1.76 +}
    1.77 +
    1.78 +nsSize
    1.79 +nsListBoxLayout::GetMaxSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState)
    1.80 +{
    1.81 +  nsSize maxSize = nsGridRowGroupLayout::GetMaxSize(aBox, aBoxLayoutState);
    1.82 +
    1.83 +  nsListBoxBodyFrame* frame = static_cast<nsListBoxBodyFrame*>(aBox);
    1.84 +  if (frame) {
    1.85 +    nscoord rowheight = frame->GetRowHeightAppUnits();
    1.86 +    maxSize.height = frame->GetRowCount() * rowheight;
    1.87 +    // Pad the height.
    1.88 +    nscoord y = frame->GetAvailableHeight();
    1.89 +    if (maxSize.height > y && y > 0 && rowheight > 0) {
    1.90 +      nscoord m = (maxSize.height-y)%rowheight;
    1.91 +      nscoord remainder = m == 0 ? 0 : rowheight - m;
    1.92 +      maxSize.height += remainder;
    1.93 +    }
    1.94 +  }
    1.95 +  return maxSize;
    1.96 +}
    1.97 +
    1.98 +NS_IMETHODIMP
    1.99 +nsListBoxLayout::Layout(nsIFrame* aBox, nsBoxLayoutState& aState)
   1.100 +{
   1.101 +  return LayoutInternal(aBox, aState);
   1.102 +}
   1.103 +
   1.104 +
   1.105 +/////////// nsListBoxLayout /////////////////////////
   1.106 +
   1.107 +/**
   1.108 + * Called to layout our our children. Does no frame construction
   1.109 + */
   1.110 +NS_IMETHODIMP
   1.111 +nsListBoxLayout::LayoutInternal(nsIFrame* aBox, nsBoxLayoutState& aState)
   1.112 +{
   1.113 +  int32_t redrawStart = -1;
   1.114 +
   1.115 +  // Get the start y position.
   1.116 +  nsListBoxBodyFrame* body = static_cast<nsListBoxBodyFrame*>(aBox);
   1.117 +  if (!body) {
   1.118 +    NS_ERROR("Frame encountered that isn't a listboxbody!");
   1.119 +    return NS_ERROR_FAILURE;
   1.120 +  }
   1.121 +
   1.122 +  nsMargin margin;
   1.123 +
   1.124 +  // Get our client rect.
   1.125 +  nsRect clientRect;
   1.126 +  aBox->GetClientRect(clientRect);
   1.127 +
   1.128 +  // Get the starting y position and the remaining available
   1.129 +  // height.
   1.130 +  nscoord availableHeight = body->GetAvailableHeight();
   1.131 +  nscoord yOffset = body->GetYPosition();
   1.132 +  
   1.133 +  if (availableHeight <= 0) {
   1.134 +    bool fixed = (body->GetFixedRowSize() != -1);
   1.135 +    if (fixed)
   1.136 +      availableHeight = 10;
   1.137 +    else
   1.138 +      return NS_OK;
   1.139 +  }
   1.140 +
   1.141 +  // run through all our currently created children
   1.142 +  nsIFrame* box = body->GetChildBox();
   1.143 +
   1.144 +  // if the reason is resize or initial we must relayout.
   1.145 +  nscoord rowHeight = body->GetRowHeightAppUnits();
   1.146 +
   1.147 +  while (box) {
   1.148 +    // If this box is dirty or if it has dirty children, we
   1.149 +    // call layout on it.
   1.150 +    nsRect childRect(box->GetRect());
   1.151 +    box->GetMargin(margin);
   1.152 +    
   1.153 +    // relayout if we must or we are dirty or some of our children are dirty
   1.154 +    //   or the client area is wider than us
   1.155 +    // XXXldb There should probably be a resize check here too!
   1.156 +    if (NS_SUBTREE_DIRTY(box) || childRect.width < clientRect.width) {
   1.157 +      childRect.x = 0;
   1.158 +      childRect.y = yOffset;
   1.159 +      childRect.width = clientRect.width;
   1.160 +      
   1.161 +      nsSize size = box->GetPrefSize(aState);
   1.162 +      body->SetRowHeight(size.height);
   1.163 +      
   1.164 +      childRect.height = rowHeight;
   1.165 +
   1.166 +      childRect.Deflate(margin);
   1.167 +      box->SetBounds(aState, childRect);
   1.168 +      box->Layout(aState);
   1.169 +    } else {
   1.170 +      // if the child did not need to be relayed out. Then its easy.
   1.171 +      // Place the child by just grabbing its rect and adjusting the y.
   1.172 +      int32_t newPos = yOffset+margin.top;
   1.173 +
   1.174 +      // are we pushing down or pulling up any rows?
   1.175 +      // Then we may have to redraw everything below the moved 
   1.176 +      // rows.
   1.177 +      if (redrawStart == -1 && childRect.y != newPos)
   1.178 +        redrawStart = newPos;
   1.179 +
   1.180 +      childRect.y = newPos;
   1.181 +      box->SetBounds(aState, childRect);
   1.182 +    }
   1.183 +
   1.184 +    // Ok now the available size gets smaller and we move the
   1.185 +    // starting position of the next child down some.
   1.186 +    nscoord size = childRect.height + margin.top + margin.bottom;
   1.187 +
   1.188 +    yOffset += size;
   1.189 +    availableHeight -= size;
   1.190 +    
   1.191 +    box = box->GetNextBox();
   1.192 +  }
   1.193 +  
   1.194 +  // We have enough available height left to add some more rows
   1.195 +  // Since we can't do this during layout, we post a callback
   1.196 +  // that will be processed after the reflow completes.
   1.197 +  body->PostReflowCallback();
   1.198 +    
   1.199 +  // if rows were pushed down or pulled up because some rows were added
   1.200 +  // before them then redraw everything under the inserted rows. The inserted
   1.201 +  // rows will automatically be redrawn because the were marked dirty on insertion.
   1.202 +  if (redrawStart > -1) {
   1.203 +    aBox->Redraw(aState);
   1.204 +  }
   1.205 +
   1.206 +  return NS_OK;
   1.207 +}
   1.208 +
   1.209 +// Creation Routines ///////////////////////////////////////////////////////////////////////
   1.210 +
   1.211 +already_AddRefed<nsBoxLayout> NS_NewListBoxLayout()
   1.212 +{
   1.213 +  nsRefPtr<nsBoxLayout> layout = new nsListBoxLayout();
   1.214 +  return layout.forget();
   1.215 +} 

mercurial