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