Back to index

nux  3.0.0
VLayout.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2010 Inalogic® Inc.
00003  *
00004  * This program is free software: you can redistribute it and/or modify it
00005  * under the terms of the GNU Lesser General Public License, as
00006  * published by the  Free Software Foundation; either version 2.1 or 3.0
00007  * of the License.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranties of
00011  * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
00012  * PURPOSE.  See the applicable version of the GNU Lesser General Public
00013  * License for more details.
00014  *
00015  * You should have received a copy of both the GNU Lesser General Public
00016  * License along with this program. If not, see <http://www.gnu.org/licenses/>
00017  *
00018  * Authored by: Jay Taoko <jaytaoko@inalogic.com>
00019  *
00020  */
00021 
00022 
00023 #include "Nux.h"
00024 #include "View.h"
00025 #include "VLayout.h"
00026 #include "HLayout.h"
00027 
00028 namespace nux
00029 {
00030 
00031   static const int VERROR = 0;
00032   NUX_IMPLEMENT_OBJECT_TYPE(VLayout);
00033 
00034   VLayout::VLayout(NUX_FILE_LINE_DECL)
00035     : LinearLayout(NUX_FILE_LINE_PARAM)
00036   {
00037 #if DEBUG_LAYOUT
00038     m_h_in_margin = 10;
00039     left_padding_ = 10;
00040     right_padding_ = 10;
00041     space_between_children_ = 10;
00042     top_padding_ = 10;
00043     bottom_padding_ = 10;
00044 #endif
00045 
00046     // Start packing the elements from the left size. Is the layout has more space than the elements can use,
00047     // leave that space on the right side of the VLayout.
00048     m_ContentStacking = eStackTop;
00049 
00050   }
00051 
00052   VLayout::VLayout(NString name, NUX_FILE_LINE_DECL)
00053     : LinearLayout(NUX_FILE_LINE_PARAM)
00054   {
00055     m_name = name;
00056 #if DEBUG_LAYOUT
00057     m_h_in_margin = 10;
00058     left_padding_ = 10;
00059     right_padding_ = 10;
00060     space_between_children_ = 10;
00061     top_padding_ = 10;
00062     bottom_padding_ = 10;
00063 #endif
00064 
00065     m_ContentStacking = eStackTop;
00066   }
00067 
00068   VLayout::~VLayout()
00069   {
00070   }
00071 
00072   void VLayout::GetCompositeList(std::list<Area *> *ViewList)
00073   {
00074     std::list<Area *>::iterator it;
00075 
00076     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00077     {
00078       if ((*it)->IsView())
00079       {
00080         View *ic = NUX_STATIC_CAST(View *, (*it));
00081         ViewList->push_back(ic);
00082       }
00083       else if ((*it)->IsLayout())
00084       {
00085         Layout *layout = NUX_STATIC_CAST(Layout *, (*it));
00086         layout->GetCompositeList(ViewList);
00087       }
00088     }
00089   }
00090 
00092 
00097   void VLayout::ComputeStacking(int remaining_height, int &offset_space, int &element_margin)
00098   {
00099     int per_element_space = 0;
00100     int total_used_space = 0;
00101     int n_elements = 0;
00102 
00103     std::list<Area *>::iterator it;
00104 
00105     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00106     {
00107       // gather all the space used by elements
00108       if ((*it)->IsVisible())
00109       {
00110         total_used_space += (*it)->GetBaseHeight();
00111         n_elements++;
00112       }
00113     }
00114 
00115     if (n_elements != 0)
00116     {
00117       // Compute the space available for each element
00118       per_element_space = (remaining_height - total_used_space) / int(n_elements);
00119     }
00120 
00121     if (per_element_space < 0)
00122     {
00123       per_element_space = 0;
00124     }
00125 
00126     int margin;
00127 
00128     if (per_element_space > 0)
00129     {
00130       margin = (per_element_space) / 2;
00131     }
00132     else
00133     {
00134       margin = 0;
00135     }
00136 
00137     LayoutContentDistribution stacking = GetContentDistribution();
00138 
00139     switch(stacking)
00140     {
00141       case MAJOR_POSITION_START:
00142       {
00143         offset_space = 0;
00144         element_margin = 0;
00145       }
00146       break;
00147 
00148       case MAJOR_POSITION_END:
00149       {
00150         offset_space = (remaining_height - total_used_space);
00151 
00152         if (offset_space < 0)
00153           offset_space = 0;
00154 
00155         element_margin = 0;
00156       }
00157       break;
00158 
00159       case eStackCenter:
00160       {
00161         offset_space = (remaining_height - total_used_space) / 2;
00162 
00163         if (offset_space < 0)
00164           offset_space = 0;
00165 
00166         element_margin = 0;
00167       }
00168       break;
00169 
00170       case eStackExpand:
00171       default:
00172       {
00173         offset_space = 0;
00174         element_margin = margin;
00175       }
00176       break;
00177     }
00178   }
00179 
00180   long VLayout::ComputeContentSize()
00181   {
00182     if (_layout_element_list.size() == 0)
00183     {
00184       return eCompliantHeight | eCompliantWidth;
00185     }
00186 
00187     std::list<Area *>::iterator it;
00188 
00189     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00190     {
00191       (*it)->SetLayoutDone(false);
00192     }
00193 
00194     int original_width = GetBaseWidth();
00195 
00196     if (GetScaleFactor() == 0)
00197     {
00198       // The size must exactly fit the children. The parent cannot be larger or smaller
00199       // than the total height of its children(+ margins).
00200       // So set the parent size to Geometry(0,0,1,1) and let the children force it to extend.
00201       if (GetParentObject() && GetParentObject()->Type().IsObjectType(HLayout::StaticObjectType))
00202       {
00203         // The parent if a HLayout. Then a Stretch factor of 0 means this layout has its width set to 1.
00204         Area::SetBaseWidth(1);
00205       }
00206       else if (GetParentObject() && GetParentObject()->Type().IsObjectType(VLayout::StaticObjectType))
00207       {
00208         // The parent if a VLayout(same type). Then a Stretch factor of 0 means this layout has its height set to 1.
00209         Area::SetBaseHeight(1);
00210       }
00211       else
00212       {
00213         // This is for when a layout is set as a composition layout of an View and its stretch factor is explicitly set to 0.
00214         Area::SetBaseWidth(1);
00215         Area::SetBaseHeight(1);
00216       }
00217 
00218       //The children will all assume their minimum size.
00219     }
00220     else
00221     {
00222       // The total size of the children(+ margins) may be smaller or equal to parent size.
00223     }
00224 
00225     bool unadjusted_layout = false;
00226     size_t num_element = 0;
00227 
00228     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00229     {
00230       if ((*it)->IsVisible())
00231         num_element++;
00232     }
00233 
00234     do
00235     {
00236       // Get layout Width and Height
00237       int width = GetBaseWidth();
00238       int height = GetBaseHeight();
00239 
00240       // Remove the margins. This is the real width and height available to the children.
00241       width -= (left_padding_ + right_padding_);
00242       height -= (int) (num_element - 1) * space_between_children_ + (top_padding_ + bottom_padding_);
00243 
00244       // Size the children according to their stretch factor.
00245       VLayoutManagement(width, height);
00246 
00247       // Objects have been resized, now position them.
00248       int current_x = GetBaseX() + left_padding_;
00249       int current_y = GetBaseY() + top_padding_;
00250 
00251       //int per_element_space = 0;
00252       //int total_used_space = 0;
00253       int offset_space = 0;
00254       int space_after_element = 0;
00255       ComputeStacking(height, offset_space, space_after_element);
00256       current_y += offset_space;
00257 
00258       for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00259       {
00260         if (!(*it)->IsVisible())
00261           continue;
00262 
00263         current_y += space_after_element;
00264 
00265         (*it)->SetBaseX(current_x);
00266         (*it)->SetBaseY(current_y);
00267 
00268         MinorDimensionSize extend = (*it)->GetExtend();
00269         MinorDimensionPosition positioning = (*it)->GetPositioning();
00270         float percentage = (*it)->GetPercentage();
00271 
00272         // Compute the size of an element in the minor dimension(horizontal)
00273         switch(extend)
00274         {
00275           case MINOR_SIZE_PERCENTAGE:
00276           {
00277             // The size of the element in the minor dimension is a percentage of layout minor dimension size.
00278             // Note that children of the processed element may force it to have a bigger size.
00279             int percentage_width = (width * percentage) / 100.0f;
00280             (*it)->SetBaseWidth(percentage_width);
00281             break;
00282           }
00283 
00284           case MINOR_SIZE_MATCHCONTENT:
00285           {
00286             // Force the element width to be the minimum has defined with SetMinimumWidth.
00287             // The children of this element can force it to get larger.
00288             (*it)->ApplyMinWidth();
00289             break;
00290           }
00291 
00292           case eFix:
00293           {
00294             //do nothing
00295             break;
00296           }
00297 
00298           case MINOR_SIZE_FULL:
00299           default:
00300           {
00301             (*it)->SetBaseWidth(width);
00302             break;
00303           }
00304         }
00305 
00306         // Compute the position of an element in the minor dimension.
00307         if ((*it)->GetBaseWidth() < width)
00308         {
00309           int widget_width = (*it)->GetBaseWidth();
00310 
00311           switch(positioning)
00312           {
00313             case MINOR_POSITION_START:
00314             {
00315               // do nothing
00316               (*it)->SetBaseX(current_x);
00317               break;
00318             }
00319             case MINOR_POSITION_END:
00320             {
00321               if (widget_width < width)
00322                 (*it)->SetBaseX(current_x + width - widget_width);
00323               else
00324                 (*it)->SetBaseX(current_x);
00325 
00326               break;
00327             }
00328 
00329             case MINOR_POSITION_CENTER:
00330             default:
00331             {
00332               if (widget_width < width)
00333                 (*it)->SetBaseX(current_x + (width - widget_width) / 2);
00334               else
00335                 (*it)->SetBaseX(current_x);
00336             }
00337           }
00338         }
00339 
00340         current_y += (*it)->GetBaseHeight() + space_after_element + space_between_children_;
00341       }
00342 
00343       // Manage child layout
00344       m_contentWidth = GetBaseWidth() - (left_padding_ + right_padding_); // Set to the size of the layout.
00345 
00346       if (num_element == 0)
00347         m_fittingHeight = (int) (top_padding_ + bottom_padding_);
00348       else
00349         m_fittingHeight = (int) (num_element - 1) * space_between_children_ + (top_padding_ + bottom_padding_);
00350 
00351       int element_width;
00352       unadjusted_layout = false;
00353 
00354       // This array is meant to store the sizes of some of the elements width. These elements must have MINOR_SIZE_FULL as extent and
00355       // they have not been not been constrained smaller after ComputeContentSize is called. Because the layout may have a stretch factor of 0
00356       // and therefore its size has been set to 1x1 at the start of this function, there is a possibility that some of the elements don't have
00357       // the full width of the layout(these elements uses their minimum width because the layout was set to a size 1x1).
00358       // We check if that is the case and force a recompute.
00359       std::vector<int> FullSizeUnadjusted;
00360 
00361       for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00362       {
00363         if (!(*it)->IsVisible())
00364           continue;
00365 
00366         bool larger_height  = false;
00367         bool smaller_height = false;
00368         bool smaller_width  = false;
00369         bool larger_width   = false;
00370         int ret = 0;
00371         
00372         if (((*it)->IsLayout() || (*it)->IsView()) /*&& ((*it)->IsLayoutDone() == false)*/ /*&& ((*it)->GetScaleFactor() != 0)*/)
00373         {
00374           Geometry pre_geo = (*it)->GetGeometry();
00375           ret = (*it)->ComputeContentSize();
00376           Geometry post_geo = (*it)->GetGeometry();
00377 
00378           larger_width    = (pre_geo.width < post_geo.width)    ? true : false;
00379           smaller_width   = (pre_geo.width > post_geo.width)    ? true : false;
00380           larger_height   = (pre_geo.height < post_geo.height)  ? true : false;
00381           smaller_height  = (pre_geo.height > post_geo.height)  ? true : false;
00382 
00383           if ((larger_height || smaller_height) && ((*it)->IsLayoutDone() == false))
00384           {
00385             // Stop computing the size of this layout. Its size was not convenient to its children. So the children size take priority
00386             // over the layout. In ComputeContentSize, the dimension of the layout has been set so it encompasses its children(and the margins).
00387             // Now the parent layout cannot be touched again: layout_done_ = true. In VLayoutManagement, it is as if the stretchfactor
00388             // of this layout is now 0.
00389             // This is the only place where a layout can have layout_done_ set to "true".
00390 
00391             // If(smaller_height == true) the layout takes less space than anticipated.
00392             // Set unadjusted_layout = true, so another pass will allow its sibling to claim more space.
00393             {
00394               unadjusted_layout = true;
00395               (*it)->SetLayoutDone(true);
00396             }
00397           }
00398 
00399           if ((smaller_width == false) && ((*it)->GetExtend() == MINOR_SIZE_FULL) && ((*it)->GetBaseWidth() < (*it)->GetMaximumWidth()))
00400           {
00401             // Catch all object whose size is possibly larger than the layout. Check their size at the end and
00402             // recompute the layout if necessary.
00403             // For layout elements, make sure that the stretch factor is not 0. If it is, it means it will not use the
00404             // size provided by the parent layout. Its size will be adjusted to the minimum size of the layout content.
00405             if (!((*it)->IsLayout() && (*it)->GetScaleFactor() == 0))
00406               FullSizeUnadjusted.push_back((*it)->GetBaseWidth());
00407           }
00408 
00409           if ((smaller_width || larger_width) && ((*it)->GetExtend() == MINOR_SIZE_MATCHCONTENT))
00410           {
00411             (*it)->SetMinimumWidth((*it)->GetBaseWidth());
00412             unadjusted_layout = true;
00413           }
00414 
00415           // Should be reactivate so that if the parent Layout does not call
00416           // ComputeContentPosition, at least it is done here to arrange the internal
00417           // element of the children.
00418           //(*it)->ComputeContentPosition(0,0);
00419         }
00420 
00421         m_fittingHeight += (*it)->GetBaseHeight();
00422 
00423         element_width = (*it)->GetBaseWidth();
00424 
00425         if ((*it)->IsSpaceLayout() == false)
00426         {
00427           if ((GetScaleFactor() != 0) && (ret & eSmallerWidth))
00428           {
00429             if (m_contentWidth < element_width)
00430             {
00431               if (m_contentWidth < GetMaximumHeight())
00432               {
00433                 // An element is larger than the layout width and the layout has not reach its maximum width yet.
00434                 m_contentWidth = element_width;
00435                 unadjusted_layout = true;
00436               }
00437             }
00438           }
00439           else
00440           {
00441             if (m_contentWidth <= element_width)
00442             {
00443               m_contentWidth = element_width;
00444             }
00445 
00446 //                    else if ((*it)->GetExtend() == MINOR_SIZE_FULL)
00447 //                    {
00448 //                        unadjusted_layout = true;
00449 //                    }
00450           }
00451         }
00452       }
00453 
00454       // Set the width of the layout to be equal to the largest width it controls.
00455       // m_contentWidth is the largest width of an element within this layout. The layout size is then
00456       // m_contentWidth + (left_padding_ + right_padding_);
00457       SetBaseWidth(m_contentWidth + (left_padding_ + right_padding_));
00458 
00459       int temp = m_contentWidth;
00460       std::vector<int>::iterator IntIterator = FullSizeUnadjusted.begin();
00461 
00462       for (IntIterator = FullSizeUnadjusted.begin(); IntIterator != FullSizeUnadjusted.end(); IntIterator++)
00463       {
00464         if ((*IntIterator) < temp)
00465         {
00466           unadjusted_layout = true;
00467         }
00468       }
00469     }
00470     while (unadjusted_layout);
00471 
00472     // m_fittingWidth is sum of the largest element width plus the outer margin.
00473     m_fittingWidth = m_contentWidth + (left_padding_ + right_padding_);
00474 
00475     // m_fittingHeight is sum of the element height plus the inner and outer margin.
00476     // If the stretch factor is 0 then, the layout height has been set to 1 and need to grow with the elements within.
00477     // If the stretch factor is not 0, then the layout height is set to m_fittingHeight only if the its height is less than m_fittingHeight;
00478     // This way, if the layout height is greater than m_fittingHeight there is space to compute the content stacking(ComputeStacking).
00479     if (GetBaseHeight() < m_fittingHeight)
00480     {
00481       SetBaseHeight(m_fittingHeight);
00482     }
00483 
00484     m_contentHeight = m_fittingHeight;
00485     long size_compliance = 0L;
00486 
00487     ComputeContentPosition(0, 0);
00488 
00489     if (GetBaseWidth() > original_width + VERROR)
00490     {
00491 #if DEBUG_LAYOUT_COMPUTATION
00492       // The layout has been resized larger in WIDTH to tightly pack its content.
00493       // Or you can say that the layout refuse to be smaller than total WIDTH of its elements.
00494       std::cout << "ComputeContentSize: VLayout Width block at " << GetWidth() << std::endl;
00495 #endif
00496       size_compliance |= eLargerWidth; // need scrollbar
00497     }
00498     else if (GetBaseWidth() + VERROR < original_width)
00499     {
00500 #if DEBUG_LAYOUT_COMPUTATION
00501       // The layout is smaller.
00502       std::cout << "ComputeContentSize: VLayout Width smaller = " << GetWidth() << std::endl;
00503 #endif
00504       size_compliance |= eSmallerWidth;
00505     }
00506     else
00507     {
00508 #if DEBUG_LAYOUT_COMPUTATION
00509       // The layout and its content resized together without trouble.
00510       std::cout << "ComputeContentSize: VLayout Width compliant = " << GetWidth() << std::endl;
00511 #endif
00512       size_compliance |= eCompliantWidth;
00513     }
00514 
00515     {
00516 #if DEBUG_LAYOUT_COMPUTATION
00517       // The layout and its content resized together without trouble.
00518       std::cout << "ComputeContentSize: VLayout Height compliant = " << m_fittingHeight << std::endl;
00519 #endif
00520       size_compliance |= eCompliantHeight;
00521     }
00522 
00523     return size_compliance;
00524   }
00525 
00526   void VLayout::VLayoutManagement(int width, int height)
00527   {
00528     bool need_recompute = false;
00529 
00530     do
00531     {
00532       int available_height = height;
00533       int max_stretchfactor = GetMaxStretchFactor();
00534       std::list<Area *>::iterator it;
00535 
00536       for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00537       {
00538         if (!(*it)->IsVisible())
00539           continue;
00540 
00541         if (((*it)->GetScaleFactor() == 0) && ((*it)->IsLayoutDone() != true))
00542         {
00543           (*it)->ApplyMinHeight();
00544         }
00545       }
00546 
00547       if (max_stretchfactor == 0)
00548       {
00549         // It means all object are fixed sized or all re-sizable object have been sized to there max or there min.
00550         if (GetScaleFactor() == 0)
00551         {
00552           // It is unlikely that we get here!
00553           int h = 0;
00554           for (it = _layout_element_list.begin(); it != _layout_element_list.end() && !need_recompute; it++)
00555           {
00556             if (!(*it)->IsVisible())
00557               continue;
00558 
00559             h += (*it)->GetBaseHeight();
00560           }
00561           SetBaseHeight(h);
00562         }
00563         return;
00564       }
00565 
00566       for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00567       {
00568         if (!(*it)->IsVisible())
00569           continue;
00570         
00571         if ((*it)->GetScaleFactor() == 0 || (*it)->IsLayoutDone() == true)
00572         {
00573           available_height -= (*it)->GetBaseHeight();
00574         }
00575       }
00576 
00577       if (available_height <= 2)
00578       {
00579         for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00580         {
00581           if (!(*it)->IsVisible())
00582             continue;
00583 
00584           if (((*it)->GetScaleFactor() != 0) && (*it)->IsArea())
00585           {
00586             // If it is not an object of type eInputArea, do not set layout_done_ to true,
00587             // so, the layout management function will later be called on the object.
00588             (*it)->ApplyMinHeight();
00589             (*it)->SetLayoutDone(true);
00590           }
00591           else if (((*it)->GetScaleFactor() != 0) && ((*it)->IsLayout()) && ((*it)->IsLayoutDone() == false))
00592           {
00593             // The out of bound must be reset to false.
00594             (*it)->ApplyMinHeight();
00595             (*it)->SetLayoutDone(false);
00596           }
00597           else if (((*it)->GetScaleFactor() != 0)  && ((*it)->IsLayoutDone() == false))
00598           {
00599             (*it)->ApplyMinHeight();
00600             // A layout must never have layout_done_ set to true "here" because it must continue
00601             // doing the layout of its children and finally resize itself to fit them.
00602             // The same way, A layout size factor should never be set to 0.
00603           }
00604         }
00605 
00606         return;
00607       }
00608 
00609       float cumul = 0;
00610       Area *LastElementThatCanBeResized = 0;
00611       int total_distributed_size = 0;
00612 
00613       for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00614       {
00615         if (!(*it)->IsVisible())
00616           continue;
00617        
00618         if (((*it)->GetScaleFactor() != 0) && ((*it)->IsLayoutDone() == false))
00619         {
00620           float sf = (float) (*it)->GetScaleFactor();
00621           cumul += sf / max_stretchfactor;
00622           LastElementThatCanBeResized = (*it);
00623         }
00624         else
00625         {
00626           total_distributed_size += (*it)->GetBaseWidth();
00627         }
00628       }
00629 
00630       //                  --
00631       //                  \      factor
00632       //    Ref_Size *     \  ------------     = available_height
00633       //                   /   max_factor
00634       //                  /
00635       //                  --
00636       //                  all element with stretchfactor != 0
00637 
00638       int ref_height = available_height / cumul;
00639 
00640       //
00641       need_recompute = false;;
00642 
00643       for (it = _layout_element_list.begin(); it != _layout_element_list.end() && !need_recompute; it++)
00644       {
00645         if (!(*it)->IsVisible())
00646           continue;
00647 
00648         if (((*it)->GetScaleFactor() != 0) && ((*it)->IsLayoutDone() == false))
00649         {
00650           int sf = (*it)->GetScaleFactor();
00651           int new_height;
00652 
00653           if (sf == max_stretchfactor)
00654           {
00655             new_height = ref_height;
00656           }
00657           else
00658           {
00659             new_height = ref_height * sf / max_stretchfactor;
00660           }
00661 
00662           total_distributed_size += new_height;
00663 
00664           if (LastElementThatCanBeResized == (*it))
00665           {
00666             // Redistribute the remaining size to the last element(at the bottom).
00667             // This is necessary because of imprecision. For instance if available_height = 451 and we have 2 elements
00668             // with the same stretch factor than each one will have a size of 225. With is correction, the first element will have a size of
00669             // 225 while the second one will have a size of 226.
00670             if (available_height - total_distributed_size > 0)
00671             {
00672               new_height += available_height - total_distributed_size;
00673               total_distributed_size = available_height;
00674             }
00675           }
00676 
00677           int elemt_max_height = (*it)->GetMaximumSize().height;
00678           int elemt_min_height = (*it)->GetMinimumSize().height;
00679 
00680           // A layout must never have layout_done_ set to true "here" because it must continue
00681           // doing the layout of its children and finally resize itself to fit them.
00682           // The same way, A layout size factor should never be set to 0.
00683           // Q: How about SpaceLayout? Should we treat them the same as layout or widget in this particular case?
00684           // A: SapceLayout are treated like widgets in this case
00685           if (new_height < elemt_min_height)
00686           {
00687             // assume the minimum width
00688             (*it)->SetBaseHeight(elemt_min_height);
00689 
00690             if (((*it)->IsLayout() == false) || (*it)->IsSpaceLayout())
00691             {
00692               (*it)->SetLayoutDone(true);
00693               need_recompute = true;
00694             }
00695           }
00696           else if (new_height > elemt_max_height)
00697           {
00698             // assume the maximum width
00699             (*it)->SetBaseHeight(elemt_max_height);
00700 
00701             if (((*it)->IsLayout() == false) || (*it)->IsSpaceLayout())
00702             {
00703               (*it)->SetLayoutDone(true);
00704               need_recompute = true;
00705             }
00706 
00707 //                 else
00708 //                 {
00709 //                     // set the extra space back in the pool
00710 //                     total_distributed_size -= (new_height - elemt_max_height);
00711 //                 }
00712           }
00713           else
00714           {
00715             (*it)->SetBaseHeight(new_height);
00716           }
00717         }
00718         else
00719         {
00720           // For fixed element, reset their size to the same so it is checked against
00721           // the min and max. This is necessary in case you have set the size of the element first then latter,
00722           // you define its MinimumSize and/or MaximumSize size.
00723           unsigned int w = (*it)->GetBaseWidth();
00724           unsigned int h = (*it)->GetBaseHeight();
00725           (*it)->SetBaseWidth(w);
00726           (*it)->SetBaseHeight(h);
00727         }
00728       }
00729     }
00730     while (need_recompute);
00731   }
00732 
00733   unsigned int VLayout::GetMaxStretchFactor()
00734   {
00735     unsigned int value = 0;
00736     unsigned int sf;
00737     std::list<Area *>::iterator it;
00738 
00739     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00740     {
00741       if (!(*it)->IsVisible())
00742         continue;
00743 
00744       // In the recursive process, make sure we get always the highest stretch factor
00745       // of an element that has not been bounded.
00746       if ((*it)->IsLayoutDone() == false)
00747       {
00748         sf = (*it)->GetScaleFactor();
00749 
00750         if (sf >= value)
00751         {
00752           value = sf;
00753         }
00754       }
00755     }
00756 
00757     return value;
00758   }
00759 
00760   void VLayout::ComputeContentPosition(float offsetX, float offsetY)
00761   {
00762     std::list<Area *>::iterator it;
00763     {
00764       unsigned int num_element = 0;
00765 
00766       for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00767       {
00768         if ((*it)->IsVisible())
00769           num_element++;
00770       }
00771       // Get layout Width and Height
00772       int width = GetBaseWidth();
00773       int height = GetBaseHeight();
00774       // remove the margins
00775       width -= (left_padding_ + right_padding_);
00776       height -= (int) (num_element - 1) * space_between_children_ + (top_padding_ + bottom_padding_);
00777 
00778       // Objects have been resized, now position them.
00779       int current_x = GetBaseX() + left_padding_ + offsetX; // add base offset in X(used for scrolling)
00780       int current_y = GetBaseY() + top_padding_ + offsetY; // add base offset in Y(used for scrolling)
00781 
00782       int offset_space = 0;
00783       int element_margin = 0;
00784       ComputeStacking(height, offset_space, element_margin);
00785       current_y += offset_space;
00786 
00787       for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00788       {
00789         if (!(*it)->IsVisible())
00790           continue;
00791         current_y += element_margin;
00792 
00793         (*it)->SetBaseX(current_x);
00794         (*it)->SetBaseY(current_y);
00795 
00796         MinorDimensionPosition positioning = (*it)->GetPositioning();
00797 
00798         if ((*it)->GetBaseWidth() < width)
00799         {
00800           int widget_width = (*it)->GetBaseWidth();
00801 
00802           switch(positioning)
00803           {
00804             case MINOR_POSITION_START:
00805             {
00806               // do nothing
00807               (*it)->SetBaseX(current_x);
00808               break;
00809             }
00810             case MINOR_POSITION_END:
00811             {
00812               if (widget_width < width)
00813                 (*it)->SetBaseX(current_x + width - widget_width);
00814               else
00815                 (*it)->SetBaseX(current_x);
00816 
00817               break;
00818             }
00819 
00820             case MINOR_POSITION_CENTER:
00821             default:
00822             {
00823               if (widget_width < width)
00824                 (*it)->SetBaseX(current_x + (width - widget_width) / 2);
00825               else
00826                 (*it)->SetBaseX(current_x);
00827             }
00828           }
00829         }
00830 
00831         current_y += (*it)->GetBaseHeight() + element_margin + space_between_children_;
00832       }
00833     }
00834 
00835     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00836     {
00837       if (!(*it)->IsVisible())
00838         continue;
00839 
00840       if ((*it)->Type().IsDerivedFromType(Layout::StaticObjectType))
00841       {
00842         (*it)->ComputeContentPosition(offsetX, offsetY);
00843       }
00844       else if ((*it)->Type().IsDerivedFromType(View::StaticObjectType))
00845       {
00846         (*it)->ComputeContentPosition(offsetX, offsetY);
00847       }
00848     }
00849   }
00850 
00851   Area* VLayout::KeyNavIteration(KeyNavDirection direction)
00852   {
00853     if (_layout_element_list.size() == 0)
00854       return NULL;
00855 
00856     if (IsVisible() == false)
00857       return NULL;
00858 
00859     if (next_object_to_key_focus_area_)
00860     {
00861       if ((direction == KEY_NAV_LEFT) || (direction == KEY_NAV_RIGHT))
00862       {
00863         // Don't know what to do with this
00864         return NULL;
00865       }
00866       std::list<Area*>::iterator it;
00867       std::list<Area*>::iterator it_next;
00868       it = std::find(_layout_element_list.begin(), _layout_element_list.end(), next_object_to_key_focus_area_);
00869 
00870       if (it == _layout_element_list.end())
00871       {
00872         // Should never happen
00873         nuxAssert(0);
00874         return NULL;
00875       }
00876 
00877       it_next = it;
00878       ++it_next;
00879 
00880       if ((direction == KEY_NAV_UP) && (it == _layout_element_list.begin()))
00881       {
00882         // can't go further
00883         return NULL;
00884       }
00885 
00886       if ((direction == KEY_NAV_DOWN) && (it_next == _layout_element_list.end()))
00887       {
00888         // can't go further
00889         return NULL;
00890       }
00891 
00892       if (direction == KEY_NAV_UP)
00893       {
00894         --it;
00895         Area* key_nav_focus = (*it)->KeyNavIteration(direction);
00896 
00897         while (key_nav_focus == NULL)
00898         {
00899           if (it == _layout_element_list.begin())
00900             break;
00901 
00902           --it;
00903           key_nav_focus = (*it)->KeyNavIteration(direction);
00904         }
00905 
00906         return key_nav_focus;
00907       }
00908 
00909       if (direction == KEY_NAV_DOWN)
00910       {
00911         ++it;
00912         Area* key_nav_focus = (*it)->KeyNavIteration(direction);
00913 
00914         while (key_nav_focus == NULL)
00915         {
00916           ++it;
00917           if (it == _layout_element_list.end())
00918             break;
00919 
00920           key_nav_focus = (*it)->KeyNavIteration(direction);
00921         }
00922 
00923         return key_nav_focus;
00924       }
00925     }
00926     else
00927     {
00928       Area* key_nav_focus = NULL;
00929 
00930       if (direction == KEY_NAV_UP)
00931       {
00932         std::list<Area*>::reverse_iterator it = _layout_element_list.rbegin();
00933         key_nav_focus = (*it)->KeyNavIteration(direction);
00934 
00935         while (key_nav_focus == NULL)
00936         {
00937           ++it;
00938           if (it == _layout_element_list.rend())
00939             break;
00940 
00941           key_nav_focus = (*it)->KeyNavIteration(direction);
00942         }
00943       }
00944       else
00945       {
00946         std::list<Area*>::iterator it = _layout_element_list.begin();
00947         key_nav_focus = (*it)->KeyNavIteration(direction);
00948 
00949         while (key_nav_focus == NULL)
00950         {
00951           ++it;
00952           if (it == _layout_element_list.end())
00953             break;
00954 
00955           key_nav_focus = (*it)->KeyNavIteration(direction);
00956         }
00957       }
00958 
00959       return key_nav_focus;
00960     }
00961 
00962     return NULL;
00963   }
00964 }