diff --git a/headers/os/interface/MenuField.h b/headers/os/interface/MenuField.h index d605419af0..770e74ef61 100644 --- a/headers/os/interface/MenuField.h +++ b/headers/os/interface/MenuField.h @@ -1,5 +1,5 @@ /* - * Copyright 2006-2015, Haiku, Inc. All rights reserved. + * Copyright 2006-2016 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. */ #ifndef _MENU_FIELD_H @@ -135,6 +135,7 @@ private: void _InitMenuBar(BMenu* menu, BRect frame, bool fixedSize); void _InitMenuBar(const BMessage* archive); + void _AddMenu(BMenu* menu); void _ValidateLayoutData(); float _MenuBarOffset() const; @@ -159,4 +160,5 @@ private: uint32 _reserved[2]; }; + #endif // _MENU_FIELD_H diff --git a/headers/os/interface/MenuItem.h b/headers/os/interface/MenuItem.h index 3edf6173f7..055ccc3c05 100644 --- a/headers/os/interface/MenuItem.h +++ b/headers/os/interface/MenuItem.h @@ -15,6 +15,10 @@ class BMessage; class BWindow; +namespace BPrivate { + class MenuItemPrivate; +} + class BMenuItem : public BArchivable, public BInvoker { public: BMenuItem(const char* label, BMessage* message, @@ -57,6 +61,7 @@ private: friend class BMenu; friend class BPopUpMenu; friend class BMenuBar; + friend class BPrivate::MenuItemPrivate; virtual void _ReservedMenuItem1(); virtual void _ReservedMenuItem2(); @@ -77,6 +82,7 @@ private: BMenuItem(const BMenuItem& other); BMenuItem& operator=(const BMenuItem& other); +private: void _InitData(); void _InitMenuData(BMenu* menu); diff --git a/headers/private/interface/ColorMenuItem.h b/headers/private/interface/ColorMenuItem.h new file mode 100644 index 0000000000..7431bd1768 --- /dev/null +++ b/headers/private/interface/ColorMenuItem.h @@ -0,0 +1,71 @@ +/* + * Copyright 2014 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * John Scipione, jscipione@gmail.com + */ +#ifndef COLOR_MENU_ITEM_H +#define COLOR_MENU_ITEM_H + + +#include +#include + + +class BColorMenuItem : public BMenuItem { +public: + BColorMenuItem(const char* label, + BMessage* message, rgb_color color, + char shortcut = 0, + uint32 modifiers = 0); + BColorMenuItem(BMenu* menu, rgb_color color, + BMessage* message = NULL); + BColorMenuItem(BMessage* data); + + static BArchivable* Instantiate(BMessage* archive); + virtual status_t Archive(BMessage* archive, + bool deep = true) const; + + virtual void DrawContent(); + virtual void GetContentSize(float* _width, float* _height); + + virtual void SetMarked(bool mark); + + rgb_color Color() const { return fColor; }; + virtual void SetColor(rgb_color color) { fColor = color; }; + +private: + virtual void _ReservedColorMenuItem1(); + virtual void _ReservedColorMenuItem2(); + virtual void _ReservedColorMenuItem3(); + virtual void _ReservedColorMenuItem4(); + virtual void _ReservedColorMenuItem5(); + virtual void _ReservedColorMenuItem6(); + virtual void _ReservedColorMenuItem7(); + virtual void _ReservedColorMenuItem8(); + virtual void _ReservedColorMenuItem9(); + virtual void _ReservedColorMenuItem10(); + virtual void _ReservedColorMenuItem11(); + virtual void _ReservedColorMenuItem12(); + virtual void _ReservedColorMenuItem13(); + virtual void _ReservedColorMenuItem14(); + virtual void _ReservedColorMenuItem15(); + virtual void _ReservedColorMenuItem16(); + virtual void _ReservedColorMenuItem17(); + virtual void _ReservedColorMenuItem18(); + virtual void _ReservedColorMenuItem19(); + virtual void _ReservedColorMenuItem20(); + + float _LeftMargin(); + float _Padding(); + float _ColorRectWidth(); + +private: + rgb_color fColor; + + uint32 _reserved[30]; +}; + + +#endif // COLOR_MENU_ITEM_H diff --git a/headers/private/interface/MenuItemPrivate.h b/headers/private/interface/MenuItemPrivate.h new file mode 100644 index 0000000000..1b4d01f7ac --- /dev/null +++ b/headers/private/interface/MenuItemPrivate.h @@ -0,0 +1,35 @@ +/* + * Copyright 2016 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * John Scipione, jscipione@gmail.com + */ +#ifndef __MENU_ITEM_PRIVATE_H +#define __MENU_ITEM_PRIVATE_H + + +#include + + +class BMenu; + +namespace BPrivate { + +class MenuItemPrivate { +public: + MenuItemPrivate(BMenuItem* menuItem); + + void SetSubmenu(BMenu* submenu); + + void Install(BWindow* window); + void Uninstall(); + +private: + BMenuItem* fMenuItem; +}; + +}; // namespace BPrivate + + +#endif // __MENU_ITEM_PRIVATE_H diff --git a/src/kits/interface/ColorMenuItem.cpp b/src/kits/interface/ColorMenuItem.cpp new file mode 100644 index 0000000000..744d1a3a21 --- /dev/null +++ b/src/kits/interface/ColorMenuItem.cpp @@ -0,0 +1,233 @@ +/* + * Copyright 2014 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * John Scipione, jscipione@gmail.com + */ + + +#include "ColorMenuItem.h" + +#include +#include +#include + +#include + +#include +#include + + +// golden ratio +#ifdef M_PHI +# undef M_PHI +#endif +#define M_PHI 1.61803398874989484820 + + +// #pragma - ColorMenuItem + + +BColorMenuItem::BColorMenuItem(const char* label, BMessage* message, + rgb_color color, char shortcut, uint32 modifiers) + : + BMenuItem(label, message, shortcut, modifiers), + fColor(color) +{ +} + + +BColorMenuItem::BColorMenuItem(BMenu* menu, rgb_color color, + BMessage* message) + : + BMenuItem(menu, message), + fColor(color) +{ +} + + +BColorMenuItem::BColorMenuItem(BMessage* data) + : + BMenuItem(data) +{ + if (data->HasColor("_color")) { + rgb_color color; + + color = data->GetColor("_color", (rgb_color){ 0, 0, 0 }); + fColor = color; + } else + fColor = (rgb_color){ 0, 0, 0 }; +} + + +BArchivable* +BColorMenuItem::Instantiate(BMessage* data) +{ + if (validate_instantiation(data, "BColorMenuItem")) + return new BColorMenuItem(data); + + return NULL; +} + + +status_t +BColorMenuItem::Archive(BMessage* data, bool deep) const +{ + status_t result = BMenuItem::Archive(data, deep); + + if (result == B_OK) + result = data->AddColor("_color", fColor); + + return result; +} + + +void +BColorMenuItem::DrawContent() +{ + float leftMargin = _LeftMargin(); + float padding = _Padding(); + float colorRectWidth = _ColorRectWidth(); + + BRect colorRect(Frame().InsetByCopy(2.0f, 2.0f)); + colorRect.left = colorRect.right = leftMargin; + colorRect.right += colorRectWidth; + + rgb_color highColor = Menu()->HighColor(); + + Menu()->SetDrawingMode(B_OP_OVER); + + Menu()->SetHighColor(fColor); + Menu()->FillRect(colorRect); + + Menu()->SetHighColor(ui_color(B_CONTROL_BORDER_COLOR)); + Menu()->StrokeRect(colorRect); + + float width = colorRectWidth + padding; + + Menu()->MovePenBy(width, 0.0f); + Menu()->SetHighColor(highColor); + + BMenuItem::DrawContent(); +} + + +void +BColorMenuItem::GetContentSize(float* _width, float* _height) +{ + float labelWidth; + float height; + BMenuItem::GetContentSize(&labelWidth, &height); + + if (_width != NULL) + *_width = _LeftMargin() + _ColorRectWidth() + _Padding() + labelWidth; + + if (_height != NULL) + *_height = height; +} + + +void +BColorMenuItem::SetMarked(bool mark) +{ + BMenuItem::SetMarked(mark); + + if (!mark) + return; + + // we are marking the item + + BMenu* menu = Menu(); + if (menu == NULL) + return; + + // we have a parent menu + + BMenu* _menu = menu; + while ((_menu = _menu->Supermenu()) != NULL) + menu = _menu; + + // went up the hierarchy to found the topmost menu + + if (menu == NULL || menu->Parent() == NULL) + return; + + // our topmost menu has a parent + + if (dynamic_cast(menu->Parent()) == NULL) + return; + + // our topmost menu's parent is a BMenuField + + BMenuItem* topLevelItem = menu->ItemAt((int32)0); + + if (topLevelItem == NULL) + return; + + // our topmost menu has a menu item + + BColorMenuItem* topLevelColorMenuItem + = dynamic_cast(topLevelItem); + if (topLevelColorMenuItem == NULL) + return; + + // our topmost menu's item is a BColorMenuItem + + // update the color + topLevelColorMenuItem->SetColor(fColor); + menu->Invalidate(); +} + + +// #pragma mark - BColorMenuItem private methods + + +float +BColorMenuItem::_LeftMargin() +{ + BPrivate::MenuPrivate menuPrivate(Menu()); + float leftMargin; + menuPrivate.GetItemMargins(&leftMargin, NULL, NULL, NULL); + return leftMargin; +} + + +float +BColorMenuItem::_Padding() +{ + return floorf(std::max(14.0f, be_plain_font->Size() + 2) / 2); +} + + +float +BColorMenuItem::_ColorRectWidth() +{ + return floorf(std::max(14.0f, be_plain_font->Size() + 2) * M_PHI); +} + + + +// #pragma mark - BColorMenuItem reserved virtual methods + + +void BColorMenuItem::_ReservedColorMenuItem1() {} +void BColorMenuItem::_ReservedColorMenuItem2() {} +void BColorMenuItem::_ReservedColorMenuItem3() {} +void BColorMenuItem::_ReservedColorMenuItem4() {} +void BColorMenuItem::_ReservedColorMenuItem5() {} +void BColorMenuItem::_ReservedColorMenuItem6() {} +void BColorMenuItem::_ReservedColorMenuItem7() {} +void BColorMenuItem::_ReservedColorMenuItem8() {} +void BColorMenuItem::_ReservedColorMenuItem9() {} +void BColorMenuItem::_ReservedColorMenuItem10() {} +void BColorMenuItem::_ReservedColorMenuItem11() {} +void BColorMenuItem::_ReservedColorMenuItem12() {} +void BColorMenuItem::_ReservedColorMenuItem13() {} +void BColorMenuItem::_ReservedColorMenuItem14() {} +void BColorMenuItem::_ReservedColorMenuItem15() {} +void BColorMenuItem::_ReservedColorMenuItem16() {} +void BColorMenuItem::_ReservedColorMenuItem17() {} +void BColorMenuItem::_ReservedColorMenuItem18() {} +void BColorMenuItem::_ReservedColorMenuItem19() {} +void BColorMenuItem::_ReservedColorMenuItem20() {} diff --git a/src/kits/interface/Jamfile b/src/kits/interface/Jamfile index df317a49b0..e69e4be1ea 100644 --- a/src/kits/interface/Jamfile +++ b/src/kits/interface/Jamfile @@ -57,6 +57,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { CheckBox.cpp ColorConversion.cpp ColorControl.cpp + ColorMenuItem.cpp Control.cpp ControlLook.cpp DecorInfo.cpp @@ -90,6 +91,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { MenuBar.cpp MenuField.cpp MenuItem.cpp + MenuItemPrivate.cpp MenuPrivate.cpp MenuWindow.cpp OptionControl.cpp diff --git a/src/kits/interface/MenuField.cpp b/src/kits/interface/MenuField.cpp index ae3812fc56..6f68f36a26 100644 --- a/src/kits/interface/MenuField.cpp +++ b/src/kits/interface/MenuField.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2013, Haiku, Inc. + * Copyright 2006-2016 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -13,17 +13,20 @@ #include #include + #include // for printf in TRACE #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -194,8 +197,6 @@ MouseDownFilter::Filter(BMessage* message, BHandler** target) // #pragma mark - BMenuField -using BPrivate::MenuPrivate; - BMenuField::BMenuField(BRect frame, const char* name, const char* label, BMenu* menu, uint32 resizingMode, uint32 flags) : @@ -300,6 +301,7 @@ BMenuField::BMenuField(BMessage* data) if (!BUnarchiver::IsArchiveManaged(data)) _InitMenuBar(data); + unarchiver.Finish(); } @@ -1081,7 +1083,7 @@ BMenuField::_DrawLabel(BRect updateRect) PushState(); rgb_color textColor; - MenuPrivate menuPrivate(fMenuBar); + BPrivate::MenuPrivate menuPrivate(fMenuBar); if (menuPrivate.State() != MENU_STATE_CLOSED) { // highlight the background of the label grey (like BeOS R5) SetLowColor(ui_color(B_MENU_SELECTED_BACKGROUND_COLOR)); @@ -1207,9 +1209,6 @@ BMenuField::_InitMenuBar(BMenu* menu, BRect frame, bool fixedSize) { CALLED(); - fMenu = menu; - InitMenu(menu); - if ((Flags() & B_SUPPORTS_LAYOUT) != 0) { fMenuBar = new _BMCMenuBar_(this); } else { @@ -1236,7 +1235,9 @@ BMenuField::_InitMenuBar(BMenu* menu, BRect frame, bool fixedSize) } AddChild(fMenuBar); - fMenuBar->AddItem(menu); + + _AddMenu(menu); + fMenuBar->SetFont(be_plain_font); } @@ -1257,7 +1258,7 @@ BMenuField::_InitMenuBar(const BMessage* archive) // this is normally done in InitObject2() } - fMenu = fMenuBar->SubmenuAt(0); + _AddMenu(fMenuBar->SubmenuAt(0)); bool disable; if (archive->FindBool("_disable", &disable) == B_OK) @@ -1271,6 +1272,62 @@ BMenuField::_InitMenuBar(const BMessage* archive) } +void +BMenuField::_AddMenu(BMenu* menu) +{ + if (menu == NULL || fMenuBar == NULL) + return; + + fMenu = menu; + InitMenu(menu); + + BMenuItem* item = NULL; + if (!menu->IsRadioMode() || (item = menu->FindMarked()) == NULL) { + // find the first enabled non-seperator item + int32 itemCount = menu->CountItems(); + for (int32 i = 0; i < itemCount; i++) { + item = menu->ItemAt((int32)i); + if (item == NULL || !item->IsEnabled() + || dynamic_cast(item) != NULL) { + item = NULL; + continue; + } + break; + } + } + + if (item == NULL) { + fMenuBar->AddItem(menu); + return; + } + + // build an empty copy of item + + BMessage data; + status_t result = item->Archive(&data, false); + if (result != B_OK) { + fMenuBar->AddItem(menu); + return; + } + + BArchivable* object = instantiate_object(&data); + if (object == NULL) { + fMenuBar->AddItem(menu); + return; + } + + BMenuItem* newItem = static_cast(object); + + // unset parameters + BPrivate::MenuItemPrivate newMenuItemPrivate(newItem); + newMenuItemPrivate.Uninstall(); + + // set the menu + newMenuItemPrivate.SetSubmenu(menu); + fMenuBar->AddItem(newItem); +} + + void BMenuField::_ValidateLayoutData() { @@ -1630,4 +1687,3 @@ B_IF_GCC_2(InvalidateLayout__10BMenuFieldb, _ZN10BMenuField16InvalidateLayoutEb) field->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data); } - diff --git a/src/kits/interface/MenuItemPrivate.cpp b/src/kits/interface/MenuItemPrivate.cpp new file mode 100644 index 0000000000..264282d85f --- /dev/null +++ b/src/kits/interface/MenuItemPrivate.cpp @@ -0,0 +1,56 @@ +/* + * Copyright 2016 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * John Scipione, jscipione@gmail.com + */ + + +#include + +#include + + +namespace BPrivate { + +MenuItemPrivate::MenuItemPrivate(BMenuItem* menuItem) + : + fMenuItem(menuItem) +{ +} + + +void +MenuItemPrivate::SetSubmenu(BMenu* submenu) +{ + delete fMenuItem->fSubmenu; + + fMenuItem->_InitMenuData(submenu); + + if (fMenuItem->fSuper != NULL) { + fMenuItem->fSuper->InvalidateLayout(); + + if (fMenuItem->fSuper->LockLooper()) { + fMenuItem->fSuper->Invalidate(); + fMenuItem->fSuper->UnlockLooper(); + } + } +} + + +void +MenuItemPrivate::Install(BWindow* window) +{ + fMenuItem->Install(window); +} + + +void +MenuItemPrivate::Uninstall() +{ + fMenuItem->Uninstall(); +} + + +} // namespace BPrivate