Back to index

nux  3.0.0
MenuBar.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 "WindowCompositor.h"
00025 #include "HLayout.h"
00026 #include "MenuBar.h"
00027 
00028 namespace nux
00029 {
00030 
00031   static const unsigned int MENU_MINIMUM_WIDTH = 10;
00032   static const unsigned int MENU_MINIMUM_HEIGHT = 16;
00033 
00034   static const unsigned int MENUBAR_ICON_WIDTH = 24;
00035   static const unsigned int 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   void MenuBar::Draw(GraphicsEngine &graphics_engine, bool force_draw)
00091   {
00092     Geometry base = GetGeometry();
00093     graphics_engine.PushClippingRectangle(base);
00094 
00095     Geometry item_geometry;
00096     std::list< MenuBarItem * >::iterator it;
00097 
00098     for (it = m_MenuBarItemList.begin(); it != m_MenuBarItemList.end(); it++)
00099     {
00100       InputArea *area = (*it)->area;
00101       item_geometry = area->GetGeometry();
00102 
00103       if (area->IsMouseInside())
00104       {
00105 
00106         GetPainter().PaintBackground(graphics_engine, item_geometry);
00107 
00108         if (!m_MenuIsActive)
00109         {
00110           GetPainter().Paint2DQuadColor(graphics_engine, item_geometry, Color(0xFF000000));
00111           //GetPainter().PaintShape(graphics_engine, item_geometry, Color(0xFF000000), eSHAPE_CORNER_ROUND2);
00112         }
00113         else
00114         {
00115           GetPainter().Paint2DQuadColor(graphics_engine, item_geometry, Color(0xFF000000));
00116           //GetPainter().PaintShapeCorner(graphics_engine, item_geometry, Color(0xFF000000), eSHAPE_CORNER_ROUND2,
00117           //eCornerTopLeft|eCornerTopRight, false);
00118         }
00119 
00120         if ((*it)->icon)
00121         {
00122           graphics_engine.GetRenderStates().SetBlend(TRUE, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00123           graphics_engine.GetRenderStates().SetColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00124           GetPainter().Draw2DTexture(graphics_engine, (*it)->icon, item_geometry.x, item_geometry.y);
00125           graphics_engine.GetRenderStates().SetColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00126           graphics_engine.GetRenderStates().SetBlend(GL_FALSE);
00127         }
00128         else
00129         {
00130           GetPainter().PaintTextLineStatic(graphics_engine, GetFont(), item_geometry, area->GetBaseString().GetTCharPtr(), GetTextColor(), true, eAlignTextCenter);
00131         }
00132       }
00133       else
00134       {
00135         GetPainter().PaintBackground(graphics_engine, item_geometry);
00136 
00137         if ((*it)->icon)
00138         {
00139           graphics_engine.GetRenderStates().SetColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00140           graphics_engine.GetRenderStates().SetBlend(TRUE, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00141           GetPainter().Draw2DTexture(graphics_engine, (*it)->icon, item_geometry.x, item_geometry.y);
00142           graphics_engine.GetRenderStates().SetColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00143           graphics_engine.GetRenderStates().SetBlend(GL_FALSE);
00144         }
00145         else
00146         {
00147           GetPainter().PaintTextLineStatic(graphics_engine, GetFont(), item_geometry, area->GetBaseString().GetTCharPtr(), GetTextColor(), true, eAlignTextCenter);
00148         }
00149       }
00150     }
00151 
00152     if (m_MenuIsActive)
00153     {
00154       InputArea *area = m_CurrentMenu->area;
00155       item_geometry = area->GetGeometry();
00156       GetPainter().PaintBackground(graphics_engine, item_geometry);
00157       GetPainter().Paint2DQuadColor(graphics_engine, item_geometry, Color(0xFF000000));
00158       //GetPainter().PaintShapeCorner(graphics_engine, item_geometry, Color(0xFF000000), eSHAPE_CORNER_ROUND2, eCornerTopLeft|eCornerTopRight, true);
00159 
00160       if (m_CurrentMenu->icon)
00161       {
00162         graphics_engine.GetRenderStates().SetBlend(TRUE, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00163         graphics_engine.GetRenderStates().SetColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00164         GetPainter().Draw2DTexture(graphics_engine, m_CurrentMenu->icon, item_geometry.x, item_geometry.y);
00165         graphics_engine.GetRenderStates().SetColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00166         graphics_engine.GetRenderStates().SetBlend(GL_FALSE);
00167       }
00168       else
00169       {
00170         GetPainter().PaintTextLineStatic(graphics_engine, GetFont(), item_geometry, area->GetBaseString().GetTCharPtr(), GetTextColor(), true, eAlignTextCenter);
00171       }
00172     }
00173 
00174     graphics_engine.PopClippingRectangle();
00175   }
00176 
00177   void MenuBar::DrawContent(GraphicsEngine &graphics_engine, bool force_draw)
00178   {
00179     graphics_engine.PushClippingRectangle(GetGeometry());
00180     graphics_engine.PopClippingRectangle();
00181   }
00182 
00183   void MenuBar::PostDraw(GraphicsEngine &graphics_engine, bool force_draw)
00184   {
00185 
00186   }
00187 
00188   void MenuBar::AddMenu(const char *MenuLabel, MenuPage *menu)
00189   {
00190     NUX_RETURN_IF_NULL(menu);
00191     AddMenu(MenuLabel, menu, 0);
00192   }
00193 
00194   void MenuBar::AddMenu(const char *MenuLabel, MenuPage *menu, BaseTexture *icon)
00195   {
00196     NUX_RETURN_IF_NULL(menu);
00197 
00198     // MenuBarItem inherits from Object: no need to Sink the reference.
00199     MenuBarItem *menubar_item(new MenuBarItem(NUX_TRACKER_LOCATION));
00200 
00201     menu->m_IsTopOfMenuChain = true;
00202     menubar_item->area->SetBaseString(MenuLabel);
00203     menubar_item->menu = menu;
00204     if (menubar_item->menu)
00205       menubar_item->menu->Reference();
00206 
00207     menubar_item->icon = icon;
00208     if (menubar_item->icon)
00209       menubar_item->icon->Reference();
00210 
00211     m_MenuBarItemList.push_back(menubar_item);
00212 
00213     //menubar_item->area->SetMinimumSize(DEFAULT_WIDGET_WIDTH, 40);
00214     if (!icon)
00215     {
00216       menubar_item->area->SetMinimumSize(Max(MENU_MINIMUM_WIDTH, (unsigned int) (10 + GetFont()->GetStringWidth(MenuLabel))), Max(MENU_MINIMUM_WIDTH, (unsigned int) 16));
00217     }
00218     else
00219     {
00220       menubar_item->area->SetMinMaxSize(MENUBAR_ICON_WIDTH, MENUBAR_ICON_HEIGHT);
00221     }
00222 
00223     menubar_item->area->mouse_enter.connect(sigc::bind(sigc::mem_fun(this, &MenuBar::EmitItemMouseEnter), menubar_item));
00224     menubar_item->area->mouse_leave.connect(sigc::bind(sigc::mem_fun(this, &MenuBar::EmitItemMouseLeave), menubar_item));
00225     menubar_item->area->mouse_down.connect(sigc::bind(sigc::mem_fun(this, &MenuBar::EmitItemMouseDown), menubar_item));
00226     menubar_item->area->mouse_drag.connect(sigc::bind(sigc::mem_fun(this, &MenuBar::RecvItemMouseDrag), menubar_item));
00227     menubar_item->area->mouse_up.connect(sigc::bind(sigc::mem_fun(this, &MenuBar::EmitItemMouseUp), menubar_item));
00228 
00229     menubar_item->menu->SetParentMenu(0);
00230     menubar_item->menu->sigActionTriggered.connect(sigc::mem_fun(this, &MenuBar::RecvSigActionTriggered));
00231     menubar_item->menu->sigTerminateMenuCascade.connect(sigc::mem_fun(this, &MenuBar::RecvSigTerminateMenuCascade));
00232     menubar_item->menu->sigMouseDownOutsideMenuCascade.connect(sigc::mem_fun(this, &MenuBar::RecvSigMouseDownOutsideMenuCascade));
00233 
00234     m_hlayout->AddView(menubar_item->area, 0, eCenter);
00235     GetWindowThread()->ComputeElementLayout(m_hlayout);
00236   }
00237 
00238   void MenuBar::EmitItemMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags, MenuBarItem *menubar_item)
00239   {
00240     if (m_MenuIsActive)
00241     {
00242       if (m_CurrentMenu && (m_CurrentMenu->menu != menubar_item->menu))
00243         m_CurrentMenu->menu->StopMenu(0, 0);
00244 
00245       Geometry geo = menubar_item->menu->GetGeometry();
00246       menubar_item->menu->m_MenuWindow = m_MenuBarWindow;
00247       menubar_item->menu->StartMenu(menubar_item->area->GetBaseX(),
00248                                      menubar_item->area->GetBaseY() + menubar_item->area->GetBaseHeight(), 0, 0);
00249 
00250       m_CurrentMenu = menubar_item;
00251 
00252       m_IsOpeningMenu = true;
00253     }
00254 
00255     QueueDraw();
00256   }
00257 
00258   void MenuBar::EmitItemMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags, MenuBarItem *menubar_item)
00259   {
00260     QueueDraw();
00261   }
00262   void MenuBar::EmitItemMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags, MenuBarItem *menubar_item)
00263   {
00264     m_MenuBarWindow = GetWindowThread()->GetWindowCompositor().GetProcessingTopView();
00265 
00266     if (m_MenuIsActive == false)
00267     {
00268       // Open the corresponding MenuPage
00269       if (m_CurrentMenu)
00270       {
00271         // This should never happen
00272         nuxAssert(0);
00273         m_CurrentMenu->menu->StopMenu();
00274       }
00275 
00276       m_MenuIsActive = true;
00277       m_CurrentMenu = menubar_item;
00278       m_CurrentMenu->menu->m_MenuWindow = m_MenuBarWindow;
00279       m_IsOpeningMenu = true;
00280 
00281       m_CurrentMenu->menu->StartMenu(menubar_item->area->GetBaseX(),
00282                                       menubar_item->area->GetBaseY() + menubar_item->area->GetBaseHeight(), 0, 0);
00283     }
00284     else
00285     {
00286       // If the mouse up that follows happen inside the area, then it is going to close the menu.
00287       m_IsOpeningMenu = false;
00288     }
00289 
00290     QueueDraw();
00291   }
00292 
00293   void MenuBar::EmitItemMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags, MenuBarItem *menubar_item)
00294   {
00295     if (m_MenuIsActive)
00296     {
00297       if (m_CurrentMenu->area->IsMouseInside())
00298       {
00299         if (m_IsOpeningMenu == false)
00300         {
00301           // close the MenuPage that is Open
00302           if (m_CurrentMenu)
00303             m_CurrentMenu->menu->StopMenu(0, 0);
00304 
00305           m_MenuIsActive = false;
00306           m_CurrentMenu = 0;
00307         }
00308         else
00309         {
00310           // The MousePress before this MouseRelease, caused the MenuPage to open.
00311           // Set m_IsOpeningMenu so the next mouse release will close the menu.
00312           m_IsOpeningMenu = false;
00313         }
00314       }
00315       else
00316       {
00317         bool hit_inside_a_menu = false;
00318         bool b = m_CurrentMenu->menu->TestMouseUp(x, y, button_flags, key_flags, hit_inside_a_menu);
00319 
00320         if (b || (hit_inside_a_menu == false))
00321         {
00322           RecvSigTerminateMenuCascade();
00323         }
00324       }
00325     }
00326 
00327     QueueDraw();
00328   }
00329 
00330   void MenuBar::RecvItemMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags, MenuBarItem *menubar_item)
00331   {
00332     // TODO: Port to new event architecture
00333 //     // Transition between one menu bar item to another
00334 //     if (GetWindowThread()->GetWindowCompositor().GetMouseFocusArea() == menubar_item->area)
00335 //     {
00336 //       if (!menubar_item->area->IsMouseInside()) // can also test GetWindowThread()->GetWindowCompositor().GetMouseOverArea() != &menubar_item->area
00337 //       {
00338 //         std::list< MenuBarItem * >::iterator it;
00339 //         // compute window coordinates x and y;
00340 //         int winx = menubar_item->area->GetBaseX() + x;
00341 //         int winy = menubar_item->area->GetBaseY() + y;
00342 // 
00343 //         for (it = m_MenuBarItemList.begin(); it != m_MenuBarItemList.end(); it++)
00344 //         {
00345 //           InputArea *area = (*it)->area;
00346 //           Geometry geometry = area->GetGeometry();
00347 // 
00348 //           if (geometry.IsPointInside(winx, winy))
00349 //           {
00350 //             // Close the menu below menubar_item(the one that has the focus
00351 //             menubar_item->area->ForceStopFocus(0, 0);
00352 // 
00353 //             // EmitItemMouseEnter is going to open the menu below(*it)
00354 //             {
00355 //               EmitItemMouseEnter(winx, winy, button_flags, key_flags, (*it));
00356 //               m_IsOpeningMenu = true;
00357 //               area->ForceStartFocus(0, 0);
00358 // 
00359 //               GetWindowThread()->GetWindowCompositor().SetMouseFocusArea(area);
00360 //               GetWindowThread()->GetWindowCompositor().SetMouseOverArea(area);
00361 //             }
00362 // 
00363 //             break;
00364 //           }
00365 //         }
00366 //       }
00367 //     }
00368   }
00369 
00370   void MenuBar::RecvSigActionTriggered(MenuPage *menu, ActionItem *action)
00371   {
00372     m_MenuIsActive = false;
00373 
00374     if (m_CurrentMenu)
00375     {
00376       m_CurrentMenu->menu->StopMenu();
00377       QueueDraw();
00378     }
00379 
00380     m_CurrentMenu = 0;
00381     m_IsOpeningMenu = false;
00382 
00383     // You can do something if you want with the menu* and the action*
00384   }
00385 
00386 
00387   void MenuBar::RecvSigTerminateMenuCascade()
00388   {
00389     m_MenuIsActive = false;
00390 
00391     if (m_CurrentMenu)
00392     {
00393       m_CurrentMenu->menu->StopMenu();
00394     }
00395 
00396     m_CurrentMenu = 0;
00397     m_IsOpeningMenu = false;
00398 
00399     QueueDraw();
00400   }
00401 
00402   void MenuBar::RecvSigMouseDownOutsideMenuCascade(MenuPage *menu, int x, int y)
00403   {
00404     Geometry geometry;
00405     std::list< MenuBarItem * >::iterator it;
00406     bool TerminateMenuCascade = 1;
00407 
00408     for (it = m_MenuBarItemList.begin(); it != m_MenuBarItemList.end(); it++)
00409     {
00410       InputArea *area = (*it)->area;
00411       geometry = area->GetGeometry();
00412 
00413       if (geometry.IsPointInside(x, y))
00414       {
00415         // The event landed on one of the MenuBar item.
00416         // Do nothing. This will be handled in the ProcessEvent of the MenuBar item where the mouse down landed.
00417         TerminateMenuCascade = 0;
00418         break;
00419       }
00420     }
00421 
00422     if (TerminateMenuCascade)
00423       RecvSigTerminateMenuCascade();
00424   }
00425 
00426 
00427 }