* Added shortcut handling to the boot loader menu (in preparation of adopting
ticket #5312). * Added shortcut 'b' to continue booting, 'r' to reboot. * Consolidated asterisk style. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36310 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -13,7 +13,8 @@
|
|||||||
class Menu;
|
class Menu;
|
||||||
class MenuItem;
|
class MenuItem;
|
||||||
|
|
||||||
typedef bool (*menu_item_hook)(Menu *, MenuItem *);
|
typedef bool (*menu_item_hook)(Menu* menu, MenuItem* item);
|
||||||
|
typedef void (*shortcut_hook)(char key);
|
||||||
|
|
||||||
|
|
||||||
enum menu_item_type {
|
enum menu_item_type {
|
||||||
@@ -52,6 +53,9 @@ public:
|
|||||||
void SetHelpText(const char* text);
|
void SetHelpText(const char* text);
|
||||||
const char* HelpText() const { return fHelpText; }
|
const char* HelpText() const { return fHelpText; }
|
||||||
|
|
||||||
|
void SetShortcut(char key);
|
||||||
|
char Shortcut() const { return fShortcut; }
|
||||||
|
|
||||||
const char* Label() const { return fLabel; }
|
const char* Label() const { return fLabel; }
|
||||||
Menu* Submenu() const { return fSubMenu; }
|
Menu* Submenu() const { return fSubMenu; }
|
||||||
|
|
||||||
@@ -70,6 +74,7 @@ private:
|
|||||||
Menu* fSubMenu;
|
Menu* fSubMenu;
|
||||||
const void* fData;
|
const void* fData;
|
||||||
const char* fHelpText;
|
const char* fHelpText;
|
||||||
|
char fShortcut;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -122,6 +127,10 @@ public:
|
|||||||
{ fChoiceText = text; }
|
{ fChoiceText = text; }
|
||||||
const char* ChoiceText() const { return fChoiceText; }
|
const char* ChoiceText() const { return fChoiceText; }
|
||||||
|
|
||||||
|
void AddShortcut(char key, shortcut_hook function);
|
||||||
|
shortcut_hook FindShortcut(char key) const;
|
||||||
|
MenuItem* FindItemByShortcut(char key);
|
||||||
|
|
||||||
void Run();
|
void Run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -129,6 +138,12 @@ private:
|
|||||||
void Draw(MenuItem* item);
|
void Draw(MenuItem* item);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct shortcut {
|
||||||
|
shortcut* next;
|
||||||
|
shortcut_hook function;
|
||||||
|
char key;
|
||||||
|
};
|
||||||
|
|
||||||
const char* fTitle;
|
const char* fTitle;
|
||||||
const char* fChoiceText;
|
const char* fChoiceText;
|
||||||
int32 fCount;
|
int32 fCount;
|
||||||
@@ -136,6 +151,7 @@ private:
|
|||||||
MenuItemList fItems;
|
MenuItemList fItems;
|
||||||
menu_type fType;
|
menu_type fType;
|
||||||
MenuItem* fSuperItem;
|
MenuItem* fSuperItem;
|
||||||
|
shortcut* fShortcuts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -151,13 +151,12 @@ MenuItem::SetData(const void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** This sets a help text that is shown when the item is
|
/*! This sets a help text that is shown when the item is
|
||||||
* selected.
|
selected.
|
||||||
* Note, unlike the label, the string is not copied, it's
|
Note, unlike the label, the string is not copied, it's
|
||||||
* just referenced and has to stay valid as long as the
|
just referenced and has to stay valid as long as the
|
||||||
* item's menu is being used.
|
item's menu is being used.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
MenuItem::SetHelpText(const char* text)
|
MenuItem::SetHelpText(const char* text)
|
||||||
{
|
{
|
||||||
@@ -165,6 +164,13 @@ MenuItem::SetHelpText(const char *text)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MenuItem::SetShortcut(char key)
|
||||||
|
{
|
||||||
|
fShortcut = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MenuItem::SetMenu(Menu* menu)
|
MenuItem::SetMenu(Menu* menu)
|
||||||
{
|
{
|
||||||
@@ -182,7 +188,8 @@ Menu::Menu(menu_type type, const char *title)
|
|||||||
fCount(0),
|
fCount(0),
|
||||||
fIsHidden(true),
|
fIsHidden(true),
|
||||||
fType(type),
|
fType(type),
|
||||||
fSuperItem(NULL)
|
fSuperItem(NULL),
|
||||||
|
fShortcuts(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,11 +227,10 @@ Menu::ItemAt(int32 index)
|
|||||||
int32
|
int32
|
||||||
Menu::IndexOf(MenuItem* searchedItem)
|
Menu::IndexOf(MenuItem* searchedItem)
|
||||||
{
|
{
|
||||||
MenuItemIterator iterator = ItemIterator();
|
|
||||||
MenuItem *item;
|
|
||||||
int32 index = 0;
|
int32 index = 0;
|
||||||
|
|
||||||
while ((item = iterator.Next()) != NULL) {
|
MenuItemIterator iterator = ItemIterator();
|
||||||
|
while (MenuItem* item = iterator.Next()) {
|
||||||
if (item == searchedItem)
|
if (item == searchedItem)
|
||||||
return index;
|
return index;
|
||||||
|
|
||||||
@@ -246,9 +252,7 @@ MenuItem *
|
|||||||
Menu::FindItem(const char* label)
|
Menu::FindItem(const char* label)
|
||||||
{
|
{
|
||||||
MenuItemIterator iterator = ItemIterator();
|
MenuItemIterator iterator = ItemIterator();
|
||||||
MenuItem *item;
|
while (MenuItem* item = iterator.Next()) {
|
||||||
|
|
||||||
while ((item = iterator.Next()) != NULL) {
|
|
||||||
if (item->Label() != NULL && !strcmp(item->Label(), label))
|
if (item->Label() != NULL && !strcmp(item->Label(), label))
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
@@ -261,9 +265,7 @@ MenuItem *
|
|||||||
Menu::FindMarked()
|
Menu::FindMarked()
|
||||||
{
|
{
|
||||||
MenuItemIterator iterator = ItemIterator();
|
MenuItemIterator iterator = ItemIterator();
|
||||||
MenuItem *item;
|
while (MenuItem* item = iterator.Next()) {
|
||||||
|
|
||||||
while ((item = iterator.Next()) != NULL) {
|
|
||||||
if (item->IsMarked())
|
if (item->IsMarked())
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
@@ -275,11 +277,10 @@ Menu::FindMarked()
|
|||||||
MenuItem*
|
MenuItem*
|
||||||
Menu::FindSelected(int32* _index)
|
Menu::FindSelected(int32* _index)
|
||||||
{
|
{
|
||||||
MenuItemIterator iterator = ItemIterator();
|
|
||||||
MenuItem *item;
|
|
||||||
int32 index = 0;
|
int32 index = 0;
|
||||||
|
|
||||||
while ((item = iterator.Next()) != NULL) {
|
MenuItemIterator iterator = ItemIterator();
|
||||||
|
while (MenuItem* item = iterator.Next()) {
|
||||||
if (item->IsSelected()) {
|
if (item->IsSelected()) {
|
||||||
if (_index != NULL)
|
if (_index != NULL)
|
||||||
*_index = index;
|
*_index = index;
|
||||||
@@ -305,7 +306,7 @@ Menu::AddItem(MenuItem *item)
|
|||||||
status_t
|
status_t
|
||||||
Menu::AddSeparatorItem()
|
Menu::AddSeparatorItem()
|
||||||
{
|
{
|
||||||
MenuItem *item = new(nothrow) MenuItem();
|
MenuItem* item = new(std::nothrow) MenuItem();
|
||||||
if (item == NULL)
|
if (item == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -323,9 +324,7 @@ Menu::RemoveItemAt(int32 index)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
MenuItemIterator iterator = ItemIterator();
|
MenuItemIterator iterator = ItemIterator();
|
||||||
MenuItem *item;
|
while (MenuItem* item = iterator.Next()) {
|
||||||
|
|
||||||
while ((item = iterator.Next()) != NULL) {
|
|
||||||
if (index-- == 0) {
|
if (index-- == 0) {
|
||||||
RemoveItem(item);
|
RemoveItem(item);
|
||||||
return item;
|
return item;
|
||||||
@@ -346,10 +345,51 @@ Menu::RemoveItem(MenuItem *item)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Menu::Draw(MenuItem *item)
|
Menu::AddShortcut(char key, shortcut_hook function)
|
||||||
{
|
{
|
||||||
if (!IsHidden())
|
Menu::shortcut* shortcut = new(std::nothrow) struct Menu::shortcut;
|
||||||
platform_update_menu_item(this, item);
|
if (shortcut == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
shortcut->key = key;
|
||||||
|
shortcut->function = function;
|
||||||
|
|
||||||
|
shortcut->next = fShortcuts;
|
||||||
|
fShortcuts = shortcut;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
shortcut_hook
|
||||||
|
Menu::FindShortcut(char key) const
|
||||||
|
{
|
||||||
|
if (key == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
const Menu::shortcut* shortcut = fShortcuts;
|
||||||
|
while (shortcut != NULL) {
|
||||||
|
if (shortcut->key == key)
|
||||||
|
return shortcut->function;
|
||||||
|
|
||||||
|
shortcut = shortcut->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MenuItem*
|
||||||
|
Menu::FindItemByShortcut(char key)
|
||||||
|
{
|
||||||
|
if (key == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
MenuItemList::Iterator iterator = ItemIterator();
|
||||||
|
while (MenuItem* item = iterator.Next()) {
|
||||||
|
if (item->Shortcut() == key)
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -360,6 +400,14 @@ Menu::Run()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Menu::Draw(MenuItem* item)
|
||||||
|
{
|
||||||
|
if (!IsHidden())
|
||||||
|
platform_update_menu_item(this, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -546,7 +594,7 @@ debug_menu_save_syslog(Menu *menu, MenuItem *item)
|
|||||||
static Menu*
|
static Menu*
|
||||||
add_boot_volume_menu(Directory* bootVolume)
|
add_boot_volume_menu(Directory* bootVolume)
|
||||||
{
|
{
|
||||||
Menu *menu = new(nothrow) Menu(CHOICE_MENU, "Select Boot Volume");
|
Menu* menu = new(std::nothrow) Menu(CHOICE_MENU, "Select Boot Volume");
|
||||||
MenuItem* item;
|
MenuItem* item;
|
||||||
void* cookie;
|
void* cookie;
|
||||||
int32 count = 0;
|
int32 count = 0;
|
||||||
@@ -707,7 +755,7 @@ add_save_debug_syslog_menu()
|
|||||||
static Menu*
|
static Menu*
|
||||||
add_debug_menu()
|
add_debug_menu()
|
||||||
{
|
{
|
||||||
Menu *menu = new(nothrow) Menu(STANDARD_MENU, "Debug Options");
|
Menu* menu = new(std::nothrow) Menu(STANDARD_MENU, "Debug Options");
|
||||||
MenuItem* item;
|
MenuItem* item;
|
||||||
|
|
||||||
#if DEBUG_SPINLOCK_LATENCIES
|
#if DEBUG_SPINLOCK_LATENCIES
|
||||||
@@ -768,14 +816,13 @@ add_debug_menu()
|
|||||||
static void
|
static void
|
||||||
apply_safe_mode_options(Menu* menu)
|
apply_safe_mode_options(Menu* menu)
|
||||||
{
|
{
|
||||||
MenuItemIterator iterator = menu->ItemIterator();
|
|
||||||
MenuItem *item;
|
|
||||||
char buffer[2048];
|
char buffer[2048];
|
||||||
int32 pos = 0;
|
int32 pos = 0;
|
||||||
|
|
||||||
buffer[0] = '\0';
|
buffer[0] = '\0';
|
||||||
|
|
||||||
while ((item = iterator.Next()) != NULL) {
|
MenuItemIterator iterator = menu->ItemIterator();
|
||||||
|
while (MenuItem* item = iterator.Next()) {
|
||||||
if (item->Type() == MENU_ITEM_SEPARATOR || !item->IsMarked()
|
if (item->Type() == MENU_ITEM_SEPARATOR || !item->IsMarked()
|
||||||
|| item->Data() == NULL || (uint32)pos > sizeof(buffer))
|
|| item->Data() == NULL || (uint32)pos > sizeof(buffer))
|
||||||
continue;
|
continue;
|
||||||
@@ -800,7 +847,7 @@ user_menu_reboot(Menu *menu, MenuItem *item)
|
|||||||
status_t
|
status_t
|
||||||
user_menu(Directory** _bootVolume)
|
user_menu(Directory** _bootVolume)
|
||||||
{
|
{
|
||||||
Menu *menu = new(nothrow) Menu(MAIN_MENU);
|
Menu* menu = new(std::nothrow) Menu(MAIN_MENU);
|
||||||
Menu* safeModeMenu = NULL;
|
Menu* safeModeMenu = NULL;
|
||||||
Menu* debugMenu = NULL;
|
Menu* debugMenu = NULL;
|
||||||
MenuItem* item;
|
MenuItem* item;
|
||||||
@@ -808,15 +855,15 @@ user_menu(Directory **_bootVolume)
|
|||||||
TRACE(("user_menu: enter\n"));
|
TRACE(("user_menu: enter\n"));
|
||||||
|
|
||||||
// Add boot volume
|
// Add boot volume
|
||||||
menu->AddItem(item = new(nothrow) MenuItem("Select boot volume",
|
menu->AddItem(item = new(std::nothrow) MenuItem("Select boot volume",
|
||||||
add_boot_volume_menu(*_bootVolume)));
|
add_boot_volume_menu(*_bootVolume)));
|
||||||
|
|
||||||
// Add safe mode
|
// Add safe mode
|
||||||
menu->AddItem(item = new(nothrow) MenuItem("Select safe mode options",
|
menu->AddItem(item = new(std::nothrow) MenuItem("Select safe mode options",
|
||||||
safeModeMenu = add_safe_mode_menu()));
|
safeModeMenu = add_safe_mode_menu()));
|
||||||
|
|
||||||
// add debug menu
|
// add debug menu
|
||||||
menu->AddItem(item = new(nothrow) MenuItem("Select debug options",
|
menu->AddItem(item = new(std::nothrow) MenuItem("Select debug options",
|
||||||
debugMenu = add_debug_menu()));
|
debugMenu = add_debug_menu()));
|
||||||
|
|
||||||
// Add platform dependent menus
|
// Add platform dependent menus
|
||||||
@@ -824,14 +871,16 @@ user_menu(Directory **_bootVolume)
|
|||||||
|
|
||||||
menu->AddSeparatorItem();
|
menu->AddSeparatorItem();
|
||||||
|
|
||||||
menu->AddItem(item = new(nothrow) MenuItem("Reboot"));
|
menu->AddItem(item = new(std::nothrow) MenuItem("Reboot"));
|
||||||
item->SetTarget(user_menu_reboot);
|
item->SetTarget(user_menu_reboot);
|
||||||
|
item->SetShortcut('r');
|
||||||
|
|
||||||
menu->AddItem(item = new(nothrow) MenuItem("Continue booting"));
|
menu->AddItem(item = new(std::nothrow) MenuItem("Continue booting"));
|
||||||
if (*_bootVolume == NULL) {
|
if (*_bootVolume == NULL) {
|
||||||
item->SetEnabled(false);
|
item->SetEnabled(false);
|
||||||
menu->ItemAt(0)->Select(true);
|
menu->ItemAt(0)->Select(true);
|
||||||
}
|
} else
|
||||||
|
item->SetShortcut('b');
|
||||||
|
|
||||||
menu->Run();
|
menu->Run();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2004-2009, Axel Dörfler, [email protected]. All rights reserved.
|
* Copyright 2004-2010, Axel Dörfler, [email protected].
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -38,6 +38,9 @@ static const console_color kArrowColor = GRAY;
|
|||||||
static int32 sMenuOffset = 0;
|
static int32 sMenuOffset = 0;
|
||||||
|
|
||||||
|
|
||||||
|
static void run_menu(Menu* menu);
|
||||||
|
|
||||||
|
|
||||||
static int32
|
static int32
|
||||||
menu_height()
|
menu_height()
|
||||||
{
|
{
|
||||||
@@ -340,6 +343,46 @@ select_next_valid_item(Menu *menu, int32 selected)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
invoke_item(Menu* menu, MenuItem* item, int32& selected, char key)
|
||||||
|
{
|
||||||
|
// leave the menu
|
||||||
|
if (item->Submenu() != NULL && key == TEXT_CONSOLE_KEY_RETURN) {
|
||||||
|
int32 offset = sMenuOffset;
|
||||||
|
menu->Hide();
|
||||||
|
|
||||||
|
run_menu(item->Submenu());
|
||||||
|
if (item->Target() != NULL)
|
||||||
|
(*item->Target())(menu, item);
|
||||||
|
|
||||||
|
// restore current menu
|
||||||
|
sMenuOffset = offset;
|
||||||
|
menu->FindSelected(&selected);
|
||||||
|
menu->Show();
|
||||||
|
draw_menu(menu);
|
||||||
|
} else if (item->Type() == MENU_ITEM_MARKABLE) {
|
||||||
|
// toggle state
|
||||||
|
item->SetMarked(!item->IsMarked());
|
||||||
|
print_item_at(selected, item);
|
||||||
|
|
||||||
|
if (item->Target() != NULL)
|
||||||
|
(*item->Target())(menu, item);
|
||||||
|
} else if (key == TEXT_CONSOLE_KEY_RETURN) {
|
||||||
|
// the space key does not exit the menu, only return does
|
||||||
|
if (menu->Type() == CHOICE_MENU
|
||||||
|
&& item->Type() != MENU_ITEM_NO_CHOICE
|
||||||
|
&& item->Type() != MENU_ITEM_TITLE)
|
||||||
|
item->SetMarked(true);
|
||||||
|
|
||||||
|
if (item->Target() != NULL)
|
||||||
|
(*item->Target())(menu, item);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
run_menu(Menu* menu)
|
run_menu(Menu* menu)
|
||||||
{
|
{
|
||||||
@@ -413,43 +456,25 @@ run_menu(Menu *menu)
|
|||||||
}
|
}
|
||||||
} else if (key == TEXT_CONSOLE_KEY_RETURN
|
} else if (key == TEXT_CONSOLE_KEY_RETURN
|
||||||
|| key == TEXT_CONSOLE_KEY_SPACE) {
|
|| key == TEXT_CONSOLE_KEY_SPACE) {
|
||||||
// leave the menu
|
if (invoke_item(menu, item, selected, key))
|
||||||
if (item->Submenu() != NULL && key == TEXT_CONSOLE_KEY_RETURN) {
|
|
||||||
int32 offset = sMenuOffset;
|
|
||||||
menu->Hide();
|
|
||||||
|
|
||||||
run_menu(item->Submenu());
|
|
||||||
if (item->Target() != NULL)
|
|
||||||
(*item->Target())(menu, item);
|
|
||||||
|
|
||||||
// restore current menu
|
|
||||||
sMenuOffset = offset;
|
|
||||||
menu->FindSelected(&selected);
|
|
||||||
menu->Show();
|
|
||||||
draw_menu(menu);
|
|
||||||
} else if (item->Type() == MENU_ITEM_MARKABLE) {
|
|
||||||
// toggle state
|
|
||||||
item->SetMarked(!item->IsMarked());
|
|
||||||
print_item_at(selected, item);
|
|
||||||
|
|
||||||
if (item->Target() != NULL)
|
|
||||||
(*item->Target())(menu, item);
|
|
||||||
} else if (key == TEXT_CONSOLE_KEY_RETURN) {
|
|
||||||
// the space key does not exit the menu
|
|
||||||
|
|
||||||
if (menu->Type() == CHOICE_MENU
|
|
||||||
&& item->Type() != MENU_ITEM_NO_CHOICE
|
|
||||||
&& item->Type() != MENU_ITEM_TITLE)
|
|
||||||
item->SetMarked(true);
|
|
||||||
|
|
||||||
if (item->Target() != NULL)
|
|
||||||
(*item->Target())(menu, item);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
} else if (key == TEXT_CONSOLE_KEY_ESCAPE
|
||||||
} else if (key == TEXT_CONSOLE_KEY_ESCAPE && menu->Type() != MAIN_MENU)
|
&& menu->Type() != MAIN_MENU) {
|
||||||
// escape key was hit
|
// escape key was hit
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
// Shortcut processing
|
||||||
|
shortcut_hook function = menu->FindShortcut(key);
|
||||||
|
if (function != NULL)
|
||||||
|
function(key);
|
||||||
|
else {
|
||||||
|
item = menu->FindItemByShortcut(key);
|
||||||
|
if (item != NULL && invoke_item(menu, item, selected,
|
||||||
|
TEXT_CONSOLE_KEY_RETURN)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
menu->Hide();
|
menu->Hide();
|
||||||
|
|||||||
Reference in New Issue
Block a user