* 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

View File

@ -1,33 +1,25 @@
/*******************************************************************************
/
/ File: Menu.h
/
/ Description: BMenu display a menu of selectable items.
/
/ Copyright 1994-98, Be Incorporated, All Rights Reserved
/
*******************************************************************************/
/*
* Copyright 2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _MENU_H
#define _MENU_H
#include <BeBuild.h>
#include <InterfaceDefs.h>
#include <List.h>
#include <View.h>
/*----------------------------------------------------------------*/
/*----- Menu declarations and structures -------------------------*/
class BMenuItem;
class BMenuBar;
namespace BPrivate {
class BMenuWindow;
class ExtraMenuData;
class TriggerList;
}
class _ExtraMenuData_;
enum menu_layout {
B_ITEMS_IN_ROW = 0,
B_ITEMS_IN_COLUMN,
@ -44,281 +36,242 @@ struct menu_info {
bool triggers_always_shown;
};
_IMPEXP_BE status_t set_menu_info(menu_info *info);
_IMPEXP_BE status_t get_menu_info(menu_info *info);
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:
BMenu( const char *title,
BMenu(const char* title,
menu_layout layout = B_ITEMS_IN_COLUMN);
BMenu(const char *title, float width, float height);
virtual ~BMenu();
BMenu(const char* title, float width, float height);
virtual ~BMenu();
BMenu(BMessage *data);
static BArchivable *Instantiate(BMessage *data);
virtual status_t Archive(BMessage *data, bool deep = true) const;
BMenu(BMessage* archive);
static BArchivable* Instantiate(BMessage* archive);
virtual status_t Archive(BMessage* archive, bool deep = true) const;
virtual void AttachedToWindow();
virtual void DetachedFromWindow();
virtual void AttachedToWindow();
virtual void DetachedFromWindow();
bool AddItem(BMenuItem *item);
bool AddItem(BMenuItem *item, int32 index);
bool AddItem(BMenuItem *item, BRect frame);
bool AddItem(BMenu *menu);
bool AddItem(BMenu *menu, int32 index);
bool AddItem(BMenu *menu, BRect frame);
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);
bool AddItem(BMenuItem* item);
bool AddItem(BMenuItem* item, int32 index);
bool AddItem(BMenuItem* item, BRect frame);
bool AddItem(BMenu* menu);
bool AddItem(BMenu* menu, int32 index);
bool AddItem(BMenu* menu, BRect frame);
bool AddList(BList* list, int32 index);
BMenuItem *ItemAt(int32 index) const;
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;
bool AddSeparatorItem();
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 max);
bool RemoveItem(BMenuItem* item);
BMenuItem* RemoveItem(int32 index);
bool RemoveItems(int32 index, int32 count,
bool deleteItems = false);
bool RemoveItem(BMenu* menu);
void SetLabelFromMarked(bool on);
bool IsLabelFromMarked();
bool IsEnabled() const;
bool IsRadioMode() const;
bool AreTriggersEnabled() const;
bool IsRedrawAfterSticky() const;
float MaxContentWidth() const;
BMenuItem* ItemAt(int32 index) const;
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;
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;
BMenuItem *Superitem() const;
void SetLabelFromMarked(bool state);
bool IsLabelFromMarked();
bool IsEnabled() const;
bool IsRadioMode() const;
bool AreTriggersEnabled() const;
bool IsRedrawAfterSticky() const;
float MaxContentWidth() const;
virtual void MessageReceived(BMessage *msg);
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);
BMenuItem* FindMarked();
virtual status_t Perform(perform_code d, void *arg);
BMenu* Supermenu() const;
BMenuItem* Superitem() const;
virtual void MakeFocus(bool state = true);
virtual void AllAttached();
virtual void AllDetached();
virtual void MessageReceived(BMessage* message);
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 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:
BMenu( BRect frame,
const char *viewName,
uint32 resizeMask,
uint32 flags,
menu_layout layout,
bool resizeToFit);
BMenu(BRect frame, const char* name,
uint32 resizeMask, uint32 flags,
menu_layout layout, bool resizeToFit);
virtual BPoint ScreenLocation();
virtual BPoint ScreenLocation();
void SetItemMargins( float left,
float top,
float right,
float bottom);
void GetItemMargins( float *left,
float *top,
float *right,
float *bottom) const;
void SetItemMargins(float left, float top, float right,
float bottom);
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:
enum add_state {
B_INITIAL_ADD,
B_PROCESSING,
B_ABORT
};
virtual bool AddDynamicItem(add_state s);
virtual void DrawBackground(BRect update);
enum add_state {
B_INITIAL_ADD,
B_PROCESSING,
B_ABORT
};
virtual bool AddDynamicItem(add_state state);
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:
friend class BWindow;
friend class BMenuBar;
friend class BMenuItem;
friend status_t _init_interface_kit_();
friend status_t set_menu_info(menu_info *);
friend status_t get_menu_info(menu_info *);
friend class BWindow;
friend class BMenuBar;
friend class BMenuItem;
friend status_t _init_interface_kit_();
friend status_t set_menu_info(menu_info* info);
friend status_t get_menu_info(menu_info* info);
struct LayoutData;
struct LayoutData;
virtual void _ReservedMenu3();
virtual void _ReservedMenu4();
virtual void _ReservedMenu5();
virtual void _ReservedMenu6();
virtual void _ReservedMenu3();
virtual void _ReservedMenu4();
virtual void _ReservedMenu5();
virtual void _ReservedMenu6();
BMenu &operator=(const BMenu &);
BMenu& operator=(const BMenu& other);
void InitData(BMessage *data = NULL);
bool _show(bool selectFirstItem = false);
void _hide();
BMenuItem *_track(int *action, long start = -1);
void _InitData(BMessage* archive);
bool _Show(bool selectFirstItem = false);
void _Hide();
BMenuItem* _Track(int* action, long start = -1);
void _UpdateStateOpenSelect(BMenuItem *item, bigtime_t &openTime, bigtime_t &closeTime);
void _UpdateStateClose(BMenuItem *item, const BPoint &where, const uint32 &buttons);
bool _AddItem(BMenuItem *item, int32 index);
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);
void _UpdateStateOpenSelect(BMenuItem* item,
bigtime_t& openTime, bigtime_t& closeTime);
void _UpdateStateClose(BMenuItem* item,
const BPoint& where, const uint32& buttons);
BRect Bump(BRect current, BPoint extent, int32 index) const;
BPoint ItemLocInRect(BRect frame) const;
BRect CalcFrame(BPoint where, bool *scrollOn);
bool ScrollMenu(BRect bounds, BPoint loc, bool *fast);
void ScrollIntoView(BMenuItem *item);
bool _AddItem(BMenuItem* item, int32 index);
bool _RemoveItems(int32 index, int32 count,
BMenuItem* item, bool deleteItems = 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);
void DrawItems(BRect updateRect);
int State(BMenuItem **item = NULL) const;
void InvokeItem(BMenuItem *item, bool now = false);
BRect _CalcFrame(BPoint where, bool* scrollOn);
bool OverSuper(BPoint loc);
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 _DrawItems(BRect updateRect);
void ItemMarked(BMenuItem *item);
void Install(BWindow *target);
void Uninstall();
void _SelectItem(BMenuItem* item, bool showSubmenu = true,
bool selectFirstItem = false);
BMenuItem *CurrentSelection() const;
bool SelectNextItem(BMenuItem *item, bool forward);
BMenuItem *NextItem(BMenuItem *item, bool forward) const;
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();
bool _OverSuper(BPoint loc);
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 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,
int32 *form, const char **prop,
BMenu **tmenu, BMenuItem **titem, int32 *user_data,
BMessage *reply) const;
bool _CustomTrackingWantsToQuit();
status_t DoMenuMsg(BMenuItem **next, BMenu *tar, BMessage *m,
BMessage *r, BMessage *spec, int32 f) const;
status_t DoMenuItemMsg(BMenuItem **next, BMenu *tar, BMessage *m,
BMessage *r, BMessage *spec, int32 f) const;
// private methods called by BWindow
int State(BMenuItem** _item = NULL) const;
void InvokeItem(BMenuItem* item, bool now = false);
void QuitTracking();
status_t DoEnabledMsg(BMenuItem *ti, BMenu *tm, BMessage *m,
BMessage *r) const;
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;
static bool sAltAsCommandKey;
static menu_info sMenuInfo;
static bool sAltAsCommandKey;
BMenuItem* fChosenItem;
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;
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;
LayoutData* fLayoutData;
int32 fSubmenus;
int32 fSubmenus;
char fTrigger;
bool fResizeToFit;
bool fUseCachedMenuLayout;
bool fEnabled;
bool fDynamicName;
bool fRadioMode;
bool fTrackNewBounds;
bool fStickyMode;
bool fIgnoreHidden;
bool fTriggerEnabled;
bool fRedrawAfterSticky;
bool fAttachAborted;
char fTrigger;
bool fResizeToFit;
bool fUseCachedMenuLayout;
bool fEnabled;
bool fDynamicName;
bool fRadioMode;
bool fTrackNewBounds;
bool fStickyMode;
bool fIgnoreHidden;
bool fTriggerEnabled;
bool fRedrawAfterSticky;
bool fAttachAborted;
};
/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
#endif /* _MENU_H */
#endif // _MENU_H

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.
*/
#ifndef _MENU_ITEM_H
@ -65,7 +65,7 @@ class BMenuItem : public BArchivable, public BInvoker {
void Uninstall();
void SetSuper(BMenu* superMenu);
void Select(bool select);
void SetAutomaticTrigger(char trigger);
void SetAutomaticTrigger(int32 index, uint32 trigger);
protected:
virtual status_t Invoke(BMessage *msg = NULL);
@ -91,13 +91,13 @@ class BMenuItem : public BArchivable, public BInvoker {
float fCachedWidth;
int16 fTriggerIndex;
char fUserTrigger;
char fAutomaticTrigger;
char fShortcutChar;
bool fMark;
bool fEnabled;
bool fSelected;
uint32 fTrigger;
uint32 _reserved[4];
uint32 _reserved[3];
};
// BSeparatorItem now has its own declaration file, but for source

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright 2001-2006, Haiku, Inc.
* Copyright 2001-2007, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -140,7 +140,7 @@ BMenuBar::Border() const
void
BMenuBar::Draw(BRect updateRect)
{
if (RelayoutIfNeeded()) {
if (_RelayoutIfNeeded()) {
Invalidate();
return;
}
@ -169,14 +169,14 @@ BMenuBar::Draw(BRect updateRect)
SetHighColor(color);
// revert to previous used color (cheap PushState()/PopState())
DrawItems(updateRect);
_DrawItems(updateRect);
}
void
BMenuBar::AttachedToWindow()
{
Install(Window());
_Install(Window());
Window()->SetKeyMenuBar(this);
BMenu::AttachedToWindow();
@ -423,7 +423,7 @@ BMenuBar::TrackTask(void *arg)
BMenuBar *menuBar = data.menuBar;
if (data.useRect)
menuBar->fExtraRect = &data.rect;
menuBar->SetStickyMode(data.sticky);
menuBar->_SetStickyMode(data.sticky);
int32 action;
menuBar->Track(&action, data.menuIndex, data.showMenu);
@ -481,24 +481,24 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
break;
BPoint where;
ulong buttons;
uint32 buttons;
GetMouse(&where, &buttons, true);
BMenuItem *menuItem = HitTestItems(where, B_ORIGIN);
BMenuItem *menuItem = _HitTestItems(where, B_ORIGIN);
if (menuItem != NULL) {
// Select item if:
// - no previous selection
// - nonsticky mode and different selection,
// - clicked in sticky mode
if (fSelected == NULL
|| (!IsStickyMode() && menuItem != fSelected)
|| (buttons != 0 && IsStickyMode())) {
|| (!_IsStickyMode() && menuItem != fSelected)
|| (buttons != 0 && _IsStickyMode())) {
if (menuItem->Submenu() != NULL) {
if (menuItem->Submenu()->Window() == NULL) {
// open the menu if it's not opened yet
_SelectItem(menuItem);
if (IsStickyMode())
SetStickyMode(false);
if (_IsStickyMode())
_SetStickyMode(false);
} else {
// Menu was already opened, close it and bail
_SelectItem(NULL);
@ -512,25 +512,27 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
}
}
if (OverSubmenu(fSelected, ConvertToScreen(where))) {
// call _track() from the selected sub-menu when the mouse cursor
if (_OverSubmenu(fSelected, ConvertToScreen(where))) {
// call _Track() from the selected sub-menu when the mouse cursor
// is over its window
BMenu *menu = fSelected->Submenu();
window->Unlock();
locked = false;
snoozeAmount = 30000;
bool wasSticky = IsStickyMode();
bool wasSticky = _IsStickyMode();
if (wasSticky)
menu->SetStickyMode(true);
menu->_SetStickyMode(true);
int localAction;
fChosenItem = menu->_track(&localAction);
if (menu->State(NULL) == MENU_STATE_TRACKING && menu->IsStickyMode())
menu->SetStickyMode(false);
fChosenItem = menu->_Track(&localAction);
if (menu->State(NULL) == MENU_STATE_TRACKING
&& menu->_IsStickyMode())
menu->_SetStickyMode(false);
// check if the user started holding down a mouse button in a submenu
if (wasSticky && !IsStickyMode())
if (wasSticky && !_IsStickyMode()) {
buttons = 1;
// buttons must have been pressed in the meantime
}
// This code is needed to make menus
// 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
// where to store the current mouse position ?
BPoint newWhere;
ulong newButtons;
uint32 newButtons;
if (window->Lock()) {
GetMouse(&newWhere, &newButtons);
window->Unlock();
@ -550,50 +552,50 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
if (fExtraRect != NULL && fExtraRect->Contains(where)
// 9 = 3 pixels ^ 2 (since point_distance() returns the square of the distance)
&& point_distance(newWhere, where) < 9) {
SetStickyMode(true);
_SetStickyMode(true);
fExtraRect = NULL;
} else
fState = MENU_STATE_CLOSED;
}
} else if (menuItem == NULL && fSelected != NULL
&& !IsStickyMode() && fState != MENU_STATE_TRACKING_SUBMENU) {
&& !_IsStickyMode() && fState != MENU_STATE_TRACKING_SUBMENU) {
_SelectItem(NULL);
fState = MENU_STATE_TRACKING;
}
if (locked)
window->Unlock();
if (fState == MENU_STATE_CLOSED
|| (buttons != 0 && IsStickyMode() && menuItem == NULL))
|| (buttons != 0 && _IsStickyMode() && menuItem == NULL))
break;
else if (buttons == 0 && !IsStickyMode()) {
if ((fSelected != NULL && fSelected->Submenu() == NULL) || menuItem == NULL) {
else if (buttons == 0 && !_IsStickyMode()) {
if ((fSelected != NULL && fSelected->Submenu() == NULL)
|| menuItem == NULL) {
fChosenItem = fSelected;
break;
} else
SetStickyMode(true);
_SetStickyMode(true);
}
if (snoozeAmount > 0)
snooze(snoozeAmount);
}
if (window->Lock()) {
if (fSelected != NULL)
_SelectItem(NULL);
if (fChosenItem != NULL)
fChosenItem->Invoke();
RestoreFocus();
window->Unlock();
}
if (IsStickyMode())
SetStickyMode(false);
if (_IsStickyMode())
_SetStickyMode(false);
DeleteMenuWindow();
_DeleteMenuWindow();
if (action != NULL)
*action = fState;
@ -602,13 +604,13 @@ BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu)
}
void
void
BMenuBar::StealFocus()
{
// We already stole the focus, don't do anything
if (fPrevFocusToken != -1)
return;
BWindow *window = Window();
if (window != NULL && window->Lock()) {
BView *focus = window->CurrentFocus();
@ -646,5 +648,5 @@ BMenuBar::InitData(menu_layout layout)
{
fLastBounds = new BRect(Bounds());
SetItemMargins(8, 2, 8, 2);
SetIgnoreHidden(true);
_SetIgnoreHidden(true);
}

View File

@ -11,14 +11,17 @@
//! Display item for BMenu class
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <Bitmap.h>
#include <MenuItem.h>
#include <Shape.h>
#include <String.h>
#include <Window.h>
#include <string.h>
#include <stdlib.h>
#include "utf8_functions.h"
const unsigned char kCtrlBits[] = {
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)
SetMarked(marked);
if (data->HasInt32("_user_trig")) {
int32 user_trig;
data->FindInt32("_user_trig", &user_trig);
SetTrigger(user_trig);
}
int32 userTrigger;
if (data->FindInt32("_user_trig", &userTrigger) == B_OK)
SetTrigger(userTrigger);
if (data->HasInt32("_shortcut")) {
int32 shortcut, mods;
@ -139,10 +138,8 @@ BMenuItem::BMenuItem(BMessage *data)
BMessage subMessage;
if (data->FindMessage("_submenu", &subMessage) == B_OK) {
BArchivable *object = instantiate_object(&subMessage);
if (object != NULL) {
BMenu *menu = dynamic_cast<BMenu *>(object);
if (menu != NULL)
_InitMenuData(menu);
}
@ -251,7 +248,7 @@ BMenuItem::SetMarked(bool state)
fMark = state;
if (state && Menu() != NULL)
Menu()->ItemMarked(this);
Menu()->_ItemMarked(this);
}
@ -260,12 +257,18 @@ BMenuItem::SetTrigger(char 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) {
fAutomaticTrigger = trigger;
fTriggerIndex = pos - Label();
fTrigger = tolower(UTF8ToCharCode(&pos));
} else {
fAutomaticTrigger = 0;
fTrigger = 0;
fTriggerIndex = -1;
}
@ -369,10 +372,10 @@ BMenuItem::Frame() const
void
BMenuItem::GetContentSize(float *width, float *height)
{
fSuper->CacheFontInfo();
fSuper->_CacheFontInfo();
fCachedWidth = fSuper->StringWidth(fLabel);
if (width)
*width = (float)ceil(fCachedWidth);
if (height)
@ -385,9 +388,9 @@ BMenuItem::TruncateLabel(float maxWidth, char *newLabel)
{
BFont font;
BString string(fLabel);
font.TruncateString(&string, B_TRUNCATE_MIDDLE, maxWidth);
string.CopyInto(newLabel, 0, string.Length());
newLabel[string.Length()] = '\0';
}
@ -396,14 +399,14 @@ BMenuItem::TruncateLabel(float maxWidth, char *newLabel)
void
BMenuItem::DrawContent()
{
fSuper->CacheFontInfo();
fSuper->_CacheFontInfo();
fSuper->MovePenBy(0, fSuper->fAscent);
BPoint lineStart = fSuper->PenLocation();
float labelWidth, labelHeight;
GetContentSize(&labelWidth, &labelHeight);
// truncate if needed
// TODO: Actually, this is still never triggered
if (fBounds.Width() > labelWidth)
@ -414,12 +417,12 @@ BMenuItem::DrawContent()
fSuper->DrawString(truncatedLabel);
delete[] truncatedLabel;
}
if (fSuper->AreTriggersEnabled() && fTriggerIndex != -1) {
float escapements[fTriggerIndex + 1];
BFont font;
fSuper->GetFont(&font);
font.GetEscapements(fLabel, fTriggerIndex + 1, escapements);
for (int32 i = 0; i < fTriggerIndex; i++)
@ -427,10 +430,10 @@ BMenuItem::DrawContent()
lineStart.x--;
lineStart.y++;
BPoint lineEnd(lineStart);
lineEnd.x += escapements[fTriggerIndex] * font.Size();
fSuper->StrokeLine(lineStart, lineEnd);
}
}
@ -462,8 +465,7 @@ BMenuItem::Draw()
if (enabled)
fSuper->SetHighColor(ui_color(B_MENU_ITEM_TEXT_COLOR));
else
fSuper->SetHighColor(tint_color(bgColor,
B_DISABLED_LABEL_TINT));
fSuper->SetHighColor(tint_color(bgColor, B_DISABLED_LABEL_TINT));
// draw content
fSuper->MovePenTo(ContentLocation());
@ -536,7 +538,7 @@ BMenuItem::_InitData()
fCachedWidth = 0;
fTriggerIndex = -1;
fUserTrigger = 0;
fAutomaticTrigger = 0;
fTrigger = 0;
fShortcutChar = 0;
fMark = false;
fEnabled = true;
@ -563,7 +565,7 @@ void
BMenuItem::Install(BWindow *window)
{
if (fSubmenu)
fSubmenu->Install(window);
fSubmenu->_Install(window);
fWindow = window;
@ -592,7 +594,7 @@ BMenuItem::Invoke(BMessage *message)
if (!message && !notify)
message = Message();
if (!message) {
if (!fSuper->IsWatched())
return err;
@ -603,7 +605,7 @@ BMenuItem::Invoke(BMessage *message)
clone.AddInt64("when", (int64)system_time());
clone.AddPointer("source", this);
clone.AddMessenger("be:sender", BMessenger(fSuper));
if (message)
err = BInvoker::Invoke(&clone);
@ -618,12 +620,13 @@ void
BMenuItem::Uninstall()
{
if (fSubmenu != NULL)
fSubmenu->Uninstall();
fSubmenu->_Uninstall();
if (Target() == fWindow)
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 = NULL;
@ -643,7 +646,7 @@ BMenuItem::SetSuper(BMenu *super)
fSuper->fSubmenus--;
fSubmenu->fSuper = super;
}
fSuper = super;
}
@ -841,13 +844,8 @@ BMenuItem::_DrawControlChar(char shortcut, BPoint where)
void
BMenuItem::SetAutomaticTrigger(char trigger)
BMenuItem::SetAutomaticTrigger(int32 index, uint32 trigger)
{
fAutomaticTrigger = trigger;
const char* pos = strchr(Label(), trigger);
if (pos != NULL)
fTriggerIndex = pos - Label();
else
fTriggerIndex = -1;
fTriggerIndex = index;
fTrigger = trigger;
}