⛏️ index : haiku.git

/*
 * Copyright 2004-2012, Axel DΓΆrfler, axeld@pinc-software.de.
 * Distributed under the terms of the MIT License.
 */


#include "RootFileSystem.h"

#include <boot/platform.h>
#include <boot/vfs.h>
#include <boot/menu.h>

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>


const char *kNormalColor = "\33[0m";
const char *kDisabledColor = "\33[31m";	// red
const char *kTitleColor = "\33[34m";	// blue


extern RootFileSystem *gRoot;
bool gShowMenu = false;


static void
print_item_at(int32 line, MenuItem *item, bool clearHelp = true)
{
	if (!item->IsEnabled())
		printf("%s    ", kDisabledColor);
	else
		printf("%2ld. ", line);

	if (item->Type() == MENU_ITEM_MARKABLE) {
		printf(" [");
		printf("%c", item->IsMarked() ? 'x' : ' ');
		printf("] ");
	} else
		printf(" ");

	printf(item->Label());

	if (item->Submenu() && item->Submenu()->Type() == CHOICE_MENU) {
		// show the current choice (if any)
		Menu *subMenu = item->Submenu();
		MenuItem *subItem = NULL;

		for (int32 i = subMenu->CountItems(); i-- > 0; ) {
			subItem = subMenu->ItemAt(i);
			if (subItem != NULL && subItem->IsMarked())
				break;
		}

		printf(" (Current: ");
		printf(subItem != NULL ? subItem->Label() : "None");
		putchar(')');
	}

	if (!item->IsEnabled())
		printf(kNormalColor);
	putchar('\n');
}


static void
draw_menu(Menu *menu)
{
	printf("\n %s--- ", kTitleColor);
	if (menu->Title())
		printf("%s", menu->Title());
	else
		printf("Welcome To The Haiku Bootloader");
	printf(" ---%s\n\n", kNormalColor);

	MenuItemIterator iterator = menu->ItemIterator();
	MenuItem *item;
	int32 i = 0;

	while ((item = iterator.Next()) != NULL) {
		if (item->Type() == MENU_ITEM_SEPARATOR) {
			putchar('\n');
			i++;
			continue;
		}

		print_item_at(i++, item, false);
	}

	int32 selected = -1;
	menu->FindSelected(&selected);
	printf("\n[%ld]? ", selected);
}


bool
dump_devices_hook(Menu *menu, MenuItem *item)
{
	puts("List of known root directories:");

	void *cookie;
	if (gRoot->Open(&cookie, O_RDONLY) == B_OK) {
		Directory *directory;
		while (gRoot->GetNextNode(cookie, (Node **)&directory) == B_OK) {
			char name[256];
			if (directory->GetName(name, sizeof(name)) == B_OK)
				printf("%s:: %s (%p)%s\n", kTitleColor, name, directory, kNormalColor);

			void *subCookie;
			if (directory->Open(&subCookie, O_RDONLY) == B_OK) {
				while (directory->GetNextEntry(subCookie, name, sizeof(name)) == B_OK) {
					printf("\t%s\n", name);
				}
				directory->Close(subCookie);
			}
		}
		gRoot->Close(cookie);
	}

	return false;
}


//	#pragma mark -


void
platform_add_menus(Menu *menu)
{
	MenuItem *item;

	switch (menu->Type()) {
		case MAIN_MENU:
			menu->AddItem(item = new MenuItem("Dump all recognized volumes"));
			item->SetTarget(dump_devices_hook);
			break;
		default:
			break;
	}
}


void
platform_update_menu_item(Menu *menu, MenuItem *item)
{
}


void
platform_run_menu(Menu *menu)
{
	// Get selected entry, or select the last one, if there is none
	int32 selected;
	MenuItem *item = menu->FindSelected(&selected);
	if (item == NULL) {
		selected = menu->CountItems() - 1;
		item = menu->ItemAt(selected);
		if (item != NULL)
			item->Select(true);
	}

	while (true) {
		draw_menu(menu);

		char buffer[32];
		if (fgets(buffer, sizeof(buffer), stdin) == NULL)
			return;

		if (buffer[0] != '\n')
			selected = atoi(buffer);

		item = menu->ItemAt(selected);
		if (item == NULL) {
			printf("Invalid choice.");
			continue;
		}

		item->Select(true);

		// leave the menu
		if (item->Submenu() != NULL) {
			menu->Hide();

			platform_run_menu(item->Submenu());
			if (item->Target() != NULL)
				(*item->Target())(menu, item);

			// restore current menu
			menu->FindSelected(&selected);
			menu->Show();
		} else if (item->Type() == MENU_ITEM_MARKABLE) {
			// toggle state
			item->SetMarked(!item->IsMarked());

			if (item->Target() != NULL)
				(*item->Target())(menu, item);
		} else if (item->Target() == NULL || (*item->Target())(menu, item))
			break;
	}
}


size_t
platform_get_user_input_text(Menu* menu, MenuItem* item, char* buffer,
	size_t bufferSize)
{
	return 0;
}