Back to index

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