diff --git a/src/kits/interface/MenuBar.cpp b/src/kits/interface/MenuBar.cpp index ec98a77fa8..6fb4f7515e 100644 --- a/src/kits/interface/MenuBar.cpp +++ b/src/kits/interface/MenuBar.cpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// Copyright (c) 2001-2002, OpenBeOS +// Copyright (c) 2001-2004, Haiku, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), @@ -20,30 +20,39 @@ // DEALINGS IN THE SOFTWARE. // // File Name: Menubar.cpp -// Author: Marc Flerackers (mflerackers@androme.be) +// Authors: Marc Flerackers (mflerackers@androme.be) +// Stefano Ceccherini (burton666@libero.it) // Description: BMenuBar is a menu that's at the root of a menu hierarchy. //------------------------------------------------------------------------------ +// TODO: Finish this class -// Standard Includes ----------------------------------------------------------- - -// System Includes ------------------------------------------------------------- +#include +#include #include #include #include -// Project Includes ------------------------------------------------------------ +#include -// Local Includes -------------------------------------------------------------- +#include -// Local Defines --------------------------------------------------------------- +struct menubar_data +{ + BMenuBar *menuBar; + int32 menuIndex; + + bool sticky; + bool showMenu; + + bool useRect; + BRect rect; +}; -// Globals --------------------------------------------------------------------- -//------------------------------------------------------------------------------ BMenuBar::BMenuBar(BRect frame, const char *title, uint32 resizeMask, menu_layout layout, bool resizeToFit) : BMenu(frame, title, resizeMask, - B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE, layout, resizeToFit), + B_WILL_DRAW | B_FRAME_EVENTS, layout, resizeToFit), fBorder(B_BORDER_FRAME), fTrackingPID(-1), fPrevFocusToken(-1), @@ -51,10 +60,10 @@ BMenuBar::BMenuBar(BRect frame, const char *title, uint32 resizeMask, fLastBounds(NULL), fTracking(false) { - // TODO: which flags to pass to BMenu? InitData(layout); } -//------------------------------------------------------------------------------ + + BMenuBar::BMenuBar(BMessage *data) : BMenu(data), fBorder(B_BORDER_FRAME), @@ -68,25 +77,38 @@ BMenuBar::BMenuBar(BMessage *data) if (data->FindInt32("_border", &border) == B_OK) SetBorder((menu_bar_border)border); + + // TODO: InitData() ?? } -//------------------------------------------------------------------------------ + + BMenuBar::~BMenuBar() { + if (fTrackingPID >= 0) { + status_t dummy; + wait_for_thread(fTrackingPID, &dummy); + } + + delete fLastBounds; } -//------------------------------------------------------------------------------ -BArchivable *BMenuBar::Instantiate(BMessage *data) + + +BArchivable * +BMenuBar::Instantiate(BMessage *data) { - if ( validate_instantiation(data, "BMenuBar")) + if (validate_instantiation(data, "BMenuBar")) return new BMenuBar(data); else return NULL; } -//------------------------------------------------------------------------------ -status_t BMenuBar::Archive(BMessage *data, bool deep) const + + +status_t +BMenuBar::Archive(BMessage *data, bool deep) const { status_t err = BMenu::Archive(data, deep); - if (err != B_OK) + if (err < B_OK) return err; if (Border() != B_BORDER_FRAME) @@ -94,197 +116,354 @@ status_t BMenuBar::Archive(BMessage *data, bool deep) const return err; } -//------------------------------------------------------------------------------ -void BMenuBar::SetBorder(menu_bar_border border) + + +void +BMenuBar::SetBorder(menu_bar_border border) { fBorder = border; } -//------------------------------------------------------------------------------ -menu_bar_border BMenuBar::Border() const + + +menu_bar_border +BMenuBar::Border() const { return fBorder; } -//------------------------------------------------------------------------------ -void BMenuBar::Draw(BRect updateRect) + + +void +BMenuBar::Draw(BRect updateRect) { // TODO: implement additional border styles - BRect bounds(Bounds()); + // Fix this function, the BMenuBar isn't drawn correctly + if (!IsEnabled()) { + LayoutItems(0); + Sync(); + Invalidate(); + } else { + BRect bounds(Bounds()); - SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_LIGHTEN_2_TINT)); - StrokeLine(BPoint(0.0f, bounds.bottom - 2.0f ), BPoint(0.0f, 0.0f)); - StrokeLine(BPoint(bounds.right, 0.0f ) ); + SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_LIGHTEN_2_TINT)); + StrokeLine(BPoint(0.0f, bounds.bottom - 2.0f), BPoint(0.0f, 0.0f)); + StrokeLine(BPoint(bounds.right, 0.0f)); - SetHighColor(tint_color ( ui_color ( B_MENU_BACKGROUND_COLOR ), B_DARKEN_1_TINT)); - StrokeLine(BPoint ( 1.0f, bounds.bottom - 1.0f ), - BPoint(bounds.right, bounds.bottom - 1.0f ) ); + SetHighColor(tint_color(ui_color( B_MENU_BACKGROUND_COLOR), B_DARKEN_1_TINT)); + StrokeLine(BPoint(1.0f, bounds.bottom - 1.0f), + BPoint(bounds.right, bounds.bottom - 1.0f)); - SetHighColor(tint_color(ui_color (B_MENU_BACKGROUND_COLOR), B_DARKEN_2_TINT)); - StrokeLine(BPoint(0.0f, bounds.bottom), BPoint(bounds.right, bounds.bottom)); - StrokeLine(BPoint(bounds.right, 0.0f), BPoint(bounds.right, bounds.bottom)); + SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_2_TINT)); + StrokeLine(BPoint(0.0f, bounds.bottom), BPoint(bounds.right, bounds.bottom)); + StrokeLine(BPoint(bounds.right, 0.0f), BPoint(bounds.right, bounds.bottom)); - DrawItems(updateRect); -} -//------------------------------------------------------------------------------ -void BMenuBar::AttachedToWindow() + DrawItems(updateRect); + } +} + + +void +BMenuBar::AttachedToWindow() { Install(Window()); Window()->SetKeyMenuBar(this); BMenu::AttachedToWindow(); } -//------------------------------------------------------------------------------ -void BMenuBar::DetachedFromWindow() + + +void +BMenuBar::DetachedFromWindow() { BMenu::DetachedFromWindow(); } -//------------------------------------------------------------------------------ -void BMenuBar::MessageReceived(BMessage *msg) + + +void +BMenuBar::MessageReceived(BMessage *msg) { BMenu::MessageReceived(msg); } -//------------------------------------------------------------------------------ -void BMenuBar::MouseDown(BPoint where) + + +void +BMenuBar::MouseDown(BPoint where) { - StealFocus(); - BMenu::MouseDown(where); - - // TODO: the real code should look like this: - /* - if (!Window()->IsActive()) - { - Window()->Activate(); - Window()->UpdateIfNeeded(); + BWindow *window = Window(); + if (!window->IsActive() || !window->IsFront()) { + window->Activate(); + window->UpdateIfNeeded(); } - StartMenuBar(); - */ + StartMenuBar(-1, false, false); } -//------------------------------------------------------------------------------ -void BMenuBar::WindowActivated(bool state) + + +void +BMenuBar::WindowActivated(bool state) { BView::WindowActivated(state); } -//------------------------------------------------------------------------------ -void BMenuBar::MouseUp(BPoint where) + + +void +BMenuBar::MouseUp(BPoint where) { - BMenu::MouseUp(where); - RestoreFocus(); - - // BView::MouseUp(where); + BView::MouseUp(where); } -//------------------------------------------------------------------------------ -void BMenuBar::FrameMoved(BPoint new_position) + + +void +BMenuBar::FrameMoved(BPoint newPosition) { - BMenu::FrameMoved(new_position); + BMenu::FrameMoved(newPosition); } -//------------------------------------------------------------------------------ -void BMenuBar::FrameResized(float new_width, float new_height) + + +void +BMenuBar::FrameResized(float newWidth, float newHeight) { - BMenu::FrameResized(new_width, new_height); + BMenu::FrameResized(newWidth, newHeight); } -//------------------------------------------------------------------------------ -void BMenuBar::Show() + + +void +BMenuBar::Show() { BView::Show(); } -//------------------------------------------------------------------------------ -void BMenuBar::Hide() + + +void +BMenuBar::Hide() { BView::Hide(); } -//------------------------------------------------------------------------------ -BHandler *BMenuBar::ResolveSpecifier(BMessage *msg, int32 index, + + +BHandler * +BMenuBar::ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, int32 form, const char *property) { return BMenu::ResolveSpecifier(msg, index, specifier, form, property); } -//------------------------------------------------------------------------------ -status_t BMenuBar::GetSupportedSuites(BMessage *data) + + +status_t +BMenuBar::GetSupportedSuites(BMessage *data) { return BMenu::GetSupportedSuites(data); } -//------------------------------------------------------------------------------ -void BMenuBar::ResizeToPreferred() + + +void +BMenuBar::ResizeToPreferred() { BMenu::ResizeToPreferred(); } -//------------------------------------------------------------------------------ -void BMenuBar::GetPreferredSize(float *width, float *height) + + +void +BMenuBar::GetPreferredSize(float *width, float *height) { BMenu::GetPreferredSize(width, height); } -//------------------------------------------------------------------------------ -void BMenuBar::MakeFocus(bool state) + + +void +BMenuBar::MakeFocus(bool state) { BMenu::MakeFocus(state); } -//------------------------------------------------------------------------------ -void BMenuBar::AllAttached() + + +void +BMenuBar::AllAttached() { BMenu::AllAttached(); } -//------------------------------------------------------------------------------ -void BMenuBar::AllDetached() + + +void +BMenuBar::AllDetached() { BMenu::AllDetached(); } -//------------------------------------------------------------------------------ -status_t BMenuBar::Perform(perform_code d, void *arg) + + +status_t +BMenuBar::Perform(perform_code d, void *arg) { return BMenu::Perform(d, arg); } -//------------------------------------------------------------------------------ + + void BMenuBar::_ReservedMenuBar1() {} void BMenuBar::_ReservedMenuBar2() {} void BMenuBar::_ReservedMenuBar3() {} void BMenuBar::_ReservedMenuBar4() {} -//------------------------------------------------------------------------------ -BMenuBar &BMenuBar::operator=(const BMenuBar &) + + +BMenuBar & +BMenuBar::operator=(const BMenuBar &) { return *this; } -//------------------------------------------------------------------------------ -void BMenuBar::StartMenuBar(int32 menuIndex, bool sticky, bool show_menu, + + +void +BMenuBar::StartMenuBar(int32 menuIndex, bool sticky, bool show_menu, BRect *special_rect) { - /* - if (!Window()) - return; + BWindow *window = Window(); + if (!window) + debugger("MenuBar must be added to a window before it can be used."); + + BAutolock lock(window); + if (lock.IsLocked()) { + fPrevFocusToken = -1; + fTracking = true; - Window()->Lock(); - Window()->MenusBeginning(); - sem_id = create_sem(??, ??); - set_menu_sem(BWindow, sem); - fTrackingPID = spawn_thread(TrackTask, "menu_tracking?", B_NORMAL_PRIORITY, ??); - Window()->Unlock(); - */ + window->MenusBeginning(); + + fMenuSem = create_sem(0, "window close sem"); + _set_menu_sem_(window, fMenuSem); + + fTrackingPID = spawn_thread(TrackTask, "menu_tracking", B_NORMAL_PRIORITY, NULL); + if (fTrackingPID >= 0) { + menubar_data data; + data.menuBar = this; + data.menuIndex = menuIndex; + data.sticky = sticky; + data.showMenu = show_menu; + data.useRect = special_rect != NULL; + if (data.useRect) + data.rect = *special_rect; + + send_data(fTrackingPID, 0, &data, sizeof(data)); + resume_thread(fTrackingPID); + + } else { + _set_menu_sem_(window, B_NO_MORE_SEMS); + delete_sem(fMenuSem); + } + } } -//------------------------------------------------------------------------------ -long BMenuBar::TrackTask(void *arg) + + +long +BMenuBar::TrackTask(void *arg) { - return -1; + menubar_data data; + thread_id id; + + receive_data(&id, &data, sizeof(data)); + + BMenuBar *menuBar = data.menuBar; + BWindow *window = menuBar->Window(); + + menuBar->SetStickyMode(data.sticky); + + int32 action; + menuBar->Track(&action, data.menuIndex, data.showMenu); + + // Sends a _MENUS_DONE_ message to the BWindow. + // Weird: There is a _MENUS_DONE_ message but not a + // _MENUS_BEGINNING_ message, in fact the MenusBeginning() + // hook function is called directly. + window->PostMessage(_MENUS_DONE_); + + _set_menu_sem_(window, B_BAD_SEM_ID); + delete_sem(menuBar->fMenuSem); + menuBar->fMenuSem = B_BAD_SEM_ID; + + return 0; } -//------------------------------------------------------------------------------ -BMenuItem *BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu) + + +BMenuItem * +BMenuBar::Track(int32 *action, int32 startIndex, bool showMenu) { - return NULL; + // TODO: This function is very incomplete and just partially working: + // For example, it doesn't respect the "sticky mode" setting. + // Cleanup + BMenuItem *resultItem = NULL; + BWindow *window = Window(); + if (window->LockWithTimeout(200000) == B_OK) { + BPoint where; + ulong buttons; + do { + printf("BMenuBar: tracking...\n"); + GetMouse(&where, &buttons); + BMenuItem *menuItem = HitTestItems(where, B_ORIGIN); + if (menuItem) { + BMenu *menu = menuItem->Submenu(); + if (menu) { + printf("BMenuBar: showing menu %s\n", menu->Name()); + menu->Show(); + do { + snooze(40000); + GetMouse(&where, &buttons); + + // If we aren't over this BMenu anymore, exit the tracking loop. + BMenuItem *testItem = HitTestItems(where, B_ORIGIN); + if (testItem != NULL && testItem != menuItem) + break; + + resultItem = menu->_track((int *)action, startIndex); + printf("BMenuBar: menu %s: action: %ld\n", menu->Name(), *action); + + // "action" is "5" when the BMenu is closed. + } while (*action != 5); + + printf("BMenuBar: hiding menu %s\n", menu->Name()); + menu->_hide(); + } + } + snooze(40000); + } while (buttons != 0); + + window->Unlock(); + } + + if (resultItem != NULL) { + printf("BMenuBar: selected item %s\n", resultItem->Label()); + resultItem->Invoke(); + } + + return resultItem; } -//------------------------------------------------------------------------------ -void BMenuBar::StealFocus() + + +void +BMenuBar::StealFocus() { - //fPrevFocusToken = _get_object_token_(Window()->CurrentFocus()); - MakeFocus(); + BWindow *window = Window(); + if (window && window->Lock()) { + BView *focus = window->CurrentFocus(); + if (focus) + fPrevFocusToken = _get_object_token_(focus); + MakeFocus(); + window->Unlock(); + } } -//------------------------------------------------------------------------------ -void BMenuBar::RestoreFocus() + + +void +BMenuBar::RestoreFocus() { - //fPrevFocusToken + BWindow *window = Window(); + if (window && window->Lock()) { + // TODO: Give focus back to the previous focus BView + window->Unlock(); + } } -//------------------------------------------------------------------------------ -void BMenuBar::InitData(menu_layout layout) + + +void +BMenuBar::InitData(menu_layout layout) { + fLastBounds = new BRect(Bounds()); SetItemMargins(8, 2, 8, 2); SetIgnoreHidden(true); } -//------------------------------------------------------------------------------