nux-1.14.0
MenuBar.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 "HLayout.h"
00026 #include "MenuBar.h"
00027 
00028 namespace nux
00029 {
00030 
00031   static const t_u32 MENU_MINIMUM_WIDTH = 10;
00032   static const t_u32 MENU_MINIMUM_HEIGHT = 16;
00033 
00034   static const t_u32 MENUBAR_ICON_WIDTH = 24;
00035   static const t_u32 MENUBAR_ICON_HEIGHT = 24;
00036 
00037   NUX_IMPLEMENT_ROOT_OBJECT_TYPE (MenuBarItem);
00038   NUX_IMPLEMENT_OBJECT_TYPE (MenuBar);
00039 
00040   MenuBarItem::MenuBarItem (NUX_FILE_LINE_DECL)
00041     :   Object (true, NUX_FILE_LINE_PARAM)
00042   {
00043     // This area is added to the layout of the MenuBar. The Menubar will will ref/unref it.
00044     area = new InputArea (NUX_TRACKER_LOCATION);
00045     icon = 0;
00046   }
00047 
00048   MenuBarItem::~MenuBarItem()
00049   {
00050     if (menu)
00051       menu->UnReference();
00052     if (icon)
00053       icon->UnReference ();
00054 
00055     // The Area is owned by the MenuBar: do nothing for area.
00056   }
00057 
00058   MenuBar::MenuBar (NUX_FILE_LINE_DECL)
00059     :   View (NUX_FILE_LINE_PARAM)
00060     ,   m_MenuIsActive (false)
00061 //,   m_CurrentMenu(0)
00062     ,   m_IsOpeningMenu (false)
00063   {
00064     m_CurrentMenu = NULL;
00065     m_MenuBarWindow = NULL;
00066     m_hlayout = new HLayout (NUX_TRACKER_LOCATION);
00067     m_hlayout->SetHorizontalInternalMargin (4);
00068     m_hlayout->SetHorizontalExternalMargin (2);
00069 
00070     SetMinimumSize (24, 24);
00071     SetMaximumSize (AREA_MAX_WIDTH, 24);
00072     SetGeometry (Geometry (0, 0, 200, 20) );
00073 
00074     m_hlayout->SetHorizontalInternalMargin (4);
00075     m_hlayout->SetVerticalExternalMargin (0);
00076     m_hlayout->SetContentDistribution (eStackLeft);
00077     SetCompositionLayout (m_hlayout);
00078   }
00079 
00080   MenuBar::~MenuBar()
00081   {
00082     std::list< MenuBarItem * >::iterator it;
00083     for (it = m_MenuBarItemList.begin(); it != m_MenuBarItemList.end(); it++)
00084     {
00085       (*it)->UnReference ();
00086     }
00087     m_MenuBarItemList.clear();
00088   }
00089 
00090   long MenuBar::ProcessEvent (IEvent &ievent, long TraverseInfo, long ProcessEventInfo)
00091   {
00092     long ret = TraverseInfo;
00093     ret = TraverseInfo;  // <<---- never forget this
00094 
00095     std::list< MenuBarItem * >::iterator it;
00096 
00097     for (it = m_MenuBarItemList.begin(); it != m_MenuBarItemList.end(); it++)
00098     {
00099       (*it)->menu->m_MenuWindow = m_MenuBarWindow;
00100       ret = (*it)->area->OnEvent (ievent, ret, ProcessEventInfo);
00101     }
00102 
00103     if (ievent.e_event == NUX_MOUSE_PRESSED)
00104     {
00105       bool mouse_down_on_menu_item = false;
00106 
00107       if (m_MenuIsActive == true)
00108       {
00109         for (it = m_MenuBarItemList.begin(); it != m_MenuBarItemList.end(); it++)
00110         {
00111           if ( (*it)->area->IsMouseInside() )
00112           {
00113             mouse_down_on_menu_item = true;
00114             break;
00115           }
00116         }
00117 
00118         if (mouse_down_on_menu_item == false)
00119         {
00120           if (m_CurrentMenu->menu->TestMouseDown() == false)
00121           {
00122             RecvSigTerminateMenuCascade();
00123           }
00124         }
00125       }
00126     }
00127 
00128 
00129     // PostProcessEvent2 must always have its last parameter set to 0
00130     // because the m_BackgroundArea is the real physical limit of the window.
00131     // So the previous test about IsPointInside do not prevail over m_BackgroundArea
00132     // testing the event by itself.
00133     ret = PostProcessEvent2 (ievent, ret, 0);
00134     return ret;
00135   }
00136 
00137   void MenuBar::Draw (GraphicsEngine &GfxContext, bool force_draw)
00138   {
00139     Geometry base = GetGeometry();
00140     GfxContext.PushClippingRectangle (base);
00141 
00142     Geometry item_geometry;
00143     std::list< MenuBarItem * >::iterator it;
00144 
00145     for (it = m_MenuBarItemList.begin(); it != m_MenuBarItemList.end(); it++)
00146     {
00147       InputArea *area = (*it)->area;
00148       item_geometry = area->GetGeometry();
00149 
00150       if (area->IsMouseInside() )
00151       {
00152 
00153         GetPainter().PaintBackground (GfxContext, item_geometry);
00154 
00155         if (!m_MenuIsActive)
00156         {
00157           GetPainter().Paint2DQuadColor (GfxContext, item_geometry, Color (0xFF000000) );
00158           //GetPainter().PaintShape(GfxContext, item_geometry, Color(0xFF000000), eSHAPE_CORNER_ROUND2);
00159         }
00160         else
00161         {
00162           GetPainter().Paint2DQuadColor (GfxContext, item_geometry, Color (0xFF000000) );
00163           //GetPainter().PaintShapeCorner(GfxContext, item_geometry, Color(0xFF000000), eSHAPE_CORNER_ROUND2,
00164           //eCornerTopLeft|eCornerTopRight, false);
00165         }
00166 
00167         if ( (*it)->icon)
00168         {
00169           GfxContext.GetRenderStates().SetBlend (TRUE, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00170           GfxContext.GetRenderStates().SetColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00171           GetPainter().Draw2DTexture (GfxContext, (*it)->icon, item_geometry.x, item_geometry.y);
00172           GfxContext.GetRenderStates().SetColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00173           GfxContext.GetRenderStates().SetBlend (GL_FALSE);
00174         }
00175         else
00176         {
00177           GetPainter().PaintTextLineStatic (GfxContext, GetFont (), item_geometry, area->GetBaseString().GetTCharPtr(), GetTextColor(), true, eAlignTextCenter);
00178         }
00179       }
00180       else
00181       {
00182         GetPainter().PaintBackground (GfxContext, item_geometry);
00183 
00184         if ( (*it)->icon)
00185         {
00186           GfxContext.GetRenderStates().SetColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00187           GfxContext.GetRenderStates().SetBlend (TRUE, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00188           GetPainter().Draw2DTexture (GfxContext, (*it)->icon, item_geometry.x, item_geometry.y);
00189           GfxContext.GetRenderStates().SetColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00190           GfxContext.GetRenderStates().SetBlend (GL_FALSE);
00191         }
00192         else
00193         {
00194           GetPainter().PaintTextLineStatic (GfxContext, GetFont (), item_geometry, area->GetBaseString().GetTCharPtr(), GetTextColor(), true, eAlignTextCenter);
00195         }
00196       }
00197     }
00198 
00199     if (m_MenuIsActive)
00200     {
00201       InputArea *area = m_CurrentMenu->area;
00202       item_geometry = area->GetGeometry();
00203       GetPainter().PaintBackground (GfxContext, item_geometry);
00204       GetPainter().Paint2DQuadColor (GfxContext, item_geometry, Color (0xFF000000) );
00205       //GetPainter().PaintShapeCorner(GfxContext, item_geometry, Color(0xFF000000), eSHAPE_CORNER_ROUND2, eCornerTopLeft|eCornerTopRight, true);
00206 
00207       if (m_CurrentMenu->icon)
00208       {
00209         GfxContext.GetRenderStates().SetBlend (TRUE, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00210         GfxContext.GetRenderStates().SetColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00211         GetPainter().Draw2DTexture (GfxContext, m_CurrentMenu->icon, item_geometry.x, item_geometry.y);
00212         GfxContext.GetRenderStates().SetColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00213         GfxContext.GetRenderStates().SetBlend (GL_FALSE);
00214       }
00215       else
00216       {
00217         GetPainter().PaintTextLineStatic (GfxContext, GetFont (), item_geometry, area->GetBaseString().GetTCharPtr(), GetTextColor(), true, eAlignTextCenter);
00218       }
00219     }
00220 
00221     GfxContext.PopClippingRectangle();
00222   }
00223 
00224   void MenuBar::DrawContent (GraphicsEngine &GfxContext, bool force_draw)
00225   {
00226     GfxContext.PushClippingRectangle (GetGeometry() );
00227     GfxContext.PopClippingRectangle();
00228   }
00229 
00230   void MenuBar::PostDraw (GraphicsEngine &GfxContext, bool force_draw)
00231   {
00232 
00233   }
00234 
00235   void MenuBar::AddMenu (const TCHAR *MenuLabel, MenuPage *menu)
00236   {
00237     NUX_RETURN_IF_NULL (menu);
00238     AddMenu (MenuLabel, menu, 0);
00239   }
00240 
00241   void MenuBar::AddMenu (const TCHAR *MenuLabel, MenuPage *menu, BaseTexture *icon)
00242   {
00243     NUX_RETURN_IF_NULL (menu);
00244 
00245     // MenuBarItem inherits from Object: no need to Sink the reference.
00246     MenuBarItem *menubar_item (new MenuBarItem(NUX_TRACKER_LOCATION) );
00247 
00248     menu->m_IsTopOfMenuChain = true;
00249     menubar_item->area->SetBaseString (MenuLabel);
00250     menubar_item->menu = menu;
00251     if (menubar_item->menu)
00252       menubar_item->menu->Reference ();
00253 
00254     menubar_item->icon = icon;
00255     if (menubar_item->icon)
00256       menubar_item->icon->Reference ();
00257 
00258     m_MenuBarItemList.push_back (menubar_item);
00259 
00260     //menubar_item->area->SetMinimumSize(DEFAULT_WIDGET_WIDTH, 40);
00261     if (!icon)
00262     {
00263       menubar_item->area->SetMinimumSize (Max (MENU_MINIMUM_WIDTH, (t_u32) (10 + GetFont ()->GetStringWidth (MenuLabel) ) ), Max (MENU_MINIMUM_WIDTH, (t_u32) 16) );
00264     }
00265     else
00266     {
00267       menubar_item->area->SetMinMaxSize (MENUBAR_ICON_WIDTH, MENUBAR_ICON_HEIGHT);
00268     }
00269 
00270     menubar_item->area->mouse_enter.connect (sigc::bind ( sigc::mem_fun (this, &MenuBar::EmitItemMouseEnter), menubar_item) );
00271     menubar_item->area->mouse_leave.connect (sigc::bind ( sigc::mem_fun (this, &MenuBar::EmitItemMouseLeave), menubar_item) );
00272     menubar_item->area->mouse_down.connect (sigc::bind ( sigc::mem_fun (this, &MenuBar::EmitItemMouseDown), menubar_item) );
00273     menubar_item->area->mouse_drag.connect (sigc::bind ( sigc::mem_fun (this, &MenuBar::RecvItemMouseDrag), menubar_item) );
00274     menubar_item->area->mouse_up.connect (sigc::bind ( sigc::mem_fun (this, &MenuBar::EmitItemMouseUp), menubar_item) );
00275 
00276     menubar_item->menu->SetParentMenu (0);
00277     menubar_item->menu->sigActionTriggered.connect (sigc::mem_fun (this, &MenuBar::RecvSigActionTriggered) );
00278     menubar_item->menu->sigTerminateMenuCascade.connect (sigc::mem_fun (this, &MenuBar::RecvSigTerminateMenuCascade) );
00279     menubar_item->menu->sigMouseDownOutsideMenuCascade.connect (sigc::mem_fun (this, &MenuBar::RecvSigMouseDownOutsideMenuCascade) );
00280 
00281     m_hlayout->AddView (menubar_item->area, 0, eCenter);
00282     GetWindowThread ()->ComputeElementLayout (m_hlayout);
00283   }
00284 
00285   void MenuBar::EmitItemMouseEnter (int x, int y, unsigned long button_flags, unsigned long key_flags, MenuBarItem *menubar_item)
00286   {
00287     if (m_MenuIsActive)
00288     {
00289       if (m_CurrentMenu && (m_CurrentMenu->menu != menubar_item->menu) )
00290         m_CurrentMenu->menu->StopMenu (0, 0);
00291 
00292       Geometry geo = menubar_item->menu->GetGeometry();
00293       menubar_item->menu->m_MenuWindow = m_MenuBarWindow;
00294       menubar_item->menu->StartMenu (menubar_item->area->GetBaseX(),
00295                                      menubar_item->area->GetBaseY() + menubar_item->area->GetBaseHeight(), 0, 0);
00296 
00297       m_CurrentMenu = menubar_item;
00298 
00299       m_IsOpeningMenu = true;
00300     }
00301 
00302     QueueDraw();
00303   }
00304 
00305   void MenuBar::EmitItemMouseLeave (int x, int y, unsigned long button_flags, unsigned long key_flags, MenuBarItem *menubar_item)
00306   {
00307     QueueDraw();
00308   }
00309   void MenuBar::EmitItemMouseDown (int x, int y, unsigned long button_flags, unsigned long key_flags, MenuBarItem *menubar_item)
00310   {
00311     m_MenuBarWindow = GetWindowCompositor ().GetProcessingTopView ();
00312 
00313     if (m_MenuIsActive == false)
00314     {
00315       // Open the corresponding MenuPage
00316       if (m_CurrentMenu)
00317       {
00318         // This should never happen
00319         nuxAssert (0);
00320         m_CurrentMenu->menu->StopMenu ();
00321       }
00322 
00323       m_MenuIsActive = true;
00324       m_CurrentMenu = menubar_item;
00325       m_CurrentMenu->menu->m_MenuWindow = m_MenuBarWindow;
00326       m_IsOpeningMenu = true;
00327 
00328       //m_CurrentMenu->area->ForceStopFocus(0, 0);
00329       m_CurrentMenu->menu->StartMenu (menubar_item->area->GetBaseX (),
00330                                       menubar_item->area->GetBaseY () + menubar_item->area->GetBaseHeight (), 0, 0);
00331     }
00332     else
00333     {
00334       // If the mouse up that follows happen inside the area, then it is going to close the menu.
00335       m_IsOpeningMenu = false;
00336     }
00337 
00338     QueueDraw ();
00339   }
00340 
00341   void MenuBar::EmitItemMouseUp (int x, int y, unsigned long button_flags, unsigned long key_flags, MenuBarItem *menubar_item)
00342   {
00343     if (m_MenuIsActive)
00344     {
00345       if (m_CurrentMenu->area->IsMouseInside() )
00346       {
00347         if (m_IsOpeningMenu == false)
00348         {
00349           // close the MenuPage that is Open
00350           if (m_CurrentMenu)
00351             m_CurrentMenu->menu->StopMenu (0, 0);
00352 
00353           m_MenuIsActive = false;
00354           m_CurrentMenu = 0;
00355         }
00356         else
00357         {
00358           // The MousePress before this MouseRelease, caused the MenuPage to open.
00359           // Set m_IsOpeningMenu so the next mouse release will close the menu.
00360           m_IsOpeningMenu = false;
00361         }
00362       }
00363       else
00364       {
00365         bool hit_inside_a_menu = false;
00366         bool b = m_CurrentMenu->menu->TestMouseUp (x, y, button_flags, key_flags, hit_inside_a_menu);
00367 
00368         if (b || (hit_inside_a_menu == false) )
00369         {
00370           RecvSigTerminateMenuCascade();
00371         }
00372       }
00373     }
00374 
00375     QueueDraw();
00376   }
00377 
00378   void MenuBar::RecvItemMouseDrag (int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags, MenuBarItem *menubar_item)
00379   {
00380     // TODO: Port to new event architecture
00381 //     // Transition between one menu bar item to another
00382 //     if (GetWindowCompositor().GetMouseFocusArea() == menubar_item->area)
00383 //     {
00384 //       if (!menubar_item->area->IsMouseInside() ) // can also test GetWindowCompositor().GetMouseOverArea() != &menubar_item->area
00385 //       {
00386 //         std::list< MenuBarItem * >::iterator it;
00387 //         // compute window coordinates x and y;
00388 //         int winx = menubar_item->area->GetBaseX() + x;
00389 //         int winy = menubar_item->area->GetBaseY() + y;
00390 // 
00391 //         for (it = m_MenuBarItemList.begin(); it != m_MenuBarItemList.end(); it++)
00392 //         {
00393 //           InputArea *area = (*it)->area;
00394 //           Geometry geometry = area->GetGeometry();
00395 // 
00396 //           if (geometry.IsPointInside (winx, winy) )
00397 //           {
00398 //             // Close the menu below menubar_item (the one that has the focus
00399 //             menubar_item->area->ForceStopFocus (0, 0);
00400 // 
00401 //             // EmitItemMouseEnter is going to open the menu below (*it)
00402 //             {
00403 //               EmitItemMouseEnter (winx, winy, button_flags, key_flags, (*it) );
00404 //               m_IsOpeningMenu = true;
00405 //               area->ForceStartFocus (0, 0);
00406 // 
00407 //               GetWindowCompositor().SetMouseFocusArea (area);
00408 //               GetWindowCompositor().SetMouseOverArea (area);
00409 //             }
00410 // 
00411 //             break;
00412 //           }
00413 //         }
00414 //       }
00415 //     }
00416   }
00417 
00418   void MenuBar::RecvSigActionTriggered (MenuPage *menu, ActionItem *action)
00419   {
00420     m_MenuIsActive = false;
00421 
00422     if (m_CurrentMenu)
00423     {
00424       m_CurrentMenu->menu->StopMenu();
00425       QueueDraw();
00426     }
00427 
00428     m_CurrentMenu = 0;
00429     m_IsOpeningMenu = false;
00430 
00431     // You can do something if you want with the menu* and the action*
00432   }
00433 
00434 
00435   void MenuBar::RecvSigTerminateMenuCascade()
00436   {
00437     m_MenuIsActive = false;
00438 
00439     if (m_CurrentMenu)
00440     {
00441       m_CurrentMenu->menu->StopMenu();
00442     }
00443 
00444     m_CurrentMenu = 0;
00445     m_IsOpeningMenu = false;
00446 
00447     QueueDraw();
00448   }
00449 
00450   void MenuBar::RecvSigMouseDownOutsideMenuCascade (MenuPage *menu, int x, int y)
00451   {
00452     Geometry geometry;
00453     std::list< MenuBarItem * >::iterator it;
00454     bool TerminateMenuCascade = 1;
00455 
00456     for (it = m_MenuBarItemList.begin(); it != m_MenuBarItemList.end(); it++)
00457     {
00458       InputArea *area = (*it)->area;
00459       geometry = area->GetGeometry();
00460 
00461       if (geometry.IsPointInside (x, y) )
00462       {
00463         // The event landed on one of the MenuBar item.
00464         // Do nothing. This will be handled in the ProcessEvent of the MenuBar item where the mouse down landed.
00465         TerminateMenuCascade = 0;
00466         break;
00467       }
00468     }
00469 
00470     if (TerminateMenuCascade)
00471       RecvSigTerminateMenuCascade();
00472   }
00473 
00474 
00475 }
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends