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