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:
parent
a583b8b54d
commit
5b7528754d
@ -24,6 +24,7 @@
|
||||
// Stefano Ceccherini (burton666@libero.it)
|
||||
// Description: BMenu display a menu of selectable items.
|
||||
//------------------------------------------------------------------------------
|
||||
#include <Debug.h>
|
||||
#include <File.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <Menu.h>
|
||||
@ -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<BMenuItem *>(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<BMenuWindow *>(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();
|
||||
|
@ -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();
|
||||
|
@ -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 <stdio.h>
|
||||
|
||||
#include <Menu.h>
|
||||
|
||||
#include <MenuWindow.h>
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user