1
0
mirror of https://github.com/DragonMinded/jubeatmenu.git synced 2024-11-14 10:17:36 +01:00

Add sliding animation when changing pages.

This commit is contained in:
Jennifer Taylor 2019-07-02 01:17:44 -07:00
parent e8d967723d
commit 42c8ae4b00
10 changed files with 863 additions and 682 deletions

66
JubeatMenu/Animation.cpp Normal file
View File

@ -0,0 +1,66 @@
#include <windows.h>
#include "Animation.h"
Animation::Animation()
{
distance = 0;
speed = 0.0;
lastMilliseconds = 0;
location = 0.0;
offset = 0;
isAnimating = false;
}
Animation::~Animation()
{
// Empty
}
void Animation::Animate(int animationOffset, int animationDistance, double pixelsPerSecond)
{
if (isAnimating) { return; }
distance = animationDistance;
location = 0.0;
offset = animationOffset;
speed = pixelsPerSecond / (1000.0);
isAnimating = true;
lastMilliseconds = CurrentMilliseconds();
}
bool Animation::IsAnimating()
{
return isAnimating;
}
int Animation::Position()
{
int position = (unsigned int)location;
if (distance < 0) { position = -position; }
return position + offset;
}
LONG Animation::CurrentMilliseconds()
{
SYSTEMTIME time;
GetSystemTime(&time);
return (time.wSecond * 1000) + time.wMilliseconds;
}
void Animation::Tick()
{
LONG currentMilliseconds = CurrentMilliseconds();
if (currentMilliseconds - lastMilliseconds > 0)
{
// Calculate how much we should have moved
location += speed * (double)(currentMilliseconds - lastMilliseconds);
if (location >= abs(distance))
{
location = abs(distance);
isAnimating = false;
}
// Remeber we moved
lastMilliseconds = currentMilliseconds;
}
}

22
JubeatMenu/Animation.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
class Animation
{
public:
Animation();
~Animation();
void Animate(int animationOffset, int animationDistance, double pixelsPerSecond);
bool IsAnimating();
void Tick();
int Position();
private:
LONG CurrentMilliseconds();
bool isAnimating;
int distance;
double location;
int offset;
double speed;
LONG lastMilliseconds;
};

View File

@ -2,6 +2,7 @@
#include <windows.h> #include <windows.h>
#include "Display.h" #include "Display.h"
#include "Animation.h"
static Menu *globalMenu; static Menu *globalMenu;
static bool globalQuit; static bool globalQuit;
@ -9,280 +10,315 @@ static unsigned int globalButtonsHeld;
static unsigned int globalSelected; static unsigned int globalSelected;
static unsigned int globalPage; static unsigned int globalPage;
static unsigned int globalSeconds; static unsigned int globalSeconds;
static Animation *globalAnimation;
static const unsigned int SELECTION_MAPPING[12] = { static const unsigned int SELECTION_MAPPING[12] = {
0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11 0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11
};
static const unsigned int DRAW_MAPPING[15] = {
0, 3, 6, 9, 12, 1, 4, 7, 10, 13, 2, 5, 8, 11, 14
};
static const unsigned int HIGHLIGHT_MAPPING[15] = {
0, 1, 2, 3, 16, 4, 5, 6, 7, 16, 8, 9, 10, 11, 16
}; };
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
switch (uMsg) switch (uMsg)
{ {
case WM_CLOSE: case WM_CLOSE:
DestroyWindow(hwnd); DestroyWindow(hwnd);
globalQuit = true; globalQuit = true;
return 0; return 0;
case WM_DESTROY: case WM_DESTROY:
PostQuitMessage(0); PostQuitMessage(0);
globalQuit = true; globalQuit = true;
return 0; return 0;
case WM_QUIT: case WM_QUIT:
globalQuit = true; globalQuit = true;
return 0; return 0;
case WM_PAINT: case WM_ERASEBKGND:
/* Grab the maximum number of menu items */ return 1;
unsigned int maxEntries = globalMenu->NumberOfEntries(); case WM_PAINT:
/* Grab the maximum number of menu items */
unsigned int maxEntries = globalMenu->NumberOfEntries();
/* Start patinting */ /* Set up double buffer */
PAINTSTRUCT ps; PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps); HDC windowHdc = BeginPaint(hwnd, &ps);
HDC hdc = CreateCompatibleDC(windowHdc);
HBITMAP Membitmap = CreateCompatibleBitmap(windowHdc, SCREEN_WIDTH, SCREEN_HEIGHT);
SelectObject(hdc, Membitmap);
/* Paint the window background */ /* Paint the window background */
HBRUSH background = CreateSolidBrush(RGB(0,0,0)); HBRUSH background = CreateSolidBrush(RGB(0,0,0));
FillRect(hdc, &ps.rcPaint, background); FillRect(hdc, &ps.rcPaint, background);
DeleteObject(background); DeleteObject(background);
/* Set up text display */ /* Set up text display */
SetTextColor(hdc, RGB(240, 240, 240)); SetTextColor(hdc, RGB(240, 240, 240));
SetBkMode(hdc, TRANSPARENT); SetBkMode(hdc, TRANSPARENT);
HFONT hItemFont = CreateFont(ITEM_FONT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, L"Verdana"); HFONT hItemFont = CreateFont(ITEM_FONT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, L"Verdana");
HFONT hInstructionsFont = CreateFont(INSTRUCTIONS_FONT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, L"Verdana"); HFONT hInstructionsFont = CreateFont(INSTRUCTIONS_FONT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, L"Verdana");
HFONT hArrowFont = CreateFont(ARROW_FONT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, L"Verdana"); HFONT hArrowFont = CreateFont(ARROW_FONT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, L"Verdana");
/* Draw top instructions */ /* Set up rectangle display */
{ HPEN redPen = CreatePen(PS_SOLID, 2, RGB(255,0,0));
RECT rect; HPEN whitePen = CreatePen(PS_SOLID, 2, RGB(255,255,255));
rect.top = VIEWPORT_TOP + TEXT_PADDING;
rect.bottom = VIEWPORT_BOTTOM - TEXT_PADDING;
rect.left = TEXT_PADDING;
rect.right = SCREEN_WIDTH - TEXT_PADDING;
char instruction_text[1024]; /* Draw top instructions */
sprintf_s( {
instruction_text, RECT rect;
1024, rect.top = VIEWPORT_TOP + TEXT_PADDING;
"Select a game by tapping its panel.\n" rect.bottom = VIEWPORT_BOTTOM - TEXT_PADDING;
"Start %s by tapping the Start Game panel.\n" rect.left = TEXT_PADDING;
"The selected game will auto-start in %d seconds.", rect.right = SCREEN_WIDTH - TEXT_PADDING;
globalMenu->GetEntryName(globalSelected),
globalSeconds
);
wchar_t* wString = new wchar_t[4096]; char instruction_text[1024];
MultiByteToWideChar(CP_ACP, 0, instruction_text, -1, wString, 4096); sprintf_s(
SelectObject(hdc, hInstructionsFont); instruction_text,
DrawText(hdc, wString, -1, &rect, DT_HIDEPREFIX | DT_LEFT | DT_TOP | DT_WORDBREAK); 1024,
delete wString; "Select a game by tapping its panel.\n"
} "Start %s by tapping the Start Game panel.\n"
"The selected game will auto-start in %d seconds.",
globalMenu->GetEntryName(globalSelected),
globalSeconds
);
/* Draw hover icons for every square, regardless of whether we put graphics in them */ wchar_t* wString = new wchar_t[4096];
for( unsigned int position = 0; position < 15; position++ ) MultiByteToWideChar(CP_ACP, 0, instruction_text, -1, wString, 4096);
{ SelectObject(hdc, hInstructionsFont);
unsigned int xPos = position % 4; DrawText(hdc, wString, -1, &rect, DT_HIDEPREFIX | DT_LEFT | DT_TOP | DT_WORDBREAK);
unsigned int yPos = position / 4; delete wString;
}
/* There is an extra pixel of bump for the second half of the squares */ /* Draw hover icons for every square, regardless of whether we put graphics in them */
unsigned int xBump = xPos >= 2 ? 1 : 0; {
unsigned int yBump = yPos >= 2 ? 1 : 0; /* Set up background colors */
SelectObject(hdc, GetStockObject(DC_BRUSH));
SetDCBrushColor(hdc, RGB(0,0,0));
unsigned int top = BUTTON_TOP + (BUTTON_VERTICAL_STRIDE * yPos) + yBump; /* Set up border color to show current held buttons */
unsigned int bottom = top + BUTTON_WIDTH; SelectObject(hdc, redPen);
unsigned int left = BUTTON_LEFT + (BUTTON_HORIZONTAL_STRIDE * xPos) + xBump;
unsigned int right = left + BUTTON_HEIGHT;
/* Set up background colors */
SelectObject(hdc, GetStockObject(DC_BRUSH));
SetDCBrushColor(hdc, RGB(0,0,0));
// Set up border color to show current held buttons /* Intentionally skip button 16 because pressing it will always
SelectObject(hdc, GetStockObject(DC_PEN)); insta-launch the selected game, so we will never need to show
if ((globalButtonsHeld >> position) & 1) a hover square. */
{ for( unsigned int position = 0; position < 15; position++ )
SetDCPenColor(hdc, RGB(255,0,0)); {
} if (!((globalButtonsHeld >> position) & 1))
else {
{ // This button isn't being held, no need to show a held box.
continue; continue;
} }
if (globalAnimation->IsAnimating() && position < 12)
// Draw bounding rectangle {
Rectangle(hdc, left, top, right, bottom); // Don't show hover while moving selection panels.
} continue;
}
/* Draw selection button */ unsigned int xPos = position % 4;
{ unsigned int yPos = position / 4;
unsigned int top = BUTTON_TOP + (BUTTON_VERTICAL_STRIDE * 3) + 1;
unsigned int bottom = top + BUTTON_WIDTH;
unsigned int left = BUTTON_LEFT + (BUTTON_HORIZONTAL_STRIDE * 3) + 1;
unsigned int right = left + BUTTON_HEIGHT;
SelectObject(hdc, GetStockObject(DC_BRUSH)); /* There is an extra pixel of bump for the second half of the squares */
SetDCBrushColor(hdc, RGB(24,24,24)); unsigned int xBump = xPos >= 2 ? 1 : 0;
SetDCPenColor(hdc, RGB(255,255,255)); unsigned int yBump = yPos >= 2 ? 1 : 0;
Rectangle(hdc, left, top, right, bottom);
RECT rect;
rect.top = top + TEXT_PADDING;
rect.bottom = bottom - TEXT_PADDING;
rect.left = left + TEXT_PADDING;
rect.right = right - TEXT_PADDING;
char start_text[64]; unsigned int top = BUTTON_TOP + (BUTTON_VERTICAL_STRIDE * yPos) + yBump;
sprintf_s(start_text, 64, "Start Game\n\n%d seconds left", globalSeconds); unsigned int bottom = top + BUTTON_WIDTH;
unsigned int left = BUTTON_LEFT + (BUTTON_HORIZONTAL_STRIDE * xPos) + xBump;
unsigned int right = left + BUTTON_HEIGHT;
wchar_t* wString = new wchar_t[4096]; // Draw bounding rectangle
MultiByteToWideChar(CP_ACP, 0, start_text, -1, wString, 4096); Rectangle(hdc, left, top, right, bottom);
SelectObject(hdc, hItemFont); }
DrawText(hdc, wString, -1, &rect, DT_HIDEPREFIX | DT_CENTER | DT_TOP); }
delete wString;
}
/* Draw previous/next page buttons */ /* Draw selection button */
if (maxEntries > GAMES_PER_PAGE) {
{ unsigned int top = BUTTON_TOP + (BUTTON_VERTICAL_STRIDE * 3) + 1;
unsigned int max_pages = ((maxEntries - GAMES_PER_PAGE) + 2) / 3; unsigned int bottom = top + BUTTON_WIDTH;
unsigned int left = BUTTON_LEFT + (BUTTON_HORIZONTAL_STRIDE * 3) + 1;
/* Scroll left button */ unsigned int right = left + BUTTON_HEIGHT;
if (globalPage < max_pages)
{
unsigned int top = BUTTON_TOP + (BUTTON_VERTICAL_STRIDE * 3) + 1;
unsigned int bottom = top + BUTTON_WIDTH;
unsigned int left = BUTTON_LEFT + (BUTTON_HORIZONTAL_STRIDE * 0) + 1;
unsigned int right = left + BUTTON_HEIGHT;
SelectObject(hdc, GetStockObject(DC_BRUSH)); SelectObject(hdc, GetStockObject(DC_BRUSH));
SetDCBrushColor(hdc, RGB(24,24,24)); SetDCBrushColor(hdc, RGB(24,24,24));
if ((globalButtonsHeld >> 12) & 1) SelectObject(hdc, whitePen);
{ Rectangle(hdc, left, top, right, bottom);
SetDCPenColor(hdc, RGB(255,0,0));
}
else
{
SetDCPenColor(hdc, RGB(255,255,255));
}
// Draw bounding rectangle RECT rect;
Rectangle(hdc, left, top, right, bottom); rect.top = top + TEXT_PADDING;
rect.bottom = bottom - TEXT_PADDING;
// Draw text rect.left = left + TEXT_PADDING;
RECT rect; rect.right = right - TEXT_PADDING;
rect.top = top + TEXT_PADDING;
rect.bottom = bottom - TEXT_PADDING;
rect.left = left + TEXT_PADDING;
rect.right = right - TEXT_PADDING;
wchar_t* wString = new wchar_t[4096]; char start_text[64];
MultiByteToWideChar(CP_ACP, 0, "<<", -1, wString, 4096); sprintf_s(start_text, 64, "Start Game\n\n%d seconds left", globalSeconds);
SelectObject(hdc, hArrowFont);
DrawText(hdc, wString, -1, &rect, DT_HIDEPREFIX | DT_CENTER | DT_VCENTER | DT_SINGLELINE);
delete wString;
}
/* Scroll right button */ wchar_t* wString = new wchar_t[4096];
if (globalPage > 0) MultiByteToWideChar(CP_ACP, 0, start_text, -1, wString, 4096);
{ SelectObject(hdc, hItemFont);
unsigned int top = BUTTON_TOP + (BUTTON_VERTICAL_STRIDE * 3) + 1; DrawText(hdc, wString, -1, &rect, DT_HIDEPREFIX | DT_CENTER | DT_TOP);
unsigned int bottom = top + BUTTON_WIDTH; delete wString;
unsigned int left = BUTTON_LEFT + (BUTTON_HORIZONTAL_STRIDE * 1) + 1; }
unsigned int right = left + BUTTON_HEIGHT;
SelectObject(hdc, GetStockObject(DC_BRUSH)); /* Draw previous/next page buttons */
SetDCBrushColor(hdc, RGB(24,24,24)); if (maxEntries > GAMES_PER_PAGE)
if ((globalButtonsHeld >> 13) & 1) {
{ unsigned int max_pages = ((maxEntries - GAMES_PER_PAGE) + 2) / 3;
SetDCPenColor(hdc, RGB(255,0,0));
}
else
{
SetDCPenColor(hdc, RGB(255,255,255));
}
// Draw bounding rectangle SelectObject(hdc, GetStockObject(DC_BRUSH));
Rectangle(hdc, left, top, right, bottom); SetDCBrushColor(hdc, RGB(24,24,24));
// Draw text
RECT rect;
rect.top = top + TEXT_PADDING;
rect.bottom = bottom - TEXT_PADDING;
rect.left = left + TEXT_PADDING;
rect.right = right - TEXT_PADDING;
wchar_t* wString = new wchar_t[4096]; /* Scroll left button */
MultiByteToWideChar(CP_ACP, 0, ">>", -1, wString, 4096); if (globalPage < max_pages)
SelectObject(hdc, hArrowFont); {
DrawText(hdc, wString, -1, &rect, DT_HIDEPREFIX | DT_CENTER | DT_VCENTER | DT_SINGLELINE); unsigned int top = BUTTON_TOP + (BUTTON_VERTICAL_STRIDE * 3) + 1;
delete wString; unsigned int bottom = top + BUTTON_WIDTH;
} unsigned int left = BUTTON_LEFT + (BUTTON_HORIZONTAL_STRIDE * 0) + 1;
} unsigned int right = left + BUTTON_HEIGHT;
/* Draw each menu item */
for( unsigned int position = 0; position < 12; position++ ) {
unsigned int xPos = position % 4;
unsigned int yPos = position / 4;
/* Look up the actual item at this position */ if ((globalButtonsHeld >> 12) & 1)
unsigned int item = SELECTION_MAPPING[position] + (globalPage * 3); {
if (item >= maxEntries) { continue; } SelectObject(hdc, redPen);
}
else
{
SelectObject(hdc, whitePen);
}
/* There is an extra pixel of bump for the second half of the squares */ // Draw bounding rectangle
unsigned int xBump = xPos >= 2 ? 1 : 0; Rectangle(hdc, left, top, right, bottom);
unsigned int yBump = yPos >= 2 ? 1 : 0;
unsigned int top = BUTTON_TOP + (BUTTON_VERTICAL_STRIDE * yPos) + yBump; // Draw text
unsigned int bottom = top + BUTTON_WIDTH; RECT rect;
unsigned int left = BUTTON_LEFT + (BUTTON_HORIZONTAL_STRIDE * xPos) + xBump; rect.top = top + TEXT_PADDING;
unsigned int right = left + BUTTON_HEIGHT; rect.bottom = bottom - TEXT_PADDING;
rect.left = left + TEXT_PADDING;
/* Set up background colors */ rect.right = right - TEXT_PADDING;
SelectObject(hdc, GetStockObject(DC_BRUSH));
if (globalSelected == item)
{
SetDCBrushColor(hdc, RGB(96,96,96));
}
else
{
SetDCBrushColor(hdc, RGB(24,24,24));
}
// Set up border color to show current held buttons wchar_t* wString = new wchar_t[4096];
SelectObject(hdc, GetStockObject(DC_PEN)); MultiByteToWideChar(CP_ACP, 0, "<<", -1, wString, 4096);
if ((globalButtonsHeld >> position) & 1) SelectObject(hdc, hArrowFont);
{ DrawText(hdc, wString, -1, &rect, DT_HIDEPREFIX | DT_CENTER | DT_VCENTER | DT_SINGLELINE);
SetDCPenColor(hdc, RGB(255,0,0)); delete wString;
} }
else
{
SetDCPenColor(hdc, RGB(255,255,255));
}
// Draw bounding rectangle
Rectangle(hdc, left, top, right, bottom);
// Set text color /* Scroll right button */
SelectObject(hdc, GetStockObject(DC_PEN)); if (globalPage > 0)
SetDCPenColor(hdc, RGB(255,255,255)); {
unsigned int top = BUTTON_TOP + (BUTTON_VERTICAL_STRIDE * 3) + 1;
unsigned int bottom = top + BUTTON_WIDTH;
unsigned int left = BUTTON_LEFT + (BUTTON_HORIZONTAL_STRIDE * 1) + 1;
unsigned int right = left + BUTTON_HEIGHT;
// Draw text if ((globalButtonsHeld >> 13) & 1)
RECT rect; {
rect.top = top + TEXT_PADDING; SelectObject(hdc, redPen);
rect.bottom = bottom - TEXT_PADDING; }
rect.left = left + TEXT_PADDING; else
rect.right = right - TEXT_PADDING; {
SelectObject(hdc, whitePen);
}
wchar_t* wString = new wchar_t[4096]; // Draw bounding rectangle
MultiByteToWideChar(CP_ACP, 0, globalMenu->GetEntryName(item), -1, wString, 4096); Rectangle(hdc, left, top, right, bottom);
SelectObject(hdc, hItemFont);
DrawText(hdc, wString, -1, &rect, DT_HIDEPREFIX | DT_CENTER | DT_TOP | DT_WORDBREAK);
delete wString;
}
DeleteObject(hItemFont); // Draw text
DeleteObject(hInstructionsFont); RECT rect;
DeleteObject(hArrowFont); rect.top = top + TEXT_PADDING;
rect.bottom = bottom - TEXT_PADDING;
EndPaint(hwnd, &ps); rect.left = left + TEXT_PADDING;
return 0; rect.right = right - TEXT_PADDING;
}
wchar_t* wString = new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, ">>", -1, wString, 4096);
SelectObject(hdc, hArrowFont);
DrawText(hdc, wString, -1, &rect, DT_HIDEPREFIX | DT_CENTER | DT_VCENTER | DT_SINGLELINE);
delete wString;
}
}
/* Draw each menu item */
for( unsigned int position = 0; position < 15; position++ )
{
/* Leave room for animating left/right swipe */
unsigned int xPos = position % 5;
unsigned int yPos = position / 5;
/* Look up the actual item at this position */
unsigned int item = DRAW_MAPPING[position] + (globalPage * 3);
if (item >= maxEntries) { continue; }
/* There is an extra pixel of bump for the second half of the squares */
unsigned int xBump = xPos >= 2 ? 1 : 0;
unsigned int yBump = yPos >= 2 ? 1 : 0;
/* Adjust position for animations */
int animationBump = 0;
if (globalAnimation->IsAnimating())
{
animationBump = globalAnimation->Position();
}
int top = BUTTON_TOP + (BUTTON_VERTICAL_STRIDE * yPos) + yBump;
int bottom = top + BUTTON_WIDTH;
int left = BUTTON_LEFT + (BUTTON_HORIZONTAL_STRIDE * xPos) + xBump + animationBump;
int right = left + BUTTON_HEIGHT;
/* Set up background colors */
SelectObject(hdc, GetStockObject(DC_BRUSH));
if (globalSelected == item)
{
SetDCBrushColor(hdc, RGB(96,96,96));
}
else
{
SetDCBrushColor(hdc, RGB(24,24,24));
}
// Set up border color to show current held buttons
if (!globalAnimation->IsAnimating() && ((globalButtonsHeld >> HIGHLIGHT_MAPPING[position]) & 1))
{
SelectObject(hdc, redPen);
}
else
{
SelectObject(hdc, whitePen);
}
// Draw bounding rectangle
Rectangle(hdc, left, top, right, bottom);
// Draw text
RECT rect;
rect.top = top + TEXT_PADDING;
rect.bottom = bottom - TEXT_PADDING;
rect.left = left + TEXT_PADDING;
rect.right = right - TEXT_PADDING;
wchar_t* wString = new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, globalMenu->GetEntryName(item), -1, wString, 4096);
SelectObject(hdc, hItemFont);
DrawText(hdc, wString, -1, &rect, DT_HIDEPREFIX | DT_CENTER | DT_TOP | DT_WORDBREAK);
delete wString;
}
DeleteObject(hItemFont);
DeleteObject(hInstructionsFont);
DeleteObject(hArrowFont);
/* Copy double-buffer over */
BitBlt(windowHdc, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, hdc, 0, 0, SRCCOPY);
DeleteObject(Membitmap);
DeleteDC(hdc);
DeleteDC(windowHdc);
EndPaint(hwnd, &ps);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam); return DefWindowProc(hwnd, uMsg, wParam, lParam);
} }
@ -290,138 +326,183 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Display::Display(HINSTANCE hInstance, IO *ioInst, Menu *mInst) Display::Display(HINSTANCE hInstance, IO *ioInst, Menu *mInst)
{ {
inst = hInstance; globalAnimation = new Animation();
globalMenu = mInst; inst = hInstance;
io = ioInst; globalMenu = mInst;
menu = mInst; io = ioInst;
page = 0; menu = mInst;
selected = 0; page = 0;
selected = 0;
newPage = -1;
lastLocation = 0;
// Register the callback // Register the callback
WNDCLASS wc = { }; WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc; wc.lpfnWndProc = WindowProc;
wc.hInstance = inst; wc.hInstance = inst;
wc.lpszClassName = CLASS_NAME; wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc); RegisterClass(&wc);
globalQuit = false; globalQuit = false;
globalButtonsHeld = 0; globalButtonsHeld = 0;
globalSelected = selected; globalSelected = selected;
globalPage = page; globalPage = page;
globalSeconds = menu->SecondsLeft(); globalSeconds = menu->SecondsLeft();
// Create an empty window // Create an empty window
hwnd = CreateWindow(CLASS_NAME, 0, WS_BORDER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, inst, NULL); hwnd = CreateWindow(CLASS_NAME, 0, WS_BORDER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, inst, NULL);
LONG lStyle = GetWindowLong(hwnd, GWL_STYLE); LONG lStyle = GetWindowLong(hwnd, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU); lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
SetWindowLong(hwnd, GWL_STYLE, lStyle); SetWindowLong(hwnd, GWL_STYLE, lStyle);
LONG lExStyle = GetWindowLong(hwnd, GWL_EXSTYLE); LONG lExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
lExStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE); lExStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
SetWindowLong(hwnd, GWL_EXSTYLE, lExStyle); SetWindowLong(hwnd, GWL_EXSTYLE, lExStyle);
/* Display it */ /* Display it */
SetWindowPos(hwnd, NULL, 0,0,0,0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER); SetWindowPos(hwnd, NULL, 0,0,0,0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
ShowWindow(hwnd, SW_SHOW); ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd); UpdateWindow(hwnd);
ShowCursor(false); ShowCursor(false);
} }
Display::~Display(void) Display::~Display()
{ {
ShowCursor(true); ShowCursor(true);
DestroyWindow(hwnd); DestroyWindow(hwnd);
UnregisterClass(CLASS_NAME, inst); UnregisterClass(CLASS_NAME, inst);
delete globalAnimation;
} }
void Display::Tick(void) void Display::Tick(void)
{ {
/* Handle windows message pump */ /* Handle windows message pump */
MSG msg = { }; MSG msg = { };
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{ {
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
} }
/* Grab the currently held buttons, calculate newly pressed */ /* Don't handle input while animating */
bool moved = false; unsigned int buttonsHeld = io->ButtonsHeld();
unsigned int buttonsHeld = io->ButtonsHeld(); globalAnimation->Tick();
if (globalAnimation->IsAnimating())
{
bool update = false;
/* Figure out actions */ if (globalButtonsHeld != buttonsHeld)
if (menu->NumberOfEntries() > GAMES_PER_PAGE) {
{ globalButtonsHeld = buttonsHeld;
unsigned int max_pages = ((menu->NumberOfEntries() - GAMES_PER_PAGE) + 2) / 3; update = true;
}
/* Activate page left/right buttons */ if (lastLocation != globalAnimation->Position())
if (io->ButtonPressed(BUTTON_13)) {
{ lastLocation = globalAnimation->Position();
/* Scroll left */ update = true;
if (page < max_pages) }
{
page++;
moved = true;
}
}
if (io->ButtonPressed(BUTTON_14)) if (update)
{ {
/* Scroll right */ InvalidateRect(hwnd, NULL, FALSE);
if (page > 0) UpdateWindow(hwnd);
{ }
page--; return;
moved = true; }
}
}
}
if (!moved) { /* See if we need to update the page after finishing animation */
/* Allow button presses to make selections */ if (newPage >= 0)
for (unsigned int btn = 0; btn < 12; btn++) { {
if (io->ButtonPressed(1 << btn)) { page = newPage;
unsigned int item = SELECTION_MAPPING[btn] + (globalPage * 3); globalPage = page;
if (item < menu->NumberOfEntries()) newPage = -1;
{ globalButtonsHeld = buttonsHeld;
selected = item; InvalidateRect(hwnd, NULL, FALSE);
} UpdateWindow(hwnd);
} return;
} }
}
/* Update the screen to show any button presses or selection /* Grab the currently held buttons, calculate newly pressed */
changes. */ bool moved = false;
bool update = false;
if (globalButtonsHeld != buttonsHeld)
{
globalButtonsHeld = buttonsHeld;
update = true;
}
if (globalSelected != selected)
{
globalSelected = selected;
update = true;
}
if (globalPage != page)
{
globalPage = page;
update = true;
}
if (globalSeconds != menu->SecondsLeft()) {
globalSeconds = menu->SecondsLeft();
update = true;
}
if (update) /* Figure out actions */
{ if (menu->NumberOfEntries() > GAMES_PER_PAGE)
InvalidateRect(hwnd, NULL, NULL); {
UpdateWindow(hwnd); unsigned int max_pages = ((menu->NumberOfEntries() - GAMES_PER_PAGE) + 2) / 3;
}
/* Activate page left/right buttons */
if (io->ButtonPressed(BUTTON_13))
{
/* Scroll left */
if (page < max_pages)
{
globalAnimation->Animate(0, -BUTTON_HORIZONTAL_STRIDE, ANIMATION_SPEED);
lastLocation = globalAnimation->Position();
newPage = page + 1;
moved = true;
}
} else if (io->ButtonPressed(BUTTON_14))
{
/* Scroll right */
if (page > 0)
{
globalAnimation->Animate(-BUTTON_HORIZONTAL_STRIDE, BUTTON_HORIZONTAL_STRIDE, ANIMATION_SPEED);
lastLocation = globalAnimation->Position();
page--;
moved = true;
}
}
}
if (!moved)
{
/* Allow button presses to make selections */
for (unsigned int btn = 0; btn < 12; btn++) {
if (io->ButtonPressed(1 << btn)) {
unsigned int item = SELECTION_MAPPING[btn] + (globalPage * 3);
if (item < menu->NumberOfEntries())
{
selected = item;
}
}
}
}
/* Update the screen to show any button presses or selection
changes. */
bool update = false;
if (globalButtonsHeld != buttonsHeld)
{
globalButtonsHeld = buttonsHeld;
update = true;
}
if (globalSelected != selected)
{
globalSelected = selected;
update = true;
}
if (globalPage != page)
{
globalPage = page;
update = true;
}
if (globalSeconds != menu->SecondsLeft()) {
globalSeconds = menu->SecondsLeft();
update = true;
}
if (update)
{
InvalidateRect(hwnd, NULL, FALSE);
UpdateWindow(hwnd);
}
} }
bool Display::WasClosed() bool Display::WasClosed()
{ {
return globalQuit; return globalQuit;
} }
unsigned int Display::GetSelectedItem() unsigned int Display::GetSelectedItem()
{ {
return selected; return selected;
} }

View File

@ -27,30 +27,34 @@
#define TEXT_PADDING 10 #define TEXT_PADDING 10
#define ANIMATION_SPEED 1000
/* Number of games to display on one screen */ /* Number of games to display on one screen */
#define GAMES_PER_PAGE 12 #define GAMES_PER_PAGE 12
class Display class Display
{ {
public: public:
Display(HINSTANCE hInstance, IO *ioInst, Menu *mInst); Display(HINSTANCE hInstance, IO *ioInst, Menu *mInst);
~Display(void); ~Display();
void Tick(); void Tick();
bool WasClosed(); bool WasClosed();
void ButtonPress(int button); void ButtonPress(int button);
void ButtonRelease(int button); void ButtonRelease(int button);
unsigned int GetSelectedItem(); unsigned int GetSelectedItem();
private: private:
HINSTANCE inst; HINSTANCE inst;
HWND hwnd; HWND hwnd;
Menu *menu; Menu *menu;
IO *io; IO *io;
unsigned int page; int newPage;
unsigned int selected; unsigned int page;
unsigned int selected;
int lastLocation;
}; };

View File

@ -2,147 +2,147 @@
IO::IO() IO::IO()
{ {
/* Start with not being ready */ /* Start with not being ready */
is_ready = false; is_ready = false;
/* Load the log function so we can output debugging */ /* Load the log function so we can output debugging */
log_function = NULL; log_function = NULL;
core = GetModuleHandleA("avs2-core.dll"); core = GetModuleHandleA("avs2-core.dll");
if (core != NULL) { if (core != NULL) {
log_function = (log_func)GetProcAddress(core, "XCgsqzn000017c"); log_function = (log_func)GetProcAddress(core, "XCgsqzn000017c");
} else { } else {
core = GetModuleHandleA("libavs-win32.dll"); core = GetModuleHandleA("libavs-win32.dll");
if (core != NULL) { if (core != NULL) {
log_function = (log_func)GetProcAddress(core, "XCd229cc000018"); log_function = (log_func)GetProcAddress(core, "XCd229cc000018");
} }
} }
debug("Initializing device.dll"); debug("Initializing device.dll");
device = GetModuleHandleA("device.dll"); device = GetModuleHandleA("device.dll");
if (device == NULL) { if (device == NULL) {
debug("Missing device.dll. Did you run this from the right directory?"); debug("Missing device.dll. Did you run this from the right directory?");
return; return;
} }
device_initialize = (INT_RET_ONE_ARG) GetProcAddress(device, "device_initialize"); device_initialize = (INT_RET_ONE_ARG) GetProcAddress(device, "device_initialize");
device_is_initialized = (INT_RET_NO_ARGS) GetProcAddress(device, "device_is_initialized"); device_is_initialized = (INT_RET_NO_ARGS) GetProcAddress(device, "device_is_initialized");
device_get_status = (INT_RET_NO_ARGS) GetProcAddress(device, "device_get_status"); device_get_status = (INT_RET_NO_ARGS) GetProcAddress(device, "device_get_status");
device_set_panel_mode = (INT_RET_ONE_ARG) GetProcAddress(device, "device_set_panel_mode"); device_set_panel_mode = (INT_RET_ONE_ARG) GetProcAddress(device, "device_set_panel_mode");
device_get_panel_trg_on = (INT_RET_THREE_ARGS) GetProcAddress(device, "device_get_panel_trg_on"); device_get_panel_trg_on = (INT_RET_THREE_ARGS) GetProcAddress(device, "device_get_panel_trg_on");
device_get_panel_trg_off = (INT_RET_THREE_ARGS) GetProcAddress(device, "device_get_panel_trg_off"); device_get_panel_trg_off = (INT_RET_THREE_ARGS) GetProcAddress(device, "device_get_panel_trg_off");
device_get_panel_trg_short_on = (INT_RET_THREE_ARGS) GetProcAddress(device, "device_get_panel_trg_short_on"); device_get_panel_trg_short_on = (INT_RET_THREE_ARGS) GetProcAddress(device, "device_get_panel_trg_short_on");
device_update = (INT_RET_NO_ARGS) GetProcAddress(device, "device_update"); device_update = (INT_RET_NO_ARGS) GetProcAddress(device, "device_update");
device_finalize = (INT_RET_NO_ARGS) GetProcAddress(device, "device_finalize"); device_finalize = (INT_RET_NO_ARGS) GetProcAddress(device, "device_finalize");
if ( if (
device_initialize == NULL || device_initialize == NULL ||
device_is_initialized == NULL || device_is_initialized == NULL ||
device_get_status == NULL || device_get_status == NULL ||
device_set_panel_mode == NULL || device_set_panel_mode == NULL ||
device_update == NULL || device_update == NULL ||
device_get_panel_trg_on == NULL || device_get_panel_trg_on == NULL ||
device_get_panel_trg_off == NULL || device_get_panel_trg_off == NULL ||
device_get_panel_trg_short_on == NULL || device_get_panel_trg_short_on == NULL ||
device_finalize == NULL device_finalize == NULL
) { ) {
debug("Couldn't find correct functions to call! Did you use the right DLLs?"); debug("Couldn't find correct functions to call! Did you use the right DLLs?");
FreeLibrary(device); FreeLibrary(device);
return; return;
} }
// First, initialize and verify. // First, initialize and verify.
debug("Initializing P4IO device"); debug("Initializing P4IO device");
device_initialize(0); device_initialize(0);
if (!device_is_initialized()) {
debug("Couldn't initialize P4IO device");
FreeLibrary(device);
return;
}
if (device_get_status() < 0) {
debug("P4IO device status returns error!");
FreeLibrary(device);
return;
}
// Configure to read panels if (!device_is_initialized()) {
debug("Configuring P4IO driver"); debug("Couldn't initialize P4IO device");
device_set_panel_mode(0); FreeLibrary(device);
return;
}
// We're ready to roll if (device_get_status() < 0) {
debug("P4IO driver ready for input"); debug("P4IO device status returns error!");
is_ready = true; FreeLibrary(device);
buttons = 0; return;
lastButtons = 0; }
// Configure to read panels
debug("Configuring P4IO driver");
device_set_panel_mode(0);
// We're ready to roll
debug("P4IO driver ready for input");
is_ready = true;
buttons = 0;
lastButtons = 0;
} }
IO::~IO(void) IO::~IO()
{ {
if (!is_ready) { return; } if (!is_ready) { return; }
debug("Finalizing P4IO driver"); debug("Finalizing P4IO driver");
device_finalize(); device_finalize();
FreeLibrary(device); FreeLibrary(device);
} }
bool IO::Ready() bool IO::Ready()
{ {
return is_ready; return is_ready;
} }
void IO::ErrorMessage(char *msg) void IO::ErrorMessage(char *msg)
{ {
debug(msg); debug(msg);
} }
void IO::Tick() void IO::Tick()
{ {
if (!is_ready) { return; } if (!is_ready) { return; }
if(device_is_initialized()) { if(device_is_initialized()) {
device_update(); device_update();
} }
// Remember last buttons so we can calculate newly // Remember last buttons so we can calculate newly
// pressed buttons. // pressed buttons.
lastButtons = buttons; lastButtons = buttons;
for (int panel = 0; panel < 16; panel++) { for (int panel = 0; panel < 16; panel++) {
int output[2] = { 0 }; int output[2] = { 0 };
device_get_panel_trg_on(panel % 4, panel / 4, output); device_get_panel_trg_on(panel % 4, panel / 4, output);
if (output[0] != 0) { if (output[0] != 0) {
// Track the button release // Track the button release
buttons &= ~(1 << panel); buttons &= ~(1 << panel);
} }
device_get_panel_trg_off(panel % 4, panel / 4, output); device_get_panel_trg_off(panel % 4, panel / 4, output);
if (output[0] != 0) { if (output[0] != 0) {
// Track the button press // Track the button press
buttons |= (1 << panel); buttons |= (1 << panel);
} }
} }
} }
unsigned int IO::ButtonsHeld() unsigned int IO::ButtonsHeld()
{ {
return buttons; return buttons;
} }
bool IO::ButtonHeld(unsigned int button) bool IO::ButtonHeld(unsigned int button)
{ {
return (ButtonsHeld() & button) != 0; return (ButtonsHeld() & button) != 0;
} }
unsigned int IO::ButtonsPressed() unsigned int IO::ButtonsPressed()
{ {
return buttons & (~lastButtons); return buttons & (~lastButtons);
} }
bool IO::ButtonPressed(unsigned int button) bool IO::ButtonPressed(unsigned int button)
{ {
return (ButtonsPressed() & button) != 0; return (ButtonsPressed() & button) != 0;
} }

View File

@ -34,34 +34,34 @@ typedef int(*INT_RET_THREE_ARGS)(int x, int y, int *out);
class IO class IO
{ {
public: public:
IO(); IO();
~IO(void); ~IO();
bool Ready(); bool Ready();
void Tick(); void Tick();
void ErrorMessage(char *msg); void ErrorMessage(char *msg);
unsigned int ButtonsHeld(); unsigned int ButtonsHeld();
unsigned int ButtonsPressed(); unsigned int ButtonsPressed();
bool ButtonHeld(unsigned int button); bool ButtonHeld(unsigned int button);
bool ButtonPressed(unsigned int button); bool ButtonPressed(unsigned int button);
private: private:
HMODULE core; HMODULE core;
HMODULE device; HMODULE device;
INT_RET_ONE_ARG device_initialize; INT_RET_ONE_ARG device_initialize;
INT_RET_NO_ARGS device_is_initialized; INT_RET_NO_ARGS device_is_initialized;
INT_RET_NO_ARGS device_get_status; INT_RET_NO_ARGS device_get_status;
INT_RET_ONE_ARG device_set_panel_mode; INT_RET_ONE_ARG device_set_panel_mode;
INT_RET_THREE_ARGS device_get_panel_trg_on; INT_RET_THREE_ARGS device_get_panel_trg_on;
INT_RET_THREE_ARGS device_get_panel_trg_off; INT_RET_THREE_ARGS device_get_panel_trg_off;
INT_RET_THREE_ARGS device_get_panel_trg_short_on; INT_RET_THREE_ARGS device_get_panel_trg_short_on;
INT_RET_NO_ARGS device_update; INT_RET_NO_ARGS device_update;
INT_RET_NO_ARGS device_finalize; INT_RET_NO_ARGS device_finalize;
log_func log_function; log_func log_function;
bool is_ready; bool is_ready;
unsigned int buttons; unsigned int buttons;
unsigned int lastButtons; unsigned int lastButtons;
}; };

View File

@ -12,105 +12,105 @@ static Menu *globalMenu = NULL;
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{ {
if (ul_reason_for_call == DLL_PROCESS_ATTACH) if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{ {
/* Remember our own instance*/ /* Remember our own instance*/
globalModule = hModule; globalModule = hModule;
/* Load the original DLL to force dependencies to load. /* Load the original DLL to force dependencies to load.
This must be done BEFORE calling dll_entry_init or This must be done BEFORE calling dll_entry_init or
this menu can't be run with a hook DLL. */ this menu can't be run with a hook DLL. */
LoadLibraryA("jubeat.dll"); LoadLibraryA("jubeat.dll");
/* Initialize the menu before any hooks run so our
file operations don't get intercepted. */
globalMenu = new Menu(L"games.ini");
}
return TRUE; /* Initialize the menu before any hooks run so our
file operations don't get intercepted. */
globalMenu = new Menu(L"games.ini");
}
return TRUE;
} }
extern "C" __declspec(dllexport) int __cdecl dll_entry_init(int a1, int a2) extern "C" __declspec(dllexport) int __cdecl dll_entry_init(int a1, int a2)
{ {
// Initialize the IO // Initialize the IO
IO *io = new IO(); IO *io = new IO();
if (!io->Ready()) if (!io->Ready())
{ {
// Failed to initialize, give up // Failed to initialize, give up
ExitProcess(0); ExitProcess(0);
return 0; return 0;
} }
// Initialize the menu // Initialize the menu
Menu *menu = globalMenu; Menu *menu = globalMenu;
if( menu->NumberOfEntries() < 1 ) if( menu->NumberOfEntries() < 1 )
{ {
io->ErrorMessage("No games configured to launch in games.ini!"); io->ErrorMessage("No games configured to launch in games.ini!");
delete menu; delete menu;
delete io; delete io;
ExitProcess(0); ExitProcess(0);
return 0; return 0;
} }
// Create menu screen // Create menu screen
Display *display = new Display(globalModule, io, menu); Display *display = new Display(globalModule, io, menu);
/* Actual game to load */ /* Actual game to load */
char *path = NULL; char *path = NULL;
/* It may have taken a long time to init */
menu->ResetTimeout();
// Input loop /* It may have taken a long time to init */
while(true) { menu->ResetTimeout();
io->Tick();
menu->Tick();
display->Tick();
/* See if somebody killed the display window */
if (display->WasClosed())
{
io->ErrorMessage("Main window closed, exiting!");
break;
}
/* Check to see if we ran out of time waiting for input */ // Input loop
if (menu->ShouldBootDefault()) while(true) {
{ io->Tick();
io->ErrorMessage("Ran out of time, booting current selection!"); menu->Tick();
int entry = display->GetSelectedItem(); display->Tick();
path = menu->GetEntryPath(entry);
break;
}
/* Check to see if the user confirmed a selection */ /* See if somebody killed the display window */
if (io->ButtonPressed(BUTTON_16)) { if (display->WasClosed())
int entry = display->GetSelectedItem(); {
path = menu->GetEntryPath(entry); io->ErrorMessage("Main window closed, exiting!");
break; break;
} }
}
// Close and free libraries /* Check to see if we ran out of time waiting for input */
delete display; if (menu->ShouldBootDefault())
delete menu; {
delete io; io->ErrorMessage("Ran out of time, booting current selection!");
int entry = display->GetSelectedItem();
path = menu->GetEntryPath(entry);
break;
}
if (path != NULL) /* Check to see if the user confirmed a selection */
{ if (io->ButtonPressed(BUTTON_16)) {
/* Launch actual game */ int entry = display->GetSelectedItem();
system(path); path = menu->GetEntryPath(entry);
} break;
}
}
// Return failure so launcher.exe doesn't attempt to // Close and free libraries
// further initialize other threads such as the net thread. delete display;
ExitProcess(0); delete menu;
return 0; delete io;
if (path != NULL)
{
/* Launch actual game */
system(path);
}
// Return failure so launcher.exe doesn't attempt to
// further initialize other threads such as the net thread.
ExitProcess(0);
return 0;
} }
extern "C" __declspec(dllexport) int __cdecl dll_entry_main() extern "C" __declspec(dllexport) int __cdecl dll_entry_main()
{ {
return 0; return 0;
} }

View File

@ -170,6 +170,10 @@
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
> >
<File
RelativePath=".\Animation.cpp"
>
</File>
<File <File
RelativePath=".\Display.cpp" RelativePath=".\Display.cpp"
> >
@ -192,6 +196,10 @@
Filter="h;hpp;hxx;hm;inl;inc;xsd" Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
> >
<File
RelativePath=".\Animation.h"
>
</File>
<File <File
RelativePath=".\Display.h" RelativePath=".\Display.h"
> >

View File

@ -5,151 +5,151 @@
Menu::Menu(_TCHAR *inifile) Menu::Menu(_TCHAR *inifile)
{ {
/* Read settings */ /* Read settings */
settings = LoadSettings( inifile, &num_programs ); settings = LoadSettings( inifile, &num_programs );
/* For exiting on defaults */ /* For exiting on defaults */
ftime(&beginning); ftime(&beginning);
} }
Menu::~Menu(void) Menu::~Menu()
{ {
} }
void Menu::ResetTimeout() void Menu::ResetTimeout()
{ {
ftime(&beginning); ftime(&beginning);
} }
void Menu::Tick() void Menu::Tick()
{ {
ftime(&current); ftime(&current);
} }
bool Menu::ShouldBootDefault() bool Menu::ShouldBootDefault()
{ {
ftime(&current); ftime(&current);
return (current.time - beginning.time) > TIMEOUT_SECONDS; return (current.time - beginning.time) > TIMEOUT_SECONDS;
} }
unsigned int Menu::SecondsLeft() unsigned int Menu::SecondsLeft()
{ {
ftime(&current); ftime(&current);
int seconds = (int)(TIMEOUT_SECONDS - (current.time - beginning.time)); int seconds = (int)(TIMEOUT_SECONDS - (current.time - beginning.time));
return seconds >= 0 ? seconds : 0; return seconds >= 0 ? seconds : 0;
} }
/** /**
* Loads an INI file with the following format: * Loads an INI file with the following format:
* *
* [Name of game to launch] * [Name of game to launch]
* launch=<location of batch/executable> * launch=<location of batch/executable>
*/ */
launcher_program_t *Menu::LoadSettings( _TCHAR *ini_file, unsigned int *final_length ) launcher_program_t *Menu::LoadSettings( _TCHAR *ini_file, unsigned int *final_length )
{ {
launcher_program_t *progs = 0; launcher_program_t *progs = 0;
*final_length = 0; *final_length = 0;
unsigned int got_name = 0; unsigned int got_name = 0;
launcher_program_t temp; launcher_program_t temp;
// Open the file // Open the file
HANDLE hFile = CreateFile(ini_file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); HANDLE hFile = CreateFile(ini_file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
char buffer[16384]; char buffer[16384];
unsigned int eof = 0; unsigned int eof = 0;
unsigned int eol = 0; unsigned int eol = 0;
unsigned int buflen = 0; unsigned int buflen = 0;
if (hFile == 0) if (hFile == 0)
{ {
return progs; return progs;
} }
memset( &temp, 0, sizeof(temp) ); memset( &temp, 0, sizeof(temp) );
memset( buffer, 0, sizeof(buffer) ); memset( buffer, 0, sizeof(buffer) );
while( !eof ) while( !eof )
{ {
DWORD length; DWORD length;
ReadFile( hFile, buffer + buflen, 1, &length, 0 ); ReadFile( hFile, buffer + buflen, 1, &length, 0 );
if (length == 0) if (length == 0)
{ {
eof = 1; eof = 1;
eol = 1; eol = 1;
} }
else if( *(buffer + buflen) == '\r' ) else if( *(buffer + buflen) == '\r' )
{ {
/* Ignore \r completely */ /* Ignore \r completely */
*(buffer + buflen) = 0; *(buffer + buflen) = 0;
} }
else if( *(buffer + buflen) == '\n' ) else if( *(buffer + buflen) == '\n' )
{ {
/* End of line */ /* End of line */
*(buffer + buflen) = 0; *(buffer + buflen) = 0;
eol = 1; eol = 1;
} }
else else
{ {
/* Valid thing */ /* Valid thing */
buflen++; buflen++;
} }
if ( eol == 1 ) if ( eol == 1 )
{ {
/* Process line */ /* Process line */
if (buffer[0] == '[' && buffer[buflen - 1] == ']' && buflen > 2) if (buffer[0] == '[' && buffer[buflen - 1] == ']' && buflen > 2)
{ {
buffer[buflen - 1] = 0; buffer[buflen - 1] = 0;
char *game = buffer + 1; char *game = buffer + 1;
/* Copy this into temp structure */ /* Copy this into temp structure */
strcpy_s( temp.name, MAX_GAME_NAME_LENGTH, game ); strcpy_s( temp.name, MAX_GAME_NAME_LENGTH, game );
got_name = 1; got_name = 1;
} }
else else
{ {
if (strncmp(buffer, "launch", 6) == 0) { if (strncmp(buffer, "launch", 6) == 0) {
unsigned int loc = 6; unsigned int loc = 6;
// Find equals sign after space // Find equals sign after space
while (loc < buflen && (buffer[loc] == ' ' || buffer[loc] == '\t')) { loc++; } while (loc < buflen && (buffer[loc] == ' ' || buffer[loc] == '\t')) { loc++; }
if (loc < buflen) if (loc < buflen)
{ {
if (buffer[loc] == '=') if (buffer[loc] == '=')
{ {
loc++; loc++;
while (loc < buflen && (buffer[loc] == ' ' || buffer[loc] == '\t')) { loc++; } while (loc < buflen && (buffer[loc] == ' ' || buffer[loc] == '\t')) { loc++; }
if (loc < buflen) if (loc < buflen)
{ {
char *launch = buffer + loc; char *launch = buffer + loc;
if( got_name == 1 ) if( got_name == 1 )
{ {
/* We have a name to associate with this */ /* We have a name to associate with this */
strcpy_s( temp.location, MAX_GAME_LOCATION_LENGTH, launch ); strcpy_s( temp.location, MAX_GAME_LOCATION_LENGTH, launch );
got_name = 0; got_name = 0;
/* Make a new spot for this, copy in */ /* Make a new spot for this, copy in */
(*final_length)++; (*final_length)++;
progs = (launcher_program_t *)realloc( progs, sizeof(launcher_program_t) * (*final_length) ); progs = (launcher_program_t *)realloc( progs, sizeof(launcher_program_t) * (*final_length) );
memcpy( progs + ((*final_length) - 1), &temp, sizeof(launcher_program_t) ); memcpy( progs + ((*final_length) - 1), &temp, sizeof(launcher_program_t) );
memset( &temp, 0, sizeof(temp) ); memset( &temp, 0, sizeof(temp) );
} }
} }
} }
} }
} }
} }
/* Reset buffer */ /* Reset buffer */
if (buflen > 0) if (buflen > 0)
{ {
memset( buffer, 0, sizeof(buffer) ); memset( buffer, 0, sizeof(buffer) );
buflen = 0; buflen = 0;
} }
/* Not end of line anymore */ /* Not end of line anymore */
eol = 0; eol = 0;
} }
} }
return progs; return progs;
} }

View File

@ -12,29 +12,29 @@
typedef struct typedef struct
{ {
char location[MAX_GAME_LOCATION_LENGTH + 1]; char location[MAX_GAME_LOCATION_LENGTH + 1];
char name[MAX_GAME_NAME_LENGTH + 1]; char name[MAX_GAME_NAME_LENGTH + 1];
} launcher_program_t; } launcher_program_t;
class Menu class Menu
{ {
public: public:
Menu(_TCHAR *inifile); Menu(_TCHAR *inifile);
~Menu(void); ~Menu();
unsigned int NumberOfEntries() { return num_programs; } unsigned int NumberOfEntries() { return num_programs; }
char *GetEntryName(unsigned int game) { return settings[game].name; } char *GetEntryName(unsigned int game) { return settings[game].name; }
char *GetEntryPath(unsigned int game) { return settings[game].location; } char *GetEntryPath(unsigned int game) { return settings[game].location; }
void Tick(); void Tick();
void ResetTimeout(); void ResetTimeout();
bool ShouldBootDefault(); bool ShouldBootDefault();
unsigned int SecondsLeft(); unsigned int SecondsLeft();
private: private:
unsigned int num_programs; unsigned int num_programs;
launcher_program_t *settings; launcher_program_t *settings;
struct timeb beginning; struct timeb beginning;
struct timeb current; struct timeb current;
launcher_program_t *LoadSettings( _TCHAR *ini_file, unsigned int *final_length ); launcher_program_t *LoadSettings( _TCHAR *ini_file, unsigned int *final_length );
}; };