diff --git a/src/kernel/boot/loader/menu.cpp b/src/kernel/boot/loader/menu.cpp index ad26a24f85..4efeeed362 100644 --- a/src/kernel/boot/loader/menu.cpp +++ b/src/kernel/boot/loader/menu.cpp @@ -1,5 +1,5 @@ /* -** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. +** Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. ** Distributed under the terms of the OpenBeOS License. */ @@ -10,18 +10,273 @@ #include +#include +#include #include #include #include #include +#include + + +MenuItem::MenuItem(const char *label, Menu *subMenu) + : + fLabel(strdup(label)), + fTarget(NULL), + fIsMarked(false), + fIsSelected(false), + fType(MENU_ITEM_STANDARD), + fMenu(NULL), + fSubMenu(subMenu) +{ +} + + +MenuItem::~MenuItem() +{ + free(const_cast(fLabel)); +} + + +void +MenuItem::SetTarget(menu_item_hook target) +{ + fTarget = target; +} + + +void +MenuItem::SetMarked(bool marked) +{ + if (fIsMarked == marked) + return; + + if (marked && fMenu != NULL && fMenu->Type() == CHOICE_MENU) { + // unmark previous item + MenuItem *markedItem = fMenu->FindMarked(); + if (markedItem != NULL) + markedItem->SetMarked(false); + } + + fIsMarked = marked; + + if (fMenu != NULL) + fMenu->Draw(this); +} + + +void +MenuItem::Select(bool selected) +{ + if (fIsSelected == selected) + return; + + if (selected && fMenu != NULL) { + // unselect previous item + MenuItem *selectedItem = fMenu->FindSelected(); + if (selectedItem != NULL) + selectedItem->Select(false); + } + + fIsSelected = selected; + + if (fMenu != NULL) + fMenu->Draw(this); +} + + +void +MenuItem::SetType(menu_item_type type) +{ + fType = type; +} + + +void +MenuItem::SetMenu(Menu *menu) +{ + fMenu = menu; +} + + +// #pragma mark - + + +Menu::Menu(menu_type type, const char *title) + : + fTitle(title), + fCount(0), + fIsHidden(true), + fType(type) +{ +} + + +Menu::~Menu() +{ + // take all remaining items with us + + MenuItem *item; + while ((item = fItems.RemoveHead()) != NULL) { + delete item; + } +} + + +MenuItem * +Menu::ItemAt(int32 index) +{ + if (index < 0 || index >= fCount) + return NULL; + + MenuItemIterator iterator = ItemIterator(); + MenuItem *item; + + while ((item = iterator.Next()) != NULL) { + if (index-- == 0) + return item; + } + + return NULL; +} + + +int32 +Menu::IndexOf(MenuItem *searchedItem) +{ + MenuItemIterator iterator = ItemIterator(); + MenuItem *item; + int32 index = 0; + + while ((item = iterator.Next()) != NULL) { + if (item == searchedItem) + return index; + + index++; + } + + return -1; +} + + +int32 +Menu::CountItems() const +{ + return fCount; +} + + +MenuItem * +Menu::FindMarked() +{ + MenuItemIterator iterator = ItemIterator(); + MenuItem *item; + + while ((item = iterator.Next()) != NULL) { + if (item->IsMarked()) + return item; + } + + return NULL; +} + + +MenuItem * +Menu::FindSelected(int32 *_index) +{ + MenuItemIterator iterator = ItemIterator(); + MenuItem *item; + int32 index = 0; + + while ((item = iterator.Next()) != NULL) { + if (item->IsSelected()) { + if (_index != NULL) + *_index = index; + return item; + } + + index++; + } + + return NULL; +} + + +void +Menu::AddItem(MenuItem *item) +{ + item->fMenu = this; + fItems.Add(item); + fCount++; +} + status_t -user_menu(Directory **_bootVolume) +Menu::AddSeparatorItem() { - platform_switch_to_text_mode(); + MenuItem *item = new MenuItem(); + if (item == NULL) + return B_NO_MEMORY; - int32 index = 1; + item->SetType(MENU_ITEM_SEPARATOR); + + AddItem(item); + return B_OK; +} + + +MenuItem * +Menu::RemoveItemAt(int32 index) +{ + if (index < 0 || index >= fCount) + return NULL; + + MenuItemIterator iterator = ItemIterator(); + MenuItem *item; + + while ((item = iterator.Next()) != NULL) { + if (index-- == 0) { + RemoveItem(item); + return item; + } + } + + return NULL; +} + + +void +Menu::RemoveItem(MenuItem *item) +{ + item->fMenu = NULL; + fItems.Remove(item); + fCount--; +} + + +void +Menu::Draw(MenuItem *item) +{ + if (!IsHidden()) + platform_update_menu_item(this, item); +} + + +void +Menu::Run() +{ +} + + +// #pragma mark - + + +static Menu * +add_boot_volume_menu(Directory *bootVolume) +{ + Menu *menu = new Menu(CHOICE_MENU, "Select Boot Volume"); + MenuItem *item; void *cookie; if (gRoot->Open(&cookie, O_RDONLY) == B_OK) { @@ -32,18 +287,62 @@ user_menu(Directory **_bootVolume) continue; char name[B_FILE_NAME_LENGTH]; - if (volume->GetName(name, sizeof(name)) == B_OK) - printf("%ld) /%s\n", index++, name); - - // ToDo: for now, just choose the first volume as boot volume - if (*_bootVolume == NULL) - *_bootVolume = volume; + if (volume->GetName(name, sizeof(name)) == B_OK) { + menu->AddItem(item = new MenuItem(name)); + if (volume == bootVolume) { + item->SetMarked(true); + item->Select(true); + } + } } gRoot->Close(cookie); } - puts("(it always tries to boot from the first for now...)"); - platform_switch_to_logo(); + menu->AddSeparatorItem(); + menu->AddItem(item = new MenuItem("Rescan volumes")); + menu->AddItem(item = new MenuItem("Return to main manu")); + + return menu; +} + + +static Menu * +add_safe_mode_menu() +{ + Menu *safeMenu = new Menu(SAFE_MODE_MENU, "Safe Mode Options"); + MenuItem *item; + + safeMenu->AddItem(item = new MenuItem("Disable user add-ons")); + item->SetType(MENU_ITEM_MARKABLE); + + platform_add_menus(safeMenu); + + safeMenu->AddSeparatorItem(); + safeMenu->AddItem(item = new MenuItem("Return to main menu")); + + return safeMenu; +} + + +status_t +user_menu(Directory **_bootVolume) +{ + Menu *menu = new Menu(MAIN_MENU); + MenuItem *item; + + // Add boot volume + menu->AddItem(item = new MenuItem("Select boot volume", add_boot_volume_menu(*_bootVolume))); + + // Add safe mode + menu->AddItem(item = new MenuItem("Select safe mode options", add_safe_mode_menu())); + + // Add platform dependent menus + platform_add_menus(menu); + + menu->AddSeparatorItem(); + menu->AddItem(item = new MenuItem("Continue booting")); + + platform_run_menu(menu); return B_OK; }