nux-1.14.0
View.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 "WindowCompositor.h"
00025 #include "Layout.h"
00026 #include "View.h"
00027 
00028 namespace nux
00029 {
00030 
00031   NUX_IMPLEMENT_OBJECT_TYPE (View);
00032 
00033   View::View (NUX_FILE_LINE_DECL)
00034     :   InputArea (NUX_FILE_LINE_PARAM)
00035   {
00036     _font = GetSysFont ();
00037     _is_view_active     = true; // The view is active by default
00038     m_CompositionLayout = 0;
00039     _need_redraw        = false;
00040     m_UseStyleDrawing   = true;
00041     m_TextColor         = Color (1.0f, 1.0f, 1.0f, 1.0f);
00042     _can_pass_focus_to_composite_layout = true;
00043     _can_focus          = true;
00044 
00045     // Set widget default size;
00046     SetMinimumSize (DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT);
00047     mouse_down_outside_pointer_grab_area.connect (sigc::mem_fun (this, &View::DoMouseDownOutsideArea));
00048   }
00049 
00050   View::~View()
00051   {
00052     // It is possible that the window thread has been deleted before the view
00053     // itself, so check prior to calling.
00054     WindowThread* wt = GetWindowThread();
00055     if (GetFocused() && HasPassiveFocus() == false && wt)
00056     {
00057       wt->SetFocusedArea (NULL);
00058     }
00059 
00060     // It is possible that the object is in the refresh list. Remove it here
00061     // before it is deleted.
00062     if (wt)
00063       wt->RemoveObjectFromLayoutQueue(this);
00064 
00065     RemoveLayout();
00066   }
00067 
00068   void View::DoMouseDownOutsideArea (int x, int y,unsigned long mousestate, unsigned long keystate)
00069   {
00070     if (GetFocused ())
00071     {
00072       SetFocused (false);
00073     }
00074   }
00075 
00076   long View::ProcessFocusEvent (IEvent &ievent, long TraverseInfo, long ProcessEventInfo)
00077   {
00078     // we assume we were chained up to by our layout
00079     if (GetLayout () == NULL)
00080       return TraverseInfo;
00081 
00082     Area *parent = GetParentObject ();
00083     if (parent == NULL)
00084     {
00085       GetLayout ()->SetFocused (false);
00086       GetLayout ()->SetFocused (true); // just reset the layout focus becase we are top level
00087     }
00088 
00089     if (parent != NULL && parent->IsLayout ())
00090     {
00091       Layout *parent_layout = (Layout *)parent;
00092       return parent_layout->ProcessFocusEvent (ievent, TraverseInfo, ProcessEventInfo);
00093     }
00094 
00095     return TraverseInfo;
00096   }
00097 
00098   // NUXTODO: Find better name
00099   long View::ComputeLayout2()
00100   {
00101     return ComputeChildLayout();
00102   }
00103 
00104   // NUXTODO: Find better name
00105   void View::ComputePosition2 (float offsetX, float offsetY)
00106   {
00107     PositionChildLayout (offsetX, offsetY);
00108   }
00109 
00110   long View::ComputeChildLayout()
00111   {
00112     if (m_CompositionLayout)
00113     {
00114       //m_CompositionLayout->SetDirty (true);
00115 //        if(m_CompositionLayout->GetStretchFactor() != 0)
00116 //        {
00117 //            PreLayoutManagement();
00118 //            long ret = m_CompositionLayout->ComputeLayout2();
00119 //            return PostLayoutManagement(ret);
00120 //        }
00121 //        else
00122       {
00123         PreLayoutManagement();
00124 
00125         int PreWidth = /*m_CompositionLayout->*/GetBaseWidth();
00126         int PreHeight = /*m_CompositionLayout->*/GetBaseHeight();
00127 
00128         long ret = m_CompositionLayout->ComputeLayout2();
00129 
00130         PostLayoutManagement (ret);
00131         //return eCompliantWidth | eCompliantHeight;
00132 
00133         int PostWidth = /*m_CompositionLayout->*/GetBaseWidth();
00134         int PostHeight = /*m_CompositionLayout->*/GetBaseHeight();
00135 
00136         long size_compliance = 0;
00137 
00138         // The layout has been resized to tightly pack its content
00139         if (PostWidth > PreWidth)
00140         {
00141           size_compliance |= eLargerWidth; // need scrollbar
00142         }
00143         else if (PostWidth < PreWidth)
00144         {
00145           size_compliance |= eSmallerWidth;
00146         }
00147         else
00148         {
00149           size_compliance |= eCompliantWidth;
00150         }
00151 
00152         // The layout has been resized to tightly pack its content
00153         if (PostHeight > PreHeight)
00154         {
00155           size_compliance |= eLargerHeight; // need scrollbar
00156         }
00157         else if (PostHeight < PreHeight)
00158         {
00159           size_compliance |= eSmallerHeight;
00160         }
00161         else
00162         {
00163           size_compliance |= eCompliantHeight;
00164         }
00165 
00166         //Area::SetGeometry(m_CompositionLayout->GetGeometry());
00167         return size_compliance;
00168       }
00169     }
00170     else
00171     {
00172       PreLayoutManagement();
00173       int ret = PostLayoutManagement (eCompliantHeight | eCompliantWidth);
00174       return ret;
00175     }
00176 
00177     return 0;
00178   }
00179 
00180   void View::PositionChildLayout (float offsetX, float offsetY)
00181   {
00182     if (m_CompositionLayout)
00183     {
00184       // This section from //1 to //2 is not needed. here we should not do any size management. Only position..
00185       //1
00186       if (m_CompositionLayout->GetStretchFactor() != 0)
00187       {
00188         m_CompositionLayout->SetGeometry (GetGeometry() );
00189       }
00190       else //2
00191       {
00192         m_CompositionLayout->SetBaseX (GetBaseX() );
00193         m_CompositionLayout->SetBaseY (GetBaseY() );
00194       }
00195 
00196       m_CompositionLayout->ComputePosition2 (offsetX, offsetY);
00197 
00198     }
00199   }
00200 
00201   void View::PreLayoutManagement()
00202   {
00203     // Give the managed layout the same size and position as the Control.
00204     if (m_CompositionLayout)
00205       m_CompositionLayout->SetGeometry (GetGeometry() );
00206   }
00207 
00208   long View::PostLayoutManagement (long LayoutResult)
00209   {
00210     // Set the geometry of the control to be the same as the managed layout.
00211     // Only the size is changed. The position of the composition layout hasn't
00212     // been changed by ComputeLayout2.
00213     if (m_CompositionLayout)
00214     {
00215       // If The layout is empty, do not change the size of the parent element.
00216       if (!m_CompositionLayout->IsEmpty() )
00217         Area::SetGeometry (m_CompositionLayout->GetGeometry() );
00218     }
00219 
00220     return LayoutResult;
00221   }
00222 
00223   void View::PreResizeGeometry()
00224   {
00225 
00226   }
00227 
00228   void View::PostResizeGeometry()
00229   {
00230   }
00231 
00232   long View::PostProcessEvent2 (IEvent &ievent, long TraverseInfo, long ProcessEventInfo)
00233   {
00234     return OnEvent (ievent, TraverseInfo, ProcessEventInfo);
00235   }
00236 
00237 
00238   void View::ProcessDraw (GraphicsEngine &GfxContext, bool force_draw)
00239   {
00240     _full_redraw = false;
00241 
00242     GfxContext.PushModelViewMatrix (Get2DMatrix ());
00243 
00244     if (force_draw)
00245     {
00246       _need_redraw = true;
00247       _full_redraw = true;
00248       Draw (GfxContext, force_draw);
00249       DrawContent (GfxContext, force_draw);
00250       PostDraw (GfxContext, force_draw);
00251     }
00252     else
00253     {
00254       if (_need_redraw)
00255       {
00256         _full_redraw = true;
00257         Draw (GfxContext, false);
00258         DrawContent (GfxContext, false);
00259         PostDraw (GfxContext, false);
00260       }
00261       else
00262       {
00263         DrawContent (GfxContext, false);
00264         PostDraw (GfxContext, false);
00265       }
00266     }
00267 
00268 // just leave this here, its helpful for debugging focus issues :)
00269 //     if (GetFocused () && _can_pass_focus_to_composite_layout == false)
00270 //     {
00271 //       GetPainter ().Paint2DQuadColor (GfxContext, GetGeometry (), nux::Color (0.2, 1.0, 0.2, 1.0));
00272 //     }
00273 
00274 //     if (GetFocused () && _can_pass_focus_to_composite_layout == true)
00275 //     {
00276 //       GetPainter ().Paint2DQuadColor (GfxContext, GetGeometry (), nux::Color (1.0, 0.2, 0.2, 1.0));
00277 //     }
00278 
00279 
00280     GfxContext.PopModelViewMatrix ();
00281 
00282     _need_redraw = false;
00283     _full_redraw = false;
00284   }
00285 
00286   void View::Draw(GraphicsEngine &GfxContext, bool force_draw)
00287   {
00288 
00289   }
00290 
00291   void View::DrawContent(GraphicsEngine &GfxContext, bool force_draw)
00292   {
00293 
00294   }
00295 
00296   void View::PostDraw(GraphicsEngine &GfxContext, bool force_draw)
00297   {
00298 
00299   }
00300 
00301   void View::QueueDraw ()
00302   {
00303     //GetWindowCompositor()..AddToDrawList(this);
00304     WindowThread* application = GetWindowThread ();
00305     if(application)
00306     {
00307       application->AddToDrawList(this);
00308       application->RequestRedraw();
00309       //GetWindowCompositor().AddToDrawList(this);
00310     }
00311     if (m_CompositionLayout)
00312       m_CompositionLayout->QueueDraw ();
00313 
00314     _need_redraw = true;
00315     OnQueueDraw.emit (this);
00316   }
00317 
00318   void View::NeedSoftRedraw()
00319   {
00320     //GetWindowCompositor()..AddToDrawList(this);
00321     WindowThread* application = GetWindowThread ();
00322     if(application)
00323     {
00324         application->AddToDrawList(this);
00325         application->RequestRedraw();
00326     }
00327     //_need_redraw = false;
00328   }
00329 
00330   bool View::IsRedrawNeeded()
00331   {
00332     return _need_redraw;
00333   }
00334 
00335   bool View::IsFullRedraw() const
00336   {
00337     return _full_redraw;
00338   }
00339 
00340   void View::DoneRedraw()
00341   {
00342     _need_redraw = false;
00343 
00344     if (m_CompositionLayout)
00345     {
00346       m_CompositionLayout->DoneRedraw();
00347     }
00348   }
00349 
00350   Layout* View::GetLayout()
00351   {
00352     return m_CompositionLayout;
00353   }
00354 
00355   Layout *View::GetCompositionLayout()
00356   {
00357     return GetLayout ();
00358   }
00359 
00360   bool View::SetLayout (Layout *layout)
00361   {
00362     nuxAssert(layout->IsLayout());
00363     NUX_RETURN_VALUE_IF_NULL (layout, false);
00364     NUX_RETURN_VALUE_IF_TRUE (m_CompositionLayout == layout, true);
00365 
00366     Area *parent = layout->GetParentObject();
00367 
00368     if (parent == this)
00369     {
00370       nuxAssert (m_CompositionLayout == layout);
00371       return false;
00372     }
00373     else if (parent != 0)
00374     {
00375       nuxDebugMsg (0, TEXT ("[View::SetCompositionLayout] Object already has a parent. You must UnParent the object before you can parenting again.") );
00376       return false;
00377     }
00378 
00379     if (m_CompositionLayout)
00380     {
00381       if (GetFocused ())
00382         m_CompositionLayout->SetFocused (false);
00383 
00384       _on_focus_changed_handler.disconnect ();
00385 
00386       /* we need to emit the signal before the unparent, just in case
00387          one of the callbacks wanted to use this object */
00388 
00389       LayoutRemoved.emit (this, m_CompositionLayout);
00390       m_CompositionLayout->UnParentObject();
00391     }
00392     layout->SetParentObject (this);
00393     m_CompositionLayout = layout;
00394 
00395     GetWindowThread()->QueueObjectLayout (this);
00396     if (GetFocused ())
00397       layout->SetFocused (true);
00398 
00399     _on_focus_changed_handler = layout->ChildFocusChanged.connect (sigc::mem_fun (this, &View::OnChildFocusChanged));
00400 
00401     LayoutAdded.emit (this, m_CompositionLayout);
00402 
00403     return true;
00404   }
00405 
00406   void View::OnChildFocusChanged (/*Area *parent,*/ Area *child)
00407   {
00408     ChildFocusChanged.emit (/*parent,*/ child);
00409   }
00410 
00411   bool View::SetCompositionLayout (Layout *layout)
00412   {
00413     return SetLayout (layout);
00414   }
00415 
00416   void View::RemoveLayout()
00417   {
00418     NUX_RETURN_IF_NULL(m_CompositionLayout);
00419 
00420     if (m_CompositionLayout)
00421       m_CompositionLayout->UnParentObject();
00422 
00423     m_CompositionLayout = 0;
00424   }
00425 
00426   void View::RemoveCompositionLayout()
00427   {
00428     RemoveLayout();
00429   }
00430 
00431   bool View::SearchInAllSubNodes (Area *bo)
00432   {
00433     if (m_CompositionLayout)
00434       return m_CompositionLayout->SearchInAllSubNodes (bo);
00435 
00436     return false;
00437   }
00438 
00439   bool View::SearchInFirstSubNodes (Area *bo)
00440   {
00441     if (m_CompositionLayout)
00442       return m_CompositionLayout->SearchInFirstSubNodes (bo);
00443 
00444     return false;
00445   }
00446 
00447   void View::SetGeometry (const Geometry &geo)
00448   {
00449     Area::SetGeometry (geo);
00450     ComputeChildLayout();
00451     PostResizeGeometry();
00452   }
00453 
00454   void View::SetFont (ObjectPtr<FontTexture> font)
00455   {
00456     _font = font;
00457   }
00458 
00459   ObjectPtr<FontTexture> View::GetFont ()
00460   {
00461     return _font;
00462   }
00463 
00464   void View::SetTextColor (const Color &color)
00465   {
00466     m_TextColor = color;
00467   }
00468 
00469   Color View::GetTextColor()
00470   {
00471     return m_TextColor;
00472   }
00473 
00474   void View::ActivateView ()
00475   {
00476     _is_view_active = false;
00477   }
00478 
00479   void View::DeactivateView ()
00480   {
00481     _is_view_active = true;
00482   }
00483 
00484   bool View::IsViewActive () const
00485   {
00486     return _is_view_active;
00487   }
00488 
00489   void View::GeometryChangePending ()
00490   {
00491     QueueDraw ();
00492   }
00493 
00494   void View::GeometryChanged ()
00495   {
00496     QueueDraw ();
00497   }
00498 
00499   bool View::DoGetFocused ()
00500   {
00501     if (HasPassiveFocus ())
00502       return GetLayout ()->GetFocused ();
00503 
00504     return _is_focused;
00505   }
00506 
00507   void View::DoSetFocused (bool focused)
00508   {
00509     if (GetFocused () == focused)
00510     {
00511       return;
00512     }
00513 
00514     InputArea::DoSetFocused (focused);
00515 
00516     if (HasPassiveFocus ())
00517     {
00518       Layout *layout = GetLayout ();
00519 
00520       InputArea::DoSetFocused (focused);
00521 
00522       if (layout != NULL)
00523       {
00524         layout->SetFocused (focused);
00525       }
00526     }
00527     else if (focused == true)
00528     {
00529       // we only set the focused area if we are not passing focus
00530       nux::GetWindowThread ()->SetFocusedArea (this);
00531     }
00532 
00533     if (focused == false)
00534     {
00535       bool has_focused_entry = false;
00536       Area *_parent = GetParentObject ();
00537       if (_parent == NULL)
00538         return;
00539 
00540       if (_parent->IsLayout ())
00541         has_focused_entry = _parent->GetFocused ();
00542 
00543       if (has_focused_entry == false)
00544         SetFocusControl (false);
00545 
00546     }
00547   }
00548 
00549   bool View::DoCanFocus ()
00550   {
00551     if (IsVisible () == false)
00552       return false;
00553 
00554     if (_can_focus == false)
00555       return false;
00556 
00557     if (_can_pass_focus_to_composite_layout)
00558     {
00559       if (GetLayout () != NULL)
00560       {
00561         return GetLayout ()->CanFocus ();
00562       }
00563     }
00564 
00565     return _can_focus;
00566   }
00567 
00568   void View::SetCanFocus (bool can_focus)
00569   {
00570     _can_focus = can_focus;
00571     if ((_can_focus == false) && GetFocused ())
00572     {
00573       SetFocused (false);
00574     }
00575   }
00576 
00577   // if we have a layout, returns true if we pass focus to it
00578   // else returns false
00579   bool View::HasPassiveFocus ()
00580   {
00581     if (_can_pass_focus_to_composite_layout && GetLayout () != NULL)
00582       return true;
00583 
00584     return false;
00585   }
00586 
00587   void View::SetFocusControl (bool focus_control)
00588   {
00589     Area *_parent = GetParentObject ();
00590     if (_parent == NULL)
00591       return;
00592 
00593     if (_parent->IsView ())
00594     {
00595       View *parent = (View*)_parent;
00596       parent->SetFocusControl (focus_control);
00597     }
00598     else if (_parent->IsLayout ())
00599     {
00600       Layout *parent = (Layout *)_parent;
00601       parent->SetFocusControl (focus_control);
00602     }
00603   }
00604 
00605   bool View::HasFocusControl()
00606   {
00607     Area *_parent = GetParentObject();
00608     if (_parent == NULL)
00609       return false;
00610 
00611     if (_parent->IsView())
00612     {
00613       View *parent = (View*)_parent;
00614       return parent->HasFocusControl();
00615     }
00616     else if (_parent->IsLayout())
00617     {
00618       Layout *parent = (Layout *)_parent;
00619       return parent->HasFocusControl();
00620     }
00621     return false;
00622   }
00623 
00624   Area* View::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type)
00625   {
00626     bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type);
00627 
00628     if (mouse_inside == false)
00629       return NULL;
00630 
00631     if (m_CompositionLayout)
00632     {
00633       Area* view = m_CompositionLayout->FindAreaUnderMouse(mouse_position, event_type);
00634 
00635       if (view)
00636         return view;
00637     }
00638 
00639     if ((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent()))
00640       return NULL;
00641     return this;
00642   }
00643 
00644   Area* View::FindKeyFocusArea(unsigned int key_symbol,
00645                       unsigned long x11_key_code,
00646                       unsigned long special_keys_state)
00647   {
00648     if (has_key_focus_)
00649     {
00650       return this;
00651     }
00652     else if (next_object_to_key_focus_area_)
00653     {
00654       return next_object_to_key_focus_area_->FindKeyFocusArea(key_symbol, x11_key_code, special_keys_state);
00655     }
00656     return NULL;
00657   }
00658 
00659   Area* View::KeyNavIteration(KeyNavDirection direction)
00660   {
00661     if (next_object_to_key_focus_area_)
00662     {
00663       return NULL;
00664     }
00665 
00666     if (IsVisible() == false)
00667       return NULL;
00668 
00669     if (AcceptKeyNavFocus())
00670     {
00671       QueueDraw();
00672       return this;
00673     }
00674     else if (m_CompositionLayout)
00675     {
00676       return m_CompositionLayout->KeyNavIteration(direction);
00677     }
00678 
00679     return NULL;
00680   }
00681 
00682   bool View::AcceptKeyNavFocus()
00683   {
00684     return true;
00685   }
00686 }
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends