Changes to make BMenu behave correctly. Implemented SetTrackingHook(). AddItem() calls the debugger in some cases, as it should. Cleanups.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10868 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stefano Ceccherini
2005-01-19 09:03:47 +00:00
parent 19b83dc2b3
commit 0c14fc6dfd
2 changed files with 77 additions and 20 deletions
+72 -17
View File
@@ -39,47 +39,73 @@
menu_info BMenu::sMenuInfo; menu_info BMenu::sMenuInfo;
#endif #endif
class _ExtraMenuData_ {
public:
menu_tracking_hook trackingHook;
void *trackingState;
_ExtraMenuData_(menu_tracking_hook func, void *state)
{
trackingHook = func;
trackingState = state;
};
};
static property_info static property_info
sPropList[] = { sPropList[] = {
{ "Enabled", { B_GET_PROPERTY, 0 }, { "Enabled", { B_GET_PROPERTY, 0 },
{ B_DIRECT_SPECIFIER, 0 }, "Returns true if menu or menu item is enabled; false " { B_DIRECT_SPECIFIER, 0 }, "Returns true if menu or menu item is enabled; false "
"otherwise." }, "otherwise." },
{ "Enabled", { B_SET_PROPERTY, 0 }, { "Enabled", { B_SET_PROPERTY, 0 },
{ B_DIRECT_SPECIFIER, 0 }, "Enables or disables menu or menu item." }, { B_DIRECT_SPECIFIER, 0 }, "Enables or disables menu or menu item." },
{ "Label", { B_GET_PROPERTY, 0 }, { "Label", { B_GET_PROPERTY, 0 },
{ B_DIRECT_SPECIFIER, 0 }, "Returns the string label of the menu or menu item." }, { B_DIRECT_SPECIFIER, 0 }, "Returns the string label of the menu or menu item." },
{ "Label", { B_SET_PROPERTY, 0 }, { "Label", { B_SET_PROPERTY, 0 },
{ B_DIRECT_SPECIFIER, 0 }, "Sets the string label of the menu or menu item." }, { B_DIRECT_SPECIFIER, 0 }, "Sets the string label of the menu or menu item." },
{ "Mark", { B_GET_PROPERTY, 0 }, { "Mark", { B_GET_PROPERTY, 0 },
{ B_DIRECT_SPECIFIER, 0 }, "Returns true if the menu item or the menu's superitem " { B_DIRECT_SPECIFIER, 0 }, "Returns true if the menu item or the menu's superitem "
"is marked; false otherwise." }, "is marked; false otherwise." },
{ "Mark", { B_SET_PROPERTY, 0 }, { "Mark", { B_SET_PROPERTY, 0 },
{ B_DIRECT_SPECIFIER, 0 }, "Marks or unmarks the menu item or the menu's superitem." }, { B_DIRECT_SPECIFIER, 0 }, "Marks or unmarks the menu item or the menu's superitem." },
{ "Menu", { B_CREATE_PROPERTY, 0 }, { "Menu", { B_CREATE_PROPERTY, 0 },
{ B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 }, { B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 },
"Adds a new menu item at the specified index with the text label found in \"data\" " "Adds a new menu item at the specified index with the text label found in \"data\" "
"and the int32 command found in \"what\" (used as the what field in the CMessage " "and the int32 command found in \"what\" (used as the what field in the CMessage "
"sent by the item)." }, "sent by the item)." },
{ "Menu", { B_DELETE_PROPERTY, 0 }, { "Menu", { B_DELETE_PROPERTY, 0 },
{ B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 }, { B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 },
"Removes the selected menu or menus." }, "Removes the selected menu or menus." },
{ "Menu", { B_GET_PROPERTY, B_SET_PROPERTY, 0 }, { "Menu", { B_GET_PROPERTY, B_SET_PROPERTY, 0 },
{ B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 }, { B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 },
"Directs scripting message to the specified menu, first popping the current " "Directs scripting message to the specified menu, first popping the current "
"specifier off the stack." }, "specifier off the stack." },
{ "MenuItem", { B_COUNT_PROPERTIES, 0 }, { "MenuItem", { B_COUNT_PROPERTIES, 0 },
{ B_DIRECT_SPECIFIER, 0 }, "Counts the number of menu items in the specified menu." }, { B_DIRECT_SPECIFIER, 0 }, "Counts the number of menu items in the specified menu." },
{ "MenuItem", { B_CREATE_PROPERTY, 0 }, { "MenuItem", { B_CREATE_PROPERTY, 0 },
{ B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 }, { B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 },
"Adds a new menu item at the specified index with the text label found in \"data\" " "Adds a new menu item at the specified index with the text label found in \"data\" "
"and the int32 command found in \"what\" (used as the what field in the CMessage " "and the int32 command found in \"what\" (used as the what field in the CMessage "
"sent by the item)." }, "sent by the item)." },
{ "MenuItem", { B_DELETE_PROPERTY, 0 }, { "MenuItem", { B_DELETE_PROPERTY, 0 },
{ B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 }, { B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 },
"Removes the specified menu item from its parent menu." }, "Removes the specified menu item from its parent menu." },
{ "MenuItem", { B_EXECUTE_PROPERTY, 0 }, { "MenuItem", { B_EXECUTE_PROPERTY, 0 },
{ B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 }, { B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 },
"Invokes the specified menu item." }, "Invokes the specified menu item." },
{ "MenuItem", { B_GET_PROPERTY, B_SET_PROPERTY, 0 }, { "MenuItem", { B_GET_PROPERTY, B_SET_PROPERTY, 0 },
{ B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 }, { B_NAME_SPECIFIER, B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, 0 },
"Directs scripting message to the specified menu, first popping the current " "Directs scripting message to the specified menu, first popping the current "
@@ -158,6 +184,10 @@ BMenu::BMenu(const char *name, float width, float height)
BMenu::~BMenu() BMenu::~BMenu()
{ {
RemoveItems(0, CountItems(), true); RemoveItems(0, CountItems(), true);
delete fCachedMenuWindow;
delete fInitMatrixSize;
delete fExtraMenuData;
} }
@@ -250,13 +280,17 @@ 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)
{ {
if (fLayout == B_ITEMS_IN_MATRIX)
debugger("BMenu::AddItem(BMenuItem *, int32) this method can only"
"be called if the menu layout is not B_ITEMS_IN_MATRIX");
return _AddItem(item, index); return _AddItem(item, index);
} }
@@ -291,6 +325,10 @@ BMenu::AddItem(BMenu *submenu)
bool bool
BMenu::AddItem(BMenu *submenu, int32 index) BMenu::AddItem(BMenu *submenu, int32 index)
{ {
if (fLayout == B_ITEMS_IN_MATRIX)
debugger("BMenu::AddItem(BMenuItem *, int32) this method can only"
"be called if the menu layout is not B_ITEMS_IN_MATRIX");
BMenuItem *item = new BMenuItem(submenu); BMenuItem *item = new BMenuItem(submenu);
if (!item) if (!item)
return false; return false;
@@ -924,8 +962,19 @@ BMenu::Track(bool openAnyway, BRect *clickToOpenRect)
UnlockLooper(); UnlockLooper();
} }
if (clickToOpenRect != NULL && LockLooper()) {
fExtraRect = clickToOpenRect;
ConvertFromScreen(fExtraRect);
UnlockLooper();
}
int action; int action;
return _track(&action, -1); BMenuItem *menuItem = _track(&action, -1);
SetStickyMode(false);
fExtraRect = NULL;
return menuItem;
} }
@@ -953,6 +1002,8 @@ BMenu::DrawBackground(BRect update)
void void
BMenu::SetTrackingHook(menu_tracking_hook func, void *state) BMenu::SetTrackingHook(menu_tracking_hook func, void *state)
{ {
delete fExtraMenuData;
fExtraMenuData = new _ExtraMenuData_(func, state);
} }
@@ -1004,6 +1055,12 @@ BMenu::_show(bool selectFirstItem)
fCachedMenuWindow = new BMenuWindow(Name()); fCachedMenuWindow = new BMenuWindow(Name());
fCachedMenuWindow->ChildAt(0)->AddChild(this); fCachedMenuWindow->ChildAt(0)->AddChild(this);
// We're doing this here because ConvertToScreen() needs:
// 1. The BView to be attached (see the above line).
// 2. The looper locked or not running (the Show() call below starts the looper)
if (fSuper != NULL)
fSuperbounds = fSuper->ConvertToScreen(fSuper->Bounds());
fCachedMenuWindow->ResizeTo(Bounds().Width() + 4, Bounds().Height() + 4); fCachedMenuWindow->ResizeTo(Bounds().Width() + 4, Bounds().Height() + 4);
fCachedMenuWindow->MoveTo(ScreenLocation()); fCachedMenuWindow->MoveTo(ScreenLocation());
fCachedMenuWindow->Show(); fCachedMenuWindow->Show();
@@ -1019,6 +1076,7 @@ BMenu::_hide()
fCachedMenuWindow->Lock(); fCachedMenuWindow->Lock();
fCachedMenuWindow->ChildAt(0)->RemoveChild(this); fCachedMenuWindow->ChildAt(0)->RemoveChild(this);
fCachedMenuWindow->Quit(); fCachedMenuWindow->Quit();
fCachedMenuWindow = NULL;
} }
} }
@@ -1034,21 +1092,21 @@ BMenu::_track(int *action, long start)
do { do {
if (LockLooper()) { if (LockLooper()) {
GetMouse(&location, &buttons); GetMouse(&location, &buttons);
if (OverSuper(location)) {
UnlockLooper();
break;
}
item = HitTestItems(location, B_ORIGIN); item = HitTestItems(location, B_ORIGIN);
if (item == NULL) {
UnlockLooper();
break;
}
// TODO: Sometimes the menu flickers a bit. // TODO: Sometimes the menu flickers a bit.
// try to be smarter and suggest an update area, // try to be smarter and suggest an update area,
// instead of invalidating the whole view. // instead of invalidating the whole view.
if (item != fSelected) { if (item != NULL && item != fSelected) {
SelectItem(item); SelectItem(item);
Invalidate(); Invalidate();
} }
UnlockLooper(); UnlockLooper();
} }
@@ -1323,14 +1381,14 @@ BMenu::InvokeItem(BMenuItem *item, bool now)
bool bool
BMenu::OverSuper(BPoint loc) BMenu::OverSuper(BPoint location)
{ {
ConvertToScreen(&loc);
if (!Supermenu()) if (!Supermenu())
return false; return false;
return Supermenu()->Frame().Contains(loc); ConvertToScreen(&location);
return fSuperbounds.Contains(location);
} }
@@ -1378,10 +1436,7 @@ BMenu::HitTestItems(BPoint where, BPoint slop) const
BRect BRect
BMenu::Superbounds() const BMenu::Superbounds() const
{ {
if (fSuper) return fSuperbounds;
return fSuper->Bounds();
return BRect();
} }
+5 -3
View File
@@ -39,7 +39,9 @@ BMenuItem::BMenuItem(const char *label, BMessage *message, char shortcut,
uint32 modifiers) uint32 modifiers)
{ {
InitData(); InitData();
fLabel = strdup(label); if (label != NULL)
fLabel = strdup(label);
SetMessage(message); SetMessage(message);
fShortcutChar = shortcut; fShortcutChar = shortcut;
@@ -161,7 +163,7 @@ BMenuItem::Archive(BMessage *data, bool deep) const
BMenuItem::~BMenuItem() BMenuItem::~BMenuItem()
{ {
free(fLabel); free(fLabel);
delete fSubmenu; delete fSubmenu;
} }
@@ -460,7 +462,7 @@ void
BMenuItem::InitData() BMenuItem::InitData()
{ {
fLabel = NULL; fLabel = NULL;
fSubmenu = 0; fSubmenu = NULL;
fWindow = NULL; fWindow = NULL;
fSuper = NULL; fSuper = NULL;
fModifiers = 0; fModifiers = 0;