Back to index

nux  3.0.0
Layout.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: Jay Taoko <jaytaoko@inalogic.com>
00019  *
00020  */
00021 
00022 
00023 #include "Nux.h"
00024 #include "Layout.h"
00025 #include "View.h"
00026 
00027 namespace nux
00028 {
00029   NUX_IMPLEMENT_OBJECT_TYPE(Layout);
00030   NUX_IMPLEMENT_OBJECT_TYPE(SpaceLayout);
00031 
00032   Layout::Layout(NUX_FILE_LINE_DECL)
00033     :   Area(NUX_FILE_LINE_PARAM)
00034   {
00035     space_between_children_ = 0;
00036 
00037     left_padding_      = 0;
00038     right_padding_     = 0;    
00039     top_padding_      = 0;
00040     bottom_padding_   = 0;
00041     m_contentWidth      = 0;
00042     m_contentHeight     = 0;
00043     m_ContentStacking   = eStackExpand;
00044     _queued_draw        = false;
00045 
00046     SetMinimumSize(1, 1);
00047   }
00048 
00049   Layout::~Layout()
00050   {
00051     // It is possible that this layout object is in the refresh list. Remove
00052     // it here before it is deleted.
00053     WindowThread* wt = GetWindowThread();
00054     if (wt)
00055       wt->RemoveObjectFromLayoutQueue(this);
00056 
00057     std::list<Area *>::iterator it;
00058 
00059     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00060     {
00061       (*it)->UnParentObject();
00062     }
00063 
00064     _layout_element_list.clear();
00065   }
00066 
00067   int Layout::GetLeftPadding() const
00068   {
00069     return left_padding_;
00070   }
00071 
00072   int Layout::GetRightPadding() const
00073   {
00074     return right_padding_;
00075   }
00076 
00077   int Layout::GetTopPadding() const
00078   {
00079     return top_padding_;
00080   }
00081 
00082   int Layout::GetBottomPadding() const
00083   {
00084     return bottom_padding_;
00085   }
00086 
00087   void Layout::SetLeftAndRightPadding(int padding)
00088   {
00089 #if DEBUG_LAYOUT
00090     return;
00091 #endif
00092     left_padding_ = padding < 0 ? 0 : padding;
00093     right_padding_ = padding < 0 ? 0 : padding;
00094   }
00095 
00096   void Layout::SetLeftAndRightPadding(int left, int right)
00097   {
00098 #if DEBUG_LAYOUT
00099     return;
00100 #endif
00101     left_padding_ = left < 0 ? 0 : left;
00102     right_padding_ = right < 0 ? 0 : right;
00103   }
00104 
00105   void Layout::SetTopAndBottomPadding(int padding)
00106   {
00107 #if DEBUG_LAYOUT
00108     return;
00109 #endif
00110     top_padding_ = padding < 0 ? 0 : padding;
00111     bottom_padding_ = padding < 0 ? 0 : padding;
00112   }
00113 
00114   void Layout::SetTopAndBottomPadding(int top, int bottom)
00115   {
00116 #if DEBUG_LAYOUT
00117     return;
00118 #endif
00119     top_padding_ = top < 0 ? 0 : top;
00120     bottom_padding_ = bottom < 0 ? 0 : bottom;
00121   }
00122 
00123   void Layout::SetPadding(int padding)
00124   {
00125     top_padding_ = padding < 0 ? 0 : padding;
00126     bottom_padding_ = top_padding_;
00127     right_padding_ = top_padding_;
00128     left_padding_ = top_padding_;
00129   }
00130 
00131   void Layout::SetPadding(int top_bottom_padding, int left_right_padding)
00132   {
00133     top_padding_ = top_bottom_padding < 0 ? 0 : top_bottom_padding;
00134     bottom_padding_ = top_padding_;
00135 
00136     right_padding_ = left_right_padding < 0 ? 0 : left_right_padding;
00137     left_padding_ = right_padding_;
00138   }
00139 
00140 
00141   void Layout::SetPadding(int top, int right, int bottom, int left)
00142   {
00143     top_padding_ = top < 0 ? 0 : top;
00144     right_padding_ = right < 0 ? 0 : right;
00145     bottom_padding_ = bottom < 0 ? 0 : bottom;
00146     left_padding_ = left < 0 ? 0 : left;
00147   }
00148 
00150   void Layout::SetHorizontalExternalMargin(int padding)
00151   {
00152     SetLeftAndRightPadding(padding);
00153   }
00154 
00156   void Layout::SetVerticalExternalMargin(int padding)
00157   {
00158     SetTopAndBottomPadding(padding);
00159   }
00160 
00161   void Layout::RemoveChildObject(Area *bo)
00162   {
00163     std::list<Area *>::iterator it;
00164     it = std::find(_layout_element_list.begin(), _layout_element_list.end(), bo);
00165 
00166     if (it != _layout_element_list.end())
00167     {
00168       /* we need to emit the signal before the un-parent, just in case
00169          one of the callbacks wanted to use this object */
00170       ViewRemoved.emit(this, bo);
00171       bo->UnParentObject();
00172       _layout_element_list.erase(it);
00173     }
00174   }
00175 
00176   bool Layout::FindWidget(Area *WidgetObject) const
00177   {
00178     std::list<Area *>::const_iterator it;
00179 
00180     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00181     {
00182       if ((*it) == WidgetObject)
00183       {
00184         return true;
00185       }
00186     }
00187 
00188     return false;
00189   }
00190 
00191   bool Layout::IsEmpty() const
00192   {
00193     return (_layout_element_list.size() == 0);
00194   }
00195 
00196 // If(stretchfactor == 0): the WidgetLayout geometry will be set to SetGeometry(0,0,1,1);
00197 // and the children will take their natural size by expending WidgetLayout.
00198 // If the parent of WidgetLayout offers more space, it won't be used by WidgetLayout.
00199   void Layout::AddLayout(Layout *layout, unsigned int stretchFactor, MinorDimensionPosition minor_position, MinorDimensionSize minor_size, float percentage, LayoutPosition index)
00200   {
00201     nuxAssertMsg(layout != 0, "[Layout::AddView] Invalid parameter.");
00202     NUX_RETURN_IF_TRUE(layout == 0);
00203     //  Should never happen
00204     nuxAssertMsg(layout != this, "[Layout::AddLayout] Error: Trying to add a layout to itself.");
00205     NUX_RETURN_IF_FALSE(layout != 0);
00206 
00207     Area *parent = layout->GetParentObject();
00208     nuxAssertMsg(parent == 0, "[Layout::AddLayout] Trying to add an object that already has a parent.");
00209     NUX_RETURN_IF_TRUE(parent != 0);
00210 
00211     nuxAssertMsg(index >= 0, "[Layout::AddLayout] Invalid index position. Adding at the beginning of the list..");
00212 
00213     layout->SetScaleFactor(stretchFactor);
00214     layout->SetPositioning(minor_position);
00215     layout->SetExtend(minor_size);
00216 
00217     if (percentage < 1.0f)
00218     {
00219       layout->SetPercentage(1.0f);
00220     }
00221     else if (percentage > 100.0f)
00222     {
00223       layout->SetPercentage(100.0f);
00224     }
00225     else
00226     {
00227       layout->SetPercentage(percentage);
00228     }
00229 
00230     layout->SetParentObject(this);
00231 
00232     layout->OnChildQueueDraw.connect(sigc::mem_fun(this, &Layout::ChildLayoutChildQueuedDraw));
00233     layout->OnQueueDraw.connect(sigc::mem_fun(this, &Layout::ChildLayoutQueuedDraw));
00234 
00235     if (index < 0)
00236       index = NUX_LAYOUT_BEGIN;
00237 
00238     if (index == NUX_LAYOUT_END || index >= _layout_element_list.size())
00239     {
00240       _layout_element_list.push_back(layout);
00241     }
00242     else
00243     {
00244       std::list<Area *>::iterator pos = _layout_element_list.begin();
00245       int idx = index;
00246       while (pos != _layout_element_list.end() && idx > 0)
00247       {
00248         idx--;
00249         pos++;
00250       }
00251       _layout_element_list.insert(pos, layout);
00252     }
00253 
00254   }
00255 
00257 
00281   void Layout::AddView(Area *bo, unsigned int stretchFactor, MinorDimensionPosition minor_position, MinorDimensionSize minor_size, float percentage, LayoutPosition index)
00282   {
00283     nuxAssertMsg(bo != 0, "[Layout::AddView] Invalid parameter.");
00284     NUX_RETURN_IF_TRUE(bo == 0);
00285 
00286     Area *parent = bo->GetParentObject();
00287     nuxAssertMsg(parent == 0, "[Layout::AddView] Trying to add an object that already has a parent.");
00288     NUX_RETURN_IF_TRUE(parent != 0);
00289 
00290     nuxAssertMsg(index >= 0, "[Layout::AddView] Invalid index position. Adding at the beginning of the list..");
00291 
00292     bo->SetScaleFactor(stretchFactor);
00293     bo->SetPositioning(minor_position);
00294     bo->SetExtend(minor_size);
00295 
00296     if (percentage < 1.0f)
00297     {
00298       bo->SetPercentage(1.0f);
00299     }
00300     else if (percentage > 100.0f)
00301     {
00302       bo->SetPercentage(100.0f);
00303     }
00304     else
00305     {
00306       bo->SetPercentage(percentage);
00307     }
00308 
00309     bo->SetParentObject(this);
00310 
00311     if (bo->IsView())
00312       static_cast<View *> (bo)->OnQueueDraw.connect(sigc::mem_fun(this, &Layout::ChildViewQueuedDraw));
00313 
00314     //if(HasFocusControl() && HasFocusableEntries() == false)
00315     //{
00316       //bo->SetFocused(true);
00317       //ChildFocusChanged(this, bo);
00318     //}
00319 
00320     if (index < 0)
00321       index = NUX_LAYOUT_BEGIN;
00322 
00323     if (index == NUX_LAYOUT_END || index >= _layout_element_list.size())
00324     {
00325       _layout_element_list.push_back(bo);
00326     }
00327     else
00328     {
00329 #if defined(NUX_OS_WINDOWS) && !defined(NUX_VISUAL_STUDIO_2010)
00330       std::list<Area *>::iterator pos = _layout_element_list.begin();
00331 #else
00332       auto pos = _layout_element_list.begin();
00333 #endif
00334       int idx = index;
00335       while (pos != _layout_element_list.end() && idx > 0)
00336       {
00337         idx--;
00338         pos++;
00339       }
00340       _layout_element_list.insert(pos, bo);
00341     }
00342 
00343     ViewAdded.emit(this, bo);
00344     //--->> Removed because it cause problem with The splitter widget: ComputeContentSize();
00345   }
00346 
00347   void Layout::AddSpace(unsigned int width, unsigned int stretchFactor, LayoutPosition index)
00348   {
00349     AddLayout(new SpaceLayout(), stretchFactor);
00350   }
00351 
00352   void Layout::Clear()
00353   {
00354     std::list<Area *>::iterator it;
00355 
00356     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00357     {
00358       (*it)->UnParentObject();
00359     }
00360 
00361     _layout_element_list.clear();
00362   }
00363 
00364   bool Layout::SearchInAllSubNodes(Area *bo)
00365   {
00366     std::list<Area *>::iterator it;
00367 
00368     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00369     {
00370       if ((*it) == bo)
00371       {
00372         return true;
00373       }
00374       else if ((*it)->IsLayout())
00375       {
00376         Layout *layout = NUX_STATIC_CAST(Layout *, (*it));
00377 
00378         if (layout->SearchInAllSubNodes(bo))
00379         {
00380           return true;
00381         }
00382       }
00383     }
00384 
00385     return false;
00386   }
00387 
00388   bool Layout::SearchInFirstSubNodes(Area *bo)
00389   {
00390     std::list<Area *>::iterator it;
00391 
00392     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00393     {
00394       if ((*it) == bo)
00395       {
00396         return true;
00397       }
00398     }
00399 
00400     return false;
00401   }
00402 
00403   unsigned int Layout::GetMaxStretchFactor()
00404   {
00405     unsigned int value = 0;
00406     unsigned int sf;
00407     std::list<Area *>::iterator it;
00408 
00409     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00410     {
00411       sf = (*it)->GetScaleFactor();
00412 
00413       if (sf >= value)
00414       {
00415         value = sf;
00416       }
00417     }
00418 
00419     return value;
00420   }
00421 
00422   unsigned int Layout::GetMinStretchFactor()
00423   {
00424     unsigned int value = 0xFFFFFFFF;
00425     unsigned int sf;
00426     std::list<Area *>::iterator it;
00427 
00428     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00429     {
00430       sf = (*it)->GetScaleFactor();
00431 
00432       if (sf <= value)
00433       {
00434         value = sf;
00435       }
00436     }
00437 
00438     return value;
00439   }
00440 
00441   unsigned int Layout::GetNumStretchFactor(unsigned int sf)
00442   {
00443     unsigned int count = 0;
00444     std::list<Area *>::iterator it;
00445 
00446     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00447     {
00448       if ((*it)->GetScaleFactor() == sf)
00449       {
00450         count++;
00451       }
00452     }
00453 
00454     return count;
00455   }
00456 
00457   void Layout::DoneRedraw()
00458   {
00459     std::list<Area *>::iterator it;
00460 
00461     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00462     {
00463       if ((*it)->IsView())
00464       {
00465         View *ic = NUX_STATIC_CAST(View *, (*it));
00466         ic->DoneRedraw();
00467       }
00468     }
00469   }
00470 
00471   Area* Layout::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type)
00472   {
00473     bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type);
00474 
00475     if (mouse_inside == false)
00476       return NULL;
00477 
00478     std::list<Area *>::iterator it;
00479     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00480     {
00481       if ((*it)->IsVisible() && (*it)->GetInputEventSensitivity())
00482       {
00483         Area* hit_view = NUX_STATIC_CAST(Area*, (*it)->FindAreaUnderMouse(mouse_position, event_type));
00484         if (hit_view)
00485           return hit_view;
00486       }
00487     }
00488 
00489     return NULL;
00490   }
00491 
00492   void Layout::ProcessDraw(GraphicsEngine &graphics_engine, bool force_draw)
00493   {
00494     std::list<Area *>::iterator it;
00495     graphics_engine.PushModelViewMatrix(Get2DMatrix());
00496 
00497     // Clip against the padding region.
00498     Geometry clip_geo = GetGeometry();
00499     clip_geo.OffsetPosition(left_padding_, top_padding_);
00500     clip_geo.OffsetSize(-left_padding_ - right_padding_, -top_padding_ - bottom_padding_);
00501 
00502     graphics_engine.PushClippingRectangle(clip_geo);
00503 
00504     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00505     {
00506       if (!(*it)->IsVisible())
00507         continue;
00508 
00509       if ((*it)->IsView())
00510       {
00511         View *ic = NUX_STATIC_CAST(View*, (*it));
00512         ic->ProcessDraw(graphics_engine, force_draw);
00513       }
00514       else if ((*it)->IsLayout())
00515       {
00516         Layout *layout = NUX_STATIC_CAST(Layout*, (*it));
00517         layout->ProcessDraw(graphics_engine, force_draw);
00518       }
00519       // InputArea should be tested last
00520       else if ((*it)->IsInputArea())
00521       {
00522         InputArea *input_area = NUX_STATIC_CAST(InputArea*, (*it));
00523         input_area->OnDraw(graphics_engine, force_draw);
00524       }
00525     }
00526 
00527     graphics_engine.PopClippingRectangle();
00528     graphics_engine.PopModelViewMatrix();
00529 
00530     //graphics_engine.PopClipOffset();
00531 
00532     _queued_draw = false;
00533   }
00534 
00535   void Layout::QueueDraw()
00536   {
00537     if (_queued_draw)
00538     {
00539       // A draw has already been scheduled.
00540       return;
00541     }
00542 
00543     std::list<Area *>::iterator it;
00544 
00545     for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++)
00546     {
00547       if ((*it)->IsView())
00548       {
00549         View *ic = NUX_STATIC_CAST(View *, (*it));
00550         ic->QueueDraw();
00551       }
00552       else if ((*it)->IsLayout())
00553       {
00554         Layout *layout = NUX_STATIC_CAST(Layout *, (*it));
00555         layout->QueueDraw();
00556       }
00557     }
00558 
00559     _queued_draw = true;
00560     OnQueueDraw.emit(this);
00561   }
00562 
00563   bool Layout::IsQueuedForDraw()
00564   {
00565     return _queued_draw;
00566   }
00567 
00568   void Layout::SetContentDistribution(LayoutContentDistribution stacking)
00569   {
00570     m_ContentStacking = stacking;
00571   }
00572 
00573   LayoutContentDistribution Layout::GetContentDistribution()
00574   {
00575     return m_ContentStacking;
00576   }
00577 
00578   void Layout::RequestBottomUpLayoutComputation(Area *bo_initiator)
00579   {
00580 
00581   }
00582 
00583   void Layout::ChildViewQueuedDraw(View *view)
00584   {
00585     OnChildQueueDraw.emit(view);
00586   }
00587 
00588   void Layout::ChildLayoutQueuedDraw(Layout *layout)
00589   {
00590     OnChildQueueDraw.emit(layout);
00591   }
00592 
00593   void Layout::ChildLayoutChildQueuedDraw(Area *area)
00594   {
00595     OnChildQueueDraw.emit(area);
00596   }
00597 
00598   bool Layout::AcceptKeyNavFocus()
00599   {
00600     return false;
00601   }
00602 }