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
This commit is contained in:
Stefano Ceccherini
2005-01-04 12:59:49 +00:00
parent a583b8b54d
commit 5b7528754d
3 changed files with 124 additions and 95 deletions
+75 -68
View File
@@ -24,6 +24,7 @@
// Stefano Ceccherini ([email protected]) // Stefano Ceccherini ([email protected])
// Description: BMenu display a menu of selectable items. // Description: BMenu display a menu of selectable items.
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#include <Debug.h>
#include <File.h> #include <File.h>
#include <FindDirectory.h> #include <FindDirectory.h>
#include <Menu.h> #include <Menu.h>
@@ -88,8 +89,7 @@ sPropList[] = {
BMenu::BMenu(const char *name, menu_layout layout) BMenu::BMenu(const char *name, menu_layout layout)
: BView(BRect(), name, B_FOLLOW_LEFT | B_FOLLOW_TOP, : BView(BRect(), name, 0, B_WILL_DRAW),
B_WILL_DRAW | B_NAVIGABLE),
fChosenItem(NULL), fChosenItem(NULL),
fPad(14.0f, 2.0f, 20.0f, 0.0f), fPad(14.0f, 2.0f, 20.0f, 0.0f),
fSelected(NULL), fSelected(NULL),
@@ -123,8 +123,7 @@ BMenu::BMenu(const char *name, menu_layout layout)
BMenu::BMenu(const char *name, float width, float height) BMenu::BMenu(const char *name, float width, float height)
: BView(BRect(0.0f, width, 0.0f, height), name, : BView(BRect(0.0f, width, 0.0f, height), name, 0, B_WILL_DRAW),
B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE),
fChosenItem(NULL), fChosenItem(NULL),
fSelected(NULL), fSelected(NULL),
fCachedMenuWindow(NULL), fCachedMenuWindow(NULL),
@@ -190,7 +189,7 @@ BMenu::Archive(BMessage *data, bool deep) const
if (Layout() != B_ITEMS_IN_ROW) { if (Layout() != B_ITEMS_IN_ROW) {
err = data->AddInt32("_layout", Layout()); err = data->AddInt32("_layout", Layout());
if (err != B_OK) if (err < B_OK)
return err; return err;
} }
@@ -251,35 +250,14 @@ BMenu::DetachedFromWindow()
bool bool
BMenu::AddItem(BMenuItem *item) BMenu::AddItem(BMenuItem *item)
{ {
return AddItem(item, CountItems()); return _AddItem(item, CountItems());
} }
bool bool
BMenu::AddItem(BMenuItem *item, int32 index) BMenu::AddItem(BMenuItem *item, int32 index)
{ {
item->fSuper = this; return _AddItem(item, index);
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;
} }
@@ -295,7 +273,7 @@ BMenu::AddItem(BMenuItem *item, BRect frame)
item->fBounds = 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); BMenuItem *item = new BMenuItem(submenu);
if (!item) if (!item)
return false; return false;
submenu->fSuper = this; return _AddItem(item, CountItems());
return AddItem(item);
} }
@@ -319,9 +295,7 @@ BMenu::AddItem(BMenu *submenu, int32 index)
if (!item) if (!item)
return false; 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"); " be called if the menu layout is B_ITEMS_IN_MATRIX");
BMenuItem *item = new BMenuItem(submenu); BMenuItem *item = new BMenuItem(submenu);
submenu->fSuper = this;
item->fBounds = frame; item->fBounds = frame;
return AddItem(item); return _AddItem(item, CountItems());
} }
bool bool
BMenu::AddList(BList *list, int32 index) 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<BMenuItem *>(list->ItemAt(i));
if (item != NULL)
_AddItem(item, index + i);
}
// TODO: return false if needed
return true;
} }
bool bool
BMenu::AddSeparatorItem() BMenu::AddSeparatorItem()
{ {
BMenuItem *item = new BSeparatorItem(); BMenuItem *item = new BSeparatorItem();
item->fSuper = this; return _AddItem(item, CountItems());
return fItems.AddItem(item);
} }
@@ -1017,11 +1000,13 @@ BMenu::InitData(BMessage *data)
bool bool
BMenu::_show(bool selectFirstItem) BMenu::_show(bool selectFirstItem)
{ {
BWindow *window = new BMenuWindow(this); // Menu windows get the BMenu's handler name
fCachedMenuWindow = new BMenuWindow(Name());
window->ResizeTo(Bounds().Width() + 1, Bounds().Height() + 1);
window->MoveTo(ScreenLocation()); fCachedMenuWindow->ChildAt(0)->AddChild(this);
window->Show(); fCachedMenuWindow->ResizeTo(Bounds().Width() + 3, Bounds().Height() + 3);
fCachedMenuWindow->MoveTo(ScreenLocation());
fCachedMenuWindow->Show();
return true; return true;
} }
@@ -1030,11 +1015,10 @@ BMenu::_show(bool selectFirstItem)
void void
BMenu::_hide() BMenu::_hide()
{ {
BWindow *window = Window(); if (fCachedMenuWindow != NULL) {
if (window) { fCachedMenuWindow->Lock();
window->RemoveChild(this); fCachedMenuWindow->ChildAt(0)->RemoveChild(this);
window->Lock(); fCachedMenuWindow->Quit();
window->Quit();
} }
} }
@@ -1046,7 +1030,7 @@ BMenu::_track(int *action, long start)
// TODO: Take Sticky mode into account, handle submenus // TODO: Take Sticky mode into account, handle submenus
BPoint location; BPoint location;
ulong buttons; ulong buttons;
BMenuItem *item = NULL; BMenuItem *item = NULL;
do { do {
if (LockLooper()) { if (LockLooper()) {
GetMouse(&location, &buttons); GetMouse(&location, &buttons);
@@ -1094,7 +1078,30 @@ BMenu::_track(int *action, long start)
bool bool
BMenu::_AddItem(BMenuItem *item, int32 index) 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); ResizeTo(width, height);
// TODO: Looks like this call is needed when the layout is // Move the BMenu to 2, 2, if it's attached to a BMenuWindow,
// B_ITEMS_IN_MATRIX, otherwise the view is placed in a wrong place // (that means it's a BMenu, BMenuBars are attached to regular BWindows).
// (by the above call). See if we can avoid this by being // This is needed to be able to draw the frame around the BMenu.
// smarter in other places. if (dynamic_cast<BMenuWindow *>(Window()) != NULL)
if (fLayout == B_ITEMS_IN_MATRIX) MoveTo(2, 2);
MoveTo(B_ORIGIN);
} }
@@ -1159,6 +1165,7 @@ void
BMenu::ComputeLayout(int32 index, bool bestFit, bool moveItems, BMenu::ComputeLayout(int32 index, bool bestFit, bool moveItems,
float* width, float* height) float* width, float* height)
{ {
// TODO: Take "bestFit", "moveItems", "index" into account.
BRect frame(0, 0, 0, 0); BRect frame(0, 0, 0, 0);
float iWidth, iHeight; float iWidth, iHeight;
BMenuItem *item = NULL; BMenuItem *item = NULL;
@@ -1173,7 +1180,7 @@ BMenu::ComputeLayout(int32 index, bool bestFit, bool moveItems,
if (item->fModifiers && item->fShortcutChar) if (item->fModifiers && item->fShortcutChar)
iWidth += 25.0f; iWidth += 25.0f;
item->fBounds.left = 2.0f; item->fBounds.left = 2.0f;
item->fBounds.top = frame.bottom; item->fBounds.top = frame.bottom;
item->fBounds.bottom = item->fBounds.top + iHeight + fPad.top + fPad.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; ItemAt(i)->fBounds.bottom = frame.bottom;
frame.right = (float)ceil(frame.right) + 8.0f; 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.right = max_c(frame.right, item->Frame().right);
frame.top = min_c(frame.top, item->Frame().top); frame.top = min_c(frame.top, item->Frame().top);
frame.bottom = max_c(frame.bottom, item->Frame().bottom); frame.bottom = max_c(frame.bottom, item->Frame().bottom);
} }
} }
break; break;
} }
@@ -1239,10 +1246,10 @@ BMenu::ComputeLayout(int32 index, bool bestFit, bool moveItems,
if ((ResizingMode() & B_FOLLOW_LEFT_RIGHT) == B_FOLLOW_LEFT_RIGHT) { if ((ResizingMode() & B_FOLLOW_LEFT_RIGHT) == B_FOLLOW_LEFT_RIGHT) {
if (Parent()) if (Parent())
*width = Parent()->Frame().Width() + 1.0f; *width = Parent()->Frame().Width();
else else
*width = Window()->Frame().Width() + 1.0f; *width = Window()->Frame().Width();
*height = frame.Height(); *height = frame.Height();
} else { } else {
*width = frame.Width(); *width = frame.Width();
+9 -7
View File
@@ -320,8 +320,8 @@ BMenuBar::operator=(const BMenuBar &)
void void
BMenuBar::StartMenuBar(int32 menuIndex, bool sticky, bool show_menu, BMenuBar::StartMenuBar(int32 menuIndex, bool sticky, bool showMenu,
BRect *special_rect) BRect *specialRect)
{ {
BWindow *window = Window(); BWindow *window = Window();
if (!window) if (!window)
@@ -343,10 +343,10 @@ BMenuBar::StartMenuBar(int32 menuIndex, bool sticky, bool show_menu,
data.menuBar = this; data.menuBar = this;
data.menuIndex = menuIndex; data.menuIndex = menuIndex;
data.sticky = sticky; data.sticky = sticky;
data.showMenu = show_menu; data.showMenu = showMenu;
data.useRect = special_rect != NULL; data.useRect = specialRect != NULL;
if (data.useRect) if (data.useRect)
data.rect = *special_rect; data.rect = *specialRect;
send_data(fTrackingPID, 0, &data, sizeof(data)); send_data(fTrackingPID, 0, &data, sizeof(data));
resume_thread(fTrackingPID); resume_thread(fTrackingPID);
@@ -406,10 +406,12 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
BMenuItem *menuItem = HitTestItems(where, B_ORIGIN); BMenuItem *menuItem = HitTestItems(where, B_ORIGIN);
if (menuItem) { if (menuItem) {
SelectItem(menuItem); SelectItem(menuItem);
BMenu *menu = menuItem->Submenu();
// TODO: Actually, this test shouldn't be needed, as // TODO: Actually, this test shouldn't be needed, as
// all BMenuBar's BMenuItems are BMenus. // all BMenuBar's BMenuItems are BMenus.
BMenu *menu = menuItem->Submenu();
if (menu) { if (menu) {
if (IsStickyPrefOn())
menu->SetStickyMode(true);
do { do {
snooze(40000); snooze(40000);
GetMouse(&where, &buttons); GetMouse(&where, &buttons);
@@ -422,7 +424,7 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
resultItem = menu->_track((int *)action, startIndex); resultItem = menu->_track((int *)action, startIndex);
// "action" is "5" when the BMenu is closed. // "action" is "5" when the BMenu is closed.
} while (*action != 5); } while (*action != 5);
} }
SelectItem(NULL); SelectItem(NULL);
Invalidate(); Invalidate();
+40 -20
View File
@@ -24,40 +24,60 @@
// Stefano Ceccherini ([email protected]) // Stefano Ceccherini ([email protected])
// Description: BMenuWindow is a custom BWindow for BMenus. // Description: BMenuWindow is a custom BWindow for BMenus.
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// TODO: Just a very simple implementation for now // TODO: Add scrollers
#include <stdio.h>
#include <Menu.h> #include <Menu.h>
#include <MenuWindow.h> #include <MenuWindow.h>
// TODO: taken from Deskbar's WindowMenu.cpp. // TODO: taken from Deskbar's WindowMenu.cpp.
// this should go to some private header. // this should go to some private header.
const window_feel kMenuWindowFeel = (window_feel)1025; 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 // 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, BWindow(BRect(0, 0, 0, 0), name, B_NO_BORDER_WINDOW_LOOK, kMenuWindowFeel,
B_NOT_ZOOMABLE) B_NOT_ZOOMABLE),
fUpperScroller(NULL),
fLowerScroller(NULL)
{ {
fMenu = menu; BMenuFrame *menuFrame = new BMenuFrame();
AddChild(fMenu); AddChild(menuFrame);
fMenu->MakeFocus(true);
} }
BMenuWindow::~BMenuWindow() BMenuWindow::~BMenuWindow()
{ {
} }
void
BMenuWindow::WindowActivated(bool active)
{
if (!active) {
RemoveChild(fMenu);
if (Lock())
Quit();
}
}