nux-1.14.0
|
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 }