nux-1.14.0
BaseWindow.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 #include "Nux.h"
00023 
00024 #include "NuxGraphics/GLTextureResourceManager.h"
00025 
00026 #include "Layout.h"
00027 #include "HLayout.h"
00028 #include "WindowCompositor.h"
00029 #include "BaseWindow.h"
00030 #include "TextEntry.h"
00031 
00032 namespace nux
00033 {
00034 
00035   NUX_IMPLEMENT_OBJECT_TYPE (BaseWindow);
00036 
00037   const int SizeGripWidth = 20;
00038   const int SizeGripHeight = 20;
00039   const int TitleBarHeight = 20;
00040 
00041   /*
00042       Elements inside the Window have coordinates based on the top-left corner of the window.
00043       This is true whether we are drawing or computing the layout. When computing the layout, use x_root and y_root to
00044       pass the top-left corner position of the window. When drawing, make a similar adjustment.
00045   */
00046 
00047   BaseWindow::BaseWindow (const TCHAR *WindowName, NUX_FILE_LINE_DECL)
00048     : View (NUX_FILE_LINE_PARAM)
00049     , _paint_layer(new ColorLayer(Color(0xFF707070)))
00050     , _opacity (1.0f)
00051   {
00052     premultiply = true;
00053     _name = WindowName;
00054     _child_need_redraw = true;
00055     m_TopBorder = 0;
00056     m_Border = 0;
00057     _size_match_layout = false;
00058     _is_visible = false;
00059     _is_modal = false;
00060 #if defined(NUX_OS_LINUX)
00061     m_input_window_enabled = false;
00062     m_input_window = 0;
00063 #endif
00064     m_layout = 0;
00065     m_configure_notify_callback = NULL;
00066     m_configure_notify_callback_data = NULL;
00067     _entering_visible_state = false;
00068     _entering_hidden_state = false;
00069     _enter_focus_input_area = NULL;
00070     accept_key_nav_focus_ = false;
00071 
00072     // Should be at the end of the constructor
00073     GetWindowCompositor().RegisterWindow (this);
00074 
00075     SetMinimumSize (1, 1);
00076     SetGeometry(Geometry(100, 100, 320, 200));
00077   }
00078 
00079   BaseWindow::~BaseWindow()
00080   {
00081     if (_enter_focus_input_area)
00082     {
00083       _enter_focus_input_area->UnReference ();
00084     }
00085 
00086 #if defined(NUX_OS_LINUX)
00087     if (m_input_window)
00088       delete m_input_window;
00089 #endif
00090   }
00091 
00092   long BaseWindow::ProcessEvent (IEvent &ievent, long TraverseInfo, long ProcessEventInfo)
00093   {
00094     long ret = TraverseInfo;
00095     long ProcEvInfo = 0;
00096 
00097     IEvent window_event = ievent;
00098     Geometry base = GetGeometry();
00099     window_event.e_x_root = base.x;
00100     window_event.e_y_root = base.y;
00101 
00102     // The child layout get the Mouse down button only if the MouseDown happened inside the client view Area
00103     Geometry viewGeometry = GetGeometry();
00104 
00105     if (ievent.e_event == NUX_MOUSE_PRESSED)
00106     {
00107       if (!viewGeometry.IsPointInside (ievent.e_x - ievent.e_x_root, ievent.e_y - ievent.e_y_root) )
00108       {
00109         ProcEvInfo = eDoNotProcess;
00110       }
00111     }
00112 
00113     if (m_layout)
00114       ret = m_layout->ProcessEvent (window_event, ret, ProcEvInfo);
00115 
00116     // PostProcessEvent2 must always have its last parameter set to 0
00117     // because the m_BackgroundArea is the real physical limit of the window.
00118     // So the previous test about IsPointInside do not prevail over m_BackgroundArea
00119     // testing the event by itself.
00120     ret = PostProcessEvent2 (ievent, ret, 0);
00121     return ret;
00122   }
00123 
00124   Area* BaseWindow::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type)
00125   {
00126     bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type);
00127 
00128     if(mouse_inside == false)
00129       return NULL;
00130 
00131     if(m_layout)
00132     {
00133       nuxAssert(m_layout->IsLayout());
00134       Area* found_area = m_layout->FindAreaUnderMouse(mouse_position, event_type);
00135       if(found_area)
00136         return found_area;
00137     }
00138 
00139     if((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent()))
00140       return NULL;
00141     return this;
00142   }
00143 
00144   void BaseWindow::Draw (GraphicsEngine &GfxContext, bool force_draw)
00145   {
00146     Geometry base = GetGeometry();
00147     // The elements position inside the window are referenced to top-left window corner. So bring base to (0, 0).
00148     base.SetX (0);
00149     base.SetY (0);
00150     GfxContext.PushClippingRectangle (base);
00151 
00152     GetPainter().PushDrawLayer(GfxContext, base, _paint_layer.get());
00153 
00154     GetPainter().PopBackground();
00155     GfxContext.PopClippingRectangle();
00156   }
00157 
00158   void BaseWindow::DrawContent (GraphicsEngine &GfxContext, bool force_draw)
00159   {
00160 
00161     Geometry base = GetGeometry();
00162     // The elements position inside the window are referenced to top-left window corner. So bring base to (0, 0).
00163     base.SetX (0);
00164     base.SetY (0);
00165 
00166 
00167     GetPainter().PushLayer(GfxContext, base, _paint_layer.get());
00168 
00169     if (m_layout)
00170     {
00171       GfxContext.PushClippingRectangle (base);
00172       m_layout->ProcessDraw (GfxContext, force_draw);
00173       GfxContext.PopClippingRectangle();
00174     }
00175 
00176     GetPainter().PopBackground();
00177   }
00178 
00179   void BaseWindow::PostDraw (GraphicsEngine &GfxContext, bool force_draw)
00180   {
00181 
00182   }
00183 
00184   void BaseWindow::SetConfigureNotifyCallback (ConfigureNotifyCallback Callback, void *Data)
00185   {
00186     m_configure_notify_callback = Callback;
00187     m_configure_notify_callback_data = Data;
00188   }
00189 
00190   void BaseWindow::AddWidget (View *ic)
00191   {
00192     if (ic && m_layout)
00193     {
00194       m_layout->AddView (ic, 0);
00195       // 0: the WidgetLayout geometry will be set to SetGeometry(0,0,1,1);
00196       // and the children will take their natural size by expending WidgetLayout.
00197       // If the parent of WidgetLayout offers more space, it won't be used by WidgetLayout.
00198 
00199       ComputeChildLayout();
00200     }
00201   }
00202 
00203   void BaseWindow::AddWidget (View *ic, int stretchfactor)
00204   {
00205     if (ic && m_layout)
00206     {
00207       m_layout->AddView (ic, stretchfactor);
00208       // if(stretchfactor ==0): the WidgetLayout geometry will be set to SetGeometry(0,0,1,1);
00209       // and the children will take their natural size by expending WidgetLayout.
00210       // If the parent of WidgetLayout offers more space, it won't be used by WidgetLayout.
00211 
00212       ComputeChildLayout();
00213     }
00214   }
00215 
00216   void BaseWindow::AddWidget (std::list<View *> *ViewList)
00217   {
00218     m_CompositionLayout->Clear();
00219 
00220     std::list<View *>::iterator it;
00221 
00222     for (it = ViewList->begin(); it != ViewList->end(); it++)
00223     {
00224       AddWidget ( (*it) );
00225     }
00226   }
00227 
00228   Layout* BaseWindow::GetLayout ()
00229   {
00230     return m_layout;
00231   }
00232 
00233   bool BaseWindow::SetLayout (Layout *layout)
00234   {
00235     if (View::SetLayout (layout) == false)
00236       return false;
00237 
00238     m_layout = layout;
00239     Geometry geo = GetGeometry();
00240     Geometry layout_geo = Geometry (geo.x + m_Border, geo.y + m_TopBorder,
00241                                     geo.GetWidth() - 2 * m_Border, geo.GetHeight() - m_Border - m_TopBorder);
00242     m_layout->SetGeometry (layout_geo);
00243 
00244     // When this call returns the layout computation is done.
00245     ComputeChildLayout();
00246     // or use
00247     //GetWindowThread()->QueueObjectLayout(m_layout);
00248 
00249     return true;
00250   }
00251 
00252   // Get a change to do any work on an element.
00253   // Here we need to position the header by hand because it is not under the control of vlayout.
00254   void BaseWindow::PreLayoutManagement()
00255   {
00256     Geometry geo = GetGeometry();
00257 
00258     if (m_configure_notify_callback)
00259     {
00260       (*m_configure_notify_callback) (GetGraphicsDisplay()->GetWindowWidth(), GetGraphicsDisplay()->GetWindowHeight(), geo, m_configure_notify_callback_data);
00261 
00262       if (geo.IsNull() )
00263       {
00264         nuxDebugMsg (TEXT ("[BaseWindow::PreLayoutManagement] Received an invalid Geometry.") );
00265         geo = GetGeometry();
00266       }
00267       else
00268       {
00269         Area::SetGeometry (geo);
00270         // Get the geometry adjusted with respect to min and max dimension of this area.
00271         geo = GetGeometry();
00272       }
00273     }
00274 
00275     if (m_layout)
00276     {
00277       Geometry layout_geo = Geometry (m_Border, m_TopBorder,
00278                                       geo.GetWidth() - 2 * m_Border, geo.GetHeight() - m_Border - m_TopBorder);
00279 
00280       if (IsSizeMatchContent ())
00281         m_layout->SetGeometry (Geometry (0, 0, 1, 1));
00282       else
00283         m_layout->SetGeometry (layout_geo);
00284     }
00285   }
00286 
00287 // Get a change to do any work on an element.
00288 // Here we need to position the header by hand because it is not under the control of vlayout.
00289   long BaseWindow::PostLayoutManagement (long LayoutResult)
00290   {
00291     if (IsSizeMatchContent() && m_layout)
00292     {
00293       Geometry layout_geometry = m_layout->GetGeometry();
00294 
00295       Geometry WindowGeometry = Geometry (GetGeometry().x,
00296                                           GetGeometry().y,
00297                                           layout_geometry.GetWidth() + 2 * m_Border,
00298                                           layout_geometry.GetHeight() + m_Border + m_TopBorder);
00299 
00300       Area::SetGeometry (WindowGeometry);
00301     }
00302 
00303     // A BaseWindow must kill the result of the management and pass it to the parent Layout.
00304     return (eCompliantHeight | eCompliantWidth);
00305     //return result;
00306   }
00307 
00308 // Get a change to do any work on an element.
00309 // Here we need to position the header by hand because it is not under the control of vlayout.
00310   void BaseWindow::PositionChildLayout (float offsetX, float offsetY)
00311   {
00312 
00313   }
00314   
00315   #if defined(NUX_OS_LINUX)
00316   void BaseWindow::EnableInputWindow (bool        b,
00317                                       const char* title,
00318                                       bool        take_focus,
00319                                       bool        override_redirect)
00320   {
00321     if (b)
00322     {
00323       if (m_input_window == 0)
00324         m_input_window = new XInputWindow (title, take_focus, override_redirect);
00325         
00326       m_input_window->Show ();
00327       m_input_window->SetGeometry (GetGeometry());
00328       m_input_window_enabled = true;
00329     }
00330     else
00331     {
00332       if (m_input_window)
00333         m_input_window->Hide ();
00334       m_input_window_enabled = false;
00335     }
00336   }
00337 
00338   bool BaseWindow::InputWindowEnabled ()
00339   {
00340     return m_input_window_enabled;
00341   }
00342   
00343   void BaseWindow::InputWindowEnableStruts (bool enable)
00344   {
00345     if (m_input_window)
00346       m_input_window->EnableStruts (enable);
00347   }
00348   
00349   bool BaseWindow::InputWindowStrutsEnabled ()
00350   {
00351     return m_input_window_enabled && m_input_window->StrutsEnabled ();
00352   }
00353   
00354   void BaseWindow::SetInputFocus ()
00355   {
00356     if (m_input_window)
00357       m_input_window->SetInputFocus ();
00358   }
00359 
00360   Window BaseWindow::GetInputWindowId ()
00361   {
00362     if (m_input_window)
00363       return m_input_window->GetWindow ();
00364     else
00365       return 0;
00366   }
00367 
00368   #endif
00369 
00370   void BaseWindow::SetGeometry (const Geometry &geo)
00371   {
00372     Area::SetGeometry (geo);
00373     
00374     #if defined(NUX_OS_LINUX)
00375     if (m_input_window)
00376       m_input_window->SetGeometry (geo);
00377     #endif
00378     //LayoutWindowElements();
00379     //ComputeChildLayout();
00380   }
00381 
00382   void BaseWindow::LayoutWindowElements()
00383   {
00384     // Define the geometry of some of the component of the window. Otherwise, if the composition layout is not set,
00385     // then the component won't be correctly placed after a SetGeometry. This can be redondant if the composition layout is set.
00386     Geometry base = GetGeometry();
00387   }
00388 
00389   void BaseWindow::SetBorder (int border)
00390   {
00391     if (m_Border != border)
00392     {
00393       m_Border = border;
00394     }
00395   }
00396 
00397   void BaseWindow::SetTopBorder (int border)
00398   {
00399     if (m_TopBorder != border)
00400     {
00401       m_TopBorder = border;
00402     }
00403   }
00404 
00405   int BaseWindow::GetBorder() const
00406   {
00407     return m_Border;
00408   }
00409 
00410   int BaseWindow::GetTopBorder() const
00411   {
00412     return m_TopBorder;
00413   }
00414 
00415   void BaseWindow::ShowWindow(bool visible, bool StartModal /*  = false */)
00416   {
00417     if (visible == _is_visible)
00418       return;
00419 
00420     _is_visible = visible;
00421     _is_modal = StartModal;
00422 
00423     if (_is_visible)
00424     {
00425       if (m_layout)
00426       {
00427         m_layout->SetGeometry(GetGeometry());
00428       }
00429 
00430       _entering_visible_state = true;
00431 
00432       sigVisible.emit(this);
00433       GetWindowCompositor().sigVisibleViewWindow.emit(this);
00434 
00435       ComputeChildLayout();
00436     }
00437     else
00438     {
00439       _entering_hidden_state = true;
00440       sigHidden.emit(this);
00441       GetWindowCompositor().sigHiddenViewWindow.emit(this);
00442     }
00443     
00444     if (_is_modal)
00445       GetWindowCompositor().StartModalWindow(ObjectWeakPtr<BaseWindow>(this));
00446 
00447     // Whether this view is added or removed, call QueueDraw. in the case where this view is removed, this is a signal 
00448     // that the region below this view need to be redrawn.
00449     QueueDraw();
00450   }
00451 
00452   bool BaseWindow::IsVisible() const
00453   {
00454     return _is_visible;
00455   }
00456 
00457   void BaseWindow::StopModal()
00458   {
00459     _is_visible = false;
00460     _is_modal = false;
00461     //ShowWindow(false);
00462     GetWindowCompositor().StopModalWindow (ObjectWeakPtr<BaseWindow> (this));
00463   }
00464 
00465   bool BaseWindow::IsModal() const
00466   {
00467     return _is_modal;
00468   }
00469 
00470   void BaseWindow::NotifyConfigurationChange (int Width, int Height)
00471   {
00472     Geometry geo = GetGeometry();
00473 
00474     if (m_configure_notify_callback)
00475     {
00476       (*m_configure_notify_callback) (GetGraphicsDisplay()->GetWindowWidth(), GetGraphicsDisplay()->GetWindowHeight(), geo, m_configure_notify_callback_data);
00477 
00478       if (geo.IsNull() )
00479       {
00480         nuxDebugMsg (TEXT ("[BaseWindow::NotifyConfigurationChange] Received an invalid Geometry.") );
00481         geo = GetGeometry();
00482       }
00483       else
00484       {
00485         Area::SetGeometry (geo);
00486         // Get the geometry adjusted with respect to min and max dimension of this area.
00487         geo = GetGeometry();
00488       }
00489     }
00490     else
00491     {
00492       return;
00493     }
00494   }
00495 
00496   void BaseWindow::SetBackgroundLayer (AbstractPaintLayer *layer)
00497   {
00498     NUX_RETURN_IF_NULL (layer);
00499     _paint_layer.reset(layer->Clone());
00500   }
00501 
00502   void BaseWindow::SetBackgroundColor (const Color &color)
00503   {
00504     _paint_layer.reset(new ColorLayer(color));
00505   }
00506 
00507   void BaseWindow::PushHigher (BaseWindow* floating_view)
00508   {
00509     GetWindowCompositor().PushHigher (this, floating_view);
00510   }
00511 
00512   void BaseWindow::PushToFront ()
00513   {
00514     GetWindowCompositor().PushToFront (this);
00515   }
00516 
00517   void BaseWindow::PushToBack ()
00518   {
00519     GetWindowCompositor().PushToBack (this);
00520   }
00521 
00522   bool BaseWindow::ChildNeedsRedraw ()
00523   {
00524     return _child_need_redraw;
00525   }
00526 
00527   void* BaseWindow::GetBackupTextureData (int &width, int &height, int &format)
00528   {
00529     return GetWindowCompositor ().GetBackupTextureData (this, width, height, format);
00530   }
00531 
00532   void BaseWindow::SetEnterFocusInputArea (InputArea *input_area)
00533   {
00534     if (_enter_focus_input_area)
00535     {
00536       _enter_focus_input_area->UnReference ();
00537     }
00538 
00539     _enter_focus_input_area = input_area;
00540     if (_enter_focus_input_area)
00541       _enter_focus_input_area->Reference ();
00542 
00543   }
00544 
00545   void BaseWindow::SetOpacity (float opacity)
00546   {
00547     if (_opacity == opacity)
00548       return;
00549 
00550     _opacity = opacity;
00551 
00552     _opacity = CLAMP (_opacity, 0.0f, 1.0f);
00553 
00554     QueueDraw ();
00555   }
00556 
00557   float BaseWindow::GetOpacity ()
00558   {
00559     return _opacity;
00560   }
00561 
00562   void BaseWindow::SetAcceptKeyNavFocus(bool accept)
00563   {
00564     accept_key_nav_focus_ = accept;
00565   }
00566 
00567   bool BaseWindow::AcceptKeyNavFocus()
00568   {
00569     return accept_key_nav_focus_;
00570   }
00571 }
00572 
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends