* 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:
Axel Dörfler
2010-04-15 18:07:40 +00:00
parent 1cae99d78e
commit 868aa7a0e0
3 changed files with 204 additions and 114 deletions
+17 -1
View File
@@ -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;
}; };
+87 -38
View File
@@ -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();
+60 -35
View File
@@ -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();