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