nux-1.14.0
FloatingWindow.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 
00025 #include "NuxGraphics/GLTextureResourceManager.h"
00026 
00027 #include "HLayout.h"
00028 #include "WindowThread.h"
00029 #include "WindowCompositor.h"
00030 #include "FloatingWindow.h"
00031 
00032 namespace nux
00033 {
00034   NUX_IMPLEMENT_OBJECT_TYPE (FloatingWindow);
00035 
00036   /*
00037       Elements inside the Window have coordinates based on the top-left corner of the window.
00038       This is true whether we are drawing or computing the layout. When computing the layout, use x_root and y_root to
00039       pass the top-left corner position of the window. When drawing, make a similar adjustment.
00040   */
00041   FloatingWindow::FloatingWindow (const TCHAR *WindowName, NUX_FILE_LINE_DECL)
00042     :   BaseWindow (WindowName, NUX_FILE_LINE_PARAM)
00043   {
00044     m_bIsVisible                = false;
00045     m_bSizeMatchLayout          = false;
00046     m_bIsModal                  = false;
00047     m_bIsVisibleSizeGrip        = true;
00048     m_SizeGripDragPositionX     = 0;
00049     m_SizeGripDragPositionY     = 0;
00050     m_hasTitleBar               = true;
00051     _resize_handle_width        = 20;
00052     _resize_handle_height       = 20;
00053     _title_bar_height           = 20;
00054 
00055     _minimize_button    = new InputArea(NUX_TRACKER_LOCATION);
00056     _minimize_button->Reference();
00057     _minimize_button->SetParentObject(this);
00058 
00059     _resize_handle      = new InputArea(NUX_TRACKER_LOCATION);
00060     _resize_handle->SinkReference();
00061     _resize_handle->SetParentObject(this);
00062 
00063     _title_bar          = new InputArea(NUX_TRACKER_LOCATION);
00064     _title_bar->SinkReference();
00065     _title_bar->SetParentObject(this);
00066 
00067     _close_button       = new InputArea(NUX_TRACKER_LOCATION);
00068     _window_title_bar   = new StaticTextBox (TEXT (""), NUX_TRACKER_LOCATION);
00069 
00070     _title_bar_layout   = new HLayout (NUX_TRACKER_LOCATION);
00071     _title_bar_layout->Reference();
00072     
00073     _minimize_button->SetMinMaxSize(20, 20);
00074     _minimize_button->SetGeometry(0, 0, 20, 20);
00075     _close_button->SetMinimumSize(20, 20);
00076     _close_button->SetGeometry(0, 0, 20, 20);
00077     _resize_handle->SetMinimumSize(_resize_handle_width, _resize_handle_height);
00078     _resize_handle->SetGeometry(Geometry(0, 0, _resize_handle_width, _resize_handle_height));
00079 
00080     _title_bar->mouse_down.connect(sigc::mem_fun(this, &FloatingWindow::RecvTitleBarMouseDown));
00081     _title_bar->mouse_drag.connect(sigc::mem_fun(this, &FloatingWindow::RecvTitleBarMouseDrag));
00082     _close_button->mouse_click.connect(sigc::mem_fun(this, &FloatingWindow::RecvCloseButtonClick));
00083 
00084     _resize_handle->mouse_drag.connect(sigc::mem_fun(this, &FloatingWindow::OnSizeGrigMouseDrag));
00085     _resize_handle->mouse_down.connect(sigc::mem_fun(this, &FloatingWindow::OnSizeGrigMouseDown));
00086 
00087     _title_bar_layout->AddView((_window_title_bar), 1, eCenter, eFix);
00088     _title_bar_layout->AddView((_close_button), 0, eCenter, eFix);
00089     _title_bar_layout->SetParentObject(this);
00090 
00091 
00092     if(HasTitleBar())
00093       SetTopBorder(24);
00094     else
00095       SetTopBorder(6);
00096 
00097     SetBorder(2);
00098 
00099     SetMinimumSize(32, 32);
00100     SetGeometry(Geometry(100, 100, 320, 200));
00101 
00102     NString Path = NUX_FINDRESOURCELOCATION (TEXT ("UITextures/AddButton.png") );
00103     MinimizeIcon = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture ();
00104     MinimizeIcon->Update (Path.GetTCharPtr() );
00105     Path = NUX_FINDRESOURCELOCATION (TEXT ("UITextures/CancelButton.png") );
00106     CloseIcon = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture ();
00107     CloseIcon->Update (Path.GetTCharPtr() );
00108 
00109     SetWindowTitle (WindowName);
00110   }
00111 
00112   FloatingWindow::~FloatingWindow()
00113   {
00114     m_InterfaceObject.clear();
00115 
00116     _resize_handle->UnParentObject();
00117     _resize_handle->UnReference();
00118 
00119     _title_bar->UnParentObject();
00120     _title_bar->UnReference();
00121 
00122     _minimize_button->UnReference();
00123     CloseIcon->UnReference();
00124     MinimizeIcon->UnReference();
00125     
00126     _title_bar_layout->UnParentObject();
00127     _title_bar_layout->UnReference();
00128   }
00129 
00130   long FloatingWindow::ProcessEvent (IEvent &ievent, long TraverseInfo, long ProcessEventInfo)
00131   {
00132     long ret = TraverseInfo;
00133     long ProcEvInfo = 0;
00134 
00135     IEvent window_event = ievent;
00136     Geometry base = GetGeometry();
00137     window_event.e_x_root = base.x;
00138     window_event.e_y_root = base.y;
00139 
00140     if (ievent.e_event == NUX_MOUSE_PRESSED)
00141     {
00142       if (!GetGeometry().IsPointInside (ievent.e_x - ievent.e_x_root, ievent.e_y - ievent.e_y_root) )
00143       {
00144         ProcEvInfo = eDoNotProcess;
00145         //return TraverseInfo;
00146       }
00147     }
00148 
00149     ret = _close_button->OnEvent (window_event, ret, ProcEvInfo);
00150 
00151     if (HasTitleBar() )
00152     {
00153       ret = _title_bar->OnEvent (window_event, ret, ProcEvInfo);
00154     }
00155 
00156 //    if(m_vertical_scrollbar_enable)
00157 //        ret = vscrollbar->ProcessEvent(ievent, ret, ProcEvInfo);
00158 //    if(m_horizontal_scrollbar_enable)
00159 //        ret = hscrollbar->ProcessEvent(ievent, ret, ProcEvInfo);
00160 
00161     if (IsSizeMatchContent() == false)
00162     {
00163       // Do not let the _resize_handle test the event because the window is not displaying it;
00164       int XGrip = window_event.e_x - window_event.e_x_root - _resize_handle->GetBaseX();
00165       int YGrip = window_event.e_y - window_event.e_y_root - _resize_handle->GetBaseY();
00166 
00167       if (ievent.e_event == NUX_MOUSE_PRESSED)
00168       {
00169         // We want to false on one half of the size grip square to register a mouse down. This is meant to leave more room
00170         // for the scrollbar buttons (if any) at the bottom right of the window.
00171         if ((XGrip > 0) && (YGrip > 0) && (XGrip > _resize_handle_height - YGrip))
00172         {
00173           ret = _resize_handle->OnEvent(window_event, ret, ProcEvInfo);
00174         }
00175       }
00176       else
00177       {
00178         ret = _resize_handle->OnEvent(window_event, ret, ProcEvInfo);
00179       }
00180     }
00181 
00182     // The child layout get the Mouse down button only if the MouseDown happened inside the client view Area
00183     Geometry viewGeometry = GetGeometry(); //Geometry(m_ViewX, m_ViewY, m_ViewWidth, m_ViewHeight);
00184 
00185     if (ievent.e_event == NUX_MOUSE_PRESSED)
00186     {
00187       if (!viewGeometry.IsPointInside (ievent.e_x - ievent.e_x_root, ievent.e_y - ievent.e_y_root) )
00188       {
00189         ProcEvInfo = eDoNotProcess;
00190       }
00191     }
00192 
00193     if (m_layout)
00194       ret = m_layout->ProcessEvent (window_event, ret, ProcEvInfo);
00195 
00196     // PostProcessEvent2 must always have its last parameter set to 0
00197     // because the m_BackgroundArea is the real physical limit of the window.
00198     // So the previous test about IsPointInside do not prevail over m_BackgroundArea
00199     // testing the event by itself.
00200     ret = PostProcessEvent2 (ievent, ret, 0);
00201     return ret;
00202   }
00203 
00204   Area* FloatingWindow::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type)
00205   {
00206     bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type);
00207 
00208     if(mouse_inside == false)
00209       return NULL;
00210 
00211     NUX_RETURN_VALUE_IF_TRUE(_resize_handle->TestMousePointerInclusion(mouse_position, event_type), _resize_handle);
00212     NUX_RETURN_VALUE_IF_TRUE(_close_button->TestMousePointerInclusion(mouse_position, event_type), _close_button);
00213 
00214     if(HasTitleBar())
00215     {
00216       NUX_RETURN_VALUE_IF_TRUE(_title_bar->TestMousePointerInclusion(mouse_position, event_type), _title_bar);
00217     }
00218 
00219 //     if(_title_bar_layout)
00220 //     {
00221 //       nuxAssert(_title_bar_layout->IsLayout());
00222 //       Area* found_area = _title_bar_layout->FindAreaUnderMouse(mouse_position, event_type);
00223 //       if(found_area)
00224 //         return found_area;
00225 //     }
00226 
00227     if(m_layout)
00228     {
00229       nuxAssert(m_layout->IsLayout());
00230       Area* found_area = m_layout->FindAreaUnderMouse(mouse_position, event_type);
00231       if(found_area)
00232         return found_area;
00233     }
00234 
00235     if((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent()))
00236       return NULL;
00237     return this;
00238   }
00239 
00240   void FloatingWindow::Draw (GraphicsEngine &GfxContext, bool force_draw)
00241   {
00242     Geometry base = GetGeometry();
00243     // The elements position inside the window are referenced to top-left window corner. So bring base to (0, 0).
00244     base.SetX (0);
00245     base.SetY (0);
00246     GfxContext.PushClippingRectangle (base);
00247 
00248     GetPainter().PushDrawShapeLayer (GfxContext, base, eSHAPE_CORNER_ROUND10, Color (0xFF707070), eCornerTopLeft | eCornerTopRight, true);
00249 
00250     if (HasTitleBar() )
00251     {
00252       GetPainter().PaintShapeCorner (GfxContext, Geometry (_title_bar->GetBaseX(), _title_bar->GetBaseY(),
00253                                  _title_bar->GetBaseWidth(), _title_bar->GetBaseHeight() ), Color (0xFF2f2f2f),
00254                                  eSHAPE_CORNER_ROUND10, eCornerTopLeft | eCornerTopRight);
00255 
00256       GetPainter().PaintTextLineStatic (GfxContext, GetSysBoldFont(), _window_title_bar->GetGeometry(), _window_title, Color (0xFFFFFFFF), true, eAlignTextCenter);
00257       GetPainter().Draw2DTextureAligned (GfxContext, CloseIcon, _close_button->GetGeometry(), TextureAlignmentStyle (eTACenter, eTACenter) );
00258     }
00259 
00260     GetPainter().PopBackground();
00261     GfxContext.PopClippingRectangle();
00262   }
00263 
00264   void FloatingWindow::DrawContent (GraphicsEngine &GfxContext, bool force_draw)
00265   {
00266     Geometry base = GetGeometry();
00267     // The elements position inside the window are referenced to top-left window corner. So bring base to (0, 0).
00268     base.SetX (0);
00269     base.SetY (0);
00270 
00271     GetPainter().PushShapeLayer (GfxContext, base, eSHAPE_CORNER_ROUND10, Color (0xFF707070), eCornerTopLeft | eCornerTopRight, true);
00272 
00273     if (m_layout)
00274     {
00275       GfxContext.PushClippingRectangle (base);
00276 
00277       m_layout->ProcessDraw (GfxContext, force_draw);
00278 
00279       GfxContext.PopClippingRectangle();
00280     }
00281 
00282     GetPainter().PopBackground();
00283   }
00284 
00285   void FloatingWindow::PostDraw (GraphicsEngine &GfxContext, bool force_draw)
00286   {
00287     if (force_draw == false)
00288     {
00289       return;
00290     }
00291 
00292     if ((IsVisibleSizeGrip () == true) && (IsSizeMatchContent () == false))
00293     {
00294       // Do not draw the size grip if the window is constrained by the size of the container layout.
00295       Geometry geo = _resize_handle->GetGeometry ();
00296       GfxContext.QRP_Triangle (geo.x + geo.width, geo.y, geo.x, geo.y + geo.height, geo.x + geo.width, geo.y + geo.height, Color (0xFF999999));
00297     }
00298   }
00299 
00300   void FloatingWindow::EnableTitleBar (bool b)
00301   {
00302     m_hasTitleBar = b;
00303     ComputeChildLayout();
00304   }
00305 
00306   bool FloatingWindow::HasTitleBar() const
00307   {
00308     return m_hasTitleBar;
00309   }
00310 
00311   void FloatingWindow::OnSizeGrigMouseDown (int x, int y, unsigned long button_flags, unsigned long key_flags)
00312   {
00313     if(IsSizeMatchContent())
00314     {
00315       return;
00316     }
00317 
00318     // Do not let the _resize_handle test the event because the window is not displaying it;
00319     int XGrip = x;
00320     int YGrip = y;
00321 
00322 
00323     // We want to false on one half of the size grip square to register a mouse down. This is meant to leave more room
00324     // for the scrollbar buttons (if any) at the bottom right of the window.
00325     if ((XGrip > 0) && (YGrip > 0) && (XGrip > _resize_handle_height - YGrip))
00326     {
00327        // has grip
00328     }
00329 
00330     m_SizeGripDragPositionX = x;
00331     m_SizeGripDragPositionY = y;
00332     //GetWindowCompositor().SetMouseFocusArea(this);
00333   }
00334 
00335   void FloatingWindow::OnSizeGrigMouseDrag (int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags)
00336   {
00337     if(IsSizeMatchContent())
00338     {
00339       return;
00340     }
00341 
00342     Geometry geo;
00343     geo = GetGeometry();
00344 
00345     int ddx = 0;
00346     int ddy = 0;
00347 
00348     if((dx > 0) && (x > m_SizeGripDragPositionX))
00349     {
00350       ddx = dx;
00351     }
00352 
00353     if((dx < 0) && (x < m_SizeGripDragPositionX))
00354     {
00355       ddx = dx;
00356     }
00357 
00358     if((dy > 0) && (y > m_SizeGripDragPositionY))
00359     {
00360       ddy = dy;
00361     }
00362 
00363     if((dy < 0) && (y < m_SizeGripDragPositionY))
00364     {
00365       ddy = dy;
00366     }
00367 
00368     geo.OffsetSize(ddx, ddy);
00369 
00370     SetGeometry(geo);
00371 
00372 #if defined(NUX_OS_LINUX)
00373     if (m_input_window != 0)
00374     {
00375       //nuxDebugMsg (TEXT("Resize Input window: %d, %d, %d, %d"), geo.x, geo.y, geo.width, geo.height);
00376       m_input_window->SetGeometry (GetGeometry());
00377     }
00378 #endif
00379 
00380     GetWindowThread()->AddObjectToRefreshList(this);
00381     QueueDraw();
00382   }
00383 
00384   void FloatingWindow::RecvTitleBarMouseDown (int x, int y, unsigned long button_flags, unsigned long key_flags)
00385   {
00386     _title_bar_mouse_down_location = Point(x, y);
00387   }
00388 
00389   void FloatingWindow::RecvTitleBarMouseDrag (int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags)
00390   {
00391     Geometry geo;
00392     geo = GetGeometry();
00393     geo.OffsetPosition (dx, dy);
00394 
00395     // Set the Window Size and Position
00396     Area::SetGeometry (geo);
00397     // No need to compute the window layout elements [LayoutWindowElements()]. They haven't changed.
00398     // No need to compute the layout [ComputeChildLayout()]. It hasn't changed.
00399 
00400     _title_bar->SetGeometry (0, 0, geo.GetWidth(), _title_bar_height);
00401 
00402 #if defined(NUX_OS_LINUX)
00403     if (m_input_window != 0)
00404     {
00405       //nuxDebugMsg (TEXT("Resize Input window: %d, %d, %d, %d"), geo.x, geo.y, geo.width, geo.height);
00406       m_input_window->SetGeometry (GetGeometry());
00407     }
00408 #endif
00409 
00410     QueueDraw();
00411   }
00412 
00413   void FloatingWindow::RecvCloseButtonClick (int x, int y, unsigned long button_flags, unsigned long key_flags)
00414   {
00415 #if defined(NUX_OS_LINUX)
00416     // Disable the input window if there is one.
00417     EnableInputWindow(false);
00418 #endif
00419     
00420     StopModal();
00421   }
00422 
00423 // Get a change to do any work on an element.
00424 // Here we need to position the header by hand because it is not under the control of vlayout.
00425   void FloatingWindow::PreLayoutManagement()
00426   {
00427     Geometry geo = GetGeometry();
00428 
00429     if (m_configure_notify_callback)
00430     {
00431       (*m_configure_notify_callback) (GetGraphicsDisplay()->GetWindowWidth(), GetGraphicsDisplay()->GetWindowHeight(), geo, m_configure_notify_callback_data);
00432 
00433       if (geo.IsNull() )
00434       {
00435         nuxDebugMsg (TEXT ("[FloatingWindow::PreLayoutManagement] Received an invalid Geometry.") );
00436         geo = GetGeometry();
00437       }
00438       else
00439       {
00440         Area::SetGeometry (geo);
00441         // Get the geometry adjusted with respect to min and max dimension of this area.
00442         geo = GetGeometry();
00443       }
00444     }
00445 
00446     // Drag Bar Geometry
00447     if (HasTitleBar() )
00448     {
00449       _title_bar->SetGeometry (0, 0, geo.GetWidth(), _title_bar_height);
00450     }
00451 
00452     // Size grip Geometry
00453     Geometry SizeGripGeometry (geo.GetWidth() - _resize_handle_width, geo.GetHeight() - _resize_handle_height,
00454                                _resize_handle_width, _resize_handle_height);
00455     _resize_handle->SetGeometry (SizeGripGeometry);
00456 
00457     if (m_layout)
00458     {
00459       Geometry layout_geo = Geometry (m_Border, m_TopBorder,
00460                                       geo.GetWidth() - 2 * m_Border, geo.GetHeight() - m_Border - m_TopBorder);
00461       m_layout->SetGeometry (layout_geo);
00462     }
00463   }
00464 
00465 // Get a change to do any work on an element.
00466 // Here we need to position the header by hand because it is not under the control of vlayout.
00467   long FloatingWindow::PostLayoutManagement (long LayoutResult)
00468   {
00469     if (IsSizeMatchContent() && m_layout)
00470     {
00471       Geometry layout_geometry = m_layout->GetGeometry();
00472 
00473       Geometry WindowGeometry = Geometry (GetGeometry().x,
00474                                           GetGeometry().y,
00475                                           layout_geometry.GetWidth() + 2 * m_Border,
00476                                           layout_geometry.GetHeight() + m_Border + m_TopBorder);
00477 
00478       Area::SetGeometry (WindowGeometry);
00479     }
00480 
00481     Geometry geo = GetGeometry();
00482 
00483     // Drag Bar Geometry
00484     if (HasTitleBar() )
00485     {
00486       _title_bar->SetGeometry (0, 0, geo.GetWidth(), _title_bar_height);
00487     }
00488 
00489     // Size grip Geometry
00490     Geometry temp (geo.GetWidth() - _resize_handle_width, geo.GetHeight() - _resize_handle_height,
00491                    _resize_handle_width, _resize_handle_height);
00492     _resize_handle->SetGeometry (temp);
00493 
00494     // Title Bar
00495     _title_bar_layout->SetGeometry (_title_bar->GetGeometry() );
00496     GetWindowThread ()->ComputeElementLayout (_title_bar_layout);
00497 
00498     // A FloatingWindow must kill the result of the management and pass it to the parent Layout.
00499     return (eCompliantHeight | eCompliantWidth);
00500     //return result;
00501   }
00502 
00503 // Get a change to do any work on an element.
00504 // Here we need to position the header by hand because it is not under the control of vlayout.
00505   void FloatingWindow::PositionChildLayout (float offsetX, float offsetY)
00506   {
00507     //ScrollView::PositionChildLayout(offsetX, offsetY);
00508 
00509     Geometry geo = GetGeometry();
00510 
00511     // Drag Bar Geometry
00512     if (HasTitleBar() )
00513     {
00514       _title_bar->SetGeometry (0, 0, geo.GetWidth(), _title_bar_height);
00515     }
00516 
00517     // Size grip Geometry
00518     Geometry temp (geo.GetWidth() - _resize_handle_width, geo.GetHeight() - _resize_handle_height,
00519                    _resize_handle_width, _resize_handle_height);
00520     _resize_handle->SetGeometry (temp);
00521 
00522     // Title Bar
00523     _title_bar_layout->SetGeometry (_title_bar->GetGeometry() );
00524     GetWindowThread ()->ComputeElementLayout (_title_bar_layout);
00525 
00526   }
00527 
00528   void FloatingWindow::LayoutWindowElements()
00529   {
00530     // Define the geometry of some of the component of the window. Otherwise, if the composition layout is not set,
00531     // then the component won't be correctly placed after a SetGeometry. This can be redundant if the composition layout is set.
00532     Geometry base = GetGeometry();
00533     _title_bar->SetGeometry (0, 0, base.GetWidth(), _title_bar_height);
00534 
00535     _title_bar_layout->SetGeometry (_title_bar->GetGeometry() );
00536     GetWindowThread ()->ComputeElementLayout (_title_bar_layout);
00537 
00538     // Size grip Geometry
00539     Geometry temp (base.GetWidth() - _resize_handle_width, base.GetHeight() - _resize_handle_height,
00540                    _resize_handle_width, _resize_handle_height);
00541     _resize_handle->SetGeometry (temp);
00542   }
00543 
00544   void FloatingWindow::SetWindowTitle (const TCHAR *title)
00545   {
00546     NUX_RETURN_IF_NULL(title)
00547     _window_title = title;
00548   }
00549 
00550   NString FloatingWindow::GetWindowTitle()
00551   {
00552     return _window_title;
00553   }
00554 
00555 }
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends