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:
+67
-60
@@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -306,9 +284,7 @@ BMenu::AddItem(BMenu *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,17 +307,28 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -351,9 +336,7 @@ 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);
|
fCachedMenuWindow->ChildAt(0)->AddChild(this);
|
||||||
window->MoveTo(ScreenLocation());
|
fCachedMenuWindow->ResizeTo(Bounds().Width() + 3, Bounds().Height() + 3);
|
||||||
window->Show();
|
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
@@ -1239,9 +1246,9 @@ 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 {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user