From 5b7528754df83835624e2536e13c848deb58ac93 Mon Sep 17 00:00:00 2001 From: Stefano Ceccherini Date: Tue, 4 Jan 2005 12:59:49 +0000 Subject: [PATCH] The frame around the BMenu is now drawn by a special class (as happens in beos), and not by BMenu::DrawBackground(). Refactored BMenuWindow to support scrolling (not implemented yet). The AddItem() functions now call the private _AddItem(). Implemented AddList(), but it's not tested. BMenus are now offsetted by 2, 2, as in BeOS. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10582 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kits/interface/Menu.cpp | 143 ++++++++++++++++-------------- src/kits/interface/MenuBar.cpp | 16 ++-- src/kits/interface/MenuWindow.cpp | 60 ++++++++----- 3 files changed, 124 insertions(+), 95 deletions(-) diff --git a/src/kits/interface/Menu.cpp b/src/kits/interface/Menu.cpp index 96d708b8aa..c334f1a1d6 100644 --- a/src/kits/interface/Menu.cpp +++ b/src/kits/interface/Menu.cpp @@ -24,6 +24,7 @@ // Stefano Ceccherini (burton666@libero.it) // Description: BMenu display a menu of selectable items. //------------------------------------------------------------------------------ +#include #include #include #include @@ -88,8 +89,7 @@ sPropList[] = { BMenu::BMenu(const char *name, menu_layout layout) - : BView(BRect(), name, B_FOLLOW_LEFT | B_FOLLOW_TOP, - B_WILL_DRAW | B_NAVIGABLE), + : BView(BRect(), name, 0, B_WILL_DRAW), fChosenItem(NULL), fPad(14.0f, 2.0f, 20.0f, 0.0f), fSelected(NULL), @@ -123,8 +123,7 @@ BMenu::BMenu(const char *name, menu_layout layout) BMenu::BMenu(const char *name, float width, float height) - : BView(BRect(0.0f, width, 0.0f, height), name, - B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE), + : BView(BRect(0.0f, width, 0.0f, height), name, 0, B_WILL_DRAW), fChosenItem(NULL), fSelected(NULL), fCachedMenuWindow(NULL), @@ -190,7 +189,7 @@ BMenu::Archive(BMessage *data, bool deep) const if (Layout() != B_ITEMS_IN_ROW) { err = data->AddInt32("_layout", Layout()); - if (err != B_OK) + if (err < B_OK) return err; } @@ -251,35 +250,14 @@ BMenu::DetachedFromWindow() bool BMenu::AddItem(BMenuItem *item) { - return AddItem(item, CountItems()); + return _AddItem(item, CountItems()); } bool BMenu::AddItem(BMenuItem *item, int32 index) { - item->fSuper = this; - - bool err = fItems.AddItem(item, index); - - if (!err) - return err; - - // Make sure we update the layout in case we are already attached. - if (Window() && fResizeToFit) { - LayoutItems(index); - Invalidate(); - } - - // Find the root menu window, so we can install this item. - BMenu *root = this; - while (root->Supermenu()) - root = root->Supermenu(); - - if (root->Window()) - Install(root->Window()); - - return err; + return _AddItem(item, index); } @@ -295,7 +273,7 @@ BMenu::AddItem(BMenuItem *item, BRect frame) item->fBounds = frame; - return AddItem(item, CountItems()); + return _AddItem(item, CountItems()); } @@ -305,10 +283,8 @@ BMenu::AddItem(BMenu *submenu) BMenuItem *item = new BMenuItem(submenu); if (!item) return false; - - submenu->fSuper = this; - - return AddItem(item); + + return _AddItem(item, CountItems()); } @@ -319,9 +295,7 @@ BMenu::AddItem(BMenu *submenu, int32 index) if (!item) return false; - submenu->fSuper = this; - - return AddItem(item, index); + return _AddItem(item, index); } @@ -333,27 +307,36 @@ BMenu::AddItem(BMenu *submenu, BRect frame) " be called if the menu layout is B_ITEMS_IN_MATRIX"); BMenuItem *item = new BMenuItem(submenu); - submenu->fSuper = this; item->fBounds = frame; - return AddItem(item); + return _AddItem(item, CountItems()); } bool BMenu::AddList(BList *list, int32 index) { - return false; + // TODO: test this function, it's not documented in the bebook. + int32 numItems = 0; + if (list != NULL) + numItems = list->CountItems(); + + for (int32 i = 0; i < numItems; i++) { + BMenuItem *item = static_cast(list->ItemAt(i)); + if (item != NULL) + _AddItem(item, index + i); + } + + // TODO: return false if needed + return true; } bool BMenu::AddSeparatorItem() { - BMenuItem *item = new BSeparatorItem(); - item->fSuper = this; - - return fItems.AddItem(item); + BMenuItem *item = new BSeparatorItem(); + return _AddItem(item, CountItems()); } @@ -1017,11 +1000,13 @@ BMenu::InitData(BMessage *data) bool BMenu::_show(bool selectFirstItem) { - BWindow *window = new BMenuWindow(this); - - window->ResizeTo(Bounds().Width() + 1, Bounds().Height() + 1); - window->MoveTo(ScreenLocation()); - window->Show(); + // Menu windows get the BMenu's handler name + fCachedMenuWindow = new BMenuWindow(Name()); + + fCachedMenuWindow->ChildAt(0)->AddChild(this); + fCachedMenuWindow->ResizeTo(Bounds().Width() + 3, Bounds().Height() + 3); + fCachedMenuWindow->MoveTo(ScreenLocation()); + fCachedMenuWindow->Show(); return true; } @@ -1030,11 +1015,10 @@ BMenu::_show(bool selectFirstItem) void BMenu::_hide() { - BWindow *window = Window(); - if (window) { - window->RemoveChild(this); - window->Lock(); - window->Quit(); + if (fCachedMenuWindow != NULL) { + fCachedMenuWindow->Lock(); + fCachedMenuWindow->ChildAt(0)->RemoveChild(this); + fCachedMenuWindow->Quit(); } } @@ -1046,7 +1030,7 @@ BMenu::_track(int *action, long start) // TODO: Take Sticky mode into account, handle submenus BPoint location; ulong buttons; - BMenuItem *item = NULL; + BMenuItem *item = NULL; do { if (LockLooper()) { GetMouse(&location, &buttons); @@ -1094,7 +1078,30 @@ BMenu::_track(int *action, long start) bool BMenu::_AddItem(BMenuItem *item, int32 index) { - return false; + ASSERT(item != NULL); + + item->SetSuper(this); + + bool err = fItems.AddItem(item, index); + + if (!err) + return err; + + // Make sure we update the layout in case we are already attached. + if (Window() && fResizeToFit) { + LayoutItems(index); + Invalidate(); + } + + // Find the root menu window, so we can install this item. + BMenu *root = this; + while (root->Supermenu()) + root = root->Supermenu(); + + if (root->Window()) + Install(root->Window()); + + return err; } @@ -1146,12 +1153,11 @@ BMenu::LayoutItems(int32 index) ResizeTo(width, height); - // TODO: Looks like this call is needed when the layout is - // B_ITEMS_IN_MATRIX, otherwise the view is placed in a wrong place - // (by the above call). See if we can avoid this by being - // smarter in other places. - if (fLayout == B_ITEMS_IN_MATRIX) - MoveTo(B_ORIGIN); + // Move the BMenu to 2, 2, if it's attached to a BMenuWindow, + // (that means it's a BMenu, BMenuBars are attached to regular BWindows). + // This is needed to be able to draw the frame around the BMenu. + if (dynamic_cast(Window()) != NULL) + MoveTo(2, 2); } @@ -1159,6 +1165,7 @@ void BMenu::ComputeLayout(int32 index, bool bestFit, bool moveItems, float* width, float* height) { + // TODO: Take "bestFit", "moveItems", "index" into account. BRect frame(0, 0, 0, 0); float iWidth, iHeight; BMenuItem *item = NULL; @@ -1173,7 +1180,7 @@ BMenu::ComputeLayout(int32 index, bool bestFit, bool moveItems, if (item->fModifiers && item->fShortcutChar) iWidth += 25.0f; - + item->fBounds.left = 2.0f; item->fBounds.top = frame.bottom; item->fBounds.bottom = item->fBounds.top + iHeight + fPad.top + fPad.bottom; @@ -1212,7 +1219,7 @@ BMenu::ComputeLayout(int32 index, bool bestFit, bool moveItems, } } - for (int i = 0; i < fItems.CountItems(); i++) + for (int32 i = 0; i < fItems.CountItems(); i++) ItemAt(i)->fBounds.bottom = frame.bottom; frame.right = (float)ceil(frame.right) + 8.0f; @@ -1228,8 +1235,8 @@ BMenu::ComputeLayout(int32 index, bool bestFit, bool moveItems, frame.right = max_c(frame.right, item->Frame().right); frame.top = min_c(frame.top, item->Frame().top); frame.bottom = max_c(frame.bottom, item->Frame().bottom); - } - } + } + } break; } @@ -1239,10 +1246,10 @@ BMenu::ComputeLayout(int32 index, bool bestFit, bool moveItems, if ((ResizingMode() & B_FOLLOW_LEFT_RIGHT) == B_FOLLOW_LEFT_RIGHT) { if (Parent()) - *width = Parent()->Frame().Width() + 1.0f; + *width = Parent()->Frame().Width(); else - *width = Window()->Frame().Width() + 1.0f; - + *width = Window()->Frame().Width(); + *height = frame.Height(); } else { *width = frame.Width(); diff --git a/src/kits/interface/MenuBar.cpp b/src/kits/interface/MenuBar.cpp index 0367f72dd3..dbcc556f4d 100644 --- a/src/kits/interface/MenuBar.cpp +++ b/src/kits/interface/MenuBar.cpp @@ -320,8 +320,8 @@ BMenuBar::operator=(const BMenuBar &) void -BMenuBar::StartMenuBar(int32 menuIndex, bool sticky, bool show_menu, - BRect *special_rect) +BMenuBar::StartMenuBar(int32 menuIndex, bool sticky, bool showMenu, + BRect *specialRect) { BWindow *window = Window(); if (!window) @@ -343,10 +343,10 @@ BMenuBar::StartMenuBar(int32 menuIndex, bool sticky, bool show_menu, data.menuBar = this; data.menuIndex = menuIndex; data.sticky = sticky; - data.showMenu = show_menu; - data.useRect = special_rect != NULL; + data.showMenu = showMenu; + data.useRect = specialRect != NULL; if (data.useRect) - data.rect = *special_rect; + data.rect = *specialRect; send_data(fTrackingPID, 0, &data, sizeof(data)); resume_thread(fTrackingPID); @@ -406,10 +406,12 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu) BMenuItem *menuItem = HitTestItems(where, B_ORIGIN); if (menuItem) { SelectItem(menuItem); + BMenu *menu = menuItem->Submenu(); // TODO: Actually, this test shouldn't be needed, as // all BMenuBar's BMenuItems are BMenus. - BMenu *menu = menuItem->Submenu(); if (menu) { + if (IsStickyPrefOn()) + menu->SetStickyMode(true); do { snooze(40000); GetMouse(&where, &buttons); @@ -422,7 +424,7 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu) resultItem = menu->_track((int *)action, startIndex); // "action" is "5" when the BMenu is closed. - } while (*action != 5); + } while (*action != 5); } SelectItem(NULL); Invalidate(); diff --git a/src/kits/interface/MenuWindow.cpp b/src/kits/interface/MenuWindow.cpp index 268e76e8cf..1408eed190 100644 --- a/src/kits/interface/MenuWindow.cpp +++ b/src/kits/interface/MenuWindow.cpp @@ -24,40 +24,60 @@ // Stefano Ceccherini (burton666@libero.it) // Description: BMenuWindow is a custom BWindow for BMenus. //------------------------------------------------------------------------------ -// TODO: Just a very simple implementation for now +// TODO: Add scrollers + +#include #include - #include // TODO: taken from Deskbar's WindowMenu.cpp. // this should go to some private header. const window_feel kMenuWindowFeel = (window_feel)1025; -BMenuWindow::BMenuWindow(BMenu *menu) +class BMenuFrame : public BView { +public: + BMenuFrame() : + BView(BRect(0, 0, 0, 0), "menu frame", B_FOLLOW_ALL_SIDES, B_WILL_DRAW) + { + }; + + virtual void AttachedToWindow() + { + BView::AttachedToWindow(); + ResizeTo(Window()->Bounds().Width(), Window()->Bounds().Height()); + }; + + virtual void Draw(BRect updateRect) + { + BRect bounds(Bounds()); + + SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_4_TINT)); + StrokeRect(bounds); + SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_2_TINT)); + StrokeLine(BPoint(bounds.left + 2, bounds.bottom - 1), + BPoint(bounds.right - 1, bounds.bottom - 1)); + SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_LIGHTEN_2_TINT)); + StrokeLine(BPoint(bounds.left + 1, bounds.top + 1), + BPoint(bounds.right - 2, bounds.top + 1)); + }; + +}; + + +BMenuWindow::BMenuWindow(const char *name) : // The window will be resized by BMenu, so just pass a dummy rect - BWindow(BRect(0, 0, 0, 0), "Menu", B_NO_BORDER_WINDOW_LOOK, kMenuWindowFeel, - B_NOT_ZOOMABLE) + BWindow(BRect(0, 0, 0, 0), name, B_NO_BORDER_WINDOW_LOOK, kMenuWindowFeel, + B_NOT_ZOOMABLE), + fUpperScroller(NULL), + fLowerScroller(NULL) { - fMenu = menu; - AddChild(fMenu); - fMenu->MakeFocus(true); + BMenuFrame *menuFrame = new BMenuFrame(); + AddChild(menuFrame); } BMenuWindow::~BMenuWindow() { } - - -void -BMenuWindow::WindowActivated(bool active) -{ - if (!active) { - RemoveChild(fMenu); - - if (Lock()) - Quit(); - } -}