nux-1.14.0
LayeredLayout.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: Neil Jagdish Patel <neil.patel@canonical.com>
00019  *
00020  */
00021 
00022 
00023 #include "Nux.h"
00024 #include "View.h"
00025 #include "LayeredLayout.h"
00026 
00027 #include <math.h>
00028 
00029 namespace nux
00030 {
00031   class LayeredChildProperties : public Area::LayoutProperties
00032   {
00033     public:
00034 
00035     LayeredChildProperties (bool expand, int x, int y, int width, int height)
00036     : m_expand (expand),
00037       m_x (x),
00038       m_y (y),
00039       m_width (width),
00040       m_height (height)
00041     {
00042 
00043     }
00044 
00045     ~LayeredChildProperties ()
00046     {
00047     }
00048 
00049     void Update (bool expand, int x, int y, int width, int height)
00050     {
00051       m_expand = expand;
00052       m_x = x;
00053       m_y = y;
00054       m_width = width;
00055       m_height = height;
00056     }
00057 
00058     bool m_expand;
00059     int  m_x;
00060     int  m_y;
00061     int  m_width;
00062     int  m_height;
00063 
00064     sigc::signal<void, Area *, bool>::iterator m_vis_it;
00065   };
00066 
00067   NUX_IMPLEMENT_OBJECT_TYPE (LayeredLayout);
00068 
00069   LayeredLayout::LayeredLayout (NUX_FILE_LINE_DECL)
00070   : Layout (NUX_FILE_LINE_PARAM),
00071     m_active_index (0),
00072     m_active_area (NULL),
00073     m_paint_all (false),
00074     m_input_mode (INPUT_MODE_ACTIVE),
00075     m_child_draw_queued (false)
00076   {
00077     m_ContentStacking = eStackLeft;
00078     OnChildQueueDraw.connect (sigc::mem_fun (this, &LayeredLayout::ChildQueueDraw));
00079   }
00080 
00081   LayeredLayout::~LayeredLayout()
00082   {
00083   }
00084 
00085   long LayeredLayout::DoFocusPrev (IEvent &ievent, long TraverseInfo, long ProcessEventInfo)
00086   {
00087     if (GetInputMode () == INPUT_MODE_ACTIVE)
00088     {
00089       Area *parent = GetParentObject ();
00090       if (parent != NULL)
00091         return SendEventToArea (parent, ievent, TraverseInfo, ProcessEventInfo);
00092     }
00093     else
00094     {
00095       return Layout::DoFocusPrev (ievent, TraverseInfo, ProcessEventInfo);
00096     }
00097 
00098     return TraverseInfo;
00099   }
00100 
00101   long LayeredLayout::DoFocusNext (IEvent &ievent, long TraverseInfo, long ProcessEventInfo)
00102   {
00103     if (GetInputMode () == INPUT_MODE_ACTIVE)
00104     {
00105       Area *parent = GetParentObject ();
00106       if (parent != NULL)
00107         return SendEventToArea (parent, ievent, TraverseInfo, ProcessEventInfo);
00108     }
00109     else
00110     {
00111       return Layout::DoFocusNext (ievent, TraverseInfo, ProcessEventInfo);
00112     }
00113     
00114     return TraverseInfo;
00115   }
00116   void LayeredLayout::GetCompositeList (std::list<Area *> *ViewList)
00117   {
00118     std::list<Area *>::iterator it;
00119 
00120     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00121     {
00122       if ( (*it)->IsView() )
00123       {
00124         View *ic = NUX_STATIC_CAST (View *, (*it) );
00125         ViewList->push_back (ic);
00126       }
00127       else if ( (*it)->IsLayout() )
00128       {
00129         Layout *layout = NUX_STATIC_CAST (Layout *, (*it) );
00130         layout->GetCompositeList (ViewList);
00131       }
00132     }
00133   }
00134 
00135   long LayeredLayout::ComputeLayout2()
00136   {
00137     nux::Geometry base = GetGeometry();
00138     std::list<Area *>::iterator it;
00139     int total_max_width = 0;
00140     int total_max_height = 0;
00141     int ret = 0;
00142 
00143     for (it = _layout_element_list.begin (); it != _layout_element_list.end (); ++it)
00144     {
00145       Area                   *area = *it;
00146       LayeredChildProperties *props;
00147       Geometry                geo = base;
00148 
00149       props = dynamic_cast<LayeredChildProperties *> (area->GetLayoutProperties ());
00150 
00151       if (props->m_expand)
00152       {
00153         int max_width, max_height;
00154 
00155         // It wants to expand, however we need to check that it doesn't need at minimum more
00156         // space than we have
00157         max_width = MAX (base.width, area->GetMinimumWidth ());
00158         max_height = MAX (base.height, area->GetMinimumHeight ());
00159 
00160         geo.width = max_width;
00161         geo.height = max_height;
00162 
00163         total_max_width = MAX (total_max_width, max_width);
00164         total_max_height = MAX (total_max_height, max_height);
00165       }
00166       else
00167       {
00168         geo.x = base.x + props->m_x;
00169         geo.y = base.y + props->m_y;
00170         geo.width = props->m_width;
00171         geo.height = props->m_height;
00172       }
00173 
00174       (*it)->SetGeometry (geo);
00175       (*it)->ComputeLayout2 ();
00176     }
00177 
00178     SetBaseSize (total_max_width, total_max_height);
00179 
00180     if (base.width < total_max_width)
00181       ret |= eLargerWidth;
00182     else
00183       ret |= eCompliantWidth; // We don't complain about getting more space
00184 
00185     if (base.height < total_max_height)
00186       ret |= eLargerHeight;
00187     else
00188       ret |= eCompliantHeight; // Don't complain about getting more space
00189 
00190     return ret;
00191   }
00192 
00193   void LayeredLayout::PaintOne (Area *_area, GraphicsEngine &gfx_context, bool force_draw)
00194   {
00195     if (_area->IsArea ())
00196     {
00197       InputArea *area = NUX_STATIC_CAST (InputArea *, _area);
00198       area->OnDraw (gfx_context, force_draw);
00199     }
00200     else if (_area->IsView ())
00201     {
00202       View *ic = NUX_STATIC_CAST (View *, _area);
00203       ic->ProcessDraw (gfx_context, force_draw);
00204     }
00205     else if (_area->IsLayout ())
00206     {
00207       Layout *layout = NUX_STATIC_CAST (Layout *, _area);
00208       layout->ProcessDraw (gfx_context, force_draw);
00209     }
00210   }
00211 
00212   void LayeredLayout::ProcessDraw (GraphicsEngine &gfx_context, bool force_draw)
00213   {
00214     Geometry base = GetGeometry ();
00215     gfx_context.PushClippingRectangle (base);
00216 
00217     if (m_paint_all)
00218     {
00219       std::list<Area *>::iterator it, eit = _layout_element_list.end ();
00220       t_u32 alpha = 0, src = 0, dest = 0;
00221 
00222       gfx_context.GetRenderStates ().GetBlend (alpha, src, dest);
00223       gfx_context.GetRenderStates ().SetBlend (true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00224 
00225       nux::GetPainter().PaintBackground(gfx_context, base);
00226       nux::GetPainter().PushBackgroundStack();
00227 
00228       for (it = _layout_element_list.begin (); it != eit; ++it)
00229       {
00230         if ((*it)->IsVisible ())
00231           PaintOne (static_cast<Area *> (*it), gfx_context, true);
00232       }
00233 
00234       nux::GetPainter().PopBackgroundStack();
00235 
00236       gfx_context.GetRenderStates ().SetBlend (alpha, src, dest);
00237 
00238       m_child_draw_queued = false;
00239     }
00240     else if (m_active_area && m_active_area->IsVisible ())
00241     {
00242       PaintOne (m_active_area, gfx_context, force_draw);
00243     }
00244 
00245     gfx_context.PopClippingRectangle ();
00246     _queued_draw = false;
00247   }
00248 
00249   Area* LayeredLayout::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type)
00250   {
00251     if(m_active_area == NULL)
00252     return NULL;
00253     
00254     bool mouse_inside = m_active_area->TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type);
00255 
00256     if(mouse_inside == false)
00257       return NULL;
00258 
00259     if(m_input_mode == INPUT_MODE_ACTIVE)
00260     {
00261       if (m_active_area && m_active_area->IsVisible () && m_active_area->IsSensitive ())
00262         return m_active_area->FindAreaUnderMouse(mouse_position, event_type);
00263     }
00264     else
00265     {
00266       std::list<Area *>::reverse_iterator it, eit = _layout_element_list.rend ();
00267 
00268       for (it = _layout_element_list.rbegin (); it != eit; ++it)
00269       {
00270         Area *area = (*it);
00271 
00272         if (area->IsVisible () && area->IsSensitive ())
00273         {
00274           return m_active_area->FindAreaUnderMouse(mouse_position, event_type);
00275         }
00276       }
00277     }
00278 
00279     return NULL;
00280   }
00281 
00282   void LayeredLayout::AddLayout (Layout                *layout,
00283                                  unsigned int           stretch_factor,
00284                                  MinorDimensionPosition positioning,
00285                                  MinorDimensionSize     extend,
00286                                  float                  percentage)
00287   {
00288     AddLayer (layout);
00289   }
00290 
00291   void LayeredLayout::AddView (Area                  *view,
00292                                unsigned int           stretch_factor,
00293                                MinorDimensionPosition positioning,
00294                                MinorDimensionSize     extend,
00295                                float                  percentage)
00296   {
00297     AddLayer (view);
00298   }
00299 
00300   void LayeredLayout::RemoveChildObject (Area *area)
00301   {
00302     RemoveLayer (area);
00303   }
00304 
00305   void LayeredLayout::Clear ()
00306   {
00307     m_active_index = 0;
00308     m_active_area = NULL;
00309 
00310     Layout::Clear ();
00311   }
00312 
00313   void LayeredLayout::ChildQueueDraw (Area *area)
00314   {
00315     m_child_draw_queued = true;
00316   }
00317 
00318   void LayeredLayout::ChildVisibilityChanged (Area *area, bool visible)
00319   {
00320     QueueDraw ();
00321   }
00322 
00323   //
00324   // LayeredLayout Methods
00325   //
00326   void LayeredLayout::AddLayer (Area *area, bool expand, int x, int y, int width, int height)
00327   {
00328     LayeredChildProperties *props;
00329 
00330     // return if the area is NULL
00331     NUX_RETURN_IF_NULL(area);
00332     // Return if the area already has a parent
00333     NUX_RETURN_IF_NOTNULL(area->GetParentObject ());
00334 
00335     props = new LayeredChildProperties (expand, x, y, width, height);
00336     area->SetLayoutProperties (props);
00337 
00338     if (!m_active_area)
00339     {
00340       m_active_area = area;
00341     }
00342 
00343     props->m_vis_it = area->OnVisibleChanged.connect (sigc::mem_fun (this, &LayeredLayout::ChildVisibilityChanged));
00344 
00345     if (area->IsLayout ())
00346       Layout::AddLayout (static_cast<Layout *> (area));
00347     else
00348       Layout::AddView (area);
00349 
00350     QueueDraw ();
00351   }
00352 
00353   void LayeredLayout::UpdateLayer (Area *area, bool expand, int x, int y, int width, int height)
00354   {
00355     LayeredChildProperties *props;
00356 
00357     NUX_RETURN_IF_NULL(area);
00358 
00359     props = dynamic_cast<LayeredChildProperties *>(area->GetLayoutProperties ());
00360     NUX_RETURN_IF_NULL(props);
00361 
00362     props->Update (expand, x, y, width, height);
00363 
00364     QueueDraw ();
00365   }
00366 
00367   void LayeredLayout::RemoveLayer (Area *area)
00368   {
00369     LayeredChildProperties *props;
00370 
00371     NUX_RETURN_IF_NULL(area);
00372 
00373     props = dynamic_cast<LayeredChildProperties *>(area->GetLayoutProperties ());
00374     NUX_RETURN_IF_NULL(props);
00375 
00376     (*props->m_vis_it).disconnect ();
00377     area->SetLayoutProperties (NULL);
00378 
00379 
00380     if (m_active_area == area)
00381     {
00382       std::list<Area *>::iterator it, eit = _layout_element_list.end ();
00383       int i = 0;
00384 
00385       m_active_index = 0;
00386       m_active_area = NULL;
00387       for (it = _layout_element_list.begin (); it != eit; ++it)
00388       {
00389         if (*it != area)
00390         {
00391           m_active_area = static_cast<Area *> (*it);
00392           m_active_index = i;
00393           break;
00394         }
00395         i++;
00396       }
00397     }
00398 
00399     Layout::RemoveChildObject (area);
00400   }
00401 
00402   void LayeredLayout::SetActiveLayerN (int index_)
00403   {
00404     std::list<Area *>::iterator it, eit = _layout_element_list.end ();
00405     int i = 0;
00406 
00407     NUX_RETURN_IF_FALSE((t_uint32)index_ < _layout_element_list.size ());
00408 
00409     if (index_ == m_active_index)
00410       return;
00411 
00412     m_active_index = index_;
00413     m_active_area = NULL;
00414     bool is_focused = GetFocused ();
00415 
00416     for (it = _layout_element_list.begin (); it != eit; ++it)
00417     {
00418       if (i == m_active_index && !m_active_area)
00419       {
00420         m_active_area = static_cast<Area *> (*it);
00421       }
00422 
00423       if ((*it)->IsView ())
00424       {
00425         static_cast<View *> (*it)->QueueDraw ();
00426         if (is_focused)
00427           static_cast<View *> (*it)->SetFocused (true);
00428       } 
00429       else if ((*it)->IsLayout ())
00430       {
00431         static_cast<Layout *> (*it)->QueueDraw ();
00432         if (is_focused)
00433           static_cast<Layout *> (*it)->SetFocused (true);
00434       }
00435 
00436       i++;
00437     }
00438 
00439     QueueDraw ();
00440   }
00441 
00442   int LayeredLayout::GetActiveLayerN ()
00443   {
00444     return m_active_index;
00445   }
00446 
00447   void LayeredLayout::SetActiveLayer  (Area *area)
00448   {
00449     std::list<Area *>::iterator it, eit = _layout_element_list.end ();
00450     int i = 0;
00451 
00452     for (it = _layout_element_list.begin (); it != eit; ++it)
00453     {
00454       Area *a = static_cast<Area *> (*it);
00455 
00456       if (area == a)
00457       {
00458         SetActiveLayerN (i);
00459         return;
00460       }
00461       i++;
00462     }
00463     nuxDebugMsg("[LayeredLayout::LowerBottom] Area (%p) is not a child of LayeredLayout (%p)", area, this);
00464   }
00465 
00466   void LayeredLayout::OnLayerGeometryChanged(Area* area, Geometry geo)
00467   {
00468     // Set the LayeredLayout to the same saize as the active layer;
00469     if(area && (area == m_active_area))
00470     {
00471       SetGeometry(geo);
00472     }
00473   }
00474 
00475   Area * LayeredLayout::GetActiveLayer ()
00476   {
00477     return m_active_area;
00478   }
00479 
00480   void LayeredLayout::SetPaintAll (bool paint_all)
00481   {
00482     if (m_paint_all == paint_all)
00483       return;
00484 
00485     m_paint_all = paint_all;
00486     QueueDraw ();
00487   }
00488 
00489   bool LayeredLayout::GetPaintAll ()
00490   {
00491     return m_paint_all;
00492   }
00493 
00494   void LayeredLayout::SetInputMode (LayeredLayout::InputMode input_mode)
00495   {
00496     if (m_input_mode == input_mode)
00497       return;
00498 
00499     m_input_mode = input_mode;
00500   }
00501 
00502   LayeredLayout::InputMode LayeredLayout::GetInputMode ()
00503   {
00504     return m_input_mode;
00505   }
00506 
00507   void LayeredLayout::Raise (Area *area, Area *above)
00508   {
00509     std::list<Area *>::iterator it, eit = _layout_element_list.end ();
00510     std::list<Area *>::iterator area_it = eit;
00511     std::list<Area *>::iterator above_it = eit;
00512 
00513     NUX_RETURN_IF_NULL(area);
00514     NUX_RETURN_IF_NULL(above);
00515 
00516     for (it = _layout_element_list.begin (); it != eit; ++it)
00517     {
00518       if (above == (*it))
00519         above_it = it;
00520       else if (area == (*it))
00521         area_it = it;
00522     }
00523 
00524     if (area_it == eit)
00525     {
00526       nuxDebugMsg("[LayeredLayout::Raise] Area %p is not a valid layer", area);
00527       return;
00528     }
00529     if (above_it == eit)
00530     {
00531       nuxDebugMsg("[LayeredLayout::Raise] Area %p is not a valid layer", above);
00532       return;
00533     }
00534 
00535     _layout_element_list.erase (area_it);
00536     _layout_element_list.insert (++above_it, area);
00537   }
00538 
00539   void LayeredLayout::Lower (Area *area, Area *below)
00540   {
00541     std::list<Area *>::iterator it, eit = _layout_element_list.end ();
00542     std::list<Area *>::iterator area_it = eit;
00543     std::list<Area *>::iterator below_it = eit;
00544 
00545     NUX_RETURN_IF_NULL(area);
00546     NUX_RETURN_IF_NULL(below);
00547 
00548     for (it = _layout_element_list.begin (); it != eit; ++it)
00549     {
00550       if (below == (*it))
00551         below_it = it;
00552       else if (area == (*it))
00553         area_it = it;
00554     }
00555 
00556     if (area_it == eit)
00557     {
00558       nuxDebugMsg("[LayeredLayout::Lower] Area %p is not a valid layer", area);
00559       return;
00560     }
00561     if (below_it == eit)
00562     {
00563       nuxDebugMsg("[LayeredLayout::Lower] Area %p is not a valid layer", below);
00564       return;
00565     }
00566 
00567     _layout_element_list.erase (area_it);
00568     _layout_element_list.insert (below_it, area);
00569   }
00570 
00571   void LayeredLayout::RaiseTop (Area *area)
00572   {
00573     std::list<Area *>::iterator it, eit = _layout_element_list.end ();
00574     std::list<Area *>::iterator area_it = eit;
00575 
00576     NUX_RETURN_IF_NULL(area);
00577 
00578     for (it = _layout_element_list.begin (); it != eit; ++it)
00579     {
00580       if (area == (*it))
00581         area_it = it;
00582     }
00583 
00584     if (area_it == eit)
00585     {
00586       nuxDebugMsg("[LayeredLayout::RaiseTop] Area %p is not a valid layer", area);
00587       return;
00588     }
00589 
00590     _layout_element_list.erase (area_it);
00591     _layout_element_list.insert (eit, area);
00592   }
00593 
00594   void LayeredLayout::LowerBottom (Area *area)
00595   {
00596     std::list<Area *>::iterator it, eit = _layout_element_list.end ();
00597     std::list<Area *>::iterator area_it = eit;
00598 
00599     NUX_RETURN_IF_NULL(area);
00600 
00601     for (it = _layout_element_list.begin (); it != eit; ++it)
00602     {
00603       if (area == (*it))
00604         area_it = it;
00605     }
00606 
00607     if (area_it == eit)
00608     {
00609       nuxDebugMsg("[LayeredLayout::LowerBottom] Area %p is not a valid layer", area);
00610       return;
00611     }
00612 
00613     _layout_element_list.erase (area_it);
00614     _layout_element_list.insert (_layout_element_list.begin (), area);
00615   }
00616 
00617   bool LayeredLayout::FocusFirstChild ()
00618   {
00619     if (m_input_mode == INPUT_MODE_ACTIVE)
00620     {
00621       m_active_area->SetFocused (true);
00622       return true;
00623     }
00624     else
00625       return Layout::FocusFirstChild ();
00626   }
00627  
00628   bool LayeredLayout::FocusLastChild ()
00629   {
00630     if (m_input_mode == INPUT_MODE_ACTIVE)
00631     {
00632       m_active_area->SetFocused (true);
00633       return true;
00634     }
00635     else
00636       return Layout::FocusLastChild ();
00637   }
00638 
00639   Area* LayeredLayout::KeyNavIteration(KeyNavDirection direction)
00640   {
00641     if (m_active_area == NULL)
00642       return NULL;
00643 
00644     if (m_active_area->IsVisible() == false)
00645       return NULL;
00646 
00647     if (next_object_to_key_focus_area_)
00648     {
00649       return NULL;
00650     }
00651     else
00652     {
00653       return m_active_area->KeyNavIteration(direction);
00654     }
00655 
00656     return NULL;
00657   }
00658 }
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends