openmohaa/code/gamespy/common/nitro/menu.c
2023-02-04 21:00:01 +01:00

410 lines
No EOL
9.5 KiB
C

#include "../nonport.h"
#include "menu.h"
#include "screen.h"
#include "key.h"
#include "touch.h"
static MenuScreen Screen;
static MenuScreenConfiguration * NextMenuScreenConfiguration;
static MenuScreenConfiguration MenuExitScreenConfiguration;
static void NewMenuScreen(MenuScreenConfiguration * configuration)
{
int count;
memset(&Screen, 0, sizeof(MenuScreen));
Screen.configuration = configuration;
Screen.listSelection = -1;
count = 0;
while(configuration->choices[count].text && (count < MAX_CHOICES))
count++;
Screen.numChoices = count;
}
static void ShowMenuScreen(void)
{
MenuScreenConfiguration * configuration = Screen.configuration;
MenuScreenChoice * choices = configuration->choices;
int options = configuration->options;
const ScreenColor normalColor = SCGray;
const ScreenColor highlightColor = SCWhite;
const ScreenColor disabledColor = SCDarkGray;
const int topTextLine = 10;
const int animationLine = (topTextLine + 2);
const int extraTextLine = (animationLine + 2);
const int keyboardTextLine = 1;
const int startKeyboardRowsLine = 3;
const int numKeyboardRows = 3;
const int numListRows = 5;
const int startListLine = 1;
const int startChoicesLine = (SCREEN_HEIGHT - (Screen.numChoices * 2));
const char keyboardRows[numKeyboardRows][32] =
{
"1 2 3 4 5 6 7 8 9 0 - + = _ . < ",
" A B C D E F G H I J K L M N O ",
" P Q R S T U V W X Y Z space "
};
const char listBorder[32] = "--------------------";
const int spacePos = (strchr(keyboardRows[2], 's') - keyboardRows[2]);
const char animationChars[] = "-*";
const gsi_time animationTickTime = 500;
BOOL done = FALSE;
int choiceIndex;
BOOL keyboard;
BOOL touching;
BOOL list;
BOOL animated;
int x, y;
int touchingLine;
int touchingPos;
int choiceLine;
int keyboardLine;
BOOL wasTouching = FALSE;
int wasTouchingChoice = -1;
ScreenColor color;
int i;
int range;
char touchingChar;
char wasTouchingChar = 0;
int keyboardPos;
int numListItems;
int listScroll = 0;
BOOL wasTouchingUp = FALSE;
BOOL wasTouchingDown = FALSE;
int listItem;
const char * choiceSelection;
int animationCount = 0;
gsi_time lastAnimationTime = current_time();
gsi_time now;
char animationText[] = "-";
// is it animated?
animated = (options & SCREEN_OPTION_ANIMATED)?TRUE:FALSE;
// is there a keyboard?
keyboard = (options & SCREEN_OPTION_KEYBOARD)?TRUE:FALSE;
// is there a list?
list = (options & SCREEN_OPTION_LIST)?TRUE:FALSE;
// we can't have a list and a keyboard
if(keyboard && list)
OS_Panic("Can't have a keyboard and a list on a menu screen\n");
// call the init func
if(configuration->initFunc)
{
configuration->initFunc();
if(NextMenuScreenConfiguration)
return;
}
// if there is a keyboard, get the initial position
if(keyboard)
keyboardPos = (int)strlen(Screen.keyboardText);
// loop until we're done
while(!done)
{
// wait for a screen update to complete
SVC_WaitVBlankIntr();
// call the think func
if(configuration->thinkFunc)
{
configuration->thinkFunc();
if(NextMenuScreenConfiguration)
return;
}
// count the number of list items
if(list)
{
for(numListItems = 0 ; numListItems < MAX_LIST_STRINGS ; numListItems++)
{
if(Screen.list[numListItems][0] == '\0')
break;
}
}
// check for a touch
touching = GetTouch(&x, &y);
if(touching)
{
// figure out which line we're touching
touchingLine = (y / (TOUCH_Y_RANGE / SCREEN_HEIGHT));
// figure out which position we're touching
touchingPos = (x / (TOUCH_X_RANGE / SCREEN_WIDTH));
}
else if (wasTouching)
{
// check for touching a choice
if(wasTouchingChoice != -1)
{
choiceSelection = choices[wasTouchingChoice].text;
wasTouchingChoice = -1;
// call the chose func
if(configuration->choseFunc)
{
configuration->choseFunc(choiceSelection);
if(NextMenuScreenConfiguration)
return;
}
}
// check for touching up on the list
else if(wasTouchingUp)
{
if(listScroll > 0)
listScroll--;
}
// check for touching down on the list
else if(wasTouchingDown)
{
if(listScroll < (numListItems - numListRows))
listScroll++;
}
// check for touching a keyboard char
else if(wasTouchingChar != 0)
{
// check for backspace
if(wasTouchingChar == '<')
{
if(keyboardPos > 0)
{
keyboardPos--;
Screen.keyboardText[keyboardPos] = '\0';
}
}
else
{
if(keyboardPos < MAX_KEYBOARD_TEXT_LEN)
{
Screen.keyboardText[keyboardPos] = wasTouchingChar;
keyboardPos++;
Screen.keyboardText[keyboardPos] = '\0';
}
}
}
}
wasTouching = touching;
// clear both screens
ClearScreens();
// show the title on the top screen
SetTopScreenLineCentered(topTextLine, SCYellow, configuration->topScreenText);
// show animation
if(animated)
{
now = current_time();
if((now - lastAnimationTime) >= animationTickTime)
{
animationCount++;
animationCount %= strlen(animationChars);
lastAnimationTime += animationTickTime;
}
animationText[0] = animationChars[animationCount];
SetTopScreenLineCentered(animationLine, SCYellow, animationText);
}
// show extra text
for(i = 0 ; i < MAX_EXTRA_TEXT_STRINGS ; i++)
{
if(options & SCREEN_OPTION_EXTRAS_CENTERED)
SetTopScreenLineCentered(extraTextLine + i, SCWhite, Screen.extraText[i]);
else
SetTopScreenLine(extraTextLine + i, SCWhite, Screen.extraText[i]);
}
// show the list
if(list)
{
// clear touching vars
wasTouchingUp = FALSE;
wasTouchingDown = FALSE;
// show "up" if needed
if(listScroll > 0)
{
if(touching && (touchingLine == startListLine))
{
wasTouchingUp = TRUE;
color = highlightColor;
}
else
{
color = normalColor;
}
SetBottomScreenLineCentered(startListLine, color, "up");
}
// show the top line
SetBottomScreenLineCentered(startListLine + 1, normalColor, listBorder);
// show the list items
for(i = 0 ; i < numListRows ; i++)
{
listItem = (listScroll + i);
if(listItem >= numListItems)
break;
// is this item being touched?
if(touching && (touchingLine == (startListLine + 2 + i)))
Screen.listSelection = listItem;
// set the color
if(Screen.listSelection == listItem)
color = highlightColor;
else
color = normalColor;
// show the item
SetBottomScreenLineCentered(startListLine + 2 + i, color, Screen.list[listScroll + i]);
}
// show the bottom line
SetBottomScreenLineCentered(startListLine + numListRows + 2, normalColor, listBorder);
// show "down" if needed
if(listScroll < (numListItems - numListRows))
{
if(touching && (touchingLine == (startListLine + numListRows + 3)))
{
wasTouchingDown = TRUE;
color = highlightColor;
}
else
{
color = normalColor;
}
SetBottomScreenLineCentered(startListLine + numListRows + 3, color, "down");
}
}
// show a keyboard
if(keyboard)
{
// show the text
SetBottomScreenLine(keyboardTextLine, SCGreen, Screen.keyboardText);
// clear touching var
wasTouchingChar = 0;
// loop through the keyboard rows
for(i = 0 ; i < numKeyboardRows ; i++)
{
// get the line to show this row on
keyboardLine = (startKeyboardRowsLine + i);
// check if we're touching this row
if(touching && (touchingLine == keyboardLine))
{
// get the char we're touching
touchingChar = keyboardRows[i][touchingPos];
// handle touching 'space' specially
if(islower(touchingChar))
{
wasTouchingChar = ' ';
touchingPos = spacePos;
range = 5;
}
else
{
if(touchingChar != ' ')
wasTouchingChar = touchingChar;
range = 1;
}
// show the keyboard row with the selection highlighted
SetBottomScreenLineHighlight(
keyboardLine, normalColor, keyboardRows[i],
touchingPos, range, highlightColor);
}
else
{
// show the keyboard row
SetBottomScreenLine(keyboardLine, normalColor, keyboardRows[i]);
}
}
}
// show the choices
wasTouchingChoice = -1;
for(choiceIndex = 0 ; choiceIndex < Screen.numChoices ; choiceIndex++)
{
// this is the line to show this choice on
choiceLine = (startChoicesLine + (choiceIndex * 2));
// check if we're touching this choice
if((choices[choiceIndex].options & CHOICE_OPTION_DISABLED) ||
((choices[choiceIndex].options & CHOICE_OPTION_NEEDS_LIST_SELECTION) && (Screen.listSelection == -1)))
{
color = disabledColor;
}
else if(touching && (touchingLine == choiceLine))
{
color = highlightColor;
wasTouchingChoice = choiceIndex;
}
else
{
color = normalColor;
}
// show the line
SetBottomScreenLineCentered(choiceLine, color, choices[choiceIndex].text);
}
}
}
void StartMenuScreen(MenuScreenConfiguration * configuration)
{
assert(configuration != NULL);
// set the initial next screen
SetNextMenuScreen(configuration);
// loop while there is a next screen to show
while(NextMenuScreenConfiguration != &MenuExitScreenConfiguration)
{
// setup the new screen
NewMenuScreen(NextMenuScreenConfiguration);
// clear the next screen setting
SetNextMenuScreen(NULL);
// show the menu screen
ShowMenuScreen();
// clear the display
ClearScreens();
}
}
void SetNextMenuScreen(MenuScreenConfiguration * configuration)
{
NextMenuScreenConfiguration = configuration;
}
void ExitMenu(void)
{
SetNextMenuScreen(&MenuExitScreenConfiguration);
}
MenuScreen * GetMenuScreen(void)
{
return &Screen;
}