nux-1.14.0
MenuPage.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 "MenuPage.h"
00026 #include "WindowCompositor.h"
00027 #include "ActionItem.h"
00028 #include "VLayout.h"
00029 #include "StaticText.h"
00030 
00031 namespace nux
00032 {
00033 
00034   NUX_IMPLEMENT_OBJECT_TYPE (MenuItem);
00035   NUX_IMPLEMENT_OBJECT_TYPE (MenuSeparator);
00036   NUX_IMPLEMENT_OBJECT_TYPE (MenuPage);
00037 
00038   static const int MENU_ICONE_WIDTH = 18;
00039   static const int MENU_ICON_HEIGHT = 18;
00040   static const int MENU_ITEM_MIN_WIDTH = 90;
00041   static const int MENU_ITEM_MIN_HEIGHT = 20;
00042   static const int MENU_ITEM_BORDER_TO_ICON_MARGIN = 5;
00043   static const int MENU_ITEM_ICON_TO_TEXT_MARGIN = 5;
00044   static const int MENU_ITEM_TEXT_TO_BORDER_MARGIN = 5;
00045 
00046 // Algorithm:
00047 // To initiate the menu, the mouse has to hit one of the menu bar item (they hold the name of the menu that are displayed).
00048 // When that happens, the menu attached to the MenuBarItem gets the focus and becomes visible. Before the mouse is released,
00049 // the flag m_NextMouseUpMeanStop is set to FALSE, meaning that the following mouse up will not be processed by the menu, even if the released happened
00050 // outside of any of the menu forming the menu cascade. This way, the menu will remain open. There are exceptions to this however.
00051 // After the firs mouse down on the MenuBarItem and before the mouse up event, if the mouse over the the opened menu,
00052 // then m_NextMouseUpMeanStop is set to TRUE. If the mouse is released over an active menu item, the menu cascade will close itself.
00053 // If the mouse is released outside any of the menu forming the menu cascade, the menu will close itself.
00054 //
00055 //
00056 
00057 
00058   MenuItem::MenuItem (const TCHAR *label, int UserValue, NUX_FILE_LINE_DECL)
00059     :   View (NUX_FILE_LINE_PARAM)
00060   {
00061     _child_menu     = 0;
00062     _action_item    = new ActionItem (label, UserValue, NUX_TRACKER_LOCATION);
00063     
00064     _pango_static_text = new StaticText (label, NUX_TRACKER_LOCATION);
00065     _pango_static_text->SetTextColor (Color (0.0f, 0.0f, 0.0f, 1.0f));
00066   }
00067 
00068   MenuItem::~MenuItem()
00069   {
00070     _pango_static_text->Dispose ();
00071 
00072     if (_action_item)
00073       _action_item->UnReference ();
00074     if (_child_menu)
00075       _child_menu->UnReference ();
00076   }
00077 
00078   void MenuItem::SetChildMenu (MenuPage *menu)
00079   {
00080     nuxAssert(menu);
00081     NUX_RETURN_IF_NULL (menu);
00082 
00083     if (_child_menu)
00084       _child_menu->UnReference ();
00085     _child_menu = menu;
00086     _child_menu->Reference ();
00087   }
00088 
00089   MenuPage *MenuItem::GetChildMenu() const
00090   {
00091     return _child_menu;
00092   }
00093 
00094   void MenuItem::SetActionItem (ActionItem *action)
00095   {
00096     nuxAssertMsg (action != 0, TEXT ("[MenuItem::SetActionItem] Parameter is Null.") );
00097 
00098     if (action == 0)
00099       return;
00100 
00101     _pango_static_text->Dispose ();
00102     if (_action_item)
00103       _action_item->UnReference ();
00104     _action_item = action;
00105     _action_item->Reference();
00106 
00107     _pango_static_text = new StaticText (_action_item->GetLabel (), NUX_TRACKER_LOCATION);
00108   }
00109 
00110   ActionItem *MenuItem::GetActionItem() const
00111   {
00112     return _action_item;
00113   }
00114 
00115   int MenuItem::GetTextWidth ()
00116   {
00117     if (_pango_static_text)
00118     {
00119       int w, h;
00120       _pango_static_text->GetTextSize (w, h);
00121       return w;
00122     }
00123     return 0;
00124   }
00125 
00126   int MenuItem::GetTextHeight ()
00127   {
00128     if (_pango_static_text)
00129     {
00130       int w, h;
00131       _pango_static_text->GetTextSize (w, h);
00132       return h;
00133     }
00134     return 0;
00135   }
00136 
00137 
00138 //ActionItem* MenuItem::GetActionItem()
00139 //{
00140 //    return &_action_item;
00141 //}
00142 
00143   long MenuItem::ProcessEvent (IEvent &ievent, long TraverseInfo, long ProcessEventInfo)
00144   {
00145     return PostProcessEvent2 (ievent, TraverseInfo, ProcessEventInfo);
00146   }
00147 
00148   void MenuItem::Draw (GraphicsEngine &GfxContext, bool force_draw)
00149   {
00150 
00151   }
00152 
00153   void MenuItem::DrawAsMenuItem (GraphicsEngine &GfxContext, const Color &textcolor, bool is_highlighted, bool isFirstItem, bool isLastItem, bool draw_icone)
00154   {
00155     Geometry geo = GetGeometry ();
00156     Geometry icon_geo (0, 0, 20, 20);
00157     Geometry text_geo = geo;
00158 
00159     text_geo.OffsetPosition (24, 0);
00160     text_geo.OffsetSize (2 * 24, 0);
00161 
00162     icon_geo.SetX (geo.x + 2);
00163     icon_geo.SetY (geo.y + 0);
00164 
00165     const TCHAR *label = _action_item->GetLabel ();
00166 
00167     if (is_highlighted)
00168     {
00169       /*
00170           if(isFirstItem && isLastItem)
00171               GetPainter().PaintShape(GfxContext, geo, COLOR_FOREGROUND_SECONDARY, eSHAPE_CORNER_ROUND4);
00172           else if(isFirstItem)
00173               GetPainter().PaintShapeCorner(GfxContext, geo, COLOR_FOREGROUND_SECONDARY, eSHAPE_CORNER_ROUND4, eCornerTopLeft | eCornerTopRight);
00174           else if(isLastItem)
00175               GetPainter().PaintShapeCorner(GfxContext, geo, COLOR_FOREGROUND_SECONDARY, eSHAPE_CORNER_ROUND4, eCornerBottomLeft | eCornerBottomRight);
00176           else
00177               GetPainter().Paint2DQuadColor(GfxContext, geo, COLOR_FOREGROUND_SECONDARY);
00178       */
00179       GetPainter().Paint2DQuadColor (GfxContext, geo, Color (0x44000000) /*COLOR_FOREGROUND_SECONDARY*/);
00180       _pango_static_text->SetTextColor (Color (1.0f, 1.0f, 1.0f, 1.0f));
00181     }
00182     else
00183     {
00184       _pango_static_text->SetTextColor (Color (0.0f, 0.0f, 0.0f, 1.0f));
00185       //GetPainter().Paint2DQuadColor(GfxContext, geo, Color(0xFF868686));
00186     }
00187 
00188     //if(m_Icon)
00189     {
00190       //GetPainter().Draw2DTextureAligned(GfxContext, &_action_item->GetIcon(), icon_geo, TextureAlignmentStyle(eTACenter, eTACenter));
00191     }
00192 
00193     if (label)
00194     {
00195       //GetPainter().PaintTextLineStatic (GfxContext, GetFont (), text_geo, std::string (label), textcolor, eAlignTextLeft);
00196 
00197       _pango_static_text->SetGeometry (text_geo);
00198       _pango_static_text->ProcessDraw (GfxContext, true);
00199     }
00200   }
00201 
00202   MenuSeparator::MenuSeparator (NUX_FILE_LINE_DECL)
00203     :   View (NUX_FILE_LINE_PARAM)
00204   {
00205 
00206   }
00207 
00208   MenuSeparator::~MenuSeparator ()
00209   {
00210 
00211   }
00212 
00213   long MenuSeparator::ProcessEvent (IEvent &ievent, long TraverseInfo, long ProcessEventInfo)
00214   {
00215     return PostProcessEvent2 (ievent, TraverseInfo, ProcessEventInfo);
00216   }
00217 
00218   void MenuSeparator::Draw (GraphicsEngine &GfxContext, bool force_draw)
00219   {
00220     Geometry base = GetGeometry();
00221     int y0 = base.y + base.GetHeight() / 2;
00222     GetPainter().Draw2DLine (GfxContext, base.x, y0, base.x + base.GetWidth(), y0, Color(0xFF222222));
00223     GetPainter().Draw2DLine (GfxContext, base.x, y0 + 1, base.x + base.GetWidth(), y0 + 1, Color(0xFFAAAAAA));
00224   }
00225 
00226   MenuPage::MenuPage(const TCHAR *title, NUX_FILE_LINE_DECL)
00227   : View (NUX_FILE_LINE_PARAM)
00228   {
00229     m_Parent = 0;
00230     m_item_width = MENU_ITEM_MIN_WIDTH;
00231     m_item_height = MENU_ITEM_MIN_HEIGHT;
00232     m_show_item_icon = true;
00233     m_MenuWindow = 0;
00234     m_Name = title;
00235     m_IsTopOfMenuChain = false;
00236     _font_name = g_strdup("Ubuntu 12");
00237 
00238     on_closure_continue_with_event_ = false;
00239 
00240     // Set Original State
00241 
00242     // Set Signals
00243     mouse_move.connect(sigc::mem_fun(this, &MenuPage::EmitMouseMove));
00244     mouse_drag.connect(sigc::mem_fun(this, &MenuPage::EmitMouseDrag));
00245     mouse_down.connect(sigc::mem_fun(this, &MenuPage::EmitMouseDown));
00246     mouse_up.connect(sigc::mem_fun(this, &MenuPage::EmitMouseUp));
00247     mouse_leave.connect(sigc::mem_fun(this, &MenuPage::RecvMouseLeave));
00248     mouse_down_outside_pointer_grab_area.connect(sigc::mem_fun (this, &MenuPage::Terminate));
00249 
00250     // Set Geometry
00251     SetGeometry(Geometry (0, 0, DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT));
00252 
00253     // Set layout
00254 
00255     m_numItem = 0;
00256     m_HighlightedItem = -1;
00257     m_IsActive = false;
00258     m_NextMouseUpMeanStop = false;
00259     m_SubMenuAction = 0;
00260 
00261     _vlayout = new VLayout (NUX_TRACKER_LOCATION);
00262     // No Need to set a composition layout.
00263     // The MenuPage is floating above everything else.
00264     SetLayout(_vlayout);
00265 
00266     SetTextColor (color::Black);
00267   }
00268 
00269   MenuPage::~MenuPage ()
00270   {
00271 //     std::vector <MenuItem*>::iterator it;
00272 // 
00273 //     for (it = m_MenuItemVector.begin(); it != m_MenuItemVector.end(); it++)
00274 //     {
00275 //       (*it)->UnReference();
00276 //     }
00277     m_MenuItemVector.clear ();
00278     m_MenuSeparatorVector.clear ();
00279     RemoveLayout ();
00280   }
00281 
00282 //void MenuPage::SetName(const TCHAR* name)
00283 //{
00284 //    m_Name = name;
00285 //}
00286 //
00287   const TCHAR *MenuPage::GetName () const
00288   {
00289     return m_Name.GetTCharPtr ();
00290   }
00291 
00292   bool MenuPage::CanClose() const
00293   {
00294     return m_Action_Triggered;
00295   }
00296 
00297   long MenuPage::ProcessEvent (Event &ievent, long TraverseInfo, long ProcessEventInfo)
00298   {
00299     long ret = TraverseInfo;
00300 
00301     Event mod_event = ievent;
00302     mod_event.e_x_root = 0;
00303     mod_event.e_y_root = 0;
00304 
00305     if (m_IsActive)
00306     {
00307       if (mod_event.e_event == NUX_MOUSE_RELEASED)
00308       {
00309         Geometry geo = GetGraphicsDisplay()->GetWindowGeometry();
00310         geo.SetX (0);
00311         geo.SetY (0);
00312 
00313         if (!geo.IsPointInside (mod_event.e_x, mod_event.e_y) /*mod_event.e_x < 0 || mod_event.e_y < 0*/)
00314         {
00315           // the event happened outside the window.
00316           NotifyTerminateMenuCascade();
00317         }
00318         else
00319         {
00320           EmitMouseUp (mod_event.e_x - GetBaseX(), mod_event.e_y - GetBaseY(), mod_event.GetMouseState(), mod_event.GetKeyState() );
00321         }
00322       }
00323       else if (mod_event.e_event == NUX_MOUSE_PRESSED)
00324       {
00325         Geometry geo = GetGraphicsDisplay()->GetWindowGeometry();
00326         geo.SetX (0);
00327         geo.SetY (0);
00328 
00329         if (!geo.IsPointInside (mod_event.e_x, mod_event.e_y) /*mod_event.e_x < 0 || mod_event.e_y < 0*/)
00330         {
00331           // the event happened outside the window.
00332           NotifyTerminateMenuCascade();
00333         }
00334         else
00335         {
00336           ret = PostProcessEvent2 (mod_event, ret, ProcessEventInfo);
00337         }
00338       }
00339       else if (mod_event.e_event == NUX_WINDOW_CONFIGURATION)
00340       {
00341         NotifyTerminateMenuCascade();
00342       }
00343       else if (mod_event.e_event == NUX_WINDOW_EXIT_FOCUS)
00344       {
00345         NotifyTerminateMenuCascade();
00346       }
00347       else
00348       {
00349         if (mod_event.e_event == NUX_MOUSE_MOVE)
00350           QueueDraw ();
00351 
00352         ret = PostProcessEvent2 (mod_event, ret, ProcessEventInfo);
00353       }
00354     }
00355 
00356     if (GetGeometry ().IsPointInside (mod_event.GetX (), mod_event.GetY ()))
00357     {
00358       ret |= eMouseEventSolved;
00359     }
00360 
00361     return ret;
00362   };
00363 
00364   Area* MenuPage::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type)
00365   {
00366     bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type);
00367 
00368     if(mouse_inside == false)
00369       return NULL;
00370 
00371     if((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent()))
00372       return NULL;
00373     return this;
00374   }
00375 
00376   void MenuPage::Draw (GraphicsEngine &GfxContext, bool force_draw)
00377   {
00378     if (m_IsActive)
00379     {
00380       Geometry base = GetGeometry ();
00381       Geometry shadow;
00382       shadow = base;
00383       shadow.OffsetPosition (4, 4);
00384       //GetPainter().PaintShape(GfxContext, shadow, Color(0xFF000000), eSHAPE_CORNER_ROUND4_SHADOW);
00385 
00386       GfxContext.PushClippingRectangle (base);
00387       GfxContext.GetRenderStates ().SetBlend (GL_TRUE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00388       GetPainter ().Paint2DQuadColor (GfxContext, base, Color (0xCCFFFFFF) );
00389       GfxContext.GetRenderStates ().SetBlend (GL_FALSE);
00390 
00391       Geometry text_area;
00392       text_area.SetX (base.x);
00393       text_area.SetY (base.y);
00394       text_area.SetWidth (base.GetWidth ());
00395       text_area.SetHeight (PRACTICAL_WIDGET_HEIGHT);
00396 
00397       int i;
00398       std::vector<MenuItem *>::iterator it;
00399       int numItem = (int) m_MenuItemVector.size ();
00400 
00401       for (it = m_MenuItemVector.begin (), i = 0; it != m_MenuItemVector.end (); it++, i++)
00402       {
00403         bool is_highlighted = (m_HighlightedItem == i);
00404         (*it)->DrawAsMenuItem (GfxContext, Color (0xFFFFFFFF) /*GetTextColor()*/, is_highlighted, i == 0, i == (numItem - 1), true);
00405       }
00406 
00407       std::vector<MenuSeparator* >::iterator separator_iterator;
00408 
00409       for (separator_iterator = m_MenuSeparatorVector.begin (); separator_iterator != m_MenuSeparatorVector.end (); separator_iterator++)
00410       {
00411         (*separator_iterator)->Draw (GfxContext, force_draw);
00412       }
00413 
00414       GfxContext.PopClippingRectangle ();
00415     }
00416   }
00417 
00418   void MenuPage::DrawContent (GraphicsEngine &GfxContext, bool force_draw)
00419   {
00420 
00421   }
00422 
00423   void MenuPage::PostDraw (GraphicsEngine &GfxContext, bool force_draw)
00424   {
00425 
00426   }
00427 
00428   void MenuPage::SetFontName (char *font_name)
00429   {
00430     std::vector<MenuItem *>::iterator it;
00431     
00432     for (it = m_MenuItemVector.begin(); it != m_MenuItemVector.end(); ++it)
00433     {
00434       (*it)->GetStaticText ()->SetFontName (font_name);
00435     }
00436 
00437     g_free (_font_name);
00438     _font_name = g_strdup (font_name);
00439   }
00440 
00441   ActionItem *MenuPage::AddAction (const TCHAR *label, int UserValue)
00442   {
00443     // pMenuItem if added to the layout do not sink the Reference.
00444     MenuItem *pMenuItem (new MenuItem (label, UserValue, NUX_TRACKER_LOCATION) );
00445     pMenuItem->GetStaticText ()->SetFontName (_font_name);
00446 
00447     m_MenuItemVector.push_back (pMenuItem);
00448     pMenuItem->SetMinimumSize (DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT);
00449 
00450     int new_item_width = pMenuItem->GetTextWidth(); //GetFont ()->GetStringWidth (pMenuItem->GetActionItem()->GetLabel() );
00451 
00452     if (new_item_width < m_item_width)
00453     {
00454       std::vector<MenuItem *>::iterator it;
00455       for (it = m_MenuItemVector.begin(); it != m_MenuItemVector.end(); it++)
00456       {
00457         if (ShowItemIcon() )
00458         {
00459           pMenuItem->SetMinMaxSize (MENU_ITEM_BORDER_TO_ICON_MARGIN
00460                                     + MENU_ICONE_WIDTH
00461                                     + MENU_ITEM_ICON_TO_TEXT_MARGIN
00462                                     + m_item_width
00463                                     + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00464         }
00465         else
00466         {
00467           pMenuItem->SetMinMaxSize (MENU_ITEM_ICON_TO_TEXT_MARGIN
00468                                     + m_item_width
00469                                     + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00470         }
00471       }
00472     }
00473     else
00474     {
00475       std::vector<MenuItem *>::iterator it;
00476       for (it = m_MenuItemVector.begin(); it != m_MenuItemVector.end(); it++)
00477       {
00478         if (ShowItemIcon() )
00479         {
00480           (*it)->SetMinMaxSize (MENU_ITEM_BORDER_TO_ICON_MARGIN
00481                                     + MENU_ICONE_WIDTH
00482                                     + MENU_ITEM_ICON_TO_TEXT_MARGIN
00483                                     + new_item_width
00484                                     + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00485         }
00486         else
00487         {
00488           (*it)->SetMinMaxSize (MENU_ITEM_ICON_TO_TEXT_MARGIN
00489                                     + new_item_width
00490                                     + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00491         }
00492 
00493         (*it)->SetBaseSize (MENU_ITEM_ICON_TO_TEXT_MARGIN
00494                             + new_item_width
00495                             + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00496       }
00497 
00498       m_item_width = new_item_width;
00499 //       SetBaseWidth (MENU_ITEM_ICON_TO_TEXT_MARGIN
00500 //                     + m_item_width
00501 //                     + MENU_ITEM_TEXT_TO_BORDER_MARGIN);
00502     }
00503 
00504     if (pMenuItem->GetChildMenu() != 0)
00505     {
00506       pMenuItem->GetChildMenu()->SetParentMenu (this);
00507     }
00508 
00509     m_numItem = (int) m_MenuItemVector.size();
00510     _vlayout->AddView (pMenuItem, 0, eLeft, eFix);
00511     ComputeChildLayout();
00512 
00513     return pMenuItem->GetActionItem();
00514   }
00515 
00516 //void MenuPage::AddActionItem(ActionItem* actionItem)
00517 //{
00518 //    nuxAssertMsg(actionItem != 0, TEXT("[MenuPage::AddActionItem] Parameter is Null."));
00519 //    if(actionItem == 0)
00520 //        return;
00521 //
00522 //     MenuItem* pMenuItem = new MenuItem(actionItem->GetLabel(), actionItem->GetUserValue(), NUX_TRACKER_LOCATION);
00523 //     pMenuItem->SinkReference ();
00524 //    pMenuItem->SetActionItem(actionItem);
00525 //
00526 //    m_MenuItemVector.push_back(pMenuItem);
00527 //    pMenuItem->SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT);
00528 //
00529 //    int new_item_width = GetFont ()->GetStringWidth(actionItem->GetLabel());
00530 //    if(new_item_width < m_item_width)
00531 //    {
00532 //        if(ShowItemIcon())
00533 //        {
00534 //            pMenuItem->SetMinMaxSize(MENU_ITEM_BORDER_TO_ICON_MARGIN
00535 //                + MENU_ICONE_WIDTH
00536 //                + MENU_ITEM_ICON_TO_TEXT_MARGIN
00537 //                + m_item_width
00538 //                + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00539 //        }
00540 //        else
00541 //        {
00542 //            pMenuItem->SetMinMaxSize(MENU_ITEM_ICON_TO_TEXT_MARGIN
00543 //                + m_item_width
00544 //                + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00545 //        }
00546 //    }
00547 //    else
00548 //    {
00549 //        if(ShowItemIcon())
00550 //        {
00551 //            pMenuItem->SetMinMaxSize(MENU_ITEM_BORDER_TO_ICON_MARGIN
00552 //                + MENU_ICONE_WIDTH
00553 //                + MENU_ITEM_ICON_TO_TEXT_MARGIN
00554 //                + new_item_width
00555 //                + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00556 //        }
00557 //        else
00558 //        {
00559 //            pMenuItem->SetMinMaxSize(MENU_ITEM_ICON_TO_TEXT_MARGIN
00560 //                + new_item_width
00561 //                + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00562 //        }
00563 //
00564 //        std::vector<MenuItem*>::iterator it;
00565 //        for(it = m_MenuItemVector.begin(); it != m_MenuItemVector.end(); it++)
00566 //        {
00567 //            (*it)->setSize(MENU_ITEM_ICON_TO_TEXT_MARGIN
00568 //                + new_item_width
00569 //                + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00570 //        }
00571 //
00572 //        m_item_width = new_item_width;
00573 //        SetWidth(MENU_ITEM_ICON_TO_TEXT_MARGIN
00574 //            + m_item_width
00575 //            + MENU_ITEM_TEXT_TO_BORDER_MARGIN);
00576 //    }
00577 //
00578 //    if(pMenuItem->GetChildMenu() != 0)
00579 //    {
00580 //        pMenuItem->GetChildMenu()->SetParentMenu(this);
00581 //    }
00582 //
00583 //    m_numItem = (int)m_MenuItemVector.size();
00584 //    _vlayout->AddView(pMenuItem, 0, eLeft, eFix);
00585 //    ComputeChildLayout();
00586 //}
00587 
00588   MenuPage *MenuPage::AddMenu (const TCHAR *label)
00589   {
00590     // pMenuItem if added to the layout do not sink the Reference.
00591     MenuItem *pMenuItem (new MenuItem (label, 0, NUX_TRACKER_LOCATION));
00592 
00593     pMenuItem->SetChildMenu (new MenuPage (label) );
00594     //pMenuItem->SetActionItem(new ActionItem());
00595     //pMenuItem->GetActionItem()->SetLabel(label);
00596     m_MenuItemVector.push_back (pMenuItem);
00597     pMenuItem->SetMinimumSize (DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT);
00598 
00599     int new_item_width = pMenuItem->GetTextWidth(); //GetFont ()->GetStringWidth (label);
00600 
00601     if (new_item_width < m_item_width)
00602     {
00603       if (ShowItemIcon() )
00604       {
00605         pMenuItem->SetMinMaxSize (MENU_ITEM_BORDER_TO_ICON_MARGIN
00606                                   + MENU_ICONE_WIDTH
00607                                   + MENU_ITEM_ICON_TO_TEXT_MARGIN
00608                                   + m_item_width
00609                                   + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00610       }
00611       else
00612       {
00613         pMenuItem->SetMinMaxSize (MENU_ITEM_ICON_TO_TEXT_MARGIN
00614                                   + m_item_width
00615                                   + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00616       }
00617     }
00618     else
00619     {
00620       if (ShowItemIcon() )
00621       {
00622         pMenuItem->SetMinMaxSize (MENU_ITEM_BORDER_TO_ICON_MARGIN
00623                                   + MENU_ICONE_WIDTH
00624                                   + MENU_ITEM_ICON_TO_TEXT_MARGIN
00625                                   + new_item_width
00626                                   + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00627       }
00628       else
00629       {
00630         pMenuItem->SetMinMaxSize (MENU_ITEM_ICON_TO_TEXT_MARGIN
00631                                   + new_item_width
00632                                   + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00633       }
00634 
00635       std::vector< MenuItem * >::iterator it;
00636 
00637       for (it = m_MenuItemVector.begin(); it != m_MenuItemVector.end(); it++)
00638       {
00639         (*it)->SetBaseSize (MENU_ITEM_ICON_TO_TEXT_MARGIN
00640                             + new_item_width
00641                             + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00642       }
00643 
00644       m_item_width = new_item_width;
00645       SetBaseWidth (MENU_ITEM_ICON_TO_TEXT_MARGIN
00646                     + m_item_width
00647                     + MENU_ITEM_TEXT_TO_BORDER_MARGIN);
00648     }
00649 
00650     if (pMenuItem->GetChildMenu() != 0)
00651     {
00652       pMenuItem->GetChildMenu()->SetParentMenu (this);
00653     }
00654 
00655     m_numItem = (int) m_MenuItemVector.size();
00656     _vlayout->AddView (pMenuItem, 0, eLeft, eFix);
00657     ComputeChildLayout();
00658 
00659     return pMenuItem->GetChildMenu();
00660   }
00661 
00662   ActionItem *MenuPage::AddSubMenu (const TCHAR *label, MenuPage *menu)
00663   {
00664     menu->m_IsTopOfMenuChain = false;
00665     // pMenuItem if added to the layout do not sink the Reference.
00666     MenuItem *pMenuItem (new MenuItem (menu->GetName(), 0, NUX_TRACKER_LOCATION));
00667     
00668     pMenuItem->SetChildMenu (menu);
00669     m_MenuItemVector.push_back (pMenuItem);
00670     pMenuItem->SetMinimumSize (DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT);
00671 
00672     int new_item_width = pMenuItem->GetTextWidth(); //GetFont ()->GetStringWidth (label);
00673 
00674     if (new_item_width < m_item_width)
00675     {
00676       if (ShowItemIcon() )
00677       {
00678         pMenuItem->SetMinMaxSize (MENU_ITEM_BORDER_TO_ICON_MARGIN
00679                                   + MENU_ICONE_WIDTH
00680                                   + MENU_ITEM_ICON_TO_TEXT_MARGIN
00681                                   + m_item_width
00682                                   + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00683       }
00684       else
00685       {
00686         pMenuItem->SetMinMaxSize (MENU_ITEM_ICON_TO_TEXT_MARGIN
00687                                   + m_item_width
00688                                   + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00689       }
00690     }
00691     else
00692     {
00693       if (ShowItemIcon() )
00694       {
00695         pMenuItem->SetMinMaxSize (MENU_ITEM_BORDER_TO_ICON_MARGIN
00696                                   + MENU_ICONE_WIDTH
00697                                   + MENU_ITEM_ICON_TO_TEXT_MARGIN
00698                                   + new_item_width
00699                                   + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00700       }
00701       else
00702       {
00703         pMenuItem->SetMinMaxSize (MENU_ITEM_ICON_TO_TEXT_MARGIN
00704                                   + new_item_width
00705                                   + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00706       }
00707 
00708       std::vector< MenuItem * >::iterator it;
00709 
00710       for (it = m_MenuItemVector.begin(); it != m_MenuItemVector.end(); it++)
00711       {
00712         (*it)->SetBaseSize (MENU_ITEM_ICON_TO_TEXT_MARGIN
00713                             + new_item_width
00714                             + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height);
00715       }
00716 
00717       m_item_width = new_item_width;
00718       SetBaseWidth (MENU_ITEM_ICON_TO_TEXT_MARGIN
00719                     + m_item_width
00720                     + MENU_ITEM_TEXT_TO_BORDER_MARGIN);
00721     }
00722 
00723     if (pMenuItem->GetChildMenu() != 0)
00724     {
00725       pMenuItem->GetChildMenu()->SetParentMenu (this);
00726     }
00727 
00728     m_numItem = (int) m_MenuItemVector.size();
00729     _vlayout->AddView (pMenuItem, 0, eLeft, eFix);
00730     ComputeChildLayout();
00731 
00732     return pMenuItem->GetActionItem();
00733   }
00734 
00735   void MenuPage::AddSeparator()
00736   {
00737     // pMenuSeparator if added to the layout do not sink the Reference.
00738     MenuSeparator *pMenuSeparator (new MenuSeparator(NUX_TRACKER_LOCATION) );
00739 
00740     m_MenuSeparatorVector.push_back (pMenuSeparator);
00741 
00742     if (ShowItemIcon() )
00743     {
00744       pMenuSeparator->SetMinMaxSize (MENU_ITEM_BORDER_TO_ICON_MARGIN
00745                                      + MENU_ICONE_WIDTH
00746                                      + MENU_ITEM_ICON_TO_TEXT_MARGIN
00747                                      + m_item_width
00748                                      + MENU_ITEM_TEXT_TO_BORDER_MARGIN, 4);
00749     }
00750     else
00751     {
00752       pMenuSeparator->SetMinMaxSize (MENU_ITEM_ICON_TO_TEXT_MARGIN
00753                                      + m_item_width
00754                                      + MENU_ITEM_TEXT_TO_BORDER_MARGIN, 4);
00755     }
00756 
00757     _vlayout->AddView (pMenuSeparator, 0, eLeft, eFix);
00758     ComputeChildLayout();
00759   }
00760 
00761   void MenuPage::RemoveItem (ActionItem *item)
00762   {
00763   }
00764 
00765   void MenuPage::RemoveAllItem()
00766   {
00767     m_MenuSeparatorVector.clear();
00768     m_MenuItemVector.clear();
00769     m_numItem = 0;
00770     _vlayout->Clear();
00771     ComputeChildLayout();
00772    
00773     //FIXME - Hack to fix a bug with the menu height not being reset after removing items
00774     Geometry base = GetGeometry ();
00775     base.height = 0;
00776     View::SetGeometry (base);
00777   }
00778 
00779   void MenuPage::EmitMouseMove (int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags)
00780   {
00781     if (IsMouseInside ())
00782     {
00783       m_NextMouseUpMeanStop = true;
00784       // Find on which item the mouse is
00785       std::vector< MenuItem * >::iterator item_iterator;
00786       t_u32 i = 0;
00787       m_HighlightedItem = -1;
00788 
00789       for (item_iterator = m_MenuItemVector.begin(), i = 0; item_iterator != m_MenuItemVector.end(); item_iterator++, i++)
00790       {
00791         int MenuY = GetBaseY();
00792         int py = (*item_iterator)->GetBaseY() - MenuY;
00793         int height = (*item_iterator)->GetBaseHeight();
00794 
00795         if ((y >= py) && (y < py + height))
00796         {
00797           m_HighlightedItem = i;
00798           QueueDraw();
00799           break;
00800         }
00801       }
00802     }
00803     else
00804     {
00805       if(m_HighlightedItem != -1)
00806       {
00807         m_HighlightedItem = -1;
00808         QueueDraw();
00809       }
00810     }
00811 
00812     if (m_HighlightedItem >= 0)
00813     {
00814       MenuItem *selected_action = m_MenuItemVector[m_HighlightedItem];
00815 
00816       if((selected_action->GetChildMenu() != 0) && selected_action->GetActionItem()->isEnabled())
00817       {
00818         // This MenuItem has a sub-MenuPage. Start it.
00819         Geometry geo = selected_action->GetGeometry();
00820         selected_action->GetChildMenu()->m_MenuWindow = selected_action->GetChildMenu()->GetParentMenu()->m_MenuWindow;
00821         selected_action->GetChildMenu()->StartMenu (geo.x + geo.GetWidth() - 5, geo.y, 0, 0);
00822 
00823         // The current SubMenu is not the same as the new one...
00824         if(m_SubMenuAction != selected_action)
00825         {
00826           // If m_SubMenuAction is not null then stop the sub menu
00827           StopActionSubMenu();
00828           // Set the Action that holds the SubMenu.
00829           m_SubMenuAction = selected_action;
00830         }
00831       }
00832       else
00833       {
00834         StopActionSubMenu();
00835       }
00836     }
00837   }
00838 
00839   void MenuPage::EmitMouseDown (int x, int y, unsigned long button_flags, unsigned long key_flags)
00840   {
00841     m_NextMouseUpMeanStop = true;
00842 
00843     EmitMouseMove (x, y, 0, 0, button_flags, key_flags);
00844   }
00845 
00846   void MenuPage::EmitMouseUp (int x, int y, unsigned long button_flags, unsigned long key_flags)
00847   {
00848     if (m_NextMouseUpMeanStop == false)
00849     {
00850       ForceStopFocus (0, 0);
00851       m_NextMouseUpMeanStop = true;
00852       return;
00853     }
00854 
00855     m_Action_Triggered = false;
00856 
00857     bool hit_inside_a_menu = false;
00858 
00859     if (m_SubMenuAction)
00860     {
00861       m_Action_Triggered = m_SubMenuAction->GetChildMenu()->TestMouseUp (x, y, button_flags, key_flags, hit_inside_a_menu);
00862     }
00863 
00864     if (m_Action_Triggered == false)
00865     {
00866       if (IsMouseInside() )
00867       {
00868         if (m_SubMenuAction)
00869         {
00870           m_Action_Triggered = false;
00871         }
00872         else if (m_HighlightedItem != -1)
00873         {
00874           if (m_MenuItemVector[m_HighlightedItem]->GetActionItem()->isEnabled() == false)
00875           {
00876             // Do nothing. We don't want to close the menu when we release the mouse over an action that is not Enabled.
00877             m_Action_Triggered = false;
00878           }
00879           else
00880           {
00881             m_Action_Triggered = true;
00882             // Fire the Action Here
00883             ExecuteActionItem (m_MenuItemVector[m_HighlightedItem]);
00884             NotifyActionTriggeredToParent (this, m_MenuItemVector[m_HighlightedItem]);
00885           }
00886         }
00887       }
00888       else
00889       {
00890         // Bellow the Mouse, there was no MenuPage when the MouseUp happened.
00891         if (hit_inside_a_menu == false)
00892         {
00893           // Terminate the MenuPage cascade
00894           NotifyTerminateMenuCascade();
00895         }
00896       }
00897     }
00898   }
00899 
00900   bool MenuPage::TestMouseUp (int x, int y, unsigned long button_flags, unsigned long key_flags, bool &hit_inside_a_menu)
00901   {
00902     m_Action_Triggered = false;
00903 
00904     if (m_SubMenuAction)
00905     {
00906       m_Action_Triggered = m_SubMenuAction->GetChildMenu()->TestMouseUp (x, y, button_flags, key_flags, hit_inside_a_menu);
00907     }
00908 
00909     if (m_Action_Triggered == false)
00910     {
00911       if (IsMouseInside() )
00912       {
00913         hit_inside_a_menu = true;
00914 
00915         if (m_SubMenuAction)
00916         {
00917           m_Action_Triggered = false;
00918           // Do nothing. We don't want to close the menu when we are above an action that has a submenu.
00919         }
00920         else if (m_HighlightedItem != -1)
00921         {
00922           if (m_MenuItemVector[m_HighlightedItem]->GetActionItem()->isEnabled() == false)
00923           {
00924             // Do nothing. We don't want to close the menu when we release the mouse over an action that is not Enabled.
00925             m_Action_Triggered = false;
00926           }
00927           else
00928           {
00929             m_Action_Triggered = true;
00930             // Fire the Action Here
00931             ExecuteActionItem (m_MenuItemVector[m_HighlightedItem]);
00932             NotifyActionTriggeredToParent (this, m_MenuItemVector[m_HighlightedItem]);
00933             // But Do not emit the Stop
00934             //sigPopupStop.emit();
00935           }
00936         }
00937       }
00938     }
00939 
00940     if (m_Action_Triggered)
00941       return true;
00942 
00943     return false;
00944   }
00945 
00946   bool MenuPage::TestMouseDown()
00947   {
00948     bool b = false;
00949 
00950     if (m_SubMenuAction)
00951     {
00952       b = m_SubMenuAction->GetChildMenu()->TestMouseDown();
00953     }
00954 
00955     if (b)
00956     {
00957       return true;
00958     }
00959     else
00960     {
00961       return IsMouseInside();
00962     }
00963   }
00964 
00965   void MenuPage::EmitMouseDrag (int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags)
00966   {
00967     if (IsMouseInside() )
00968       EmitMouseMove (x, y, 0, 0, button_flags, key_flags);
00969   }
00970 
00971   void MenuPage::RecvMouseLeave (int x, int y, unsigned long button_flags, unsigned long key_flags)
00972   {
00973     // Cancel selected item when the mouse is out.
00974     if (m_HighlightedItem != -1)
00975     {
00976       MenuItem *item = m_MenuItemVector[m_HighlightedItem];
00977 
00978       if (item->GetChildMenu() )
00979       {
00980         if (!item->GetChildMenu()->IsActive() )
00981         {
00982           m_HighlightedItem = -1;
00983         }
00984       }
00985       else
00986       {
00987         m_HighlightedItem = -1;
00988       }
00989     }
00990 
00991     QueueDraw();
00992   }
00993 
00994   void MenuPage::StartMenu (int MenuXPosition, int MenuYPosition, int x, int y, bool OverrideCurrentMenuChain)
00995   {
00996     Geometry base = GetGeometry();
00997     base.SetX (MenuXPosition);
00998     base.SetY (MenuYPosition);
00999 
01000     int WindowWidth = GetGraphicsEngine().GetWindowWidth();
01001     int WindowHeight = GetGraphicsEngine().GetWindowHeight();
01002 
01003     // Correct the position of the MenuPage if is going out of the screen
01004     // The first page of a menu chain has less opportunities to be adjusted than its child pages.
01005     // The first page of a menu chain has (GetParentMenu() == 0) return true.
01006     int MenuLeft = base.x + base.GetWidth() + 5;
01007 
01008     if (MenuLeft > WindowWidth)
01009     {
01010       base.OffsetPosition (WindowWidth - MenuLeft, 0);
01011     }
01012 
01013     int MenuRight = base.x;
01014 
01015     if ( (MenuRight < 0) && (GetParentMenu() != 0) )
01016     {
01017       base.OffsetPosition (-MenuRight, 0);
01018     }
01019 
01020     int MenuBottom = base.y + base.GetHeight() + 5;
01021 
01022     if ( (MenuBottom > WindowHeight) && (GetParentMenu() != 0) )
01023     {
01024       base.OffsetPosition (0, WindowHeight - MenuBottom);
01025     }
01026 
01027     int MenuTop = base.y - 5;
01028 
01029     if ( (MenuTop < 0) && (GetParentMenu() != 0) )
01030     {
01031       base.OffsetPosition (0, -MenuTop);
01032     }
01033 
01034     SetGeometry (base);
01035 
01036     SetActive (true);
01037 
01038     // Add the menu to the stack manager popup list.
01039     if (GetParentMenu() == 0)
01040     {
01041       // This is the head of the menu chain
01042       m_MenuWindow = GetWindowCompositor().GetProcessingTopView();
01043     }
01044 
01045     GetWindowCompositor().AddMenu (this, m_MenuWindow/*, OverrideCurrentMenuChain*/);
01046     m_NextMouseUpMeanStop = false;
01047 
01048     StopActionSubMenu();
01049   }
01050 
01051   void MenuPage::StopMenu (int x, int y)
01052   {
01053     SetActive (false);
01054     ForceStopFocus (x, y);
01055     // The Stack Manager will remove all popup that are not visible anymore
01056     m_NextMouseUpMeanStop = false;
01057     m_HighlightedItem = -1;
01058 
01059     StopActionSubMenu();
01060 
01061     // The MenuPage does not need to be redrawn, but in embedded mode, this triggers a dirty Area on 
01062     // the BaseWindow and it informs the system to update this egion of the screen
01063     // (where the menu is about to disappear).
01064     QueueDraw ();
01065 
01066     /*Area *top_area = GetWindowCompositor().GetProcessingTopView ();
01067     if (top_area)
01068     {
01069       if (top_area->IsView ())
01070       {
01071         NUX_STATIC_CAST (View*, top_area)->QueueDraw ();
01072       }
01073       
01074       if (top_area->IsLayout ())
01075       {
01076         NUX_STATIC_CAST (Layout*, top_area)->QueueDraw ();
01077       }
01078     }*/
01079   }
01080 
01081 // Never call this function directly
01082   void MenuPage::Terminate (int x, int y, unsigned long button_flags, unsigned long key_flags)
01083   {
01084   }
01085 
01086   void MenuPage::StopActionSubMenu()
01087   {
01088     if (m_SubMenuAction)
01089     {
01090       if (m_SubMenuAction->GetChildMenu() )
01091       {
01092         m_SubMenuAction->GetChildMenu()->StopMenu (0, 0);
01093       }
01094     }
01095 
01096     m_SubMenuAction = 0;
01097   }
01098 
01099   void MenuPage::ExecuteActionItem (MenuItem *menuItem)
01100   {
01101     menuItem->GetActionItem()->Trigger();
01102   }
01103 
01104   void MenuPage::NotifyActionTriggeredToParent (MenuPage *menu, MenuItem *menuItem)
01105   {
01106     if (m_Parent)
01107     {
01108       m_Parent->NotifyActionTriggeredToParent (menu, menuItem);
01109     }
01110     else
01111     {
01112       sigActionTriggered.emit (menu, menuItem->GetActionItem() );
01113     }
01114 
01115     StopMenu();
01116   }
01117 
01118   void MenuPage::NotifyTerminateMenuCascade()
01119   {
01120     if (m_Parent)
01121     {
01122       m_Parent->NotifyTerminateMenuCascade();
01123     }
01124     else
01125     {
01126       sigTerminateMenuCascade.emit();
01127     }
01128 
01129 //     if(IsActive())
01130 //     {
01131 //         StopMenu();
01132 //     }
01133   }
01134 
01135   void MenuPage::NotifyMouseDownOutsideMenuCascade (int x, int y)
01136   {
01137     if (m_Parent)
01138     {
01139       m_Parent->NotifyMouseDownOutsideMenuCascade (x, y);
01140     }
01141     else
01142     {
01143       // This is the top MenuPage in a menu chain.
01144       // If this MenuPage has been registered with a MenuBar, then the MenuBar will intercept this signal
01145       // and terminate the menu chain.
01146       sigMouseDownOutsideMenuCascade.emit (this, x, y);
01147 
01148       // It is also possible that this MenuPage is not associated to a MenuBar (called directly for a contextual menu)
01149       if (m_IsTopOfMenuChain == false)
01150       {
01151         // This MenuPage is not attached to a MenuBar
01152         if (IsActive() )
01153         {
01154           //StopMenu();
01155         }
01156       }
01157     }
01158   }
01159 
01160   void MenuPage::SetParentMenu (MenuPage *parent)
01161   {
01162     m_Parent = parent;
01163   }
01164 
01165   MenuPage *MenuPage::GetParentMenu()
01166   {
01167     return m_Parent;
01168   }
01169 
01170   long MenuPage::ComputeChildLayout()
01171   {
01172     return View::ComputeChildLayout();
01173   }
01174 
01175   void MenuPage::SetGeometry (const Geometry &geo)
01176   {
01177     // The MenuPage widget cannot be resized by the client. The menu widget controls its own size.
01178 
01179     Geometry base = GetGeometry();
01180     // We are only interested in the position X/Y. The popup figures out its width and height by itself.
01181     base.SetX (geo.x);
01182     base.SetY (geo.y);
01183 
01184     base.SetWidth (geo.GetWidth() );
01185     base.SetHeight (m_numItem * PRACTICAL_WIDGET_HEIGHT);
01186 
01187     SetBaseXY (geo.x, geo.y);
01188 
01189     PositionChildLayout (0, 0);
01190   }
01191 
01192   ActionItem *MenuPage::GetActionItem (int index) const
01193   {
01194     nuxAssert (index >= 0);
01195 
01196     if (index >= (int) m_MenuItemVector.size() )
01197       return 0;
01198 
01199     return m_MenuItemVector[index]->GetActionItem();
01200   }
01201 
01202   int MenuPage::GetActionItemIndex (ActionItem *action) const
01203   {
01204     if (action == 0)
01205       return -1;
01206 
01207     for (int i = 0; i < (int) m_MenuItemVector.size(); i++)
01208     {
01209       if (action == m_MenuItemVector[i]->GetActionItem() )
01210       {
01211         return i;
01212       }
01213     }
01214 
01215     return -1;
01216   }
01217 
01218   Geometry MenuPage::GetAbsoluteGeometry () const
01219   {
01220     return GetGeometry();  
01221   }
01222 
01223   Geometry MenuPage::GetRootGeometry () const
01224   {
01225     return GetGeometry();
01226   }
01227 
01228   void MenuPage::SetOnClosureContinueEventCycle(bool on_closure_continue_with_event)
01229   {
01230     on_closure_continue_with_event_ = on_closure_continue_with_event;
01231   }
01232 
01233   bool MenuPage::OnClosureContinueEventCycle() const
01234   {
01235     return on_closure_continue_with_event_;
01236   }
01237 }
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends