Author: axeld Date: 2010-04-15 20:07:40 +0200 (Thu, 15 Apr 2010) New Revision: 36310 Changeset: http://dev.haiku-os.org/changeset/36310/haiku Ticket: http://dev.haiku-os.org/ticket/5312 Modified: haiku/trunk/headers/private/kernel/boot/menu.h haiku/trunk/src/system/boot/loader/menu.cpp haiku/trunk/src/system/boot/platform/generic/text_menu.cpp Log: * 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. Modified: haiku/trunk/headers/private/kernel/boot/menu.h =================================================================== --- haiku/trunk/headers/private/kernel/boot/menu.h 2010-04-15 18:02:06 UTC (rev 36309) +++ haiku/trunk/headers/private/kernel/boot/menu.h 2010-04-15 18:07:40 UTC (rev 36310) @@ -13,7 +13,8 @@ class Menu; 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 { @@ -52,6 +53,9 @@ void SetHelpText(const char* text); const char* HelpText() const { return fHelpText; } + void SetShortcut(char key); + char Shortcut() const { return fShortcut; } + const char* Label() const { return fLabel; } Menu* Submenu() const { return fSubMenu; } @@ -70,6 +74,7 @@ Menu* fSubMenu; const void* fData; const char* fHelpText; + char fShortcut; }; @@ -122,13 +127,23 @@ { fChoiceText = text; } const char* ChoiceText() const { return fChoiceText; } - void Run(); + void AddShortcut(char key, shortcut_hook function); + shortcut_hook FindShortcut(char key) const; + MenuItem* FindItemByShortcut(char key); + void Run(); + private: friend class MenuItem; void Draw(MenuItem* item); private: + struct shortcut { + shortcut* next; + shortcut_hook function; + char key; + }; + const char* fTitle; const char* fChoiceText; int32 fCount; @@ -136,6 +151,7 @@ MenuItemList fItems; menu_type fType; MenuItem* fSuperItem; + shortcut* fShortcuts; }; Modified: haiku/trunk/src/system/boot/loader/menu.cpp =================================================================== --- haiku/trunk/src/system/boot/loader/menu.cpp 2010-04-15 18:02:06 UTC (rev 36309) +++ haiku/trunk/src/system/boot/loader/menu.cpp 2010-04-15 18:07:40 UTC (rev 36310) @@ -151,23 +151,29 @@ } -/** This sets a help text that is shown when the item is - * selected. - * Note, unlike the label, the string is not copied, it's - * just referenced and has to stay valid as long as the - * item's menu is being used. - */ - +/*! This sets a help text that is shown when the item is + selected. + Note, unlike the label, the string is not copied, it's + just referenced and has to stay valid as long as the + item's menu is being used. +*/ void -MenuItem::SetHelpText(const char *text) +MenuItem::SetHelpText(const char* text) { fHelpText = text; } void -MenuItem::SetMenu(Menu *menu) +MenuItem::SetShortcut(char key) { + fShortcut = key; +} + + +void +MenuItem::SetMenu(Menu* menu) +{ fMenu = menu; } @@ -175,14 +181,15 @@ // #pragma mark - -Menu::Menu(menu_type type, const char *title) +Menu::Menu(menu_type type, const char* title) : fTitle(title), fChoiceText(NULL), fCount(0), fIsHidden(true), fType(type), - fSuperItem(NULL) + fSuperItem(NULL), + fShortcuts(NULL) { } @@ -199,7 +206,7 @@ } -MenuItem * +MenuItem* Menu::ItemAt(int32 index) { if (index < 0 || index >= fCount) @@ -218,13 +225,12 @@ int32 -Menu::IndexOf(MenuItem *searchedItem) +Menu::IndexOf(MenuItem* searchedItem) { - MenuItemIterator iterator = ItemIterator(); - MenuItem *item; int32 index = 0; - while ((item = iterator.Next()) != NULL) { + MenuItemIterator iterator = ItemIterator(); + while (MenuItem* item = iterator.Next()) { if (item == searchedItem) return index; @@ -242,13 +248,11 @@ } -MenuItem * -Menu::FindItem(const char *label) +MenuItem* +Menu::FindItem(const char* label) { MenuItemIterator iterator = ItemIterator(); - MenuItem *item; - - while ((item = iterator.Next()) != NULL) { + while (MenuItem* item = iterator.Next()) { if (item->Label() != NULL && !strcmp(item->Label(), label)) return item; } @@ -257,13 +261,11 @@ } -MenuItem * +MenuItem* Menu::FindMarked() { MenuItemIterator iterator = ItemIterator(); - MenuItem *item; - - while ((item = iterator.Next()) != NULL) { + while (MenuItem* item = iterator.Next()) { if (item->IsMarked()) return item; } @@ -272,14 +274,13 @@ } -MenuItem * -Menu::FindSelected(int32 *_index) +MenuItem* +Menu::FindSelected(int32* _index) { - MenuItemIterator iterator = ItemIterator(); - MenuItem *item; int32 index = 0; - while ((item = iterator.Next()) != NULL) { + MenuItemIterator iterator = ItemIterator(); + while (MenuItem* item = iterator.Next()) { if (item->IsSelected()) { if (_index != NULL) *_index = index; @@ -294,7 +295,7 @@ void -Menu::AddItem(MenuItem *item) +Menu::AddItem(MenuItem* item) { item->fMenu = this; fItems.Add(item); @@ -305,7 +306,7 @@ status_t Menu::AddSeparatorItem() { - MenuItem *item = new(nothrow) MenuItem(); + MenuItem* item = new(std::nothrow) MenuItem(); if (item == NULL) return B_NO_MEMORY; @@ -316,16 +317,14 @@ } -MenuItem * +MenuItem* Menu::RemoveItemAt(int32 index) { if (index < 0 || index >= fCount) return NULL; MenuItemIterator iterator = ItemIterator(); - MenuItem *item; - - while ((item = iterator.Next()) != NULL) { + while (MenuItem* item = iterator.Next()) { if (index-- == 0) { RemoveItem(item); return item; @@ -337,7 +336,7 @@ void -Menu::RemoveItem(MenuItem *item) +Menu::RemoveItem(MenuItem* item) { item->fMenu = NULL; fItems.Remove(item); @@ -346,13 +345,54 @@ void -Menu::Draw(MenuItem *item) +Menu::AddShortcut(char key, shortcut_hook function) { - if (!IsHidden()) - platform_update_menu_item(this, item); + Menu::shortcut* shortcut = new(std::nothrow) struct Menu::shortcut; + 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; +} + + void Menu::Run() { @@ -360,6 +400,14 @@ } +void +Menu::Draw(MenuItem* item) +{ + if (!IsHidden()) + platform_update_menu_item(this, item); +} + + // #pragma mark - @@ -415,9 +463,9 @@ static bool -user_menu_boot_volume(Menu *menu, MenuItem *item) +user_menu_boot_volume(Menu* menu, MenuItem* item) { - Menu *super = menu->Supermenu(); + Menu* super = menu->Supermenu(); if (super == NULL) { // huh? return true; @@ -434,7 +482,7 @@ static bool -debug_menu_display_syslog(Menu *menu, MenuItem *item) +debug_menu_display_syslog(Menu* menu, MenuItem* item) { ring_buffer* buffer = (ring_buffer*)gKernelArgs.debug_output; if (buffer == NULL) @@ -520,7 +568,7 @@ static bool -debug_menu_toggle_debug_syslog(Menu *menu, MenuItem *item) +debug_menu_toggle_debug_syslog(Menu* menu, MenuItem* item) { gKernelArgs.keep_debug_output_buffer = item->IsMarked(); return true; @@ -528,7 +576,7 @@ static bool -debug_menu_save_syslog(Menu *menu, MenuItem *item) +debug_menu_save_syslog(Menu* menu, MenuItem* item) { Directory* volume = (Directory*)item->Data(); @@ -543,17 +591,17 @@ } -static Menu * -add_boot_volume_menu(Directory *bootVolume) +static Menu* +add_boot_volume_menu(Directory* bootVolume) { - Menu *menu = new(nothrow) Menu(CHOICE_MENU, "Select Boot Volume"); - MenuItem *item; - void *cookie; + Menu* menu = new(std::nothrow) Menu(CHOICE_MENU, "Select Boot Volume"); + MenuItem* item; + void* cookie; int32 count = 0; if (gRoot->Open(&cookie, O_RDONLY) == B_OK) { - Directory *volume; - while (gRoot->GetNextNode(cookie, (Node **)&volume) == B_OK) { + Directory* volume; + while (gRoot->GetNextNode(cookie, (Node**)&volume) == B_OK) { // only list bootable volumes if (!is_bootable(volume)) continue; @@ -601,11 +649,11 @@ } -static Menu * +static Menu* add_safe_mode_menu() { - Menu *safeMenu = new(nothrow) Menu(SAFE_MODE_MENU, "Safe Mode Options"); - MenuItem *item; + Menu* safeMenu = new(nothrow) Menu(SAFE_MODE_MENU, "Safe Mode Options"); + MenuItem* item; safeMenu->AddItem(item = new(nothrow) MenuItem("Safe mode")); item->SetData(B_SAFEMODE_SAFE_MODE); @@ -704,11 +752,11 @@ } -static Menu * +static Menu* add_debug_menu() { - Menu *menu = new(nothrow) Menu(STANDARD_MENU, "Debug Options"); - MenuItem *item; + Menu* menu = new(std::nothrow) Menu(STANDARD_MENU, "Debug Options"); + MenuItem* item; #if DEBUG_SPINLOCK_LATENCIES item = new(std::nothrow) MenuItem("Disable latency checks"); @@ -766,22 +814,21 @@ static void -apply_safe_mode_options(Menu *menu) +apply_safe_mode_options(Menu* menu) { - MenuItemIterator iterator = menu->ItemIterator(); - MenuItem *item; char buffer[2048]; int32 pos = 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() || item->Data() == NULL || (uint32)pos > sizeof(buffer)) continue; size_t totalBytes = snprintf(buffer + pos, sizeof(buffer) - pos, - "%s true\n", (const char *)item->Data()); + "%s true\n", (const char*)item->Data()); pos += std::min(totalBytes, sizeof(buffer) - pos - 1); } @@ -790,7 +837,7 @@ static bool -user_menu_reboot(Menu *menu, MenuItem *item) +user_menu_reboot(Menu* menu, MenuItem* item) { platform_exit(); return true; @@ -798,25 +845,25 @@ status_t -user_menu(Directory **_bootVolume) +user_menu(Directory** _bootVolume) { - Menu *menu = new(nothrow) Menu(MAIN_MENU); - Menu *safeModeMenu = NULL; - Menu *debugMenu = NULL; - MenuItem *item; + Menu* menu = new(std::nothrow) Menu(MAIN_MENU); + Menu* safeModeMenu = NULL; + Menu* debugMenu = NULL; + MenuItem* item; TRACE(("user_menu: enter\n")); // 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 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())); // 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())); // Add platform dependent menus @@ -824,20 +871,22 @@ menu->AddSeparatorItem(); - menu->AddItem(item = new(nothrow) MenuItem("Reboot")); + menu->AddItem(item = new(std::nothrow) MenuItem("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) { item->SetEnabled(false); menu->ItemAt(0)->Select(true); - } + } else + item->SetShortcut('b'); menu->Run(); // See if a new boot device has been selected, and propagate that back if (item->Data() != NULL) - *_bootVolume = (Directory *)item->Data(); + *_bootVolume = (Directory*)item->Data(); apply_safe_mode_options(safeModeMenu); apply_safe_mode_options(debugMenu); Modified: haiku/trunk/src/system/boot/platform/generic/text_menu.cpp =================================================================== --- haiku/trunk/src/system/boot/platform/generic/text_menu.cpp 2010-04-15 18:02:06 UTC (rev 36309) +++ haiku/trunk/src/system/boot/platform/generic/text_menu.cpp 2010-04-15 18:07:40 UTC (rev 36310) @@ -1,5 +1,5 @@ /* - * Copyright 2004-2009, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx All rights reserved. + * Copyright 2004-2010, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx * Distributed under the terms of the MIT License. */ @@ -38,6 +38,9 @@ static int32 sMenuOffset = 0; +static void run_menu(Menu* menu); + + static int32 menu_height() { @@ -340,8 +343,48 @@ } +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 -run_menu(Menu *menu) +run_menu(Menu* menu) { sMenuOffset = 0; menu->Show(); @@ -413,43 +456,25 @@ } } else if (key == TEXT_CONSOLE_KEY_RETURN || key == TEXT_CONSOLE_KEY_SPACE) { - // 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 - - 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); - + if (invoke_item(menu, item, selected, key)) break; - } - } else if (key == TEXT_CONSOLE_KEY_ESCAPE && menu->Type() != MAIN_MENU) + } else if (key == TEXT_CONSOLE_KEY_ESCAPE + && menu->Type() != MAIN_MENU) { // escape key was hit 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();