BColorMenuItem: add custom color menufield
http://insightfactory.tumblr.com/image/142366356207 * Make the color box a rectangle with proportions of golden ratio. * Override GetContentSize() to make menu item area larger. * Label should never truncate since I make sure there is enough room. * Draw the label using BMenuItem parent class * Carefully adjust the spacing so that there is an attractive amount of padding between the checkmark and color box and the color box and label. Add _AddMenu method to BMenuField that adds BColorMenuItem as its base menu item. This shows the BColorMenuItem in the closed state. Create BPrivate::MenuItemPrivate Add a SetSubmenu() method to MenuItemPrivate that gives you the ability to add a submenu after creating the object. This method should be public Skip disabled items Color gets updated even if you select an item in a submenu
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2014 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* John Scipione, [email protected]
|
||||
*/
|
||||
#ifndef COLOR_MENU_ITEM_H
|
||||
#define COLOR_MENU_ITEM_H
|
||||
|
||||
|
||||
#include <InterfaceDefs.h>
|
||||
#include <MenuItem.h>
|
||||
|
||||
|
||||
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
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2016 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* John Scipione, [email protected]
|
||||
*/
|
||||
#ifndef __MENU_ITEM_PRIVATE_H
|
||||
#define __MENU_ITEM_PRIVATE_H
|
||||
|
||||
|
||||
#include <MenuItem.h>
|
||||
|
||||
|
||||
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
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright 2014 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* John Scipione, [email protected]
|
||||
*/
|
||||
|
||||
|
||||
#include "ColorMenuItem.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <MenuField.h>
|
||||
#include <MenuPrivate.h>
|
||||
|
||||
|
||||
// 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<BMenuField*>(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<BColorMenuItem*>(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() {}
|
||||
@@ -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
|
||||
|
||||
@@ -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 <MenuField.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <stdio.h>
|
||||
// for printf in TRACE
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <AbstractLayoutItem.h>
|
||||
#include <Archivable.h>
|
||||
#include <BMCPrivate.h>
|
||||
#include <ControlLook.h>
|
||||
#include <LayoutUtils.h>
|
||||
#include <MenuBar.h>
|
||||
#include <MenuItem.h>
|
||||
#include <MenuItemPrivate.h>
|
||||
#include <MenuPrivate.h>
|
||||
#include <Message.h>
|
||||
#include <MessageFilter.h>
|
||||
@@ -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<BSeparatorItem*>(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<BMenuItem*>(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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 <MenuItemPrivate.h>
|
||||
|
||||
#include <Menu.h>
|
||||
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user