* Rewrote the trigger selection mechanism: it now searches for uppercase

characters first, and then falls back to take everything. fTrigger is now
  uint32 and works with all unicode characters; unlike in BeOS, the
  MenuTriggerTest application now works correctly in Haiku.
* fTriggerIndex is now a character position, not a byte position of the label;
  this allows BMenuItem::DrawContent() to draw the trigger at the correct
  position, even if there are multi-byte UTF-8 characters.
* The above fixed bug #1506; triggers are still not working, though.
* Rewrote Menu.h header.
* Renamed all private methods (that are not called by BWindow) to have the
  underscore prefix.
* Removed unused methods.
* Some minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22384 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2007-09-30 10:52:45 +00:00
parent 05bcaa5a60
commit 083de48a4b
5 changed files with 676 additions and 797 deletions
+203 -250
View File
@@ -1,33 +1,25 @@
/******************************************************************************* /*
/ * Copyright 2007, Haiku, Inc. All Rights Reserved.
/ File: Menu.h * Distributed under the terms of the MIT License.
/ */
/ Description: BMenu display a menu of selectable items.
/
/ Copyright 1994-98, Be Incorporated, All Rights Reserved
/
*******************************************************************************/
#ifndef _MENU_H #ifndef _MENU_H
#define _MENU_H #define _MENU_H
#include <BeBuild.h>
#include <InterfaceDefs.h> #include <InterfaceDefs.h>
#include <List.h> #include <List.h>
#include <View.h> #include <View.h>
/*----------------------------------------------------------------*/
/*----- Menu declarations and structures -------------------------*/
class BMenuItem; class BMenuItem;
class BMenuBar; class BMenuBar;
namespace BPrivate { namespace BPrivate {
class BMenuWindow; class BMenuWindow;
class ExtraMenuData;
class TriggerList;
} }
class _ExtraMenuData_;
enum menu_layout { enum menu_layout {
B_ITEMS_IN_ROW = 0, B_ITEMS_IN_ROW = 0,
B_ITEMS_IN_COLUMN, B_ITEMS_IN_COLUMN,
@@ -44,281 +36,242 @@ struct menu_info {
bool triggers_always_shown; bool triggers_always_shown;
}; };
_IMPEXP_BE status_t set_menu_info(menu_info *info); status_t get_menu_info(menu_info* info);
_IMPEXP_BE status_t get_menu_info(menu_info *info); status_t set_menu_info(menu_info* info);
typedef bool (* menu_tracking_hook )(BMenu *, void *); typedef bool (*menu_tracking_hook)(BMenu* menu, void* state);
/*----------------------------------------------------------------*/
/*----- BMenu class ----------------------------------------------*/
class BMenu : public BView class BMenu : public BView {
{
public: public:
BMenu( const char *title, BMenu(const char* title,
menu_layout layout = B_ITEMS_IN_COLUMN); menu_layout layout = B_ITEMS_IN_COLUMN);
BMenu(const char *title, float width, float height); BMenu(const char* title, float width, float height);
virtual ~BMenu(); virtual ~BMenu();
BMenu(BMessage *data); BMenu(BMessage* archive);
static BArchivable *Instantiate(BMessage *data); static BArchivable* Instantiate(BMessage* archive);
virtual status_t Archive(BMessage *data, bool deep = true) const; virtual status_t Archive(BMessage* archive, bool deep = true) const;
virtual void AttachedToWindow(); virtual void AttachedToWindow();
virtual void DetachedFromWindow(); virtual void DetachedFromWindow();
bool AddItem(BMenuItem *item); bool AddItem(BMenuItem* item);
bool AddItem(BMenuItem *item, int32 index); bool AddItem(BMenuItem* item, int32 index);
bool AddItem(BMenuItem *item, BRect frame); bool AddItem(BMenuItem* item, BRect frame);
bool AddItem(BMenu *menu); bool AddItem(BMenu* menu);
bool AddItem(BMenu *menu, int32 index); bool AddItem(BMenu* menu, int32 index);
bool AddItem(BMenu *menu, BRect frame); bool AddItem(BMenu* menu, BRect frame);
bool AddList(BList *list, int32 index); bool AddList(BList* list, int32 index);
bool AddSeparatorItem();
bool RemoveItem(BMenuItem *item);
BMenuItem *RemoveItem(int32 index);
bool RemoveItems(int32 index,
int32 count,
bool del = false);
bool RemoveItem(BMenu *menu);
BMenuItem *ItemAt(int32 index) const; bool AddSeparatorItem();
BMenu *SubmenuAt(int32 index) const;
int32 CountItems() const;
int32 IndexOf(BMenuItem *item) const;
int32 IndexOf(BMenu *menu) const;
BMenuItem *FindItem(uint32 command) const;
BMenuItem *FindItem(const char *name) const;
virtual status_t SetTargetForItems(BHandler *target); bool RemoveItem(BMenuItem* item);
virtual status_t SetTargetForItems(BMessenger messenger); BMenuItem* RemoveItem(int32 index);
virtual void SetEnabled(bool state); bool RemoveItems(int32 index, int32 count,
virtual void SetRadioMode(bool state); bool deleteItems = false);
virtual void SetTriggersEnabled(bool state); bool RemoveItem(BMenu* menu);
virtual void SetMaxContentWidth(float max);
void SetLabelFromMarked(bool on); BMenuItem* ItemAt(int32 index) const;
bool IsLabelFromMarked(); BMenu* SubmenuAt(int32 index) const;
bool IsEnabled() const; int32 CountItems() const;
bool IsRadioMode() const; int32 IndexOf(BMenuItem* item) const;
bool AreTriggersEnabled() const; int32 IndexOf(BMenu* menu) const;
bool IsRedrawAfterSticky() const; BMenuItem* FindItem(uint32 command) const;
float MaxContentWidth() const; BMenuItem* FindItem(const char* name) const;
BMenuItem *FindMarked(); virtual status_t SetTargetForItems(BHandler* target);
virtual status_t SetTargetForItems(BMessenger messenger);
virtual void SetEnabled(bool state);
virtual void SetRadioMode(bool state);
virtual void SetTriggersEnabled(bool state);
virtual void SetMaxContentWidth(float maxWidth);
BMenu *Supermenu() const; void SetLabelFromMarked(bool state);
BMenuItem *Superitem() const; bool IsLabelFromMarked();
bool IsEnabled() const;
bool IsRadioMode() const;
bool AreTriggersEnabled() const;
bool IsRedrawAfterSticky() const;
float MaxContentWidth() const;
virtual void MessageReceived(BMessage *msg); BMenuItem* FindMarked();
virtual void KeyDown(const char *bytes, int32 numBytes);
virtual void Draw(BRect updateRect);
virtual BSize MinSize();
virtual BSize MaxSize();
virtual BSize PreferredSize();
virtual void GetPreferredSize(float *width, float *height);
virtual void ResizeToPreferred();
virtual void DoLayout();
virtual void FrameMoved(BPoint new_position);
virtual void FrameResized(float new_width, float new_height);
void InvalidateLayout();
virtual void InvalidateLayout(bool descendants);
virtual BHandler *ResolveSpecifier(BMessage *msg,
int32 index,
BMessage *specifier,
int32 form,
const char *property);
virtual status_t GetSupportedSuites(BMessage *data);
virtual status_t Perform(perform_code d, void *arg); BMenu* Supermenu() const;
BMenuItem* Superitem() const;
virtual void MakeFocus(bool state = true); virtual void MessageReceived(BMessage* message);
virtual void AllAttached(); virtual void KeyDown(const char* bytes, int32 numBytes);
virtual void AllDetached(); virtual void Draw(BRect updateRect);
virtual BSize MinSize();
virtual BSize MaxSize();
virtual BSize PreferredSize();
virtual void GetPreferredSize(float* _width, float* _height);
virtual void ResizeToPreferred();
virtual void DoLayout();
virtual void FrameMoved(BPoint newPosition);
virtual void FrameResized(float newWidth, float newHeight);
void InvalidateLayout();
virtual void InvalidateLayout(bool descendants);
virtual BHandler* ResolveSpecifier(BMessage* message, int32 index,
BMessage* specifier, int32 form,
const char* property);
virtual status_t GetSupportedSuites(BMessage* data);
virtual status_t Perform(perform_code d, void* arg);
virtual void MakeFocus(bool focus = true);
virtual void AllAttached();
virtual void AllDetached();
protected: protected:
BMenu(BRect frame, const char* name,
BMenu( BRect frame, uint32 resizeMask, uint32 flags,
const char *viewName, menu_layout layout, bool resizeToFit);
uint32 resizeMask,
uint32 flags,
menu_layout layout,
bool resizeToFit);
virtual BPoint ScreenLocation(); virtual BPoint ScreenLocation();
void SetItemMargins( float left, void SetItemMargins(float left, float top, float right,
float top, float bottom);
float right, void GetItemMargins(float* left, float* top,
float bottom); float* right, float* bottom) const;
void GetItemMargins( float *left,
float *top,
float *right,
float *bottom) const;
menu_layout Layout() const; menu_layout Layout() const;
virtual void Show();
void Show(bool selectFirstItem);
void Hide();
BMenuItem* Track(bool startOpened = false,
BRect* specialRect = NULL);
virtual void Show();
void Show(bool selectFirstItem);
void Hide();
BMenuItem *Track( bool start_opened = false,
BRect *special_rect = NULL);
public: public:
enum add_state { enum add_state {
B_INITIAL_ADD, B_INITIAL_ADD,
B_PROCESSING, B_PROCESSING,
B_ABORT B_ABORT
}; };
virtual bool AddDynamicItem(add_state s); virtual bool AddDynamicItem(add_state state);
virtual void DrawBackground(BRect update); virtual void DrawBackground(BRect update);
void SetTrackingHook(menu_tracking_hook hook,
void* state);
void SetTrackingHook(menu_tracking_hook func, void *state);
/*----- Private or reserved -----------------------------------------*/
private: private:
friend class BWindow; friend class BWindow;
friend class BMenuBar; friend class BMenuBar;
friend class BMenuItem; friend class BMenuItem;
friend status_t _init_interface_kit_(); friend status_t _init_interface_kit_();
friend status_t set_menu_info(menu_info *); friend status_t set_menu_info(menu_info* info);
friend status_t get_menu_info(menu_info *); friend status_t get_menu_info(menu_info* info);
struct LayoutData; struct LayoutData;
virtual void _ReservedMenu3(); virtual void _ReservedMenu3();
virtual void _ReservedMenu4(); virtual void _ReservedMenu4();
virtual void _ReservedMenu5(); virtual void _ReservedMenu5();
virtual void _ReservedMenu6(); virtual void _ReservedMenu6();
BMenu &operator=(const BMenu &); BMenu& operator=(const BMenu& other);
void InitData(BMessage *data = NULL); void _InitData(BMessage* archive);
bool _show(bool selectFirstItem = false); bool _Show(bool selectFirstItem = false);
void _hide(); void _Hide();
BMenuItem *_track(int *action, long start = -1); BMenuItem* _Track(int* action, long start = -1);
void _UpdateStateOpenSelect(BMenuItem *item, bigtime_t &openTime, bigtime_t &closeTime); void _UpdateStateOpenSelect(BMenuItem* item,
void _UpdateStateClose(BMenuItem *item, const BPoint &where, const uint32 &buttons); bigtime_t& openTime, bigtime_t& closeTime);
void _UpdateStateClose(BMenuItem* item,
bool _AddItem(BMenuItem *item, int32 index); const BPoint& where, const uint32& buttons);
bool RemoveItems(int32 index,
int32 count,
BMenuItem *item,
bool del = false);
bool RelayoutIfNeeded();
void LayoutItems(int32 index);
BSize _ValidatePreferredSize();
void ComputeLayout(int32 index, bool bestFit, bool moveItems,
float* width, float* height);
void _ComputeColumnLayout(int32 index, bool bestFit, bool moveItems, BRect &outRect);
void _ComputeRowLayout(int32 index, bool bestFit, bool moveItems, BRect &outRect);
void _ComputeMatrixLayout(BRect &outRect);
BRect Bump(BRect current, BPoint extent, int32 index) const; bool _AddItem(BMenuItem* item, int32 index);
BPoint ItemLocInRect(BRect frame) const; bool _RemoveItems(int32 index, int32 count,
BRect CalcFrame(BPoint where, bool *scrollOn); BMenuItem* item, bool deleteItems = false);
bool ScrollMenu(BRect bounds, BPoint loc, bool *fast); bool _RelayoutIfNeeded();
void ScrollIntoView(BMenuItem *item); void _LayoutItems(int32 index);
BSize _ValidatePreferredSize();
void _ComputeLayout(int32 index, bool bestFit,
bool moveItems, float* width, float* height);
void _ComputeColumnLayout(int32 index, bool bestFit,
bool moveItems, BRect& outRect);
void _ComputeRowLayout(int32 index, bool bestFit,
bool moveItems, BRect& outRect);
void _ComputeMatrixLayout(BRect& outRect);
void DrawItems(BRect updateRect); BRect _CalcFrame(BPoint where, bool* scrollOn);
int State(BMenuItem **item = NULL) const;
void InvokeItem(BMenuItem *item, bool now = false);
bool OverSuper(BPoint loc); void _DrawItems(BRect updateRect);
bool OverSubmenu(BMenuItem *item, BPoint loc);
BPrivate::BMenuWindow* MenuWindow();
void DeleteMenuWindow();
BMenuItem *HitTestItems(BPoint where, BPoint slop = B_ORIGIN) const;
BRect Superbounds() const;
void CacheFontInfo();
void ItemMarked(BMenuItem *item); bool _OverSuper(BPoint loc);
void Install(BWindow *target); bool _OverSubmenu(BMenuItem* item, BPoint loc);
void Uninstall(); BPrivate::BMenuWindow* _MenuWindow();
void _SelectItem(BMenuItem* item, bool showSubmenu = true, void _DeleteMenuWindow();
bool selectFirstItem = false); BMenuItem* _HitTestItems(BPoint where,
BMenuItem *CurrentSelection() const; BPoint slop = B_ORIGIN) const;
bool SelectNextItem(BMenuItem *item, bool forward); BRect _Superbounds() const;
BMenuItem *NextItem(BMenuItem *item, bool forward) const; void _CacheFontInfo();
bool IsItemVisible(BMenuItem *item) const;
void SetIgnoreHidden(bool on);
void SetStickyMode(bool on);
bool IsStickyMode() const;
void CalcTriggers();
const char *ChooseTrigger(const char *title, BList *chars);
void UpdateWindowViewSize(bool upWind = true);
bool IsStickyPrefOn();
void RedrawAfterSticky(BRect bounds);
bool OkToProceed(BMenuItem *);
bool CustomTrackingWantsToQuit();
void QuitTracking(); void _ItemMarked(BMenuItem* item);
void _Install(BWindow* target);
void _Uninstall();
void _SelectItem(BMenuItem* item,
bool showSubmenu = true,
bool selectFirstItem = false);
bool _SelectNextItem(BMenuItem* item, bool forward);
BMenuItem* _NextItem(BMenuItem* item, bool forward) const;
void _SetIgnoreHidden(bool on);
void _SetStickyMode(bool on);
bool _IsStickyMode() const;
void _CalcTriggers();
bool _ChooseTrigger(const char* title, int32& index,
uint32& trigger, BPrivate::TriggerList& triggers);
void _UpdateWindowViewSize(bool updatePosition = true);
bool _OkToProceed(BMenuItem* item);
status_t ParseMsg(BMessage *msg, int32 *sindex, BMessage *spec, bool _CustomTrackingWantsToQuit();
int32 *form, const char **prop,
BMenu **tmenu, BMenuItem **titem, int32 *user_data,
BMessage *reply) const;
status_t DoMenuMsg(BMenuItem **next, BMenu *tar, BMessage *m, // private methods called by BWindow
BMessage *r, BMessage *spec, int32 f) const; int State(BMenuItem** _item = NULL) const;
status_t DoMenuItemMsg(BMenuItem **next, BMenu *tar, BMessage *m, void InvokeItem(BMenuItem* item, bool now = false);
BMessage *r, BMessage *spec, int32 f) const; void QuitTracking();
status_t DoEnabledMsg(BMenuItem *ti, BMenu *tm, BMessage *m, static menu_info sMenuInfo;
BMessage *r) const; static bool sAltAsCommandKey;
status_t DoLabelMsg(BMenuItem *ti, BMenu *tm, BMessage *m,
BMessage *r) const;
status_t DoMarkMsg(BMenuItem *ti, BMenu *tm, BMessage *m,
BMessage *r) const;
status_t DoDeleteMsg(BMenuItem *ti, BMenu *tm, BMessage *m,
BMessage *r) const;
status_t DoCreateMsg(BMenuItem *ti, BMenu *tm, BMessage *m,
BMessage *r, bool menu) const;
static menu_info sMenuInfo; BMenuItem* fChosenItem;
static bool sAltAsCommandKey; BList fItems;
BRect fPad;
BMenuItem* fSelected;
BPrivate::BMenuWindow* fCachedMenuWindow;
BMenu* fSuper;
BMenuItem* fSuperitem;
BRect fSuperbounds;
float fAscent;
float fDescent;
float fFontHeight;
uint32 fState;
menu_layout fLayout;
BRect* fExtraRect;
float fMaxContentWidth;
BPoint* fInitMatrixSize;
BPrivate::ExtraMenuData* fExtraMenuData;
BMenuItem *fChosenItem; LayoutData* fLayoutData;
BList fItems;
BRect fPad;
BMenuItem *fSelected;
BPrivate::BMenuWindow* fCachedMenuWindow;
BMenu *fSuper;
BMenuItem *fSuperitem;
BRect fSuperbounds;
float fAscent;
float fDescent;
float fFontHeight;
uint32 fState;
menu_layout fLayout;
BRect *fExtraRect;
float fMaxContentWidth;
BPoint *fInitMatrixSize;
_ExtraMenuData_ *fExtraMenuData;
LayoutData* fLayoutData; int32 fSubmenus;
int32 fSubmenus; char fTrigger;
bool fResizeToFit;
char fTrigger; bool fUseCachedMenuLayout;
bool fResizeToFit; bool fEnabled;
bool fUseCachedMenuLayout; bool fDynamicName;
bool fEnabled; bool fRadioMode;
bool fDynamicName; bool fTrackNewBounds;
bool fRadioMode; bool fStickyMode;
bool fTrackNewBounds; bool fIgnoreHidden;
bool fStickyMode; bool fTriggerEnabled;
bool fIgnoreHidden; bool fRedrawAfterSticky;
bool fTriggerEnabled; bool fAttachAborted;
bool fRedrawAfterSticky;
bool fAttachAborted;
}; };
/*-------------------------------------------------------------*/ #endif // _MENU_H
/*-------------------------------------------------------------*/
#endif /* _MENU_H */
+4 -4
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2006, Haiku, Inc. All Rights Reserved. * Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _MENU_ITEM_H #ifndef _MENU_ITEM_H
@@ -65,7 +65,7 @@ class BMenuItem : public BArchivable, public BInvoker {
void Uninstall(); void Uninstall();
void SetSuper(BMenu* superMenu); void SetSuper(BMenu* superMenu);
void Select(bool select); void Select(bool select);
void SetAutomaticTrigger(char trigger); void SetAutomaticTrigger(int32 index, uint32 trigger);
protected: protected:
virtual status_t Invoke(BMessage *msg = NULL); virtual status_t Invoke(BMessage *msg = NULL);
@@ -91,13 +91,13 @@ class BMenuItem : public BArchivable, public BInvoker {
float fCachedWidth; float fCachedWidth;
int16 fTriggerIndex; int16 fTriggerIndex;
char fUserTrigger; char fUserTrigger;
char fAutomaticTrigger;
char fShortcutChar; char fShortcutChar;
bool fMark; bool fMark;
bool fEnabled; bool fEnabled;
bool fSelected; bool fSelected;
uint32 fTrigger;
uint32 _reserved[4]; uint32 _reserved[3];
}; };
// BSeparatorItem now has its own declaration file, but for source // BSeparatorItem now has its own declaration file, but for source
File diff suppressed because it is too large Load Diff
+38 -36
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2006, Haiku, Inc. * Copyright 2001-2007, Haiku, Inc.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -140,7 +140,7 @@ BMenuBar::Border() const
void void
BMenuBar::Draw(BRect updateRect) BMenuBar::Draw(BRect updateRect)
{ {
if (RelayoutIfNeeded()) { if (_RelayoutIfNeeded()) {
Invalidate(); Invalidate();
return; return;
} }
@@ -169,14 +169,14 @@ BMenuBar::Draw(BRect updateRect)
SetHighColor(color); SetHighColor(color);
// revert to previous used color (cheap PushState()/PopState()) // revert to previous used color (cheap PushState()/PopState())
DrawItems(updateRect); _DrawItems(updateRect);
} }
void void
BMenuBar::AttachedToWindow() BMenuBar::AttachedToWindow()
{ {
Install(Window()); _Install(Window());
Window()->SetKeyMenuBar(this); Window()->SetKeyMenuBar(this);
BMenu::AttachedToWindow(); BMenu::AttachedToWindow();
@@ -423,7 +423,7 @@ BMenuBar::TrackTask(void *arg)
BMenuBar *menuBar = data.menuBar; BMenuBar *menuBar = data.menuBar;
if (data.useRect) if (data.useRect)
menuBar->fExtraRect = &data.rect; menuBar->fExtraRect = &data.rect;
menuBar->SetStickyMode(data.sticky); menuBar->_SetStickyMode(data.sticky);
int32 action; int32 action;
menuBar->Track(&action, data.menuIndex, data.showMenu); menuBar->Track(&action, data.menuIndex, data.showMenu);
@@ -481,24 +481,24 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
break; break;
BPoint where; BPoint where;
ulong buttons; uint32 buttons;
GetMouse(&where, &buttons, true); GetMouse(&where, &buttons, true);
BMenuItem *menuItem = HitTestItems(where, B_ORIGIN); BMenuItem *menuItem = _HitTestItems(where, B_ORIGIN);
if (menuItem != NULL) { if (menuItem != NULL) {
// Select item if: // Select item if:
// - no previous selection // - no previous selection
// - nonsticky mode and different selection, // - nonsticky mode and different selection,
// - clicked in sticky mode // - clicked in sticky mode
if (fSelected == NULL if (fSelected == NULL
|| (!IsStickyMode() && menuItem != fSelected) || (!_IsStickyMode() && menuItem != fSelected)
|| (buttons != 0 && IsStickyMode())) { || (buttons != 0 && _IsStickyMode())) {
if (menuItem->Submenu() != NULL) { if (menuItem->Submenu() != NULL) {
if (menuItem->Submenu()->Window() == NULL) { if (menuItem->Submenu()->Window() == NULL) {
// open the menu if it's not opened yet // open the menu if it's not opened yet
_SelectItem(menuItem); _SelectItem(menuItem);
if (IsStickyMode()) if (_IsStickyMode())
SetStickyMode(false); _SetStickyMode(false);
} else { } else {
// Menu was already opened, close it and bail // Menu was already opened, close it and bail
_SelectItem(NULL); _SelectItem(NULL);
@@ -512,25 +512,27 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
} }
} }
if (OverSubmenu(fSelected, ConvertToScreen(where))) { if (_OverSubmenu(fSelected, ConvertToScreen(where))) {
// call _track() from the selected sub-menu when the mouse cursor // call _Track() from the selected sub-menu when the mouse cursor
// is over its window // is over its window
BMenu *menu = fSelected->Submenu(); BMenu *menu = fSelected->Submenu();
window->Unlock(); window->Unlock();
locked = false; locked = false;
snoozeAmount = 30000; snoozeAmount = 30000;
bool wasSticky = IsStickyMode(); bool wasSticky = _IsStickyMode();
if (wasSticky) if (wasSticky)
menu->SetStickyMode(true); menu->_SetStickyMode(true);
int localAction; int localAction;
fChosenItem = menu->_track(&localAction); fChosenItem = menu->_Track(&localAction);
if (menu->State(NULL) == MENU_STATE_TRACKING && menu->IsStickyMode()) if (menu->State(NULL) == MENU_STATE_TRACKING
menu->SetStickyMode(false); && menu->_IsStickyMode())
menu->_SetStickyMode(false);
// check if the user started holding down a mouse button in a submenu // check if the user started holding down a mouse button in a submenu
if (wasSticky && !IsStickyMode()) if (wasSticky && !_IsStickyMode()) {
buttons = 1; buttons = 1;
// buttons must have been pressed in the meantime // buttons must have been pressed in the meantime
}
// This code is needed to make menus // This code is needed to make menus
// that are children of BMenuFields "sticky" (see ticket #953) // that are children of BMenuFields "sticky" (see ticket #953)
@@ -541,7 +543,7 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
// TODO: Maybe have a shared struct between all menus // TODO: Maybe have a shared struct between all menus
// where to store the current mouse position ? // where to store the current mouse position ?
BPoint newWhere; BPoint newWhere;
ulong newButtons; uint32 newButtons;
if (window->Lock()) { if (window->Lock()) {
GetMouse(&newWhere, &newButtons); GetMouse(&newWhere, &newButtons);
window->Unlock(); window->Unlock();
@@ -550,50 +552,50 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
if (fExtraRect != NULL && fExtraRect->Contains(where) if (fExtraRect != NULL && fExtraRect->Contains(where)
// 9 = 3 pixels ^ 2 (since point_distance() returns the square of the distance) // 9 = 3 pixels ^ 2 (since point_distance() returns the square of the distance)
&& point_distance(newWhere, where) < 9) { && point_distance(newWhere, where) < 9) {
SetStickyMode(true); _SetStickyMode(true);
fExtraRect = NULL; fExtraRect = NULL;
} else } else
fState = MENU_STATE_CLOSED; fState = MENU_STATE_CLOSED;
} }
} else if (menuItem == NULL && fSelected != NULL } else if (menuItem == NULL && fSelected != NULL
&& !IsStickyMode() && fState != MENU_STATE_TRACKING_SUBMENU) { && !_IsStickyMode() && fState != MENU_STATE_TRACKING_SUBMENU) {
_SelectItem(NULL); _SelectItem(NULL);
fState = MENU_STATE_TRACKING; fState = MENU_STATE_TRACKING;
} }
if (locked) if (locked)
window->Unlock(); window->Unlock();
if (fState == MENU_STATE_CLOSED if (fState == MENU_STATE_CLOSED
|| (buttons != 0 && IsStickyMode() && menuItem == NULL)) || (buttons != 0 && _IsStickyMode() && menuItem == NULL))
break; break;
else if (buttons == 0 && !IsStickyMode()) { else if (buttons == 0 && !_IsStickyMode()) {
if ((fSelected != NULL && fSelected->Submenu() == NULL) || menuItem == NULL) { if ((fSelected != NULL && fSelected->Submenu() == NULL)
|| menuItem == NULL) {
fChosenItem = fSelected; fChosenItem = fSelected;
break; break;
} else } else
SetStickyMode(true); _SetStickyMode(true);
} }
if (snoozeAmount > 0) if (snoozeAmount > 0)
snooze(snoozeAmount); snooze(snoozeAmount);
} }
if (window->Lock()) { if (window->Lock()) {
if (fSelected != NULL) if (fSelected != NULL)
_SelectItem(NULL); _SelectItem(NULL);
if (fChosenItem != NULL) if (fChosenItem != NULL)
fChosenItem->Invoke(); fChosenItem->Invoke();
RestoreFocus(); RestoreFocus();
window->Unlock(); window->Unlock();
} }
if (IsStickyMode()) if (_IsStickyMode())
SetStickyMode(false); _SetStickyMode(false);
DeleteMenuWindow(); _DeleteMenuWindow();
if (action != NULL) if (action != NULL)
*action = fState; *action = fState;
@@ -602,13 +604,13 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
} }
void void
BMenuBar::StealFocus() BMenuBar::StealFocus()
{ {
// We already stole the focus, don't do anything // We already stole the focus, don't do anything
if (fPrevFocusToken != -1) if (fPrevFocusToken != -1)
return; return;
BWindow *window = Window(); BWindow *window = Window();
if (window != NULL && window->Lock()) { if (window != NULL && window->Lock()) {
BView *focus = window->CurrentFocus(); BView *focus = window->CurrentFocus();
@@ -646,5 +648,5 @@ BMenuBar::InitData(menu_layout layout)
{ {
fLastBounds = new BRect(Bounds()); fLastBounds = new BRect(Bounds());
SetItemMargins(8, 2, 8, 2); SetItemMargins(8, 2, 8, 2);
SetIgnoreHidden(true); _SetIgnoreHidden(true);
} }
+41 -43
View File
@@ -11,14 +11,17 @@
//! Display item for BMenu class //! Display item for BMenu class
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <Bitmap.h> #include <Bitmap.h>
#include <MenuItem.h> #include <MenuItem.h>
#include <Shape.h> #include <Shape.h>
#include <String.h> #include <String.h>
#include <Window.h> #include <Window.h>
#include <string.h> #include "utf8_functions.h"
#include <stdlib.h>
const unsigned char kCtrlBits[] = { const unsigned char kCtrlBits[] = {
0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x14, 0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x14,
@@ -112,13 +115,9 @@ BMenuItem::BMenuItem(BMessage *data)
if (data->FindBool("_marked", &marked) == B_OK) if (data->FindBool("_marked", &marked) == B_OK)
SetMarked(marked); SetMarked(marked);
if (data->HasInt32("_user_trig")) { int32 userTrigger;
int32 user_trig; if (data->FindInt32("_user_trig", &userTrigger) == B_OK)
SetTrigger(userTrigger);
data->FindInt32("_user_trig", &user_trig);
SetTrigger(user_trig);
}
if (data->HasInt32("_shortcut")) { if (data->HasInt32("_shortcut")) {
int32 shortcut, mods; int32 shortcut, mods;
@@ -139,10 +138,8 @@ BMenuItem::BMenuItem(BMessage *data)
BMessage subMessage; BMessage subMessage;
if (data->FindMessage("_submenu", &subMessage) == B_OK) { if (data->FindMessage("_submenu", &subMessage) == B_OK) {
BArchivable *object = instantiate_object(&subMessage); BArchivable *object = instantiate_object(&subMessage);
if (object != NULL) { if (object != NULL) {
BMenu *menu = dynamic_cast<BMenu *>(object); BMenu *menu = dynamic_cast<BMenu *>(object);
if (menu != NULL) if (menu != NULL)
_InitMenuData(menu); _InitMenuData(menu);
} }
@@ -251,7 +248,7 @@ BMenuItem::SetMarked(bool state)
fMark = state; fMark = state;
if (state && Menu() != NULL) if (state && Menu() != NULL)
Menu()->ItemMarked(this); Menu()->_ItemMarked(this);
} }
@@ -260,12 +257,18 @@ BMenuItem::SetTrigger(char trigger)
{ {
fUserTrigger = trigger; fUserTrigger = trigger;
const char* pos = strchr(Label(), trigger); // try uppercase letters first
const char* pos = strchr(Label(), toupper(trigger));
if (pos == NULL) {
// take lowercase, too
pos = strchr(Label(), trigger);
}
if (pos != NULL) { if (pos != NULL) {
fAutomaticTrigger = trigger;
fTriggerIndex = pos - Label(); fTriggerIndex = pos - Label();
fTrigger = tolower(UTF8ToCharCode(&pos));
} else { } else {
fAutomaticTrigger = 0; fTrigger = 0;
fTriggerIndex = -1; fTriggerIndex = -1;
} }
@@ -369,10 +372,10 @@ BMenuItem::Frame() const
void void
BMenuItem::GetContentSize(float *width, float *height) BMenuItem::GetContentSize(float *width, float *height)
{ {
fSuper->CacheFontInfo(); fSuper->_CacheFontInfo();
fCachedWidth = fSuper->StringWidth(fLabel); fCachedWidth = fSuper->StringWidth(fLabel);
if (width) if (width)
*width = (float)ceil(fCachedWidth); *width = (float)ceil(fCachedWidth);
if (height) if (height)
@@ -385,9 +388,9 @@ BMenuItem::TruncateLabel(float maxWidth, char *newLabel)
{ {
BFont font; BFont font;
BString string(fLabel); BString string(fLabel);
font.TruncateString(&string, B_TRUNCATE_MIDDLE, maxWidth); font.TruncateString(&string, B_TRUNCATE_MIDDLE, maxWidth);
string.CopyInto(newLabel, 0, string.Length()); string.CopyInto(newLabel, 0, string.Length());
newLabel[string.Length()] = '\0'; newLabel[string.Length()] = '\0';
} }
@@ -396,14 +399,14 @@ BMenuItem::TruncateLabel(float maxWidth, char *newLabel)
void void
BMenuItem::DrawContent() BMenuItem::DrawContent()
{ {
fSuper->CacheFontInfo(); fSuper->_CacheFontInfo();
fSuper->MovePenBy(0, fSuper->fAscent); fSuper->MovePenBy(0, fSuper->fAscent);
BPoint lineStart = fSuper->PenLocation(); BPoint lineStart = fSuper->PenLocation();
float labelWidth, labelHeight; float labelWidth, labelHeight;
GetContentSize(&labelWidth, &labelHeight); GetContentSize(&labelWidth, &labelHeight);
// truncate if needed // truncate if needed
// TODO: Actually, this is still never triggered // TODO: Actually, this is still never triggered
if (fBounds.Width() > labelWidth) if (fBounds.Width() > labelWidth)
@@ -414,12 +417,12 @@ BMenuItem::DrawContent()
fSuper->DrawString(truncatedLabel); fSuper->DrawString(truncatedLabel);
delete[] truncatedLabel; delete[] truncatedLabel;
} }
if (fSuper->AreTriggersEnabled() && fTriggerIndex != -1) { if (fSuper->AreTriggersEnabled() && fTriggerIndex != -1) {
float escapements[fTriggerIndex + 1]; float escapements[fTriggerIndex + 1];
BFont font; BFont font;
fSuper->GetFont(&font); fSuper->GetFont(&font);
font.GetEscapements(fLabel, fTriggerIndex + 1, escapements); font.GetEscapements(fLabel, fTriggerIndex + 1, escapements);
for (int32 i = 0; i < fTriggerIndex; i++) for (int32 i = 0; i < fTriggerIndex; i++)
@@ -427,10 +430,10 @@ BMenuItem::DrawContent()
lineStart.x--; lineStart.x--;
lineStart.y++; lineStart.y++;
BPoint lineEnd(lineStart); BPoint lineEnd(lineStart);
lineEnd.x += escapements[fTriggerIndex] * font.Size(); lineEnd.x += escapements[fTriggerIndex] * font.Size();
fSuper->StrokeLine(lineStart, lineEnd); fSuper->StrokeLine(lineStart, lineEnd);
} }
} }
@@ -462,8 +465,7 @@ BMenuItem::Draw()
if (enabled) if (enabled)
fSuper->SetHighColor(ui_color(B_MENU_ITEM_TEXT_COLOR)); fSuper->SetHighColor(ui_color(B_MENU_ITEM_TEXT_COLOR));
else else
fSuper->SetHighColor(tint_color(bgColor, fSuper->SetHighColor(tint_color(bgColor, B_DISABLED_LABEL_TINT));
B_DISABLED_LABEL_TINT));
// draw content // draw content
fSuper->MovePenTo(ContentLocation()); fSuper->MovePenTo(ContentLocation());
@@ -536,7 +538,7 @@ BMenuItem::_InitData()
fCachedWidth = 0; fCachedWidth = 0;
fTriggerIndex = -1; fTriggerIndex = -1;
fUserTrigger = 0; fUserTrigger = 0;
fAutomaticTrigger = 0; fTrigger = 0;
fShortcutChar = 0; fShortcutChar = 0;
fMark = false; fMark = false;
fEnabled = true; fEnabled = true;
@@ -563,7 +565,7 @@ void
BMenuItem::Install(BWindow *window) BMenuItem::Install(BWindow *window)
{ {
if (fSubmenu) if (fSubmenu)
fSubmenu->Install(window); fSubmenu->_Install(window);
fWindow = window; fWindow = window;
@@ -592,7 +594,7 @@ BMenuItem::Invoke(BMessage *message)
if (!message && !notify) if (!message && !notify)
message = Message(); message = Message();
if (!message) { if (!message) {
if (!fSuper->IsWatched()) if (!fSuper->IsWatched())
return err; return err;
@@ -603,7 +605,7 @@ BMenuItem::Invoke(BMessage *message)
clone.AddInt64("when", (int64)system_time()); clone.AddInt64("when", (int64)system_time());
clone.AddPointer("source", this); clone.AddPointer("source", this);
clone.AddMessenger("be:sender", BMessenger(fSuper)); clone.AddMessenger("be:sender", BMessenger(fSuper));
if (message) if (message)
err = BInvoker::Invoke(&clone); err = BInvoker::Invoke(&clone);
@@ -618,12 +620,13 @@ void
BMenuItem::Uninstall() BMenuItem::Uninstall()
{ {
if (fSubmenu != NULL) if (fSubmenu != NULL)
fSubmenu->Uninstall(); fSubmenu->_Uninstall();
if (Target() == fWindow) if (Target() == fWindow)
SetTarget(BMessenger()); SetTarget(BMessenger());
if (fShortcutChar != 0 && (fModifiers & B_COMMAND_KEY) && fWindow != NULL) if (fShortcutChar != 0 && (fModifiers & B_COMMAND_KEY) != 0
&& fWindow != NULL)
fWindow->RemoveShortcut(fShortcutChar, fModifiers); fWindow->RemoveShortcut(fShortcutChar, fModifiers);
fWindow = NULL; fWindow = NULL;
@@ -643,7 +646,7 @@ BMenuItem::SetSuper(BMenu *super)
fSuper->fSubmenus--; fSuper->fSubmenus--;
fSubmenu->fSuper = super; fSubmenu->fSuper = super;
} }
fSuper = super; fSuper = super;
} }
@@ -841,13 +844,8 @@ BMenuItem::_DrawControlChar(char shortcut, BPoint where)
void void
BMenuItem::SetAutomaticTrigger(char trigger) BMenuItem::SetAutomaticTrigger(int32 index, uint32 trigger)
{ {
fAutomaticTrigger = trigger; fTriggerIndex = index;
fTrigger = trigger;
const char* pos = strchr(Label(), trigger);
if (pos != NULL)
fTriggerIndex = pos - Label();
else
fTriggerIndex = -1;
} }