Back to index

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