Re: Publishing the flexible box model

L. David Baron wrote:
> On Wednesday 2008-06-04 17:50 -0700, Andrew Fedoniouk wrote:
>> Consider following markup:
>>
>> <body>
>>  <div>On the top</div>
>>  <div>On the bottom</div>
>> </body>
>>
>> and we would like to "stick" second div to the bottom and first one to  
>> the top of the view. How would you
>> accomplish that with XUL flexes? Probably I have missed something but  
>> that is impossible with XUL flexes.
> 
> <body style="display:box; box-orient:vertical">
>   <div>On the top</div>
>   <div style="box-flex: 1"></div> <!-- maybe needs 'display: box' ? -->
>   <div>On the bottom</div>
> </body>

David, I think you already know why this is bad.
div in the middle is not a solution if we speak about CSS.

> 
>> Flexibility is really a length unit rather than some property.
> 
> No, since some layout models (traditional document layout) use one
> dimension as input and the other as output; you can only flex in a
> dimension that is input to the algorithm.  In the existing CSS
> model, in many cases, there is no sensible height that is input to
> the algorithm (or, depending on how you look at it, multiple heights
> that might be of interest).
> 

I am not sure I understand this:
"you can *only* flex in a dimension that is input to the algorithm"

This
   <body><table width=100% height=100%></table></body>
works perfectly well in Gecko as in other engines.

(In html/table percents behave as flex units)

So we already know how to flex things in both dimensions.
That is why I am confused by your statement.

Flexes defined in the context of some container. Content
is measured normally (position:static) and if there is a free
space left then this free space is getting distributed
among all lengths having flex units - parts competing for free
space.

For inline-block elements container is a line box so this:

<p>Input:<input style="width:1*; height:1*" /><br/>
Input #2:<input style="width:1*; height:1*" /></p>

will be rendered as:

   |Input:[~~~~~~~input~~~~~~~~]|
   |Input #2:[~~~~~input~~~~~~~]|

Height if these inputs (height:1*) will be set to the
height of correspondent line box.

For containers that have display-model:block-inside
flexes of children are computed against width and height
such containers. For children of flow:vertical containers:

   width:auto, margin-left/right:auto are exactly
   width:1*, margin-left/right:1* - nothing new here.

and
   height:1* and/or margin-left/right:1* declares
   this block as competing for free space distribution.

If such container has declared height greater than intrinsic height
of the content then it means that there is a free space.
This space can be distributed among flexes.

Flex distribution algorithm is simple. I've attached
implementation that I use ( libra.h ).

-- 
Andrew Fedoniouk.

http://terrainformatica.com
//|
//|----------------------------------------------------------------------+
//| H-SMILE core                                                         |
//|----------------------------------------------------------------------+
//| Copyright (c) 2001-2008 Andrew Fedoniouk and                         |
//| Terra Informatica Software, Inc.                                     |
//|----------------------------------------------------------------------+
//|

//|
//| Flex (Springs) distribution algorithm implementation.
//| 

namespace html  
{

  class libra
  {
  public:
    struct item 
    {
      int  vmin;
      int  vmax;  
      int  v;     // computed value
      int  p;     // weight (>0)
    };

    int         ptotal;
    int         vtotalmin;
    int         autos;
    int         freespace;
    
    spring_engine() 
    { 
      clear();
    }

    void clear() 
    { 
      ptotal = 0;
      vtotalmin = 0;
      autos = 0;
      freespace = 0;
    }

    // adds flex item to distribute
    
    // param: valmin/valmax, min/max constraints.
    // param: percent - weight

    void add(int valmin, int valmax, int percent)
    {
      item i;
      i.v = i.vmin = valmin;
      if(valmax && (valmax < valmin)) 
        i.vmax = valmin;
      else
        i.vmax = valmax;

      i.p = percent;
      ptotal += percent;

      if (valmax) 
        ++autos;
      if(percent == 0)
        vtotalmin += valmin;
      add_item(i);
    }

    inline int val(int i) { return (head() + i)->v; }

    // param: total, total container width to distribute.
    // param: max100, flag - true - do 100%% normalization
    // return: actual content width.

    inline int calc(int total, bool max100 = true) 
    {
      freespace = total - vtotalmin;
      if(freespace <= 0 || ptotal == 0)
        return vtotalmin;

      item *start = head();
      item *i = start;
      item *end = tail();

      int ptotalmin = ptotal;

      if(max100)
      {
         if (ptotal < 100)
          ptotal = 100; // key point
      }
      
      ptotalmin = ptotal - ptotalmin;
      int save_ptotal = ptotal;

      // worst case is n*n scans of the set. 
      for(item* iteration = start; iteration < end; ++iteration)
      {
        for(i = start;i < end; ++i)
        {
          if(i->p == 0)
            continue; // skip elements having fixed size

          if( ptotal == 0 )
          {
            //assert(false);
            break;
          }
                  
          int v = (freespace * i->p) / ptotal; // v, value - width candidate
          if( v < i->vmin )
          {
            // minimum reached, exclude from distribution list
            i->v = i->vmin;
            vtotalmin += i->v;
            save_ptotal -= i->p;
            i->p = 0; 
            break; 
          }
          if(autos && i->vmax && ( v > i->vmax ))
          {
            // maximum reached, exclude from distribution list
            i->v = i->vmax;
            vtotalmin += i->v;
            save_ptotal -= i->p;
            i->p = 0; 
            break;
          }
          i->v = v;
          freespace -= v;
          ptotal -= i->p;

          if(ptotal <= ptotalmin)
             break;  //done
        }

        if(ptotal <= ptotalmin || freespace <= 0) 
          break; //done

        ptotal = save_ptotal;
        freespace = total - vtotalmin;
      }
      
      return total - freespace;
    }

    virtual void  add_item(const item& it) = 0;
    virtual item* head() = 0;
    virtual item* tail() = 0;

  };

}

Received on Thursday, 5 June 2008 03:10:25 UTC