Interface and implementation for simplifying editing of Settings via a menu.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33904 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,382 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "SettingsMenu.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <Looper.h>
|
||||||
|
#include <Menu.h>
|
||||||
|
|
||||||
|
#include <AutoDeleter.h>
|
||||||
|
|
||||||
|
#include "MessageCodes.h"
|
||||||
|
#include "SettingsDescription.h"
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - SettingsMenu
|
||||||
|
|
||||||
|
|
||||||
|
SettingsMenu::SettingsMenu()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SettingsMenu::~SettingsMenu()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - SettingMenuItem
|
||||||
|
|
||||||
|
|
||||||
|
SettingMenuItem::SettingMenuItem(Setting* setting, const char* label,
|
||||||
|
BMessage* message, char shortcut, uint32 modifiers)
|
||||||
|
:
|
||||||
|
BMenuItem(label, message, shortcut, modifiers),
|
||||||
|
fSetting(setting)
|
||||||
|
{
|
||||||
|
fSetting->AcquireReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SettingMenuItem::SettingMenuItem(Setting* setting, BMenu* menu,
|
||||||
|
BMessage* message)
|
||||||
|
:
|
||||||
|
BMenuItem(menu, message),
|
||||||
|
fSetting(setting)
|
||||||
|
{
|
||||||
|
fSetting->AcquireReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SettingMenuItem::~SettingMenuItem()
|
||||||
|
{
|
||||||
|
fSetting->ReleaseReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingMenuItem::PrepareToShow(BLooper* parentLooper, BHandler* targetHandler,
|
||||||
|
Settings* settings)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
SettingMenuItem::Finish(BLooper* parentLooper, BHandler* targetHandler,
|
||||||
|
bool force)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingMenuItem::ItemSelected(Settings* settings)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BoolMenuItem
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsMenuImpl::MenuItem : public SettingMenuItem {
|
||||||
|
public:
|
||||||
|
MenuItem(Setting* setting,
|
||||||
|
const char* label, BMessage* message,
|
||||||
|
char shortcut = 0, uint32 modifiers = 0)
|
||||||
|
:
|
||||||
|
SettingMenuItem(setting, label, message, shortcut, modifiers)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem(Setting* setting, BMenu* menu, BMessage* message = NULL)
|
||||||
|
:
|
||||||
|
SettingMenuItem(setting, menu, message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void PrepareToShow(BLooper* parentLooper, BHandler* targetHandler,
|
||||||
|
Settings* settings)
|
||||||
|
{
|
||||||
|
BMessage* message = new BMessage(
|
||||||
|
MSG_SETTINGS_MENU_IMPL_ITEM_SELECTED);
|
||||||
|
if (message == NULL)
|
||||||
|
return;
|
||||||
|
message->AddPointer("setting", fSetting);
|
||||||
|
|
||||||
|
SetMessage(message);
|
||||||
|
SetTarget(targetHandler);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsMenuImpl::BoolMenuItem : public MenuItem {
|
||||||
|
public:
|
||||||
|
BoolMenuItem(BoolSetting* setting)
|
||||||
|
:
|
||||||
|
MenuItem(setting, setting->Name(), NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - OptionMenuItem
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsMenuImpl::OptionMenuItem : public BMenuItem {
|
||||||
|
public:
|
||||||
|
OptionMenuItem(SettingsOption* option)
|
||||||
|
:
|
||||||
|
BMenuItem(option->Name(), NULL),
|
||||||
|
fOption(option)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsOption* Option() const
|
||||||
|
{
|
||||||
|
return fOption;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrepareToShow(BLooper* parentLooper, BHandler* targetHandler,
|
||||||
|
Settings* settings, OptionsSetting* setting)
|
||||||
|
{
|
||||||
|
BMessage* message = new BMessage(
|
||||||
|
MSG_SETTINGS_MENU_IMPL_OPTION_ITEM_SELECTED);
|
||||||
|
if (message == NULL)
|
||||||
|
return;
|
||||||
|
message->AddPointer("setting", static_cast<Setting*>(setting));
|
||||||
|
message->AddPointer("option", fOption);
|
||||||
|
|
||||||
|
SetMessage(message);
|
||||||
|
SetTarget(targetHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SettingsOption* fOption;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - OptionsMenuItem
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsMenuImpl::OptionsMenuItem : public MenuItem {
|
||||||
|
public:
|
||||||
|
OptionsMenuItem(OptionsSetting* setting, BMenu* menu)
|
||||||
|
:
|
||||||
|
MenuItem(setting, menu)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void PrepareToShow(BLooper* parentLooper, BHandler* targetHandler,
|
||||||
|
Settings* settings)
|
||||||
|
{
|
||||||
|
SettingsOption* selectedOption = settings->OptionValue(
|
||||||
|
dynamic_cast<OptionsSetting*>(GetSetting()));
|
||||||
|
|
||||||
|
for (int32 i = 0; BMenuItem* item = Submenu()->ItemAt(i); i++) {
|
||||||
|
OptionMenuItem* optionItem = dynamic_cast<OptionMenuItem*>(item);
|
||||||
|
if (optionItem != NULL)
|
||||||
|
optionItem->PrepareToShow(parentLooper, targetHandler,
|
||||||
|
settings, dynamic_cast<OptionsSetting*>(GetSetting()));
|
||||||
|
|
||||||
|
optionItem->SetMarked(optionItem->Option() == selectedOption);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionItemSelected(Settings* settings, SettingsOption* option)
|
||||||
|
{
|
||||||
|
settings->SetValue(fSetting,
|
||||||
|
BVariant(option->ID(), B_VARIANT_DONT_COPY_DATA));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - SettingsMenuImpl
|
||||||
|
|
||||||
|
|
||||||
|
SettingsMenuImpl::SettingsMenuImpl(Settings* settings)
|
||||||
|
:
|
||||||
|
fSettings(settings),
|
||||||
|
fMenu(NULL)
|
||||||
|
{
|
||||||
|
fSettings->AcquireReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SettingsMenuImpl::~SettingsMenuImpl()
|
||||||
|
{
|
||||||
|
RemoveFromMenu();
|
||||||
|
fSettings->ReleaseReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
SettingsMenuImpl::AddItem(SettingMenuItem* item)
|
||||||
|
{
|
||||||
|
return fMenuItems.AddItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
SettingsMenuImpl::AddBoolItem(BoolSetting* setting)
|
||||||
|
{
|
||||||
|
SettingMenuItem* item = new(std::nothrow) BoolMenuItem(setting);
|
||||||
|
if (item == NULL || !AddItem(item)) {
|
||||||
|
delete item;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
SettingsMenuImpl::AddOptionsItem(OptionsSetting* setting)
|
||||||
|
{
|
||||||
|
// create the submenu
|
||||||
|
BMenu* menu = new(std::nothrow) BMenu(setting->Name());
|
||||||
|
if (menu == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// create the menu item
|
||||||
|
OptionsMenuItem* item = new(std::nothrow) OptionsMenuItem(setting, menu);
|
||||||
|
if (item == NULL) {
|
||||||
|
delete menu;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ObjectDeleter<OptionsMenuItem> itemDeleter(item);
|
||||||
|
|
||||||
|
// create sub menu items for the options
|
||||||
|
int32 count = setting->CountOptions();
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
SettingsOption* option = setting->OptionAt(i);
|
||||||
|
BMenuItem* optionItem = new(std::nothrow) OptionMenuItem(option);
|
||||||
|
if (optionItem == NULL || !menu->AddItem(optionItem)) {
|
||||||
|
delete optionItem;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AddItem(item))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
itemDeleter.Detach();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMenuImpl::AddToMenu(BMenu* menu, int32 index)
|
||||||
|
{
|
||||||
|
if (fMenu != NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
fMenu = menu;
|
||||||
|
|
||||||
|
for (int32 i = 0; SettingMenuItem* item = fMenuItems.ItemAt(i); i++) {
|
||||||
|
if (!fMenu->AddItem(item, index + i)) {
|
||||||
|
for (i--; i >= 0; i--)
|
||||||
|
fMenu->RemoveItem(fMenuItems.ItemAt(i));
|
||||||
|
|
||||||
|
menu = NULL;
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsMenuImpl::RemoveFromMenu()
|
||||||
|
{
|
||||||
|
if (fMenu == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int32 i = 0; SettingMenuItem* item = fMenuItems.ItemAt(i); i++)
|
||||||
|
fMenu->RemoveItem(item);
|
||||||
|
|
||||||
|
fMenu = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsMenuImpl::PrepareToShow(BLooper* parentLooper)
|
||||||
|
{
|
||||||
|
parentLooper->AddHandler(this);
|
||||||
|
|
||||||
|
for (int32 i = 0; SettingMenuItem* item = fMenuItems.ItemAt(i); i++)
|
||||||
|
item->PrepareToShow(parentLooper, this, fSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
SettingsMenuImpl::Finish(BLooper* parentLooper, bool force)
|
||||||
|
{
|
||||||
|
bool stillActive = false;
|
||||||
|
|
||||||
|
for (int32 i = 0; SettingMenuItem* item = fMenuItems.ItemAt(i); i++)
|
||||||
|
stillActive |= item->Finish(parentLooper, this, force);
|
||||||
|
|
||||||
|
parentLooper->RemoveHandler(this);
|
||||||
|
|
||||||
|
return stillActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsMenuImpl::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case MSG_SETTINGS_MENU_IMPL_ITEM_SELECTED:
|
||||||
|
{
|
||||||
|
Setting* setting;
|
||||||
|
if (message->FindPointer("setting", (void**)&setting) != B_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (SettingMenuItem* item = _FindMenuItem(setting))
|
||||||
|
item->ItemSelected(fSettings);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MSG_SETTINGS_MENU_IMPL_OPTION_ITEM_SELECTED:
|
||||||
|
{
|
||||||
|
Setting* setting;
|
||||||
|
SettingsOption* option;
|
||||||
|
if (message->FindPointer("setting", (void**)&setting) != B_OK
|
||||||
|
|| message->FindPointer("option", (void**)&option) != B_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the options setting item
|
||||||
|
OptionsMenuItem* optionsItem = dynamic_cast<OptionsMenuItem*>(
|
||||||
|
_FindMenuItem(setting));
|
||||||
|
if (optionsItem == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
optionsItem->OptionItemSelected(fSettings, option);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
BHandler::MessageReceived(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SettingMenuItem*
|
||||||
|
SettingsMenuImpl::_FindMenuItem(Setting* setting) const
|
||||||
|
{
|
||||||
|
for (int32 i = 0; SettingMenuItem* item = fMenuItems.ItemAt(i); i++) {
|
||||||
|
if (item->GetSetting() == setting)
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef SETTINGS_MENU_H
|
||||||
|
#define SETTINGS_MENU_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <MenuItem.h>
|
||||||
|
|
||||||
|
#include <Referenceable.h>
|
||||||
|
|
||||||
|
#include "Settings.h"
|
||||||
|
|
||||||
|
|
||||||
|
class BoolSetting;
|
||||||
|
class OptionsSetting;
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsMenu : public BReferenceable {
|
||||||
|
public:
|
||||||
|
SettingsMenu();
|
||||||
|
virtual ~SettingsMenu();
|
||||||
|
|
||||||
|
virtual status_t AddToMenu(BMenu* menu, int32 index) = 0;
|
||||||
|
virtual void RemoveFromMenu() = 0;
|
||||||
|
|
||||||
|
virtual void PrepareToShow(BLooper* parentLooper) = 0;
|
||||||
|
virtual bool Finish(BLooper* parentLooper, bool force) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SettingMenuItem : public BMenuItem {
|
||||||
|
public:
|
||||||
|
SettingMenuItem(Setting* setting,
|
||||||
|
const char* label, BMessage* message,
|
||||||
|
char shortcut = 0, uint32 modifiers = 0);
|
||||||
|
SettingMenuItem(Setting* setting, BMenu* menu,
|
||||||
|
BMessage* message = NULL);
|
||||||
|
virtual ~SettingMenuItem();
|
||||||
|
|
||||||
|
Setting* GetSetting() const { return fSetting; }
|
||||||
|
|
||||||
|
virtual void PrepareToShow(BLooper* parentLooper,
|
||||||
|
BHandler* targetHandler,
|
||||||
|
Settings* settings);
|
||||||
|
virtual bool Finish(BLooper* parentLooper,
|
||||||
|
BHandler* targetHandler, bool force);
|
||||||
|
|
||||||
|
virtual void ItemSelected(Settings* settings);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Setting* fSetting;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsMenuImpl : public SettingsMenu, private BHandler {
|
||||||
|
public:
|
||||||
|
SettingsMenuImpl(Settings* settings);
|
||||||
|
virtual ~SettingsMenuImpl();
|
||||||
|
|
||||||
|
bool AddItem(SettingMenuItem* item);
|
||||||
|
// takes over ownership
|
||||||
|
bool AddBoolItem(BoolSetting* setting);
|
||||||
|
bool AddOptionsItem(OptionsSetting* setting);
|
||||||
|
|
||||||
|
BMenu* Menu() const { return fMenu; }
|
||||||
|
virtual status_t AddToMenu(BMenu* menu, int32 index);
|
||||||
|
virtual void RemoveFromMenu();
|
||||||
|
|
||||||
|
virtual void PrepareToShow(BLooper* parentLooper);
|
||||||
|
virtual bool Finish(BLooper* parentLooper, bool force);
|
||||||
|
|
||||||
|
Settings* GetSettings() const { return fSettings; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class MenuItem;
|
||||||
|
class BoolMenuItem;
|
||||||
|
class OptionMenuItem;
|
||||||
|
class OptionsMenuItem;
|
||||||
|
|
||||||
|
typedef BObjectList<SettingMenuItem> MenuItemList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SettingMenuItem* _FindMenuItem(Setting* setting) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Settings* fSettings;
|
||||||
|
BMenu* fMenu;
|
||||||
|
MenuItemList fMenuItems;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SETTINGS_MENU_H
|
||||||
Reference in New Issue
Block a user