Back to index

nux  3.0.0
LayeredLayout.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2010 Inalogic® Inc.
00003  *
00004  * This program is free software: you can redistribute it and/or modify it
00005  * under the terms of the GNU Lesser General Public License, as
00006  * published by the  Free Software Foundation; either version 2.1 or 3.0
00007  * of the License.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranties of
00011  * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
00012  * PURPOSE.  See the applicable version of the GNU Lesser General Public
00013  * License for more details.
00014  *
00015  * You should have received a copy of both the GNU Lesser General Public
00016  * License along with this program. If not, see <http://www.gnu.org/licenses/>
00017  *
00018  * Authored by: 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   LayeredLayout::LayeredChildProperties::LayeredChildProperties(bool expand, int x, int y, int width, int height)
00032   : m_expand(expand),
00033     m_x(x),
00034     m_y(y),
00035     m_width(width),
00036     m_height(height)
00037   {}
00038 
00039   LayeredLayout::LayeredChildProperties::~LayeredChildProperties()
00040   {}
00041 
00042   void LayeredLayout::LayeredChildProperties::Update(bool expand, int x, int y, int width, int height)
00043   {
00044     m_expand = expand;
00045     m_x = x;
00046     m_y = y;
00047     m_width = width;
00048     m_height = height;
00049   }
00050 
00051   NUX_IMPLEMENT_OBJECT_TYPE(LayeredLayout);
00052 
00053   LayeredLayout::LayeredLayout(NUX_FILE_LINE_DECL)
00054   : Layout(NUX_FILE_LINE_PARAM),
00055     m_active_index(0),
00056     m_active_area(NULL),
00057     m_paint_all(false),
00058     m_input_mode(INPUT_MODE_ACTIVE),
00059     m_child_draw_queued(false)
00060   {
00061     m_ContentStacking = eStackLeft;
00062     OnChildQueueDraw.connect(sigc::mem_fun(this, &LayeredLayout::ChildQueueDraw));
00063   }
00064 
00065   LayeredLayout::~LayeredLayout()
00066   {
00067   }
00068 
00069   void LayeredLayout::GetCompositeList(std::list<Area*> *ViewList)
00070   {
00071     std::list<Area*>::iterator it;
00072 
00073     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00074     {
00075       if ((*it)->IsView())
00076       {
00077         View *ic = NUX_STATIC_CAST(View*, (*it));
00078         ViewList->push_back(ic);
00079       }
00080       else if ((*it)->IsLayout())
00081       {
00082         Layout *layout = NUX_STATIC_CAST(Layout *, (*it));
00083         layout->GetCompositeList(ViewList);
00084       }
00085     }
00086   }
00087 
00088   long LayeredLayout::ComputeContentSize()
00089   {
00090     nux::Geometry base = GetGeometry();
00091     std::list<Area *>::iterator it;
00092     int total_max_width = 0;
00093     int total_max_height = 0;
00094     int ret = 0;
00095 
00096     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it)
00097     {
00098       Area                   *area = *it;
00099       std::shared_ptr<LayeredChildProperties> props;
00100       Geometry                geo = base;
00101 
00102       AreaPropertyMap::iterator prop_it = area_property_map_.find(area);
00103       if (prop_it != area_property_map_.end())
00104       {
00105         props = prop_it->second;
00106       }
00107       else
00108       {
00109         props = NULL;
00110       }
00111 
00112       if (props && props->m_expand)
00113       {
00114         int max_width, max_height;
00115 
00116         // It wants to expand, however we need to check that it doesn't need at minimum more
00117         // space than we have
00118         max_width = base.width >= area->GetMinimumWidth() ? base.width : area->GetMinimumWidth();
00119         max_height = base.height >= area->GetMinimumHeight() ? base.height : area->GetMinimumHeight();
00120 
00121         geo.width = max_width;
00122         geo.height = max_height;
00123 
00124         total_max_width = total_max_width >= max_width ? total_max_width : max_width;
00125         total_max_height = total_max_height >= max_height ? total_max_height : max_height;
00126       }
00127       else if (props)
00128       {
00129         geo.x = base.x + props->m_x;
00130         geo.y = base.y + props->m_y;
00131         geo.width = props->m_width;
00132         geo.height = props->m_height;
00133       }
00134 
00135       (*it)->SetGeometry(geo);
00136       (*it)->ComputeContentSize();
00137     }
00138 
00139     SetBaseSize(total_max_width, total_max_height);
00140 
00141     if (base.width < total_max_width)
00142       ret |= eLargerWidth;
00143     else
00144       ret |= eCompliantWidth; // We don't complain about getting more space
00145 
00146     if (base.height < total_max_height)
00147       ret |= eLargerHeight;
00148     else
00149       ret |= eCompliantHeight; // Don't complain about getting more space
00150 
00151     return ret;
00152   }
00153 
00154   void LayeredLayout::PaintOne(Area *_area, GraphicsEngine &graphics_engine, bool force_draw)
00155   {
00156     if (_area->IsView())
00157     {
00158       View *ic = NUX_STATIC_CAST(View *, _area);
00159       ic->ProcessDraw(graphics_engine, force_draw);
00160     }
00161     else if (_area->IsLayout())
00162     {
00163       Layout *layout = NUX_STATIC_CAST(Layout *, _area);
00164       layout->ProcessDraw(graphics_engine, force_draw);
00165     }
00166     else if (_area->IsArea())
00167     {
00168       InputArea *area = NUX_STATIC_CAST(InputArea *, _area);
00169       area->OnDraw(graphics_engine, force_draw);
00170     }
00171   }
00172 
00173   void LayeredLayout::ProcessDraw(GraphicsEngine &graphics_engine, bool force_draw)
00174   {
00175     Geometry base = GetGeometry();
00176     graphics_engine.PushClippingRectangle(base);
00177 
00178     if (m_paint_all)
00179     {
00180       std::list<Area *>::iterator it, eit = _layout_element_list.end();
00181       unsigned int alpha = 0, src = 0, dest = 0;
00182 
00183       graphics_engine.GetRenderStates().GetBlend(alpha, src, dest);
00184       graphics_engine.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00185 
00186       nux::GetPainter().PaintBackground(graphics_engine, base);
00187       nux::GetPainter().PushBackgroundStack();
00188 
00189       for (it = _layout_element_list.begin(); it != eit; ++it)
00190       {
00191         if ((*it)->IsVisible())
00192           PaintOne(static_cast<Area *> (*it), graphics_engine, true);
00193       }
00194 
00195       nux::GetPainter().PopBackgroundStack();
00196 
00197       graphics_engine.GetRenderStates().SetBlend(alpha, src, dest);
00198 
00199       m_child_draw_queued = false;
00200     }
00201     else if (m_active_area && m_active_area->IsVisible())
00202     {
00203       PaintOne(m_active_area, graphics_engine, force_draw);
00204     }
00205 
00206     graphics_engine.PopClippingRectangle();
00207     _queued_draw = false;
00208   }
00209 
00210   Area* LayeredLayout::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type)
00211   {
00212     if (m_active_area == NULL)
00213     return NULL;
00214 
00215     bool mouse_inside = m_active_area->TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type);
00216 
00217     if (mouse_inside == false)
00218       return NULL;
00219 
00220     if (m_input_mode == INPUT_MODE_ACTIVE)
00221     {
00222       if (m_active_area && m_active_area->GetInputEventSensitivity() && m_active_area->GetInputEventSensitivity())
00223         return m_active_area->FindAreaUnderMouse(mouse_position, event_type);
00224     }
00225     else
00226     {
00227       std::list<Area *>::reverse_iterator it, eit = _layout_element_list.rend();
00228 
00229       for (it = _layout_element_list.rbegin(); it != eit; ++it)
00230       {
00231         Area *area = (*it);
00232 
00233         if (area->IsVisible() && area->GetInputEventSensitivity())
00234         {
00235           return m_active_area->FindAreaUnderMouse(mouse_position, event_type);
00236         }
00237       }
00238     }
00239 
00240     return NULL;
00241   }
00242 
00243   void LayeredLayout::AddLayout(Layout                *layout,
00244                                 unsigned int           stretch_factor,
00245                                 MinorDimensionPosition positioning,
00246                                 MinorDimensionSize     extend,
00247                                 float                  percentage)
00248   {
00249     AddLayer(layout);
00250   }
00251 
00252   void LayeredLayout::AddView(Area                  *view,
00253                               unsigned int           stretch_factor,
00254                               MinorDimensionPosition positioning,
00255                               MinorDimensionSize     extend,
00256                               float                  percentage)
00257   {
00258     AddLayer(view);
00259   }
00260 
00261   void LayeredLayout::RemoveChildObject(Area *area)
00262   {
00263     RemoveLayer(area);
00264   }
00265 
00266   void LayeredLayout::Clear()
00267   {
00268     m_active_index = 0;
00269     m_active_area = NULL;
00270 
00271     Layout::Clear();
00272   }
00273 
00274   void LayeredLayout::ChildQueueDraw(Area *area)
00275   {
00276     m_child_draw_queued = true;
00277   }
00278 
00279   void LayeredLayout::ChildVisibilityChanged(Area *area, bool visible)
00280   {
00281     QueueDraw();
00282   }
00283 
00284   //
00285   // LayeredLayout Methods
00286   //
00287   void LayeredLayout::AddLayer(Area *area, bool expand, int x, int y, int width, int height)
00288   {
00289     // return if the area is NULL
00290     NUX_RETURN_IF_NULL(area);
00291     // Return if the area already has a parent
00292     NUX_RETURN_IF_NOTNULL(area->GetParentObject());
00293 
00294     std::shared_ptr<LayeredChildProperties> props(new LayeredChildProperties(expand, x, y, width, height));
00295 
00296     AreaPropertyMap::iterator it = area_property_map_.find(area);
00297     if (it != area_property_map_.end())
00298     {
00299       area_property_map_.erase(it);
00300     }
00301     area_property_map_[area] = props;
00302 
00303     if (!m_active_area)
00304     {
00305       m_active_area = area;
00306     }
00307 
00308     props->m_vis_it = area->OnVisibleChanged.connect(sigc::mem_fun(this, &LayeredLayout::ChildVisibilityChanged));
00309 
00310     if (area->IsLayout())
00311       Layout::AddLayout(static_cast<Layout *> (area));
00312     else
00313       Layout::AddView(area);
00314 
00315     QueueDraw();
00316   }
00317 
00318   void LayeredLayout::UpdateLayer(Area *area, bool expand, int x, int y, int width, int height)
00319   {
00320     std::shared_ptr<LayeredChildProperties> props;
00321 
00322     NUX_RETURN_IF_NULL(area);
00323 
00324     AreaPropertyMap::iterator it = area_property_map_.find(area);
00325     if (it != area_property_map_.end())
00326     {
00327       props = it->second;
00328     }
00329     else
00330     {
00331       props = NULL;
00332     }
00333 
00334     if (props == NULL)
00335       return;
00336 
00337     props->Update(expand, x, y, width, height);
00338 
00339     QueueDraw();
00340   }
00341 
00342   void LayeredLayout::RemoveLayer(Area *area)
00343   {
00344     if (area == NULL)
00345       return;
00346 
00347     std::shared_ptr<LayeredChildProperties> props;
00348 
00349     AreaPropertyMap::iterator prop_it = area_property_map_.find(area);
00350     if (prop_it != area_property_map_.end())
00351     {
00352       props = prop_it->second;
00353     }
00354     else
00355     {
00356       return;
00357     }
00358 
00359     (*props->m_vis_it).disconnect();
00360     area_property_map_.erase(prop_it);
00361 
00362     if (m_active_area == area)
00363     {
00364       std::list<Area *>::iterator it, eit = _layout_element_list.end();
00365 
00366       int index = 0;
00367       m_active_index = 0;
00368       m_active_area = NULL;
00369       for (it = _layout_element_list.begin(); it != eit; ++it, ++index)
00370       {
00371         if (*it != area)
00372         {
00373           m_active_area = static_cast<Area *> (*it);
00374           m_active_index = index;
00375           break;
00376         }
00377       }
00378     }
00379 
00380     Layout::RemoveChildObject(area);
00381   }
00382 
00383   void LayeredLayout::SetActiveLayerN(int index_)
00384   {
00385     std::list<Area *>::iterator it, eit = _layout_element_list.end();
00386     int i = 0;
00387 
00388     NUX_RETURN_IF_FALSE((unsigned int)index_ < _layout_element_list.size());
00389 
00390     if (index_ == m_active_index)
00391       return;
00392 
00393     m_active_index = index_;
00394     m_active_area = NULL;
00395 
00396     for (it = _layout_element_list.begin(); it != eit; ++it)
00397     {
00398       if (i == m_active_index && !m_active_area)
00399       {
00400         m_active_area = static_cast<Area *> (*it);
00401       }
00402 
00403       if ((*it)->IsView())
00404       {
00405         static_cast<View *> (*it)->QueueDraw();
00406       }
00407       else if ((*it)->IsLayout())
00408       {
00409         static_cast<Layout *> (*it)->QueueDraw();
00410       }
00411 
00412       i++;
00413     }
00414 
00415     QueueDraw();
00416   }
00417 
00418   int LayeredLayout::GetActiveLayerN()
00419   {
00420     return m_active_index;
00421   }
00422 
00423   void LayeredLayout::SetActiveLayer  (Area *area)
00424   {
00425     std::list<Area *>::iterator it, eit = _layout_element_list.end();
00426     int i = 0;
00427 
00428     for (it = _layout_element_list.begin(); it != eit; ++it)
00429     {
00430       Area *a = static_cast<Area *> (*it);
00431 
00432       if (area == a)
00433       {
00434         SetActiveLayerN(i);
00435         return;
00436       }
00437       i++;
00438     }
00439     nuxDebugMsg("[LayeredLayout::LowerBottom] Area(%p) is not a child of LayeredLayout(%p)", area, this);
00440   }
00441 
00442   void LayeredLayout::OnLayerGeometryChanged(Area* area, Geometry geo)
00443   {
00444     // Set the LayeredLayout to the same saize as the active layer;
00445     if (area && (area == m_active_area))
00446     {
00447       SetGeometry(geo);
00448     }
00449   }
00450 
00451   Area * LayeredLayout::GetActiveLayer()
00452   {
00453     return m_active_area;
00454   }
00455 
00456   void LayeredLayout::SetPaintAll(bool paint_all)
00457   {
00458     if (m_paint_all == paint_all)
00459       return;
00460 
00461     m_paint_all = paint_all;
00462     QueueDraw();
00463   }
00464 
00465   bool LayeredLayout::GetPaintAll()
00466   {
00467     return m_paint_all;
00468   }
00469 
00470   void LayeredLayout::SetInputMode(LayeredLayout::InputMode input_mode)
00471   {
00472     if (m_input_mode == input_mode)
00473       return;
00474 
00475     m_input_mode = input_mode;
00476   }
00477 
00478   LayeredLayout::InputMode LayeredLayout::GetInputMode()
00479   {
00480     return m_input_mode;
00481   }
00482 
00483   void LayeredLayout::Raise(Area *area, Area *above)
00484   {
00485     std::list<Area *>::iterator it, eit = _layout_element_list.end();
00486     std::list<Area *>::iterator area_it = eit;
00487     std::list<Area *>::iterator above_it = eit;
00488 
00489     NUX_RETURN_IF_NULL(area);
00490     NUX_RETURN_IF_NULL(above);
00491 
00492     for (it = _layout_element_list.begin(); it != eit; ++it)
00493     {
00494       if (above == (*it))
00495         above_it = it;
00496       else if (area == (*it))
00497         area_it = it;
00498     }
00499 
00500     if (area_it == eit)
00501     {
00502       nuxDebugMsg("[LayeredLayout::Raise] Area %p is not a valid layer", area);
00503       return;
00504     }
00505     if (above_it == eit)
00506     {
00507       nuxDebugMsg("[LayeredLayout::Raise] Area %p is not a valid layer", above);
00508       return;
00509     }
00510 
00511     _layout_element_list.erase(area_it);
00512     _layout_element_list.insert(++above_it, area);
00513   }
00514 
00515   void LayeredLayout::Lower(Area *area, Area *below)
00516   {
00517     std::list<Area *>::iterator it, eit = _layout_element_list.end();
00518     std::list<Area *>::iterator area_it = eit;
00519     std::list<Area *>::iterator below_it = eit;
00520 
00521     NUX_RETURN_IF_NULL(area);
00522     NUX_RETURN_IF_NULL(below);
00523 
00524     for (it = _layout_element_list.begin(); it != eit; ++it)
00525     {
00526       if (below == (*it))
00527         below_it = it;
00528       else if (area == (*it))
00529         area_it = it;
00530     }
00531 
00532     if (area_it == eit)
00533     {
00534       nuxDebugMsg("[LayeredLayout::Lower] Area %p is not a valid layer", area);
00535       return;
00536     }
00537     if (below_it == eit)
00538     {
00539       nuxDebugMsg("[LayeredLayout::Lower] Area %p is not a valid layer", below);
00540       return;
00541     }
00542 
00543     _layout_element_list.erase(area_it);
00544     _layout_element_list.insert(below_it, area);
00545   }
00546 
00547   void LayeredLayout::RaiseTop(Area *area)
00548   {
00549     std::list<Area *>::iterator it, eit = _layout_element_list.end();
00550     std::list<Area *>::iterator area_it = eit;
00551 
00552     NUX_RETURN_IF_NULL(area);
00553 
00554     for (it = _layout_element_list.begin(); it != eit; ++it)
00555     {
00556       if (area == (*it))
00557         area_it = it;
00558     }
00559 
00560     if (area_it == eit)
00561     {
00562       nuxDebugMsg("[LayeredLayout::RaiseTop] Area %p is not a valid layer", area);
00563       return;
00564     }
00565 
00566     _layout_element_list.erase(area_it);
00567     _layout_element_list.insert(eit, area);
00568   }
00569 
00570   void LayeredLayout::LowerBottom(Area *area)
00571   {
00572     std::list<Area *>::iterator it, eit = _layout_element_list.end();
00573     std::list<Area *>::iterator area_it = eit;
00574 
00575     NUX_RETURN_IF_NULL(area);
00576 
00577     for (it = _layout_element_list.begin(); it != eit; ++it)
00578     {
00579       if (area == (*it))
00580         area_it = it;
00581     }
00582 
00583     if (area_it == eit)
00584     {
00585       nuxDebugMsg("[LayeredLayout::LowerBottom] Area %p is not a valid layer", area);
00586       return;
00587     }
00588 
00589     _layout_element_list.erase(area_it);
00590     _layout_element_list.insert(_layout_element_list.begin(), area);
00591   }
00592 
00593   Area* LayeredLayout::KeyNavIteration(KeyNavDirection direction)
00594   {
00595     if (m_active_area == NULL)
00596       return NULL;
00597 
00598     if (m_active_area->IsVisible() == false)
00599       return NULL;
00600 
00601     if (next_object_to_key_focus_area_)
00602     {
00603       return NULL;
00604     }
00605     else
00606     {
00607       return m_active_area->KeyNavIteration(direction);
00608     }
00609 
00610     return NULL;
00611   }
00612 }