- ImageScroller WIP commit.

This commit is contained in:
Christoph Oelckers 2020-10-08 22:20:41 +02:00
parent 15eaf86f5a
commit 6ba06f5ed0
11 changed files with 540 additions and 37 deletions

View file

@ -1553,3 +1553,11 @@ void V_CalcCleanFacs(int designwidth, int designheight, int realwidth, int realh
*cleanx = *cleany = std::min(realwidth / designwidth, realheight / designheight); *cleanx = *cleany = std::min(realwidth / designwidth, realheight / designheight);
} }
DEFINE_ACTION_FUNCTION(_Screen, SetOffset)
{
PARAM_PROLOGUE;
PARAM_FLOAT(x);
PARAM_FLOAT(y);
ACTION_RETURN_VEC2(twod->SetOffset(DVector2(x, y)));
}

View file

@ -122,6 +122,7 @@ bool OkForLocalization(FTextureID texnum, const char* substitute);
IMPLEMENT_CLASS(DMenuDescriptor, false, false) IMPLEMENT_CLASS(DMenuDescriptor, false, false)
IMPLEMENT_CLASS(DListMenuDescriptor, false, false) IMPLEMENT_CLASS(DListMenuDescriptor, false, false)
IMPLEMENT_CLASS(DOptionMenuDescriptor, false, false) IMPLEMENT_CLASS(DOptionMenuDescriptor, false, false)
IMPLEMENT_CLASS(DImageScrollerDescriptor, false, false)
DMenuDescriptor *GetMenuDescriptor(int name) DMenuDescriptor *GetMenuDescriptor(int name)
{ {
@ -136,6 +137,13 @@ DEFINE_ACTION_FUNCTION_NATIVE(DMenuDescriptor, GetDescriptor, GetMenuDescriptor)
ACTION_RETURN_OBJECT(GetMenuDescriptor(name.GetIndex())); ACTION_RETURN_OBJECT(GetMenuDescriptor(name.GetIndex()));
} }
size_t DMenuDescriptor::PropagateMark()
{
for (auto item : mItems) GC::Mark(item);
return 0;
}
void DListMenuDescriptor::Reset() void DListMenuDescriptor::Reset()
{ {
// Reset the default settings (ignore all other values in the struct) // Reset the default settings (ignore all other values in the struct)
@ -162,12 +170,6 @@ DEFINE_ACTION_FUNCTION(DListMenuDescriptor, Reset)
} }
size_t DListMenuDescriptor::PropagateMark()
{
for (auto item : mItems) GC::Mark(item);
return 0;
}
void DOptionMenuDescriptor::Reset() void DOptionMenuDescriptor::Reset()
{ {
// Reset the default settings (ignore all other values in the struct) // Reset the default settings (ignore all other values in the struct)
@ -178,12 +180,6 @@ void DOptionMenuDescriptor::Reset()
mFont = BigUpper; mFont = BigUpper;
} }
size_t DOptionMenuDescriptor::PropagateMark()
{
for (auto item : mItems) GC::Mark(item);
return 0;
}
void M_MarkMenus() void M_MarkMenus()
{ {
MenuDescriptorList::Iterator it(MenuDescriptors); MenuDescriptorList::Iterator it(MenuDescriptors);
@ -1045,6 +1041,15 @@ DEFINE_FIELD(FOptionMenuSettings, mFontColorHighlight)
DEFINE_FIELD(FOptionMenuSettings, mFontColorSelection) DEFINE_FIELD(FOptionMenuSettings, mFontColorSelection)
DEFINE_FIELD(FOptionMenuSettings, mLinespacing) DEFINE_FIELD(FOptionMenuSettings, mLinespacing)
DEFINE_FIELD(DImageScrollerDescriptor, mItems)
DEFINE_FIELD(DImageScrollerDescriptor, textBackground)
DEFINE_FIELD(DImageScrollerDescriptor, textBackgroundBrightness)
DEFINE_FIELD(DImageScrollerDescriptor,textFont)
DEFINE_FIELD(DImageScrollerDescriptor, textScale)
DEFINE_FIELD(DImageScrollerDescriptor, mAnimatedTransition)
DEFINE_FIELD(DImageScrollerDescriptor, virtWidth)
DEFINE_FIELD(DImageScrollerDescriptor, virtHeight)
struct IJoystickConfig; struct IJoystickConfig;
// These functions are used by dynamic menu creation. // These functions are used by dynamic menu creation.

View file

@ -66,7 +66,7 @@ public:
bool mProtected = false; bool mProtected = false;
TArray<DMenuItemBase *> mItems; TArray<DMenuItemBase *> mItems;
virtual size_t PropagateMark() { return 0; } size_t PropagateMark() override;
}; };
@ -95,7 +95,6 @@ public:
int mVirtHeight; int mVirtHeight;
void Reset(); void Reset();
size_t PropagateMark() override;
}; };
struct FOptionMenuSettings struct FOptionMenuSettings
@ -128,10 +127,22 @@ public:
void CalcIndent(); void CalcIndent();
DMenuItemBase *GetItem(FName name); DMenuItemBase *GetItem(FName name);
void Reset(); void Reset();
size_t PropagateMark() override;
~DOptionMenuDescriptor() = default; ~DOptionMenuDescriptor() = default;
}; };
class DImageScrollerDescriptor : public DMenuDescriptor
{
DECLARE_CLASS(DOptionMenuDescriptor, DMenuDescriptor)
public:
FTextureID textBackground;
PalEntry textBackgroundBrightness;
FFont *textFont;
double textScale;
bool mAnimatedTransition;
int virtWidth, virtHeight;
};
typedef TMap<FName, DMenuDescriptor *> MenuDescriptorList; typedef TMap<FName, DMenuDescriptor *> MenuDescriptorList;

View file

@ -50,6 +50,7 @@
#include "texturemanager.h" #include "texturemanager.h"
#include "printf.h" #include "printf.h"
#include "i_interface.h" #include "i_interface.h"
#include "templates.h"
bool CheckSkipGameOptionBlock(FScanner& sc); bool CheckSkipGameOptionBlock(FScanner& sc);
@ -629,7 +630,7 @@ static bool ReplaceMenu(FScanner &sc, DMenuDescriptor *desc)
{ {
// If this tries to replace an option menu with an option menu, let's append all new entries to the old menu. // If this tries to replace an option menu with an option menu, let's append all new entries to the old menu.
// Otherwise bail out because for list menus it's not that simple. // Otherwise bail out because for list menus it's not that simple.
if (desc->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor)) || (*pOld)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) if (!desc->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor)) || !(*pOld)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor)))
{ {
sc.ScriptMessage("Cannot replace protected menu %s.", desc->mMenuName.GetChars()); sc.ScriptMessage("Cannot replace protected menu %s.", desc->mMenuName.GetChars());
return true; return true;
@ -1052,6 +1053,214 @@ static void ParseAddOptionMenu(FScanner &sc)
} }
//=============================================================================
//
//
//
//=============================================================================
static void ParseImageScrollerBody(FScanner& sc, DImageScrollerDescriptor* desc)
{
sc.MustGetStringName("{");
while (!sc.CheckString("}"))
{
sc.MustGetString();
if (sc.Compare("else"))
{
SkipSubBlock(sc);
}
else if (sc.Compare("ifgame"))
{
if (!CheckSkipGameBlock(sc))
{
// recursively parse sub-block
ParseImageScrollerBody(sc, desc);
}
}
else if (sc.Compare("ifnotgame"))
{
if (!CheckSkipGameBlock(sc, true))
{
// recursively parse sub-block
ParseImageScrollerBody(sc, desc);
}
}
else if (sc.Compare("ifoption"))
{
if (!CheckSkipOptionBlock(sc))
{
// recursively parse sub-block
ParseImageScrollerBody(sc, desc);
}
}
else if (sc.Compare("animatedtransition"))
{
desc->mAnimatedTransition = true;
}
else if (sc.Compare("textBackground"))
{
sc.MustGetString();
desc->textBackground = GetMenuTexture(sc.String);
}
else if (sc.Compare("textBackgroundBrightness"))
{
sc.MustGetFloat();
int bb = clamp(int(sc.Float * 255), 0, 255);
desc->textBackgroundBrightness = PalEntry(255, bb, bb, bb);
}
else if (sc.Compare("textScale"))
{
sc.MustGetFloat();
desc->textScale = sc.Float;
}
else if (sc.Compare("textFont"))
{
sc.MustGetString();
FFont* newfont = V_GetFont(sc.String);
if (newfont != nullptr) desc->textFont = newfont;
}
else
{
bool success = false;
FStringf buildname("ImageScrollerPage%s", sc.String);
// Handle one special case: MapControl maps to Control with one parameter different
PClass* cls = PClass::FindClass(buildname);
if (cls != nullptr && cls->IsDescendantOf("ImageScrollerPage"))
{
auto func = dyn_cast<PFunction>(cls->FindSymbol("Init", true));
if (func != nullptr && !(func->Variants[0].Flags & (VARF_Protected | VARF_Private))) // skip internal classes which have a protected init method.
{
auto& args = func->Variants[0].Proto->ArgumentTypes;
TArray<VMValue> params;
int start = 1;
params.Push(0);
if (args.Size() > 1 && args[1] == NewPointer(PClass::FindClass("ImageScrollerDescriptor")))
{
params.Push(desc);
start = 2;
}
auto TypeCVar = NewPointer(NewStruct("CVar", nullptr, true));
// Note that this array may not be reallocated so its initial size must be the maximum possible elements.
TArray<FString> strings(args.Size());
for (unsigned i = start; i < args.Size(); i++)
{
sc.MustGetString();
if (args[i] == TypeString)
{
strings.Push(sc.String);
params.Push(&strings.Last());
}
else if (args[i] == TypeName)
{
params.Push(FName(sc.String).GetIndex());
}
else if (args[i] == TypeColor)
{
params.Push(V_GetColor(nullptr, sc));
}
else if (args[i]->isIntCompatible())
{
char* endp;
int v = (int)strtoll(sc.String, &endp, 0);
if (*endp != 0)
{
// special check for font color ranges.
v = V_FindFontColor(sc.String);
if (v == CR_UNTRANSLATED && !sc.Compare("untranslated"))
{
// todo: check other data types that may get used.
sc.ScriptError("Integer expected, got %s", sc.String);
}
}
if (args[i] == TypeBool) v = !!v;
params.Push(v);
}
else if (args[i]->isFloat())
{
char* endp;
double v = strtod(sc.String, &endp);
if (*endp != 0)
{
sc.ScriptError("Float expected, got %s", sc.String);
}
params.Push(v);
}
else if (args[i] == TypeCVar)
{
auto cv = FindCVar(sc.String, nullptr);
if (cv == nullptr && *sc.String)
{
if (func->Variants[0].ArgFlags[i] & VARF_Optional)
sc.ScriptMessage("Unknown CVar %s", sc.String);
else
sc.ScriptError("Unknown CVar %s", sc.String);
}
params.Push(cv);
}
else
{
sc.ScriptError("Invalid parameter type %s for image page", args[i]->DescriptiveName());
}
if (sc.CheckString(","))
{
if (i == args.Size() - 1)
{
sc.ScriptError("Too many parameters for %s", cls->TypeName.GetChars());
}
}
else
{
if (i < args.Size() - 1 && !(func->Variants[0].ArgFlags[i + 1] & VARF_Optional))
{
sc.ScriptError("Insufficient parameters for %s", cls->TypeName.GetChars());
}
break;
}
}
DMenuItemBase* item = (DMenuItemBase*)cls->CreateNew();
params[0] = item;
VMCallWithDefaults(func->Variants[0].Implementation, params, nullptr, 0);
desc->mItems.Push((DMenuItemBase*)item);
success = true;
}
}
if (!success)
{
sc.ScriptError("Unknown keyword '%s'", sc.String);
}
}
}
}
//=============================================================================
//
//
//
//=============================================================================
static void ParseImageScroller(FScanner& sc)
{
sc.MustGetString();
DImageScrollerDescriptor* desc = Create<DImageScrollerDescriptor>();
desc->textBackground.SetInvalid();
desc->textBackgroundBrightness = 0xffffffff;
desc->textFont = SmallFont;
desc->textScale = 1;
desc->mAnimatedTransition = false;
ParseImageScrollerBody(sc, desc);
bool scratch = ReplaceMenu(sc, desc);
if (scratch) delete desc;
}
//============================================================================= //=============================================================================
// //
// //
@ -1118,6 +1327,10 @@ void M_ParseMenuDefs()
I_FatalError("You cannot add menu items to the menu default settings."); I_FatalError("You cannot add menu items to the menu default settings.");
} }
} }
else if (sc.Compare("IMAGESCROLLER"))
{
ParseImageScroller(sc);
}
else else
{ {
sc.ScriptError("Unknown keyword '%s'", sc.String); sc.ScriptError("Unknown keyword '%s'", sc.String);

View file

@ -137,8 +137,6 @@ bool AppActive = true;
FString currentGame; FString currentGame;
FString LumpFilter; FString LumpFilter;
TMap<FName, int32_t> NameToTileIndex; // for assigning names to tiles. The menu accesses this list. By default it gets everything from the dynamic tile map in Duke Nukem and Redneck Rampage.
// Todo: Add additional definition file for the other games or textures not in that list so that the menu does not have to rely on indices.
CVAR(Bool, queryiwad, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); CVAR(Bool, queryiwad, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
CVAR(String, defaultiwad, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG); CVAR(String, defaultiwad, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
@ -1822,6 +1820,7 @@ static const gamefilter games[] = {
{ "Blood", GAMEFLAG_BLOOD}, { "Blood", GAMEFLAG_BLOOD},
{ "ShadowWarrior", GAMEFLAG_SW}, { "ShadowWarrior", GAMEFLAG_SW},
{ "Exhumed", GAMEFLAG_POWERSLAVE | GAMEFLAG_EXHUMED}, { "Exhumed", GAMEFLAG_POWERSLAVE | GAMEFLAG_EXHUMED},
{ "Plutopak", GAMEFLAG_PLUTOPAK},
{ "Worldtour", GAMEFLAG_WORLDTOUR}, { "Worldtour", GAMEFLAG_WORLDTOUR},
{ "Shareware", GAMEFLAG_SHAREWARE}, { "Shareware", GAMEFLAG_SHAREWARE},
}; };

View file

@ -23,12 +23,10 @@ extern bool r_NoInterpolate;
struct MapRecord; struct MapRecord;
extern MapRecord* g_nextmap; extern MapRecord* g_nextmap;
extern int g_nextskill; extern int g_nextskill;
extern FMemArena dump; // this is for memory blocks than cannot be deallocated without some huge effort. Put them in here so that they do not register on shutdown. extern FMemArena dump; // this is for memory blocks than cannot be deallocated without some huge effort. Put them in here so that they do not register on shutdown.
extern TMap<FName, int32_t> NameToTileIndex;
int CONFIG_Init(); int CONFIG_Init();
// I am not sure if anything below will survive for long... // I am not sure if anything below will survive for long...

View file

@ -518,6 +518,9 @@ x(INGAMEDUKETHREEDEE, 2499)
x(TENSCREEN, 2500) x(TENSCREEN, 2500)
x(PLUTOPAKSPRITE, 2501) x(PLUTOPAKSPRITE, 2501)
x(MENUPLUTOPAKSPRITE, 2503) x(MENUPLUTOPAKSPRITE, 2503)
x(CREDITPAGE1, 2504)
x(CREDITPAGE2, 2505)
x(CREDITPAGE3, 2506)
x(DEVISTATOR, 2510) x(DEVISTATOR, 2510)
x(KNEE, 2521) x(KNEE, 2521)
x(CROSSHAIR, 2523) x(CROSSHAIR, 2523)

View file

@ -199,19 +199,15 @@ LISTMENU "SkillMenu"
// //
//------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------
/*
ImageScroller "HelpMenu" ImageScroller "HelpMenu"
{ {
ifgame(Duke, Nam, WW2GI) ifgame(Duke, Nam, WW2GI)
{ {
ImageItem "#3280" ImageItem "TEXTSTORY"
ImageItem "#2445" ImageItem "F1HELP"
class "$.ImageScrollerMenu" animatedtransition
ifgame(Duke, Nam, WW2GI)
{
animatedtransition
}
} }
/*
ifgame(Redneck, RedneckRides) ifgame(Redneck, RedneckRides)
{ {
ImageItem "#2541" ImageItem "#2541"
@ -242,8 +238,8 @@ ImageScroller "HelpMenu"
ImageItem "#5261" ImageItem "#5261"
} }
} }
*/
} }
*/
//------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------
// //
@ -256,17 +252,16 @@ ImageScroller "HelpMenu"
// //
//------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------
/*
ImageScroller "CreditsMenu" ImageScroller "CreditsMenu"
{ {
ifgame(Duke, Nam, WW2GI) ifgame(Duke, Nam, WW2GI)
{ {
ImageItem "#2504" ImageItem "CREDITPAGE1"
ImageItem "#2505" ImageItem "CREDITPAGE2"
ImageItem "#2506" ImageItem "CREDITPAGE3"
animatedtransition animatedtransition
class "Duke.ImageScrollerMenu"
} }
/*
ifgame(Redneck) ifgame(Redneck)
{ {
// no point putting this into the string table. // no point putting this into the string table.
@ -346,8 +341,8 @@ ImageScroller "CreditsMenu"
ImageItem "#4979" ImageItem "#4979"
ImageItem "#5113" ImageItem "#5113"
} }
*/
} }
*/
//------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------
// //

View file

@ -20,6 +20,7 @@ version "4.3"
#include "zscript/ui/menu/reverbedit.zs" #include "zscript/ui/menu/reverbedit.zs"
#include "zscript/ui/menu/textentermenu.zs" #include "zscript/ui/menu/textentermenu.zs"
#include "zscript/ui/menu/menucustomize.zs" #include "zscript/ui/menu/menucustomize.zs"
#include "zscript/ui/menu/imagescroller.zs"
#include "zscript/games/duke/ui/menu.zs" #include "zscript/games/duke/ui/menu.zs"
#include "zscript/games/blood/ui/menu.zs" #include "zscript/games/blood/ui/menu.zs"

View file

@ -399,6 +399,7 @@ struct Screen native
native static int, int, int, int GetClipRect(); native static int, int, int, int GetClipRect();
native static int, int, int, int GetViewWindow(); native static int, int, int, int GetViewWindow();
native static double, double, double, double GetFullscreenRect(double vwidth, double vheight, int fsmode); native static double, double, double, double GetFullscreenRect(double vwidth, double vheight, int fsmode);
native static Vector2 SetOffset(double x, double y);
} }
struct Font native struct Font native

View file

@ -0,0 +1,269 @@
/*
** imagescroller.cpp
** Scrolls through multiple fullscreen image pages,
**
**---------------------------------------------------------------------------
** Copyright 2019-220 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
class ImageScrollerDescriptor : MenuDescriptor native
{
native Array<ImageScrollerPage> mItems;
native Font textFont;
native TextureID textBackground;
native Color textBackgroundBrightness;
native double textScale;
native bool mAnimatedTransition;
native int virtWidth, virtHeight;
}
class ImageScrollerPage : MenuItemBase
{
int virtWidth, virtHeight;
protected void DrawText(Font fnt, int color, double x, double y, String text)
{
screen.DrawText(fnt, color, x, y, text, DTA_VirtualWidth, virtWidth, DTA_VirtualHeight, virtHeight, DTA_FullscreenScale, FSMode_ScaleToFit43);
}
protected void DrawTexture(TextureID tex, double x, double y)
{
screen.DrawTexture(tex, true, x, y, DTA_VirtualWidth, virtWidth, DTA_VirtualHeight, virtHeight, DTA_FullscreenScale, FSMode_ScaleToFit43);
}
}
//=============================================================================
//
// an image page
//
//=============================================================================
class ImageScrollerPageImageItem : ImageScrollerPage
{
TextureID mTexture;
void Init(ImageScrollerDescriptor desc, String patch)
{
Super.Init();
mTexture = TexMan.CheckForTexture(patch);
}
override void Drawer(bool selected)
{
Screen.DrawTexture(mTexture, true, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal);
}
}
//=============================================================================
//
// a simple text page
//
//=============================================================================
class ImageScrollerPageTextItem : ImageScrollerPage
{
Font mFont;
BrokenLines mText;
TextureID mTexture;
Color mBrightness;
double mTextScale;
void Init(ImageScrollerDescriptor desc, String txt, int y = -1)
{
Super.Init();
mTexture = desc.textBackground;
mBrightness = desc.textBackgroundBrightness;
mFont = desc.textFont;
mTextScale = desc.textScale;
virtWidth = desc.virtWidth;
virtHeight = desc.virtHeight;
mText = mFont.BreakLines(Stringtable.Localize(txt), virtWidth / mTextScale);
mYpos = y >= 0? y : virtHeight / 2 - mText.Count() * mFont.GetHeight() / 2;
}
override void Drawer(bool selected)
{
Screen.DrawTexture(mTexture, true, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal, DTA_Color, mBrightness);
int fontheight = mFont.GetHeight() * mTextScale;
let y = mYpos;
let c = mText.Count();
for (int i = 0; i < c; i++)
{
screen.DrawText (mFont, Font.CR_UNTRANSLATED, virtWidth/2 - mText.StringWidth(i) * mTextScale / 2, y, mText.StringAt(i), DTA_ScaleX, mTextScale, DTA_ScaleY, mTextScale,
DTA_VirtualWidth, virtWidth, DTA_VirtualHeight, virtHeight, DTA_FullscreenScale, FSMode_ScaleToFit43);
y += fontheight;
}
}
}
//=============================================================================
//
// The main class
//
//=============================================================================
class ImageScrollerMenu : Menu
{
ImageScrollerPage previous;
ImageScrollerPage current;
double start;
int length;
int dir;
int index;
ImageScrollerDescriptor mDesc;
private void StartTransition(ImageScrollerPage to, int animtype)
{
if (AnimatedTransition)
{
start = MSTime() * (120. / 1000.);
length = 30;
dir = animtype;
previous = current;
}
current = to;
}
void Init(Menu parent, ImageScrollerDescriptor desc)
{
mParentMenu = parent;
index = 0;
mDesc = desc;
AnimatedTransition = desc.mAnimatedTransition;
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent(int mkey, bool fromcontroller)
{
if (mDesc.mItems.Size() <= 1)
{
if (mkey == MKEY_Enter) mkey = MKEY_Back;
else if (mkey == MKEY_Right || mkey == MKEY_Left) return true;
}
switch (mkey)
{
case MKEY_Back:
// Before going back the currently running transition must be terminated.
previous = null;
return Super.MenuEvent(mkey, fromcontroller);
case MKEY_Left:
if (previous == null)
{
if (--index < 0) index = mDesc.mItems.Size() - 1;
let next = mDesc.mItems[index];
StartTransition(next, -1);
MenuSound("menu/choose");
}
return true;
case MKEY_Right:
case MKEY_Enter:
if (previous == null)
{
int oldindex = index;
if (++index >= mDesc.mItems.Size()) index = 0;
let next = mDesc.mItems[index];
StartTransition(next, 1);
MenuSound("menu/choose");
}
return true;
default:
return Super.MenuEvent(mkey, fromcontroller);
}
}
//=============================================================================
//
//
//
//=============================================================================
override bool MouseEvent(int type, int x, int y)
{
// Todo: Implement some form of drag event to switch between pages.
if (type == MOUSE_Release)
{
return MenuEvent(MKEY_Enter, false);
}
return Super.MouseEvent(type, x, y);
}
//=============================================================================
//
//
//
//=============================================================================
private bool DrawTransition()
{
double now = MSTime() * (120. / 1000.);
if (now < start + length)
{
double factor = screen.GetWidth()/2;
double phase = (now - start) / length * 180. + 90.;
screen.SetOffset(0, factor * dir * (sin(phase) - 1.));
previous.Drawer(false);
screen.SetOffset(0, factor * dir * (sin(phase) + 1.));
current.Drawer(false);
screen.SetOffset(0, 0);
return true;
}
previous = null;
return false;
}
//=============================================================================
//
//
//
//=============================================================================
override void Drawer()
{
if (previous != null)
{
if (DrawTransition()) return;
previous = null;
}
current.Drawer(false);
}
}