Add license browser, improve touchscreen UI

This commit is contained in:
elasota
2020-10-24 23:39:55 -04:00
parent 4f70ce1c9f
commit b9ea9450f1
42 changed files with 2582 additions and 69 deletions

View File

@@ -14,6 +14,7 @@
#include "PLResources.h"
#include "PLSound.h"
#include "PLPasStr.h"
#include "PLScrollBarWidget.h"
#include "PLStandardColors.h"
#include "PLSysCalls.h"
#include "PLTimeTaggedVOSEvent.h"
@@ -40,6 +41,9 @@ static void UnHiLiteOkayButton (DrawSurface *surface);
static void UpdateMainPict (Dialog *);
static int16_t AboutFilter(void *context, Dialog *, const TimeTaggedVOSEvent *evt);
static int16_t AboutFrameworkFilter(void *context, Dialog *, const TimeTaggedVOSEvent *evt);
static int16_t LicenseReaderFilter(void *context, Dialog *, const TimeTaggedVOSEvent *evt);
static void DrawLicenseReader(Window *window);
void DoLicenseReader(int licenseResID);
static Point okayButtLowerV, okayButtUpperV;
@@ -47,6 +51,45 @@ static Rect okayButtonBounds, mainPICTBounds;
static Boolean okayButtIsHiLit, clickedDownInOkay;
struct LicenseReaderLine
{
PortabilityLayer::PascalStr<80> m_text;
};
static const unsigned int kLicenseReaderPointHistoryLength = 3;
static Boolean licenseReaderIsScrolling;
static Point licenseReaderPointHistory[kLicenseReaderPointHistoryLength];
static int32_t licenseReaderVelocity;
static unsigned int licenseReaderTextScroll;
static unsigned int licenseReaderTextScrollMax;
static unsigned int licenseReaderNumLines;
static THandle<LicenseReaderLine> licenseReaderLines;
static const unsigned int kLicenseReaderTextSpacing = 10;
static const Rect licenseReaderTextRect = Rect::Create(16, 16, 344, 496);
static PortabilityLayer::ScrollBarWidget *licenseReaderScrollBarWidget;
static void InitLicenseReader(unsigned int numLines)
{
for (unsigned int i = 0; i < kLicenseReaderPointHistoryLength; i++)
licenseReaderPointHistory[i] = Point::Create(0, 0);
licenseReaderIsScrolling = false;
licenseReaderTextScroll = 0;
licenseReaderVelocity = 0;
licenseReaderTextScrollMax = numLines * kLicenseReaderTextSpacing;
if (licenseReaderTextScrollMax < licenseReaderTextRect.Height())
licenseReaderTextScrollMax = 0;
else
licenseReaderTextScrollMax -= licenseReaderTextRect.Height();
licenseReaderNumLines = numLines;
licenseReaderScrollBarWidget = nullptr;
}
//============================================================== Functions
//-------------------------------------------------------------- DoAbout
// Brings up the About dialog box.
@@ -98,9 +141,168 @@ void DoAbout (void)
aboutDialog->Destroy();
}
void DoLicenseReader(int resID)
{
static const int kLicenseReaderDialogTemplateID = 2006;
THandle<uint8_t> licenseTextHandle = PortabilityLayer::ResourceManager::GetInstance()->GetAppResource('LICS', resID).StaticCast<uint8_t>();
if (!licenseTextHandle)
return;
// Count lines
unsigned int numLines = 1;
const uint8_t *licenseText = *licenseTextHandle;
const size_t licenseTextLength = licenseTextHandle.MMBlock()->m_size;
for (size_t i = 0; i < licenseTextLength; i++)
{
if (licenseText[i] == '\n')
numLines++;
}
licenseReaderLines = NewHandle(sizeof(LicenseReaderLine) * numLines).StaticCast<LicenseReaderLine>();
if (!licenseReaderLines)
{
licenseTextHandle.Dispose();
return;
}
LicenseReaderLine *lines = *licenseReaderLines;
unsigned int lineIndex = 0;
size_t lineStart = 0;
for (size_t i = 0; i < licenseTextLength; i++)
{
if (licenseText[i] == '\n')
{
assert(i - lineStart <= 80);
lines[lineIndex++].m_text.Set(i - lineStart, reinterpret_cast<const char*>(licenseText + lineStart));
lineStart = i + 1;
}
}
assert(licenseTextLength - lineStart <= 80);
lines[lineIndex++].m_text.Set(licenseTextLength - lineStart, reinterpret_cast<const char*>(licenseText + lineStart));
assert(lineIndex == numLines);
licenseTextHandle.Dispose();
const Rect windowRect = Rect::Create(0, 0, 396, 528);
PortabilityLayer::WindowDef wdef = PortabilityLayer::WindowDef::Create(windowRect, PortabilityLayer::WindowStyleFlags::kAlert, true, 0, 0, PSTR(""));
PortabilityLayer::DialogManager *dialogManager = PortabilityLayer::DialogManager::GetInstance();
Dialog *dialog = dialogManager->LoadDialogFromTemplate(kLicenseReaderDialogTemplateID, windowRect, true, false, 0, 0, PL_GetPutInFrontWindowPtr(), PSTR(""), nullptr);
DrawDefaultButton(dialog);
int16_t hit = 0;
InitLicenseReader(numLines);
DrawLicenseReader(dialog->GetWindow());
if (licenseReaderTextScrollMax != 0)
{
PortabilityLayer::WidgetBasicState state;
state.m_rect = Rect::Create(licenseReaderTextRect.top, licenseReaderTextRect.right, licenseReaderTextRect.bottom, licenseReaderTextRect.right + 16);
state.m_refConstant = 2;
state.m_window = dialog->GetWindow();
state.m_max = licenseReaderTextScrollMax;
state.m_state = 0;
licenseReaderScrollBarWidget = PortabilityLayer::ScrollBarWidget::Create(state, nullptr);
}
dialog->GetWindow()->DrawControls();
do
{
hit = dialog->ExecuteModal(nullptr, LicenseReaderFilter);
} while (hit != kOkayButton);
dialog->Destroy();
licenseReaderLines.Dispose();
}
void DoAboutOpenSource(void)
{
static const int kExportSourceItem = 2;
static const int kAerofoilLicenseButton = 4;
static const int kGliderPROLicenseButton = 6;
static const int kOpenSansLicenseButton = 8;
static const int kRobotoMonoLicenseButton = 10;
static const int kGochiHandLicenseButton = 12;
static const int kLibIConvLicenseButton = 14;
static const int kRapidJSONLicenseButton = 16;
static const int kZLibLicenseButton = 18;
static const int kFreeTypeLicenseButton = 20;
static const int kSDLLicenseButton = 22;
static const int kLicenseResourceApache = 1000;
static const int kLicenseResourceGPLv2 = 1001;
static const int kLicenseResourceLGPLv3 = 1002;
static const int kLicenseResourceOFL = 1003;
static const int kLicenseResourceRapidJSON = 1004;
static const int kLicenseResourceZLib = 1005;
static const int kLicenseResourceSDL = 1006;
static const int kAboutOpenSourceDialogTemplateID = 2005;
const Rect windowRect = Rect::Create(0, 0, 324, 512);
PortabilityLayer::WindowDef wdef = PortabilityLayer::WindowDef::Create(windowRect, PortabilityLayer::WindowStyleFlags::kAlert, true, 0, 0, PSTR(""));
PortabilityLayer::DialogManager *dialogManager = PortabilityLayer::DialogManager::GetInstance();
Dialog *dialog = dialogManager->LoadDialogFromTemplate(kAboutOpenSourceDialogTemplateID, windowRect, true, false, 0, 0, PL_GetPutInFrontWindowPtr(), PSTR(""), nullptr);
DrawDefaultButton(dialog);
if (thisMac.isTouchscreen)
dialog->GetItems()[kExportSourceItem - 1].GetWidget()->SetEnabled(true);
int16_t hit = 0;
do
{
hit = dialog->ExecuteModal(nullptr, AboutFrameworkFilter);
switch (hit)
{
case kExportSourceItem:
DoExportSourceCode();
break;
case kAerofoilLicenseButton:
case kGliderPROLicenseButton:
DoLicenseReader(kLicenseResourceGPLv2);
break;
case kOpenSansLicenseButton:
case kRobotoMonoLicenseButton:
DoLicenseReader(kLicenseResourceApache);
break;
case kGochiHandLicenseButton:
DoLicenseReader(kLicenseResourceOFL);
break;
case kLibIConvLicenseButton:
case kFreeTypeLicenseButton:
DoLicenseReader(kLicenseResourceLGPLv3);
break;
case kZLibLicenseButton:
DoLicenseReader(kLicenseResourceZLib);
break;
case kSDLLicenseButton:
DoLicenseReader(kLicenseResourceSDL);
break;
default:
break;
}
} while (hit != kOkayButton);
dialog->Destroy();
}
void DoAboutFramework (void)
{
#define kAboutFrameworkDialogTemplateID 2000
static const int kAboutFrameworkDialogTemplateID = 2000;
static const int kAboutOpenSourceButton = 2;
const Rect windowRect = Rect::Create(0, 0, 272, 450);
@@ -153,6 +355,9 @@ void DoAboutFramework (void)
do
{
hit = dialog->ExecuteModal(nullptr, AboutFrameworkFilter);
if (hit == kAboutOpenSourceButton)
DoAboutOpenSource();
} while (hit != kOkayButton);
dialog->Destroy();
@@ -366,3 +571,193 @@ static int16_t AboutFrameworkFilter(void *context, Dialog *dialog, const TimeTag
return hit;
}
void DrawLicenseReader(Window *window)
{
PortabilityLayer::RenderedFont *rfont = GetMonospaceFont(10, PortabilityLayer::FontFamilyFlag_None, true);
if (!rfont)
return;
PortabilityLayer::ResolveCachingColor whiteColor(StdColors::White());
PortabilityLayer::ResolveCachingColor blackColor(StdColors::Black());
DrawSurface *surface = window->GetDrawSurface();
surface->FillRect(licenseReaderTextRect, whiteColor);
int32_t ascent = rfont->GetMetrics().m_ascent;
const LicenseReaderLine *lines = *licenseReaderLines;
for (unsigned int i = 0; i < licenseReaderNumLines; i++)
{
int32_t lineY = licenseReaderTextRect.top + ascent + static_cast<int32_t>(kLicenseReaderTextSpacing * i);
lineY -= static_cast<int32_t>(licenseReaderTextScroll);
surface->DrawStringConstrained(Point::Create(licenseReaderTextRect.left, lineY), lines[i].m_text.ToShortStr(), licenseReaderTextRect, blackColor, rfont);
}
}
static void CycleLicenseReaderMouseHistory()
{
for (unsigned int ri = 1; ri < kLicenseReaderPointHistoryLength; ri++)
{
unsigned int i = kLicenseReaderPointHistoryLength - ri;
licenseReaderPointHistory[i] = licenseReaderPointHistory[i - 1];
}
}
static void HandleLicenseReaderScroll(Window *window, int32_t offset)
{
int32_t newScroll = static_cast<int32_t>(licenseReaderTextScroll) + offset;
if (newScroll < 0)
newScroll = 0;
else if (newScroll > static_cast<int32_t>(licenseReaderTextScrollMax))
newScroll = licenseReaderTextScrollMax;
if (newScroll != licenseReaderTextScroll)
{
licenseReaderTextScroll = newScroll;
licenseReaderScrollBarWidget->SetState(newScroll);
DrawLicenseReader(window);
}
}
static void AutoScrollLicenseReader(Window *window)
{
if (licenseReaderIsScrolling)
return;
int32_t decayRate = 2;
if (licenseReaderVelocity < 0)
{
HandleLicenseReaderScroll(window, licenseReaderVelocity);
licenseReaderVelocity += decayRate;
if (licenseReaderVelocity > 0)
licenseReaderVelocity = 0;
}
else if (licenseReaderVelocity > 0)
{
HandleLicenseReaderScroll(window, licenseReaderVelocity);
licenseReaderVelocity -= decayRate;
if (licenseReaderVelocity < 0)
licenseReaderVelocity = 0;
}
}
static void ComputeLicenseReaderVelocity()
{
int32_t velocity = licenseReaderPointHistory[kLicenseReaderPointHistoryLength - 1].v - licenseReaderPointHistory[0].v;
licenseReaderVelocity = velocity;
}
static void LicenseReaderScrollBarUpdate(void *captureContext, PortabilityLayer::Widget *widget, int part)
{
Window *window = static_cast<Window*>(captureContext); // This is stupid and very lazy...
const int incrementalStepping = kLicenseReaderTextSpacing;
const int pageStepping = 20;
switch (part)
{
case kControlUpButtonPart:
widget->SetState(widget->GetState() - incrementalStepping);
break;
case kControlDownButtonPart:
widget->SetState(widget->GetState() + incrementalStepping);
break;
case kControlPageUpPart:
widget->SetState(widget->GetState() - pageStepping * incrementalStepping);
break;
case kControlPageDownPart:
widget->SetState(widget->GetState() + pageStepping * incrementalStepping);
break;
default:
break;
};
licenseReaderTextScroll = widget->GetState();
DrawLicenseReader(window);
}
static int16_t LicenseReaderFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt)
{
bool handledIt = false;
int16_t hit = -1;
if (!evt)
{
if (licenseReaderIsScrolling)
CycleLicenseReaderMouseHistory();
else
AutoScrollLicenseReader(dialog->GetWindow());
return -1;
}
Window *window = dialog->GetWindow();
DrawSurface *surface = window->GetDrawSurface();
if (evt->IsKeyDownEvent())
{
switch (PackVOSKeyCode(evt->m_vosEvent.m_event.m_keyboardInputEvent))
{
case PL_KEY_SPECIAL(kEnter):
case PL_KEY_NUMPAD_SPECIAL(kEnter):
dialog->GetItems()[kOkayButton - 1].GetWidget()->SetHighlightStyle(kControlButtonPart, true);
PLSysCalls::Sleep(8);
dialog->GetItems()[kOkayButton - 1].GetWidget()->SetHighlightStyle(kControlButtonPart, false);
hit = kOkayButton;
handledIt = true;
break;
default:
handledIt = false;
break;
}
}
if (evt->m_vosEvent.m_eventType == GpVOSEventTypes::kMouseInput)
{
const GpMouseInputEvent &mouseEvt = evt->m_vosEvent.m_event.m_mouseInputEvent;
Point mouseLocalPt = window->MouseToLocal(mouseEvt);
switch (mouseEvt.m_eventType)
{
case GpMouseEventTypes::kDown:
if (licenseReaderTextRect.Contains(mouseLocalPt))
{
for (unsigned int i = 0; i < kLicenseReaderPointHistoryLength; i++)
licenseReaderPointHistory[i] = mouseLocalPt;
licenseReaderIsScrolling = true;
}
else if (licenseReaderScrollBarWidget->GetRect().Contains(mouseLocalPt))
{
licenseReaderScrollBarWidget->Capture(dialog->GetWindow(), mouseLocalPt, LicenseReaderScrollBarUpdate);
licenseReaderTextScroll = licenseReaderScrollBarWidget->GetState();
DrawLicenseReader(dialog->GetWindow());
}
break;
case GpMouseEventTypes::kLeave:
case GpMouseEventTypes::kUp:
licenseReaderIsScrolling = false;
ComputeLicenseReaderVelocity();
break;
case GpMouseEventTypes::kMove:
if (licenseReaderIsScrolling)
{
Point prevPoint = licenseReaderPointHistory[0];
licenseReaderPointHistory[0] = mouseLocalPt;
HandleLicenseReaderScroll(window, prevPoint.v - mouseLocalPt.v);
}
break;
default:
break;
}
}
if (!handledIt)
return -1;
return hit;
}

View File

@@ -42,6 +42,7 @@ LOCAL_SRC_FILES := \
InterfaceInit.cpp \
Link.cpp \
Main.cpp \
MainMenuUI.cpp \
MainWindow.cpp \
Map.cpp \
Marquee.cpp \

View File

@@ -14,6 +14,7 @@
#include "Environ.h"
#include "House.h"
#include "InputManager.h"
#include "MainMenuUI.h"
#include "ObjectEdit.h"
#include "Rect2i.h"
#include "WindowManager.h"
@@ -125,7 +126,7 @@ void HandleMouseEvent (const GpMouseInputEvent &theEvent, uint32_t tick)
if (vDelta < 0)
vDelta = -vDelta;
if (((tick - lastUp) < doubleTime) && (hDelta < 5) &&
(vDelta < 5))
(vDelta < 5))
isDoubleClick = true;
else
{
@@ -141,6 +142,9 @@ void HandleMouseEvent (const GpMouseInputEvent &theEvent, uint32_t tick)
HandleToolsClick(evtPoint);
else if (whichWindow == linkWindow)
HandleLinkClick(evtPoint);
else if (HandleMainMenuUIClick(whichWindow, evtPoint))
{
}
break;
default:
@@ -328,6 +332,8 @@ void HandleSplashResolutionChange(void)
InitScoreboardMap();
//RefreshScoreboard(wasScoreboardTitleMode);
//DumpScreenOn(&justRoomsRect);
HandleMainMenuUIResolutionChange();
}
void KeepWindowInBounds(Window *window)
@@ -401,6 +407,8 @@ void HandleIdleTask (void)
HandleSplashResolutionChange();
}
}
TickMainMenuUI();
}
//-------------------------------------------------------------- HandleEvent
@@ -410,7 +418,7 @@ void HandleIdleTask (void)
void HandleEvent (void)
{
TimeTaggedVOSEvent theEvent;
uint32_t sleep = 2;
uint32_t sleep = 1;
bool itHappened = true;
const KeyDownStates *eventKeys = PortabilityLayer::InputManager::GetInstance()->GetKeys();
@@ -456,12 +464,13 @@ void HandleEvent (void)
}
else
HandleIdleTask();
if ((theMode == kSplashMode) && doAutoDemo && !switchedOut)
{
if (TickCount() >= incrementModeTime)
DoDemoGame();
}
}
//-------------------------------------------------------------- IgnoreThisClick

View File

@@ -166,6 +166,7 @@ void FillScreenRed (void);
void DumpToResEditFile (Ptr, long);
void HandleEvent (void); // --- Event.c
void HandleIdleTask (void);
void IgnoreThisClick (void);
void SwitchToDepth (short, Boolean); // --- Environs.c

View File

@@ -4,7 +4,7 @@
// GliderDefines.h
//----------------------------------------------------------------------------
//============================================================================
#pragma once
//============================================================== Defines

View File

@@ -1,9 +1,12 @@
//============================================================================
//----------------------------------------------------------------------------
// GliderProtos.h
//----------------------------------------------------------------------------
//============================================================================
#pragma once
#include "PLCore.h"
#include "GliderStructs.h"
struct GpMouseInputEvent;

View File

@@ -3,8 +3,9 @@
// GliderStructs.h
//----------------------------------------------------------------------------
//============================================================================
#pragma once
#include "GliderDefines.h"
#include "PLQDOffscreen.h"
#include "GpVOSEvent.h"
#include "ByteSwap.h"

View File

@@ -103,6 +103,7 @@
<ClCompile Include="InterfaceInit.cpp" />
<ClCompile Include="Link.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="MainMenuUI.cpp" />
<ClCompile Include="MainWindow.cpp" />
<ClCompile Include="Map.cpp" />
<ClCompile Include="Marquee.cpp" />
@@ -162,6 +163,7 @@
<ClInclude Include="GliderStructs.h" />
<ClInclude Include="GliderVars.h" />
<ClInclude Include="House.h" />
<ClInclude Include="MainMenuUI.h" />
<ClInclude Include="MainWindow.h" />
<ClInclude Include="Map.h" />
<ClInclude Include="Marquee.h" />

View File

@@ -219,6 +219,9 @@
<ClCompile Include="SourceExport.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MainMenuUI.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="SoundSync.h">
@@ -302,5 +305,8 @@
<ClInclude Include="Utilities.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MainMenuUI.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -67,9 +67,12 @@ void InitializeMenus (void)
if (optionsMenu == nil)
RedAlert(kErrFailedResourceLoad);
InsertMenu(optionsMenu, 0);
menusUp = true;
PortabilityLayer::MenuManager::GetInstance()->SetMenuVisible(true);
if (!thisMac.isTouchscreen)
{
menusUp = true;
PortabilityLayer::MenuManager::GetInstance()->SetMenuVisible(true);
}
houseMenu = GetMenu(kHouseMenuID);
if (houseMenu == nil)

View File

@@ -19,6 +19,7 @@
#include "IGpDisplayDriver.h"
#include "GpIOStream.h"
#include "House.h"
#include "MainMenuUI.h"
#include "MenuManager.h"
#include "RenderedFont.h"
#include "ResolveCachingColor.h"
@@ -523,8 +524,12 @@ int gpAppMain()
UpdateMainWindow();
if (thisMac.isTouchscreen)
StartMainMenuUI();
while (!quitting) // this is the main loop
HandleEvent();
/*
#if BUILD_ARCADE_VERSION
ShowMenuBarOld();

489
GpApp/MainMenuUI.cpp Normal file
View File

@@ -0,0 +1,489 @@
#include "MainMenuUI.h"
#include "FontFamily.h"
#include "GpApplicationName.h"
#include "HostDisplayDriver.h"
#include "GliderProtos.h"
#include "Externs.h"
#include "IGpDisplayDriver.h"
#include "PLCore.h"
#include "PLQDraw.h"
#include "PLStandardColors.h"
#include "PLSysCalls.h"
#include "RenderedFont.h"
#include "GpRenderedFontMetrics.h"
#include "ResolveCachingColor.h"
#include "PLTimeTaggedVOSEvent.h"
#include "WindowDef.h"
#include "WindowManager.h"
#include "Vec2i.h"
struct MainMenuControlState
{
Window *m_window;
int m_targetHorizontalCoordinate;
Point m_dimensions;
int m_page;
};
struct MainMenuUIState
{
enum ControlID
{
Control_NewGame,
Control_LoadSavedGame,
Control_HighScores,
Control_Page0To1,
Control_LoadHouse,
Control_Demo,
Control_Page1To2,
Control_AboutApplication,
Control_AboutFramework,
Control_Page2To0,
Control_Count,
};
enum ControlStyle
{
ControlStyle_Icon,
ControlStyle_Text,
};
MainMenuControlState m_controls[Control_Count];
int m_scrollInOffset;
int m_scrollInStep;
int m_scrollOutDistance;
int m_currentPage;
ControlID m_activeControl;
static const unsigned int kControlHeight = 40;
static const unsigned int kControlFontSize = 24;
static const unsigned int kControlLeftSpacing = 20;
static const unsigned int kControlBottomSpacing = 20;
static const unsigned int kControlIntermediateSpacing = 16;
static const unsigned int kControlInteriorSpacing = 6;
static const unsigned int kControlScrollInDecay = 2;
static const unsigned int kControlScrollInDecayFalloffBits = 0;
};
static MainMenuUIState mainMenu;
static MainMenuUIState::ControlStyle GetControlStyleForControl(MainMenuUIState::ControlID controlID)
{
switch (controlID)
{
case MainMenuUIState::Control_Page0To1:
case MainMenuUIState::Control_Page1To2:
case MainMenuUIState::Control_Page2To0:
return MainMenuUIState::ControlStyle_Icon;
default:
return MainMenuUIState::ControlStyle_Text;
};
}
static PLPasStr GetTextForControl(MainMenuUIState::ControlID controlID)
{
switch (controlID)
{
case MainMenuUIState::Control_NewGame:
return PSTR("New Game");
case MainMenuUIState::Control_LoadSavedGame:
return PSTR("Resume Game");
case MainMenuUIState::Control_LoadHouse:
return PSTR("Load House");
case MainMenuUIState::Control_Demo:
return PSTR("Demo");
case MainMenuUIState::Control_HighScores:
return PSTR("High Scores");
case MainMenuUIState::Control_AboutApplication:
return PSTR("About Glider PRO");
case MainMenuUIState::Control_AboutFramework:
return PSTR("About " GP_APPLICATION_NAME);
default:
return PSTR("");
};
}
static void DrawMainMenuControl(DrawSurface *surface, MainMenuUIState::ControlID controlID, bool clicked)
{
Rect surfaceRect = surface->m_port.GetRect();
PortabilityLayer::ResolveCachingColor blackColor(StdColors::Black());
PortabilityLayer::ResolveCachingColor whiteColor(StdColors::White());
PortabilityLayer::ResolveCachingColor borderColor1(PortabilityLayer::RGBAColor::Create(255, 51, 51, 255));
PortabilityLayer::ResolveCachingColor borderColor2(PortabilityLayer::RGBAColor::Create(255, 153, 51, 255));
surface->FrameRect(surfaceRect, blackColor);
surface->FrameRect(surfaceRect.Inset(1, 1), borderColor1);
surface->FrameRect(surfaceRect.Inset(2, 2), borderColor2);
if (clicked)
surface->FillRect(surfaceRect.Inset(3, 3), borderColor2);
else
surface->FillRect(surfaceRect.Inset(3, 3), whiteColor);
switch (GetControlStyleForControl(controlID))
{
case MainMenuUIState::ControlStyle_Text:
{
PortabilityLayer::RenderedFont *rfont = GetHandwritingFont(MainMenuUIState::kControlFontSize, PortabilityLayer::FontFamilyFlag_None, true);
if (!rfont)
return;
int32_t verticalOffset = (static_cast<int32_t>(surface->m_port.GetRect().Height()) + rfont->GetMetrics().m_ascent) / 2;
surface->DrawString(Point::Create(MainMenuUIState::kControlInteriorSpacing, verticalOffset), GetTextForControl(controlID), blackColor, rfont);
}
break;
case MainMenuUIState::ControlStyle_Icon:
{
const int dotSize = 4;
const int dotSpacing = 2;
const int dotCount = 3;
const int dotTotalSize = dotSpacing * (dotCount - 1) + dotSize * dotCount;
int32_t dotHorizontalOffset = (static_cast<int32_t>(surface->m_port.GetRect().Width()) - dotTotalSize) / 2;
int32_t dotVerticalOffset = (static_cast<int32_t>(surface->m_port.GetRect().Height()) - dotSize) / 2;
for (int i = 0; i < dotCount; i++)
{
int32_t hCoord = dotHorizontalOffset + i * (dotSize + dotSpacing);
surface->FillEllipse(Rect::Create(dotVerticalOffset, hCoord, dotVerticalOffset + dotSize, hCoord + dotSize), blackColor);
}
}
break;
default:
break;
}
}
void StartScrollForPage()
{
unsigned int displayHeight = 0;
PortabilityLayer::HostDisplayDriver::GetInstance()->GetDisplayResolution(nullptr, &displayHeight);
DismissMainMenuUI();
int page = mainMenu.m_currentPage;
PortabilityLayer::WindowManager *wm = PortabilityLayer::WindowManager::GetInstance();
int totalWidth = 0;
for (int controlID = 0; controlID < MainMenuUIState::Control_Count; controlID++)
{
if (mainMenu.m_controls[controlID].m_page == page)
totalWidth = mainMenu.m_controls[controlID].m_targetHorizontalCoordinate + mainMenu.m_controls[controlID].m_dimensions.h;
}
mainMenu.m_scrollInStep = 1;
mainMenu.m_scrollInOffset = 0;
while (mainMenu.m_scrollInOffset < totalWidth)
{
mainMenu.m_scrollInOffset += (mainMenu.m_scrollInStep >> MainMenuUIState::kControlScrollInDecayFalloffBits);
mainMenu.m_scrollInStep += MainMenuUIState::kControlScrollInDecay;
}
mainMenu.m_scrollOutDistance = totalWidth;
for (int i = 0; i < MainMenuUIState::Control_Count; i++)
{
MainMenuControlState &control = mainMenu.m_controls[i];
if (control.m_page == page)
{
const uint16_t styleFlags = PortabilityLayer::WindowStyleFlags::kBorderless;
PortabilityLayer::WindowDef wdef = PortabilityLayer::WindowDef::Create(Rect::Create(0, 0, control.m_dimensions.v, control.m_dimensions.h), styleFlags, true, 0, 0, PSTR(""));
control.m_window = wm->CreateWindow(wdef);
control.m_window->SetPosition(PortabilityLayer::Vec2i(control.m_targetHorizontalCoordinate - mainMenu.m_scrollInOffset, displayHeight - MainMenuUIState::kControlBottomSpacing - control.m_dimensions.v));
wm->PutWindowBehind(control.m_window, wm->GetPutInFrontSentinel());
DrawMainMenuControl(control.m_window->GetDrawSurface(), static_cast<MainMenuUIState::ControlID>(i), false);
}
}
}
void StartMainMenuUI()
{
DismissMainMenuUI();
PortabilityLayer::RenderedFont *rfont = GetHandwritingFont(MainMenuUIState::kControlFontSize, PortabilityLayer::FontFamilyFlag_None, true);
if (!rfont)
return;
for (int controlID = 0; controlID < MainMenuUIState::Control_Count; controlID++)
{
MainMenuControlState &control = mainMenu.m_controls[controlID];
MainMenuUIState::ControlStyle controlStyle = GetControlStyleForControl(static_cast<MainMenuUIState::ControlID>(controlID));
if (controlStyle == MainMenuUIState::ControlStyle_Text)
{
size_t textLength = rfont->MeasurePStr(GetTextForControl(static_cast<MainMenuUIState::ControlID>(controlID)));
control.m_dimensions.h = textLength + MainMenuUIState::kControlInteriorSpacing * 2;
control.m_dimensions.v = MainMenuUIState::kControlHeight;
}
else
control.m_dimensions.h = control.m_dimensions.v = MainMenuUIState::kControlHeight;
}
mainMenu.m_controls[MainMenuUIState::Control_LoadHouse].m_page = 1;
mainMenu.m_controls[MainMenuUIState::Control_Demo].m_page = 1;
mainMenu.m_controls[MainMenuUIState::Control_Page1To2].m_page = 1;
mainMenu.m_controls[MainMenuUIState::Control_AboutApplication].m_page = 2;
mainMenu.m_controls[MainMenuUIState::Control_AboutFramework].m_page = 2;
mainMenu.m_controls[MainMenuUIState::Control_Page2To0].m_page = 2;
for (int i = 0; i < MainMenuUIState::Control_Count; i++)
{
if (i == 0 || mainMenu.m_controls[i].m_page != mainMenu.m_controls[i - 1].m_page)
mainMenu.m_controls[i].m_targetHorizontalCoordinate = MainMenuUIState::kControlLeftSpacing;
else
mainMenu.m_controls[i].m_targetHorizontalCoordinate = mainMenu.m_controls[i - 1].m_targetHorizontalCoordinate + mainMenu.m_controls[i - 1].m_dimensions.h + MainMenuUIState::kControlIntermediateSpacing;
}
mainMenu.m_currentPage = 0;
StartScrollForPage();
}
static void DismissMainMenuUIPage()
{
unsigned int displayHeight = 0;
PortabilityLayer::HostDisplayDriver::GetInstance()->GetDisplayResolution(nullptr, &displayHeight);
PortabilityLayer::WindowManager *wm = PortabilityLayer::WindowManager::GetInstance();
while (mainMenu.m_scrollInOffset < mainMenu.m_scrollOutDistance)
{
mainMenu.m_scrollInOffset += (mainMenu.m_scrollInStep >> MainMenuUIState::kControlScrollInDecayFalloffBits);
mainMenu.m_scrollInStep += MainMenuUIState::kControlScrollInDecay;
for (int i = 0; i < MainMenuUIState::Control_Count; i++)
{
MainMenuControlState &control = mainMenu.m_controls[i];
if (control.m_page == mainMenu.m_currentPage)
control.m_window->SetPosition(PortabilityLayer::Vec2i(control.m_targetHorizontalCoordinate - mainMenu.m_scrollInOffset, displayHeight - MainMenuUIState::kControlBottomSpacing - control.m_dimensions.v));
}
Delay(1, nullptr);
}
}
void TickMainMenuUI()
{
if (mainMenu.m_scrollInOffset > 0)
{
PortabilityLayer::WindowManager *wm = PortabilityLayer::WindowManager::GetInstance();
unsigned int displayHeight = 0;
PortabilityLayer::HostDisplayDriver::GetInstance()->GetDisplayResolution(nullptr, &displayHeight);
mainMenu.m_scrollInStep -= MainMenuUIState::kControlScrollInDecay;
mainMenu.m_scrollInOffset -= (mainMenu.m_scrollInStep >> MainMenuUIState::kControlScrollInDecayFalloffBits);
for (int i = 0; i < MainMenuUIState::Control_Count; i++)
{
MainMenuControlState &control = mainMenu.m_controls[i];
if (control.m_page == mainMenu.m_currentPage)
control.m_window->SetPosition(PortabilityLayer::Vec2i(control.m_targetHorizontalCoordinate - mainMenu.m_scrollInOffset, displayHeight - MainMenuUIState::kControlBottomSpacing - control.m_dimensions.v));
}
}
}
void DismissMainMenuUI()
{
PortabilityLayer::WindowManager *wm = PortabilityLayer::WindowManager::GetInstance();
for (int i = 0; i < MainMenuUIState::Control_Count; i++)
{
MainMenuControlState &control = mainMenu.m_controls[i];
if (control.m_window)
{
wm->DestroyWindow(control.m_window);
control.m_window = nullptr;
}
}
}
void HandleMainMenuUIResolutionChange()
{
PortabilityLayer::WindowManager *wm = PortabilityLayer::WindowManager::GetInstance();
unsigned int displayHeight = 0;
PortabilityLayer::HostDisplayDriver::GetInstance()->GetDisplayResolution(nullptr, &displayHeight);
for (int i = 0; i < MainMenuUIState::Control_Count; i++)
{
MainMenuControlState &control = mainMenu.m_controls[i];
if (control.m_window)
{
PortabilityLayer::Vec2i pos = control.m_window->GetPosition();
pos.m_y = displayHeight - MainMenuUIState::kControlBottomSpacing - MainMenuUIState::kControlHeight;
control.m_window->SetPosition(pos);
wm->PutWindowBehind(control.m_window, wm->GetPutInFrontSentinel());
}
}
}
static void MainMenuUIMouseMove(Window *window, MainMenuUIState::ControlID controlID, const Point &localPoint)
{
if (window->GetSurfaceRect().Contains(localPoint))
{
if (mainMenu.m_activeControl != controlID)
{
DrawMainMenuControl(window->GetDrawSurface(), controlID, true);
mainMenu.m_activeControl = controlID;
}
}
else
{
if (mainMenu.m_activeControl == controlID)
{
DrawMainMenuControl(window->GetDrawSurface(), controlID, false);
mainMenu.m_activeControl = MainMenuUIState::Control_Count;
}
}
}
static void HandleMainMenuUISelection(MainMenuUIState::ControlID controlID)
{
switch (controlID)
{
case MainMenuUIState::Control_NewGame:
DismissMainMenuUIPage();
DoGameMenu(iNewGame);
break;
case MainMenuUIState::Control_LoadSavedGame:
DismissMainMenuUIPage();
DoGameMenu(iOpenSavedGame);
StartMainMenuUI();
break;
case MainMenuUIState::Control_HighScores:
DismissMainMenuUIPage();
DoOptionsMenu(iHighScores);
StartMainMenuUI();
break;
case MainMenuUIState::Control_LoadHouse:
DismissMainMenuUIPage();
DoGameMenu(iLoadHouse);
StartMainMenuUI();
break;
case MainMenuUIState::Control_Demo:
DismissMainMenuUIPage();
DoOptionsMenu(iHelp);
StartMainMenuUI();
break;
case MainMenuUIState::Control_AboutApplication:
DismissMainMenuUIPage();
DoAppleMenu(iAbout);
StartScrollForPage();
break;
case MainMenuUIState::Control_AboutFramework:
DismissMainMenuUIPage();
DoAppleMenu(iAboutAerofoil);
StartScrollForPage();
break;
case MainMenuUIState::Control_Page0To1:
DismissMainMenuUIPage();
mainMenu.m_currentPage = 1;
StartScrollForPage();
break;
case MainMenuUIState::Control_Page1To2:
DismissMainMenuUIPage();
mainMenu.m_currentPage = 2;
StartScrollForPage();
break;
case MainMenuUIState::Control_Page2To0:
DismissMainMenuUIPage();
mainMenu.m_currentPage = 0;
StartScrollForPage();
break;
default:
break;
}
}
bool HandleMainMenuUIClick(Window *window, const Point &pt)
{
MainMenuUIState::ControlID controlID = MainMenuUIState::Control_Count;
if (mainMenu.m_scrollInOffset != 0)
return true;
for (int i = 0; i < MainMenuUIState::Control_Count; i++)
{
const MainMenuControlState &control = mainMenu.m_controls[i];
if (control.m_window == window)
{
controlID = static_cast<MainMenuUIState::ControlID>(i);
break;
}
}
if (controlID == MainMenuUIState::Control_Count)
return false;
DrawMainMenuControl(mainMenu.m_controls[controlID].m_window->GetDrawSurface(), controlID, true);
mainMenu.m_activeControl = controlID;
for (;;)
{
TimeTaggedVOSEvent evt;
if (WaitForEvent(&evt, 1))
{
if (evt.m_vosEvent.m_eventType == GpVOSEventTypes::kMouseInput)
{
const GpMouseInputEvent &mouseEvt = evt.m_vosEvent.m_event.m_mouseInputEvent;
if (mouseEvt.m_eventType == GpMouseEventTypes::kLeave)
return true;
if (mouseEvt.m_eventType == GpMouseEventTypes::kMove || mouseEvt.m_eventType == GpMouseEventTypes::kDown || mouseEvt.m_eventType == GpMouseEventTypes::kUp)
{
MainMenuUIMouseMove(window, controlID, window->MouseToLocal(mouseEvt));
}
if (mouseEvt.m_eventType == GpMouseEventTypes::kUp)
{
if (mainMenu.m_activeControl != MainMenuUIState::Control_Count)
{
DrawMainMenuControl(mainMenu.m_controls[controlID].m_window->GetDrawSurface(), controlID, false);
HandleMainMenuUISelection(controlID);
}
return true;
}
}
}
}
return true;
}

10
GpApp/MainMenuUI.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
struct Point;
struct Window;
void StartMainMenuUI();
void TickMainMenuUI();
void DismissMainMenuUI();
void HandleMainMenuUIResolutionChange();
bool HandleMainMenuUIClick(Window *window, const Point &pt);

View File

@@ -30,8 +30,6 @@
void DrawOnSplash (DrawSurface *surface);
void SetPaletteToGrays (void);
void HardDrawMainWindow (void);
void KeepWindowInBounds(Window *window);
CTabHandle theCTab;
@@ -53,6 +51,7 @@ Boolean fadeGraysOut, isDoColorFade, splashDrawn;
extern short toolSelected;
extern Boolean noRoomAtAll, isUseSecondScreen;
extern Boolean quickerTransitions, houseIsReadOnly;
extern Boolean menusUp;
//============================================================== Functions
//-------------------------------------------------------------- DrawOnSplash
@@ -111,7 +110,12 @@ void RedrawSplashScreen (void)
CopyRectMainToWork(&workSrcRect);
mainWindow->GetDrawSurface()->m_port.SetDirty(PortabilityLayer::QDPortDirtyFlag_Contents);
PortabilityLayer::MenuManager::GetInstance()->SetMenuVisible(true);
if (!thisMac.isTouchscreen)
{
menusUp = true;
PortabilityLayer::MenuManager::GetInstance()->SetMenuVisible(true);
}
}
//-------------------------------------------------------------- UpdateMainWindow

View File

@@ -15,6 +15,7 @@
#include "DialogManager.h"
#include "DialogUtils.h"
#include "Externs.h"
#include "Environ.h"
#include "House.h"
#include "MenuManager.h"
#include "ObjectEdit.h"
@@ -417,6 +418,13 @@ void DoOptionsMenu (short theItem)
}
}
CloseMainWindow();
if (thisMac.isTouchscreen)
{
menusUp = false;
PortabilityLayer::MenuManager::GetInstance()->SetMenuVisible(false);
}
OpenMainWindow();
incrementModeTime = TickCount() + kIdleSplashTicks;
}
@@ -425,6 +433,10 @@ void DoOptionsMenu (short theItem)
theMode = kEditMode;
StopTheMusic();
CloseMainWindow();
menusUp = true;
PortabilityLayer::MenuManager::GetInstance()->SetMenuVisible(true);
OpenMainWindow();
OpenCloseEditWindows();
}

View File

@@ -9,6 +9,7 @@
#include "PLStandardColors.h"
#include "PLSysCalls.h"
#include "RenderedFont.h"
#include "GpApplicationName.h"
#include "GpRenderedFontMetrics.h"
#include "ResolveCachingColor.h"
#include "ZipFile.h"
@@ -711,7 +712,7 @@ bool ExportSourceToStream (GpIOStream *stream)
void DoExportSourceCode (void)
{
GpIOStream *stream = PortabilityLayer::HostFileSystem::GetInstance()->OpenFile(PortabilityLayer::VirtualDirectories::kSourceExport, "SourceExport.zip", true, GpFileCreationDispositions::kCreateOrOverwrite);
GpIOStream *stream = PortabilityLayer::HostFileSystem::GetInstance()->OpenFile(PortabilityLayer::VirtualDirectories::kSourceExport, GP_APPLICATION_NAME "SourceCode.zip", true, GpFileCreationDispositions::kCreateOrOverwrite);
if (!stream)
return;