nux-1.14.0
GridVLayout.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 "GridVLayout.h"
00026 #include "HLayout.h"
00027 #include "VLayout.h"
00028 
00029 namespace nux
00030 {
00031 
00032   static const t_s32 VERROR = 0;
00033   NUX_IMPLEMENT_OBJECT_TYPE (GridVLayout);
00034 
00035   GridVLayout::GridVLayout (NUX_FILE_LINE_DECL)
00036     :   Layout (NUX_FILE_LINE_PARAM)
00037   {
00038 #if DEBUG_LAYOUT
00039     m_h_in_margin = 10;
00040     m_h_out_margin = 10;
00041     m_v_in_margin = 10;
00042     m_v_out_margin = 10;
00043 #endif
00044 
00045     _children_size = Size (64, 64);
00046     _force_children_size = true;
00047     _partial_visibility = true;
00048     _num_row = 1;
00049     _num_column = 1;
00050     _dynamic_column = true;
00051     _width_match_content = true;
00052 
00053     // Start packing the elements from the top. Is the layout has more space than the elements can use,
00054     // leave that space at the bottom of the GridVLayout.
00055     m_ContentStacking = eStackLeft;
00056 
00057     SetMinimumSize(32, 32);
00058   }
00059 
00060   GridVLayout::~GridVLayout()
00061   {
00062 
00063   }
00064 
00065   int GridVLayout::GetChildPos (Area *child)
00066   {
00067     int position = 0;
00068     std::list<Area *>::const_iterator it;
00069     for (it = GetChildren ().begin(); it != GetChildren ().end(); it++)
00070     {
00071       if ((*it) == child)
00072         break;
00073 
00074       if ((*it)->CanFocus ())
00075       {
00076         position++;
00077       }
00078     }
00079 
00080     return position;
00081   }
00082 
00083   Area* GridVLayout::GetChildAtPosition (int pos)
00084   {
00085     int position = 0;
00086     std::list<Area *>::const_iterator it;
00087     for (it = GetChildren ().begin(); it != GetChildren ().end(); it++)
00088     {
00089       if (position == pos)
00090         return (*it);
00091 
00092       if ((*it)->CanFocus ())
00093       {
00094         position++;
00095       }
00096     }   
00097 
00098     return NULL;
00099   }
00100 
00101   void GridVLayout::EnablePartialVisibility (bool partial_visibility)
00102   {
00103     _partial_visibility = partial_visibility;
00104   }
00105 
00106   void GridVLayout::SetChildrenSize (int width, int height)
00107   {
00108     _children_size = Size (width, height);
00109   }
00110 
00111   Size GridVLayout::GetChildrenSize () const
00112   {
00113     return _children_size;
00114   }
00115 
00116   void GridVLayout::ForceChildrenSize (bool force)
00117   {
00118     _force_children_size = force;
00119   }
00120 
00121   int GridVLayout::GetNumColumn () const
00122   {
00123     return _num_column;
00124   }
00125 
00126   int GridVLayout::GetNumRow () const
00127   {
00128     return _num_row;
00129   }
00130 
00131   void GridVLayout::SetWidthMatchContent (bool match_content)
00132   {
00133     _width_match_content = match_content;
00134   }
00135 
00136   bool GridVLayout::GetWidthMatchContent () const
00137   {
00138     return _width_match_content;
00139   }
00140 
00141   void GridVLayout::GetCompositeList (std::list<Area *> *ViewList)
00142   {
00143     std::list<Area *>::iterator it;
00144 
00145     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00146     {
00147       if ( (*it)->IsView() )
00148       {
00149         View *ic = static_cast<View *>(*it);
00150         ViewList->push_back (ic);
00151       }
00152       else if ( (*it)->IsLayout() )
00153       {
00154         Layout *layout = static_cast<Layout *>(*it);
00155         layout->GetCompositeList (ViewList);
00156       }
00157     }
00158   }
00159 
00160   long GridVLayout::ComputeLayout2()
00161   {
00162     std::list<Area *> elements;
00163 
00164     if (GetStretchFactor() == 0)
00165     {
00166       ApplyMinHeight();
00167     }
00168 
00169     if (_layout_element_list.size() == 0)
00170     {
00171       return eCompliantHeight | eCompliantWidth;
00172     }
00173 
00174     t_s32 num_elements = 0;
00175 
00176     std::list<Area *>::iterator it;
00177     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00178     {
00179       if ((*it)->IsVisible ())
00180       {
00181         (*it)->SetLayoutDone (false);
00182         elements.push_back (*it);
00183         num_elements++;
00184       }
00185     }
00186 
00187     t_s32 original_width = GetBaseWidth();
00188 
00189     nux::Geometry base = GetGeometry();
00190     it = elements.begin();
00191     int num_row = 0;
00192     int num_column = 0;
00193 
00194     if (num_elements > 0)
00195       ++num_column;
00196 
00197     if (_dynamic_column)
00198     {
00199       int X = base.x + m_h_out_margin;
00200       int Y = base.y + m_v_out_margin;
00201 
00202       bool first_element_of_column = true;
00203 
00204       for (int i = 0; i < num_elements; i++)
00205       {
00206         if (num_column == 1)
00207           num_row++;
00208 
00209         if (first_element_of_column)
00210         {
00211           first_element_of_column = false;
00212         }
00213 
00214         if (_force_children_size)
00215         {
00216           (*it)->SetMinimumSize (_children_size.width, _children_size.height);
00217         }
00218 
00219         (*it)->SetGeometry (nux::Geometry (X, Y, _children_size.width, _children_size.height));
00220 
00221         (*it)->ComputeLayout2();
00222 
00223         Y += _children_size.height + m_v_in_margin;
00224 
00225         it++;
00226 
00227         if ((!_partial_visibility) && (Y + _children_size.height > base.y + base.height - m_v_out_margin))
00228         {
00229           X += _children_size.width + m_h_in_margin;
00230           Y = base.y + m_v_out_margin;
00231 
00232           first_element_of_column = true;
00233           if(i < num_elements - 1)
00234             ++num_column;
00235         }
00236         else if (Y >= base.y + base.height)
00237         {
00238           X += _children_size.width + m_h_in_margin;
00239           Y = base.y + m_v_out_margin;
00240 
00241           first_element_of_column = true;
00242           if (i < num_elements - 1)
00243             ++num_column;
00244         }
00245       }
00246     }
00247 
00248     _num_row = num_row;
00249     _num_column = num_column;
00250 
00251     if ((GetStretchFactor() == 0) || _width_match_content)
00252     {
00253       int w = num_column * _children_size.width + 2 * m_h_out_margin + (num_column - 1) * m_h_in_margin;
00254       SetMinimumWidth (w);
00255       SetBaseWidth (w);
00256     }
00257 
00258     long size_compliance = 0L;
00259 
00260     if (GetBaseWidth() > original_width + VERROR)
00261     {
00262 #if DEBUG_LAYOUT_COMPUTATION
00263       // The layout has been resized larger in WIDTH to tightly pack its content.
00264       // Or you can say that the layout refuse to be smaller than total WIDTH of its elements.
00265       std::cout << "ComputeLayout2: VLayout Width block at " << GetWidth() << std::endl;
00266 #endif
00267       size_compliance |= eLargerWidth; // need scrollbar
00268     }
00269     else if (GetBaseWidth() + VERROR < original_width)
00270     {
00271 #if DEBUG_LAYOUT_COMPUTATION
00272       // The layout is smaller.
00273       std::cout << "ComputeLayout2: VLayout Width smaller = " << GetWidth() << std::endl;
00274 #endif
00275       size_compliance |= eSmallerWidth;
00276     }
00277     else
00278     {
00279 #if DEBUG_LAYOUT_COMPUTATION
00280       // The layout and its content resized together without trouble.
00281       std::cout << "ComputeLayout2: VLayout Width compliant = " << GetWidth() << std::endl;
00282 #endif
00283       size_compliance |= eCompliantWidth;
00284     }
00285 
00286     {
00287 #if DEBUG_LAYOUT_COMPUTATION
00288       // The layout and its content resized together without trouble.
00289       std::cout << "ComputeLayout2: VLayout Height compliant = " << m_fittingHeight << std::endl;
00290 #endif
00291       size_compliance |= eCompliantHeight;
00292     }
00293 
00294     return size_compliance;
00295   }
00296 
00297   void GridVLayout::ProcessDraw (GraphicsEngine &GfxContext, bool force_draw)
00298   {
00299     std::list<Area *> elements;
00300     std::list<Area *>::iterator it = _layout_element_list.begin ();
00301 
00302     GfxContext.PushModelViewMatrix (Get2DMatrix ());
00303 
00304     for (it = _layout_element_list.begin (); it != _layout_element_list.end (); ++it)
00305     {
00306       if ((*it)->IsVisible ())
00307         elements.push_back (*it);
00308     }
00309 
00310     it = elements.begin ();
00311 
00312     Geometry base = GetGeometry ();
00313     Geometry parent_geometry = GetAbsoluteGeometry ();
00314     Geometry visibility_geometry = parent_geometry;
00315     if (GetToplevel ())
00316     {
00317       parent_geometry = GetToplevel ()->GetAbsoluteGeometry ();
00318     }
00319 
00320     visibility_geometry = parent_geometry.Intersect (GetAbsoluteGeometry ());
00321 
00322     GfxContext.PushClippingRectangle (base);
00323 
00324     for (int i = 0; i < _num_column; i++)
00325     {
00326       for (int j = 0; j < _num_row; j++)
00327       {
00328         if (it == elements.end ())
00329           break;
00330 
00331         Geometry intersection = base.Intersect ((*it)->GetGeometry ());
00332 
00333         // Test if the element is inside the Grid before rendering.
00334         if (!visibility_geometry.IsNull ())
00335         {
00336           int X = base.x + m_h_out_margin + i * (_children_size.width + m_h_in_margin);
00337           int Y = base.y + m_v_out_margin + j * (_children_size.height + m_v_in_margin);
00338 
00339           GfxContext.PushClippingRectangle (Geometry (X, Y, _children_size.width, _children_size.height));
00340           if ((*it)->IsView ())
00341           {
00342             View *ic = static_cast<View *>(*it);
00343             ic->ProcessDraw (GfxContext, force_draw);
00344           }
00345           else if ((*it)->IsLayout ())
00346           {
00347             Layout *layout = static_cast<Layout *>(*it);
00348             layout->ProcessDraw (GfxContext, force_draw);
00349           }
00350 
00351           GfxContext.PopClippingRectangle ();
00352         }
00353 
00354         it++;
00355       }
00356     }
00357 
00358     GfxContext.PopClippingRectangle ();
00359     GfxContext.PopModelViewMatrix ();
00360 
00361     _queued_draw = false;
00362   }
00363 
00364   Area* GridVLayout::KeyNavIteration(KeyNavDirection direction)
00365   {
00366     if (_layout_element_list.size() == 0)
00367       return NULL;
00368 
00369     if (IsVisible() == false)
00370       return NULL;
00371 
00372     if (next_object_to_key_focus_area_)
00373     {
00374       std::list<Area*>::iterator it;
00375       std::list<Area*>::iterator it_next;
00376       it = std::find (_layout_element_list.begin(), _layout_element_list.end(), next_object_to_key_focus_area_);
00377       it_next = it;
00378       ++it_next;
00379 
00380       if (it == _layout_element_list.end())
00381       {
00382         // Should never happen
00383         nuxAssert (0);
00384         return NULL;
00385       }
00386 
00387       int position = GetChildPos(*it); // note that (*it) == next_object_to_key_focus_area_
00388       int nun_column = GetNumColumn();
00389       int nun_row = GetNumRow();
00390 
00391       if ((direction == KEY_NAV_UP) && (it == _layout_element_list.begin()))
00392       {
00393         // first item
00394         return NULL;
00395       }
00396 
00397       if ((direction == KEY_NAV_DOWN) && (it_next == _layout_element_list.end()))
00398       {
00399         // last item
00400         return NULL;
00401       }
00402 
00403       if ((direction == KEY_NAV_UP) && ((position % nun_row) == 0))
00404       {
00405         // Left edge
00406         return NULL;
00407       }
00408 
00409       if ((direction == KEY_NAV_DOWN) && (position == (position / nun_row) * nun_row + (nun_row -1)))
00410       {
00411         // right edge
00412         return NULL;
00413       }
00414 
00415       if ((direction == KEY_NAV_LEFT) && ((position / nun_row) == 0))
00416       {
00417         // top edge
00418         return NULL;
00419       }
00420 
00421       if ((direction == KEY_NAV_RIGHT) && ((position / nun_row) == nun_column))
00422       {
00423         // bottom edge
00424         return NULL;
00425       }
00426 
00428       if (direction == KEY_NAV_UP)
00429       {
00430         --it;
00431         Area* key_nav_focus = (*it)->KeyNavIteration(direction);
00432 
00433         while (key_nav_focus == NULL)
00434         {
00435           int pos = GetChildPos(*it);
00436           if (it == _layout_element_list.begin() || ((pos % nun_row) == 0))
00437             break;
00438 
00439           --it;
00440           key_nav_focus = (*it)->KeyNavIteration(direction);
00441         }
00442 
00443         return key_nav_focus;
00444       }
00445 
00446       if (direction == KEY_NAV_DOWN)
00447       {
00448         ++it;
00449         Area* key_nav_focus = (*it)->KeyNavIteration(direction);
00450 
00451         while (key_nav_focus == NULL)
00452         {
00453           ++it;
00454           int pos = GetChildPos(*it);
00455 
00456           if ((it == _layout_element_list.end()) || (pos == (pos / nun_row) * nun_row + (nun_row -1)))
00457             break;
00458 
00459           key_nav_focus = (*it)->KeyNavIteration(direction);
00460         }
00461 
00462         return key_nav_focus;
00463       }
00464 
00465       if (direction == KEY_NAV_LEFT)
00466       {
00467         for (int i = 0; i < nun_row; ++i)
00468         {
00469           --it;
00470         }
00471         return (*it)->KeyNavIteration(direction);
00472       }
00473 
00474       if (direction == KEY_NAV_RIGHT)
00475       {
00476         for (int i = 0; i < nun_row; ++i)
00477         {
00478           ++it;
00479           if (it == _layout_element_list.end())
00480             return NULL;
00481         }
00482         return (*it)->KeyNavIteration(direction);
00483       }
00484     }
00485     else
00486     {
00487       std::list<Area*>::iterator it;
00488       it = _layout_element_list.begin();
00489       return (*it)->KeyNavIteration(direction);
00490     }
00491 
00492     return NULL;
00493   }
00494 }
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends