mirror of
https://github.com/ptitSeb/Serious-Engine
synced 2024-11-25 03:40:26 +01:00
1915 lines
53 KiB
C++
1915 lines
53 KiB
C++
/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */
|
|
|
|
#include "StdH.h"
|
|
#include <Engine/Base/KeyNames.h>
|
|
#include <Engine/CurrentVersion.h>
|
|
#include "MenuPrinting.h"
|
|
#include <GameMP/LCDDrawing.h>
|
|
#include "LevelInfo.h"
|
|
#include "VarList.h"
|
|
|
|
extern CFontData _fdBig;
|
|
extern CFontData _fdMedium;
|
|
extern CFontData _fdSmall;
|
|
extern CSoundData *_psdSelect;
|
|
|
|
CMenuGadget *_pmgLastActivatedGadget = NULL;
|
|
|
|
extern CSoundData *_psdPress;
|
|
extern PIX _pixCursorPosI;
|
|
extern PIX _pixCursorPosJ;
|
|
extern BOOL _bDefiningKey = FALSE;
|
|
extern BOOL _bEditingString = FALSE;
|
|
extern INDEX sam_bWideScreen;
|
|
|
|
|
|
CMenuGadget::CMenuGadget( void)
|
|
{
|
|
mg_pmgLeft = NULL;
|
|
mg_pmgRight = NULL;
|
|
mg_pmgUp = NULL;
|
|
mg_pmgDown = NULL;
|
|
|
|
mg_bVisible = TRUE;
|
|
mg_bEnabled = TRUE;
|
|
mg_bLabel = FALSE;
|
|
mg_bFocused = FALSE;
|
|
mg_iInList = -1; // not in list
|
|
}
|
|
|
|
void CMenuGadget::OnActivate( void)
|
|
{
|
|
NOTHING;
|
|
}
|
|
|
|
// return TRUE if handled
|
|
BOOL CMenuGadget::OnKeyDown( int iVKey)
|
|
{
|
|
// if return pressed
|
|
if( iVKey==VK_RETURN || iVKey==VK_LBUTTON) {
|
|
// activate
|
|
OnActivate();
|
|
// key is handled
|
|
return TRUE;
|
|
}
|
|
// key is not handled
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL CMenuGadget::OnChar(MSG msg)
|
|
{
|
|
// key is not handled
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void CMenuGadget::OnSetFocus( void)
|
|
{
|
|
mg_bFocused = TRUE;
|
|
if( !IsSeparator())
|
|
{
|
|
PlayMenuSound(_psdSelect);
|
|
IFeel_PlayEffect("Menu_select");
|
|
}
|
|
}
|
|
|
|
void CMenuGadget::OnKillFocus( void)
|
|
{
|
|
mg_bFocused = FALSE;
|
|
}
|
|
|
|
void CMenuGadget::Appear( void)
|
|
{
|
|
mg_bVisible = TRUE;
|
|
}
|
|
|
|
void CMenuGadget::Disappear( void)
|
|
{
|
|
mg_bVisible = FALSE;
|
|
mg_bFocused = FALSE;
|
|
}
|
|
|
|
void CMenuGadget::Think( void)
|
|
{
|
|
}
|
|
void CMenuGadget::OnMouseOver(PIX pixI, PIX pixJ)
|
|
{
|
|
}
|
|
|
|
// get current color for the gadget
|
|
COLOR CMenuGadget::GetCurrentColor(void)
|
|
{
|
|
// use normal colors
|
|
COLOR colUnselected = LCDGetColor(C_GREEN, "unselected");
|
|
COLOR colSelected = LCDGetColor(C_WHITE, "selected");
|
|
// if disabled
|
|
if (!mg_bEnabled) {
|
|
// use a bit darker colors
|
|
colUnselected = LCDGetColor(C_dGREEN, "disabled unselected");
|
|
colSelected = LCDGetColor(C_GRAY, "disabled selected");
|
|
// if label
|
|
if (mg_bLabel) {
|
|
// use white
|
|
colUnselected = colSelected = LCDGetColor(C_WHITE, "label");
|
|
}
|
|
}
|
|
// use unselected color
|
|
COLOR colRet = colUnselected;
|
|
// if selected
|
|
if( mg_bFocused) {
|
|
// oscilate towards selected color
|
|
FLOAT tmNow = _pTimer->GetHighPrecisionTimer().GetSeconds();
|
|
colRet = LerpColor( (colUnselected>>1)&0x7F7F7F7F, colSelected, sin(tmNow*10.0f)*0.5f+0.5f);
|
|
}
|
|
|
|
return colRet|CT_OPAQUE;
|
|
}
|
|
|
|
void CMenuGadget::Render( CDrawPort *pdp)
|
|
{
|
|
}
|
|
|
|
void CMGTitle::Render( CDrawPort *pdp)
|
|
{
|
|
SetFontTitle(pdp);
|
|
|
|
PIXaabbox2D box = FloatBoxToPixBox(pdp, mg_boxOnScreen);
|
|
PIX pixI = box.Center()(1);
|
|
PIX pixJ = box.Min()(2);
|
|
|
|
pdp->PutTextC( mg_strText, pixI, pixJ, LCDGetColor(C_WHITE|CT_OPAQUE, "title"));
|
|
}
|
|
|
|
CMGButton::CMGButton( void)
|
|
{
|
|
mg_pActivatedFunction = NULL;
|
|
mg_iIndex = 0;
|
|
mg_iCenterI = 0;
|
|
mg_iTextMode = 1;
|
|
mg_bfsFontSize = BFS_MEDIUM;
|
|
mg_iCursorPos = -1;
|
|
mg_bRectangle = FALSE;
|
|
mg_bMental = FALSE;
|
|
}
|
|
|
|
|
|
void CMGButton::SetText( CTString strNew)
|
|
{
|
|
mg_strText = strNew;
|
|
}
|
|
|
|
|
|
void CMGButton::OnActivate( void)
|
|
{
|
|
if( mg_pActivatedFunction!=NULL && mg_bEnabled)
|
|
{
|
|
PlayMenuSound(_psdPress);
|
|
IFeel_PlayEffect("Menu_press");
|
|
_pmgLastActivatedGadget = this;
|
|
(*mg_pActivatedFunction)();
|
|
}
|
|
}
|
|
|
|
|
|
BOOL CMGVarButton::IsSeparator(void)
|
|
{
|
|
if( mg_pvsVar==NULL) return FALSE;
|
|
return mg_pvsVar->vs_bSeparator;
|
|
}
|
|
|
|
|
|
BOOL CMGVarButton::IsEnabled(void)
|
|
{
|
|
return( _gmRunningGameMode==GM_NONE
|
|
|| mg_pvsVar==NULL
|
|
|| mg_pvsVar->vs_bCanChangeInGame);
|
|
}
|
|
|
|
|
|
void CMGButton::Render( CDrawPort *pdp)
|
|
{
|
|
if (mg_bfsFontSize==BFS_LARGE) {
|
|
SetFontBig(pdp);
|
|
} else if (mg_bfsFontSize==BFS_MEDIUM) {
|
|
SetFontMedium(pdp);
|
|
} else {
|
|
ASSERT(mg_bfsFontSize==BFS_SMALL);
|
|
SetFontSmall(pdp);
|
|
}
|
|
pdp->SetTextMode(mg_iTextMode);
|
|
|
|
PIXaabbox2D box = FloatBoxToPixBox(pdp, mg_boxOnScreen);
|
|
COLOR col = GetCurrentColor();
|
|
if(mg_bEditing) {
|
|
col = LCDGetColor(C_GREEN|0xFF, "editing");
|
|
}
|
|
|
|
COLOR colRectangle = col;
|
|
if( mg_bHighlighted) {
|
|
col = LCDGetColor(C_WHITE|0xFF, "hilited");
|
|
if( !mg_bFocused) {
|
|
colRectangle = LCDGetColor(C_WHITE|0xFF, "hilited rectangle");
|
|
}
|
|
}
|
|
if (mg_bMental) {
|
|
FLOAT tmIn = 0.2f;
|
|
FLOAT tmOut = 1.0f;
|
|
FLOAT tmFade = 0.1f;
|
|
FLOAT tmExist = tmFade+tmIn+tmFade;
|
|
FLOAT tmTotal = tmFade+tmIn+tmFade+tmOut;
|
|
|
|
FLOAT tmTime = _pTimer->GetHighPrecisionTimer().GetSeconds();
|
|
FLOAT fFactor = 1;
|
|
if (tmTime>0.1f) {
|
|
tmTime = fmod(tmTime, tmTotal);
|
|
fFactor = CalculateRatio(tmTime, 0, tmExist, tmFade/tmExist, tmFade/tmExist);
|
|
}
|
|
col = (col&~0xFF)|INDEX(0xFF*fFactor);
|
|
}
|
|
|
|
if( mg_bRectangle) {
|
|
// put border
|
|
const PIX pixLeft = box.Min()(1);
|
|
const PIX pixUp = box.Min()(2)-3;
|
|
const PIX pixWidth = box.Size()(1)+1;
|
|
const PIX pixHeight = box.Size()(2);
|
|
pdp->DrawBorder( pixLeft, pixUp, pixWidth, pixHeight, colRectangle);
|
|
}
|
|
|
|
if( mg_bEditing) {
|
|
// put border
|
|
PIX pixLeft = box.Min()(1);
|
|
PIX pixUp = box.Min()(2)-3;
|
|
PIX pixWidth = box.Size()(1)+1;
|
|
PIX pixHeight = box.Size()(2);
|
|
if (mg_strLabel!="") {
|
|
pixLeft = box.Min()(1)+box.Size()(1)*0.55f;
|
|
pixWidth = box.Size()(1)*0.45f+1;
|
|
}
|
|
pdp->Fill( pixLeft, pixUp, pixWidth, pixHeight, LCDGetColor(C_dGREEN|0x40, "edit fill"));
|
|
}
|
|
|
|
|
|
INDEX iCursor = mg_iCursorPos;
|
|
|
|
// print text
|
|
if (mg_strLabel!="") {
|
|
PIX pixIL = box.Min()(1)+box.Size()(1)*0.45f;
|
|
PIX pixIR = box.Min()(1)+box.Size()(1)*0.55f;
|
|
PIX pixJ = box.Min()(2);
|
|
|
|
pdp->PutTextR( mg_strLabel, pixIL, pixJ, col);
|
|
pdp->PutText( mg_strText, pixIR, pixJ, col);
|
|
} else {
|
|
CTString str = mg_strText;
|
|
if (pdp->dp_FontData->fd_bFixedWidth) {
|
|
str = str.Undecorated();
|
|
INDEX iLen = str.Length();
|
|
INDEX iMaxLen = ClampDn(box.Size()(1)/(pdp->dp_pixTextCharSpacing+pdp->dp_FontData->fd_pixCharWidth), 1L);
|
|
if (iCursor>=iMaxLen) {
|
|
str.TrimRight(iCursor);
|
|
str.TrimLeft(iMaxLen);
|
|
iCursor = iMaxLen;
|
|
} else {
|
|
str.TrimRight(iMaxLen);
|
|
}
|
|
}
|
|
if( mg_iCenterI==-1) pdp->PutText( str, box.Min()(1), box.Min()(2), col);
|
|
else if( mg_iCenterI==+1) pdp->PutTextR( str, box.Max()(1), box.Min()(2), col);
|
|
else pdp->PutTextC( str, box.Center()(1), box.Min()(2), col);
|
|
}
|
|
|
|
// put cursor if editing
|
|
if( mg_bEditing && (((ULONG)(_pTimer->GetRealTimeTick()*2))&1)) {
|
|
PIX pixX = box.Min()(1) + GetCharOffset( pdp, iCursor);
|
|
if (mg_strLabel!="") {
|
|
pixX += box.Size()(1)*0.55f;
|
|
}
|
|
PIX pixY = box.Min()(2);
|
|
if (!pdp->dp_FontData->fd_bFixedWidth) {
|
|
pixY -= pdp->dp_fTextScaling *2;
|
|
}
|
|
pdp->PutText( "|", pixX, pixY, LCDGetColor(C_WHITE|0xFF, "editing cursor"));
|
|
}
|
|
}
|
|
|
|
|
|
PIX CMGButton::GetCharOffset( CDrawPort *pdp, INDEX iCharNo)
|
|
{
|
|
if (pdp->dp_FontData->fd_bFixedWidth) {
|
|
return (pdp->dp_FontData->fd_pixCharWidth+pdp->dp_pixTextCharSpacing)*(iCharNo-0.5f);
|
|
}
|
|
CTString strCut(mg_strText);
|
|
strCut.TrimLeft( strlen(mg_strText)-iCharNo);
|
|
PIX pixFullWidth = pdp->GetTextWidth(mg_strText);
|
|
PIX pixCutWidth = pdp->GetTextWidth(strCut);
|
|
// !!!! not implemented for different centering
|
|
return pixFullWidth-pixCutWidth;
|
|
}
|
|
|
|
CMGModel::CMGModel(void)
|
|
{
|
|
mg_fFloorY = 0;
|
|
}
|
|
|
|
void CMGModel::Render( CDrawPort *pdp)
|
|
{
|
|
// if no model
|
|
if (mg_moModel.GetData()==NULL) {
|
|
// just render text
|
|
mg_strText = TRANS("No model");
|
|
CMGButton::Render(pdp);
|
|
return;
|
|
}
|
|
|
|
// get position on screen
|
|
PIXaabbox2D box = FloatBoxToPixBox(pdp, mg_boxOnScreen);
|
|
CDrawPort dpModel(pdp, box);
|
|
dpModel.Lock();
|
|
dpModel.FillZBuffer(1.0f);
|
|
|
|
LCDSetDrawport(&dpModel);
|
|
// clear menu here
|
|
dpModel.Fill(C_BLACK|255);
|
|
LCDRenderClouds1();
|
|
LCDRenderClouds2();
|
|
|
|
// prepare projection
|
|
CRenderModel rmRenderModel;
|
|
CPerspectiveProjection3D pr;
|
|
pr.FOVL() = sam_bWideScreen ? AngleDeg(45.0f) : AngleDeg(30.0f);
|
|
pr.ScreenBBoxL() = FLOATaabbox2D(
|
|
FLOAT2D(0.0f, 0.0f),
|
|
FLOAT2D((float)dpModel.GetWidth(), (float)dpModel.GetHeight())
|
|
);
|
|
pr.AspectRatioL() = 1.0f;
|
|
pr.FrontClipDistanceL() = 0.3f;
|
|
pr.ViewerPlacementL() = CPlacement3D(FLOAT3D(0,0,0), ANGLE3D(0,0,0));
|
|
|
|
// initialize remdering
|
|
CAnyProjection3D apr;
|
|
apr = pr;
|
|
BeginModelRenderingView(apr, &dpModel);
|
|
rmRenderModel.rm_vLightDirection = FLOAT3D( 0.2f, -0.2f, -0.2f);
|
|
|
|
// if model needs floor
|
|
if (mg_moFloor.GetData()!=NULL) {
|
|
// set floor's position
|
|
CPlacement3D pl = mg_plModel;
|
|
pl.pl_OrientationAngle = ANGLE3D(0,0,0);
|
|
pl.pl_PositionVector = mg_plModel.pl_PositionVector;
|
|
pl.pl_PositionVector(2) += mg_fFloorY;
|
|
rmRenderModel.SetObjectPlacement(pl);
|
|
|
|
// render the floor
|
|
rmRenderModel.rm_colLight = C_WHITE;
|
|
rmRenderModel.rm_colAmbient = C_WHITE;
|
|
mg_moFloor.SetupModelRendering( rmRenderModel);
|
|
mg_moFloor.RenderModel( rmRenderModel);
|
|
}
|
|
|
|
// set model's position
|
|
CPlacement3D pl;
|
|
pl.pl_OrientationAngle = mg_plModel.pl_OrientationAngle;
|
|
pl.pl_PositionVector = mg_plModel.pl_PositionVector;
|
|
extern FLOAT sam_fPlayerOffset;
|
|
pl.pl_PositionVector(3) += sam_fPlayerOffset;
|
|
rmRenderModel.SetObjectPlacement(pl);
|
|
|
|
// render the model
|
|
rmRenderModel.rm_colLight = LerpColor(C_BLACK, C_WHITE, 0.4f)|CT_OPAQUE;
|
|
rmRenderModel.rm_colAmbient = LerpColor(C_BLACK, C_WHITE, 0.2f)|CT_OPAQUE;
|
|
mg_moModel.SetupModelRendering( rmRenderModel);
|
|
FLOATplane3D plFloorPlane = FLOATplane3D( FLOAT3D( 0.0f, 1.0f, 0.0f),
|
|
mg_plModel.pl_PositionVector(2)+mg_fFloorY);
|
|
FLOAT3D vShadowLightDir = FLOAT3D( -0.2f, -0.4f, -0.6f);
|
|
CPlacement3D plLightPlacement = CPlacement3D(
|
|
mg_plModel.pl_PositionVector+
|
|
vShadowLightDir*mg_plModel.pl_PositionVector(3)*5,
|
|
ANGLE3D(0,0,0));
|
|
mg_moModel.RenderShadow( rmRenderModel, plLightPlacement, 200.0f, 200.0f, 1.0f, plFloorPlane);
|
|
mg_moModel.RenderModel( rmRenderModel);
|
|
EndModelRenderingView();
|
|
|
|
LCDScreenBox(LCDGetColor(C_GREEN, "model box")|GetCurrentColor());
|
|
|
|
dpModel.Unlock();
|
|
|
|
pdp->Unlock();
|
|
pdp->Lock();
|
|
LCDSetDrawport(pdp);
|
|
|
|
// print the model name
|
|
{
|
|
PIXaabbox2D box = FloatBoxToPixBox(pdp, BoxPlayerModelName());
|
|
COLOR col = GetCurrentColor();
|
|
|
|
PIX pixI = box.Min()(1);
|
|
PIX pixJ = box.Max()(2);
|
|
pdp->PutText( mg_strText, pixI, pixJ, col);
|
|
}
|
|
}
|
|
|
|
|
|
// ------- Edit gadget implementation
|
|
CMGEdit::CMGEdit(void)
|
|
{
|
|
mg_pstrToChange = NULL;
|
|
mg_ctMaxStringLen = 70;
|
|
Clear();
|
|
}
|
|
|
|
|
|
void CMGEdit::Clear(void)
|
|
{
|
|
mg_iCursorPos = 0;
|
|
mg_bEditing = FALSE;
|
|
_bEditingString = FALSE;
|
|
}
|
|
|
|
|
|
void CMGEdit::OnActivate(void)
|
|
{
|
|
if (!mg_bEnabled) {
|
|
return;
|
|
}
|
|
ASSERT( mg_pstrToChange != NULL);
|
|
PlayMenuSound( _psdPress);
|
|
IFeel_PlayEffect("Menu_press");
|
|
SetText( mg_strText);
|
|
mg_iCursorPos = strlen(mg_strText);
|
|
mg_bEditing = TRUE;
|
|
_bEditingString = TRUE;
|
|
}
|
|
|
|
|
|
// focus lost
|
|
void CMGEdit::OnKillFocus(void)
|
|
{
|
|
// go out of editing mode
|
|
if( mg_bEditing) {
|
|
OnKeyDown(VK_RETURN);
|
|
Clear();
|
|
}
|
|
// proceed
|
|
CMenuGadget::OnKillFocus();
|
|
}
|
|
|
|
|
|
// helper function for deleting char(s) from string
|
|
static void Key_BackDel( CTString &str, INDEX &iPos, BOOL bShift, BOOL bRight)
|
|
{
|
|
// do nothing if string is empty
|
|
INDEX ctChars = strlen(str);
|
|
if( ctChars==0) return;
|
|
if( bRight && iPos<ctChars) { // DELETE key
|
|
if( bShift) {
|
|
// delete to end of line
|
|
str.TrimRight(iPos);
|
|
} else {
|
|
// delete only one char
|
|
str.DeleteChar(iPos);
|
|
}
|
|
}
|
|
if( !bRight && iPos>0) { // BACKSPACE key
|
|
if( bShift) {
|
|
// delete to start of line
|
|
str.TrimLeft(ctChars-iPos);
|
|
iPos=0;
|
|
} else {
|
|
// delete only one char
|
|
str.DeleteChar(iPos-1);
|
|
iPos--;
|
|
}
|
|
}
|
|
}
|
|
|
|
// key/mouse button pressed
|
|
BOOL CMGEdit::OnKeyDown( int iVKey)
|
|
{
|
|
// if not in edit mode
|
|
if( !mg_bEditing) {
|
|
// behave like normal gadget
|
|
return CMenuGadget::OnKeyDown(iVKey);
|
|
}
|
|
|
|
// finish editing?
|
|
BOOL bShift = GetKeyState(VK_SHIFT) & 0x8000;
|
|
switch( iVKey) {
|
|
case VK_UP: case VK_DOWN:
|
|
case VK_RETURN: case VK_LBUTTON: *mg_pstrToChange = mg_strText; Clear(); OnStringChanged(); break;
|
|
case VK_ESCAPE: case VK_RBUTTON: mg_strText = *mg_pstrToChange; Clear(); OnStringCanceled(); break;
|
|
case VK_LEFT: if( mg_iCursorPos > 0) mg_iCursorPos--; break;
|
|
case VK_RIGHT: if( mg_iCursorPos < strlen(mg_strText)) mg_iCursorPos++; break;
|
|
case VK_HOME: mg_iCursorPos = 0; break;
|
|
case VK_END: mg_iCursorPos = strlen(mg_strText); break;
|
|
case VK_BACK: Key_BackDel( mg_strText, mg_iCursorPos, bShift, FALSE); break;
|
|
case VK_DELETE: Key_BackDel( mg_strText, mg_iCursorPos, bShift, TRUE); break;
|
|
default: break; // ignore all other special keys
|
|
}
|
|
|
|
// key is handled
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// char typed
|
|
BOOL CMGEdit::OnChar( MSG msg)
|
|
{
|
|
// if not in edit mode
|
|
if( !mg_bEditing) {
|
|
// behave like normal gadget
|
|
return CMenuGadget::OnChar(msg);
|
|
}
|
|
// only chars are allowed
|
|
const INDEX ctFullLen = mg_strText.Length();
|
|
const INDEX ctNakedLen = mg_strText.LengthNaked();
|
|
mg_iCursorPos = Clamp( mg_iCursorPos, 0L, ctFullLen);
|
|
int iVKey = msg.wParam;
|
|
if( isprint(iVKey) && ctNakedLen<=mg_ctMaxStringLen) {
|
|
mg_strText.InsertChar( mg_iCursorPos, (char)iVKey);
|
|
mg_iCursorPos++;
|
|
}
|
|
// key is handled
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void CMGEdit::Render( CDrawPort *pdp)
|
|
{
|
|
if( mg_bEditing) {
|
|
mg_iTextMode = -1;
|
|
} else if( mg_bFocused) {
|
|
mg_iTextMode = 0;
|
|
} else {
|
|
mg_iTextMode = 1;
|
|
}
|
|
if (mg_strText=="" && !mg_bEditing) {
|
|
if (mg_bfsFontSize==BFS_SMALL) {
|
|
mg_strText="*";
|
|
} else {
|
|
mg_strText=TRANS("<none>");
|
|
}
|
|
CMGButton::Render(pdp);
|
|
mg_strText="";
|
|
} else {
|
|
CMGButton::Render(pdp);
|
|
}
|
|
}
|
|
void CMGEdit::OnStringChanged(void)
|
|
{
|
|
}
|
|
void CMGEdit::OnStringCanceled(void)
|
|
{
|
|
}
|
|
|
|
|
|
void CMGArrow::Render( CDrawPort *pdp)
|
|
{
|
|
SetFontMedium(pdp);
|
|
|
|
PIXaabbox2D box = FloatBoxToPixBox(pdp, mg_boxOnScreen);
|
|
COLOR col = GetCurrentColor();
|
|
|
|
CTString str;
|
|
if (mg_adDirection==AD_NONE) {
|
|
str = "???";
|
|
} else if (mg_adDirection==AD_UP) {
|
|
str = TRANS("Page Up");
|
|
} else if (mg_adDirection==AD_DOWN) {
|
|
str = TRANS("Page Down");
|
|
} else {
|
|
ASSERT(FALSE);
|
|
}
|
|
PIX pixI = box.Min()(1);
|
|
PIX pixJ = box.Min()(2);
|
|
pdp->PutText( str, pixI, pixJ, col);
|
|
}
|
|
|
|
void CMGArrow::OnActivate(void)
|
|
{
|
|
if (mg_adDirection==AD_UP) {
|
|
pgmCurrentMenu->ScrollList(-3);
|
|
} else if (mg_adDirection==AD_DOWN) {
|
|
pgmCurrentMenu->ScrollList(+3);
|
|
}
|
|
}
|
|
|
|
#define HSCOLUMNS 6
|
|
CTString strHighScores[HIGHSCORE_COUNT+1][HSCOLUMNS];
|
|
FLOAT afI[HSCOLUMNS] = {
|
|
0.12f, 0.15f, 0.6f, 0.7f, 0.78f, 0.9f
|
|
};
|
|
|
|
void CMGHighScore::Render( CDrawPort *pdp)
|
|
{
|
|
SetFontMedium(pdp);
|
|
|
|
COLOR colHeader = LCDGetColor(C_GREEN|255, "hiscore header");
|
|
COLOR colData = LCDGetColor(C_mdGREEN|255, "hiscore data");
|
|
COLOR colLastSet = LCDGetColor(C_mlGREEN|255, "hiscore last set");
|
|
INDEX iLastSet = _pGame->gm_iLastSetHighScore;
|
|
|
|
CTString strText;
|
|
|
|
strHighScores[0][0] = TRANS("No.");
|
|
strHighScores[0][1] = TRANS("Player Name");
|
|
strHighScores[0][2] = TRANS("Difficulty");
|
|
strHighScores[0][3] = TRANS("Time");
|
|
strHighScores[0][4] = TRANS("Kills");
|
|
strHighScores[0][5] = TRANS("Score");
|
|
|
|
{for (INDEX i=0; i<HIGHSCORE_COUNT; i++) {
|
|
switch(_pGame->gm_ahseHighScores[i].hse_gdDifficulty) {
|
|
default:
|
|
ASSERT(FALSE);
|
|
case (CSessionProperties::GameDifficulty)-100:
|
|
strHighScores[i+1][1] = "---";
|
|
continue;
|
|
break;
|
|
case CSessionProperties::GD_TOURIST:
|
|
strHighScores[i+1][2] = TRANS("Tourist");
|
|
break;
|
|
case CSessionProperties::GD_EASY:
|
|
strHighScores[i+1][2] = TRANS("Easy");
|
|
break;
|
|
case CSessionProperties::GD_NORMAL:
|
|
strHighScores[i+1][2] = TRANS("Normal");
|
|
break;
|
|
case CSessionProperties::GD_HARD:
|
|
strHighScores[i+1][2] = TRANS("Hard");
|
|
break;
|
|
case CSessionProperties::GD_EXTREME:
|
|
strHighScores[i+1][2] = TRANS("Serious");
|
|
break;
|
|
case CSessionProperties::GD_EXTREME+1:
|
|
strHighScores[i+1][2] = TRANS("Mental");
|
|
break;
|
|
}
|
|
strHighScores[i+1][0].PrintF("%d", i+1);
|
|
strHighScores[i+1][1] = _pGame->gm_ahseHighScores[i].hse_strPlayer;
|
|
strHighScores[i+1][3] = TimeToString(_pGame->gm_ahseHighScores[i].hse_tmTime);
|
|
strHighScores[i+1][4].PrintF("%03d", _pGame->gm_ahseHighScores[i].hse_ctKills);
|
|
strHighScores[i+1][5].PrintF("%9d", _pGame->gm_ahseHighScores[i].hse_ctScore);
|
|
}}
|
|
|
|
PIX pixJ = pdp->GetHeight()*0.25f;
|
|
{for (INDEX iRow=0; iRow<HIGHSCORE_COUNT+1; iRow++) {
|
|
COLOR col = (iRow==0) ? colHeader : colData;
|
|
if (iLastSet!=-1 && iRow-1==iLastSet) {
|
|
col = colLastSet;
|
|
}
|
|
{for (INDEX iColumn=0; iColumn<HSCOLUMNS; iColumn++) {
|
|
PIX pixI = pdp->GetWidth()*afI[iColumn];
|
|
if (iColumn==1) {
|
|
pdp->PutText(strHighScores[iRow][iColumn], pixI, pixJ, col);
|
|
} else {
|
|
pdp->PutTextR(strHighScores[iRow][iColumn], pixI, pixJ, col);
|
|
}
|
|
}}
|
|
if (iRow==0) {
|
|
pixJ+=pdp->GetHeight()*0.06f;
|
|
} else {
|
|
pixJ+=pdp->GetHeight()*0.04f;
|
|
}
|
|
}}
|
|
}
|
|
|
|
// ------- Trigger button implementation
|
|
INDEX GetNewLoopValue( int iVKey, INDEX iCurrent, INDEX ctMembers)
|
|
{
|
|
INDEX iPrev = (iCurrent+ctMembers-1)%ctMembers;
|
|
INDEX iNext = (iCurrent+1)%ctMembers;
|
|
// return and right arrow set new text
|
|
if( iVKey == VK_RETURN || iVKey==VK_LBUTTON || iVKey==VK_RIGHT )
|
|
{
|
|
return iNext;
|
|
}
|
|
// left arrow and backspace sets prev text
|
|
else if( (iVKey == VK_BACK || iVKey==VK_RBUTTON) || (iVKey == VK_LEFT) )
|
|
{
|
|
return iPrev;
|
|
}
|
|
return iCurrent;
|
|
}
|
|
|
|
CMGTrigger::CMGTrigger( void)
|
|
{
|
|
mg_pOnTriggerChange = NULL;
|
|
mg_iCenterI = 0;
|
|
mg_bVisual = FALSE;
|
|
}
|
|
|
|
void CMGTrigger::ApplyCurrentSelection(void)
|
|
{
|
|
mg_iSelected = Clamp(mg_iSelected, 0L, mg_ctTexts-1L);
|
|
mg_strValue = mg_astrTexts[ mg_iSelected];
|
|
}
|
|
|
|
|
|
void CMGTrigger::OnSetNextInList(int iVKey)
|
|
{
|
|
if( mg_pPreTriggerChange != NULL) {
|
|
mg_pPreTriggerChange(mg_iSelected);
|
|
}
|
|
|
|
mg_iSelected = GetNewLoopValue( iVKey, mg_iSelected, mg_ctTexts);
|
|
mg_strValue = mg_astrTexts[ mg_iSelected];
|
|
|
|
if( mg_pOnTriggerChange != NULL) {
|
|
(*mg_pOnTriggerChange)(mg_iSelected);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL CMGTrigger::OnKeyDown( int iVKey)
|
|
{
|
|
if( (iVKey == VK_RETURN || iVKey==VK_LBUTTON) ||
|
|
(iVKey == VK_LEFT) ||
|
|
(iVKey == VK_BACK || iVKey==VK_RBUTTON) ||
|
|
(iVKey == VK_RIGHT) )
|
|
{
|
|
// key is handled
|
|
if( mg_bEnabled) OnSetNextInList(iVKey);
|
|
return TRUE;
|
|
}
|
|
// key is not handled
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void CMGTrigger::Render( CDrawPort *pdp)
|
|
{
|
|
SetFontMedium(pdp);
|
|
|
|
PIXaabbox2D box = FloatBoxToPixBox(pdp, mg_boxOnScreen);
|
|
PIX pixIL = box.Min()(1)+box.Size()(1)*0.45f;
|
|
PIX pixIR = box.Min()(1)+box.Size()(1)*0.55f;
|
|
PIX pixJ = box.Min()(2);
|
|
|
|
COLOR col = GetCurrentColor();
|
|
if (!mg_bVisual || mg_strValue=="") {
|
|
CTString strValue = mg_strValue;
|
|
if (mg_bVisual) {
|
|
strValue = TRANS("none");
|
|
}
|
|
if (mg_iCenterI==-1) {
|
|
pdp->PutText( mg_strLabel, box.Min()(1), pixJ, col);
|
|
pdp->PutTextR( strValue, box.Max()(1), pixJ, col);
|
|
} else {
|
|
pdp->PutTextR( mg_strLabel, pixIL, pixJ, col);
|
|
pdp->PutText( strValue, pixIR, pixJ, col);
|
|
}
|
|
} else {
|
|
CTString strLabel = mg_strLabel+": ";
|
|
pdp->PutText(strLabel, box.Min()(1), pixJ, col);
|
|
CTextureObject to;
|
|
try {
|
|
to.SetData_t(mg_strValue);
|
|
CTextureData *ptd = (CTextureData *)to.GetData();
|
|
PIX pixSize = box.Size()(2);
|
|
PIX pixCX = box.Max()(1)-pixSize/2;
|
|
PIX pixCY = box.Center()(2);
|
|
pdp->PutTexture( &to, PIXaabbox2D(
|
|
PIX2D(pixCX-pixSize/2, pixCY-pixSize/2),
|
|
PIX2D(pixCX-pixSize/2+pixSize, pixCY-pixSize/2+pixSize)), C_WHITE|255);
|
|
} catch (char *strError) {
|
|
CPrintF("%s\n", strError);
|
|
}
|
|
to.SetData(NULL);
|
|
}
|
|
}
|
|
|
|
CMGSlider::CMGSlider()
|
|
{
|
|
mg_iMinPos = 0;
|
|
mg_iMaxPos = 16;
|
|
mg_iCurPos = 8;
|
|
mg_pOnSliderChange = NULL;
|
|
mg_fFactor = 1.0f;
|
|
}
|
|
|
|
void CMGSlider::ApplyCurrentPosition( void)
|
|
{
|
|
mg_iCurPos = Clamp(mg_iCurPos, mg_iMinPos, mg_iMaxPos);
|
|
FLOAT fStretch = FLOAT(mg_iCurPos)/(mg_iMaxPos-mg_iMinPos);
|
|
mg_fFactor = fStretch;
|
|
|
|
if (mg_pOnSliderChange!=NULL) {
|
|
mg_pOnSliderChange(mg_iCurPos);
|
|
}
|
|
}
|
|
|
|
void CMGSlider::ApplyGivenPosition( INDEX iMin, INDEX iMax, INDEX iCur)
|
|
{
|
|
mg_iMinPos = iMin;
|
|
mg_iMaxPos = iMax;
|
|
mg_iCurPos = iCur;
|
|
ApplyCurrentPosition();
|
|
}
|
|
|
|
|
|
BOOL CMGSlider::OnKeyDown( int iVKey)
|
|
{
|
|
// if scrolling left
|
|
if( (iVKey==VK_BACK || iVKey==VK_LEFT) && mg_iCurPos>mg_iMinPos) {
|
|
mg_iCurPos --;
|
|
ApplyCurrentPosition();
|
|
return TRUE;
|
|
// if scrolling right
|
|
} else if( (iVKey==VK_RETURN || iVKey==VK_RIGHT) && mg_iCurPos<mg_iMaxPos) {
|
|
mg_iCurPos++;
|
|
ApplyCurrentPosition();
|
|
return TRUE;
|
|
// if lmb pressed
|
|
} else if (iVKey==VK_LBUTTON) {
|
|
// get position of slider box on screen
|
|
PIXaabbox2D boxSlider = GetSliderBox();
|
|
// if mouse is within
|
|
if (boxSlider>=PIX2D(_pixCursorPosI, _pixCursorPosJ)) {
|
|
// set new position exactly where mouse pointer is
|
|
FLOAT fRatio = FLOAT(_pixCursorPosI-boxSlider.Min()(1))/boxSlider.Size()(1);
|
|
fRatio = (fRatio-0.01f)/(0.99f-0.01f);
|
|
fRatio = Clamp(fRatio, 0.0f, 1.0f);
|
|
mg_iCurPos = fRatio*(mg_iMaxPos-mg_iMinPos) + mg_iMinPos;
|
|
ApplyCurrentPosition();
|
|
return TRUE;
|
|
}
|
|
}
|
|
return CMenuGadget::OnKeyDown( iVKey);
|
|
}
|
|
|
|
|
|
PIXaabbox2D CMGSlider::GetSliderBox(void)
|
|
{
|
|
extern CDrawPort *pdp;
|
|
PIXaabbox2D box = FloatBoxToPixBox(pdp, mg_boxOnScreen);
|
|
PIX pixIR = box.Min()(1)+box.Size()(1)*0.55f;
|
|
PIX pixJ = box.Min()(2);
|
|
PIX pixJSize = box.Size()(2)*0.95f;
|
|
PIX pixISizeR = box.Size()(1)*0.45f;
|
|
if( sam_bWideScreen) pixJSize++;
|
|
return PIXaabbox2D( PIX2D(pixIR+1, pixJ+1), PIX2D(pixIR+pixISizeR-2, pixJ+pixJSize-2));
|
|
}
|
|
|
|
|
|
void CMGSlider::Render( CDrawPort *pdp)
|
|
{
|
|
SetFontMedium(pdp);
|
|
|
|
// get geometry
|
|
COLOR col = GetCurrentColor();
|
|
PIXaabbox2D box = FloatBoxToPixBox(pdp, mg_boxOnScreen);
|
|
PIX pixIL = box.Min()(1)+box.Size()(1)*0.45f;
|
|
PIX pixIR = box.Min()(1)+box.Size()(1)*0.55f;
|
|
PIX pixJ = box.Min()(2);
|
|
PIX pixJSize = box.Size()(2)*0.95f;
|
|
PIX pixISizeR = box.Size()(1)*0.45f;
|
|
if( sam_bWideScreen) pixJSize++;
|
|
|
|
// print text left of slider
|
|
pdp->PutTextR( mg_strText, pixIL, pixJ, col);
|
|
|
|
// draw box around slider
|
|
LCDDrawBox(0, -1, PIXaabbox2D( PIX2D(pixIR+1, pixJ), PIX2D(pixIR+pixISizeR-2, pixJ+pixJSize-2)),
|
|
LCDGetColor(C_GREEN|255, "slider box"));
|
|
|
|
// draw filled part of slider
|
|
pdp->Fill( pixIR+2, pixJ+1, (pixISizeR-5)*mg_fFactor, (pixJSize-4), col);
|
|
|
|
// print percentage text
|
|
CTString strPercentage;
|
|
strPercentage.PrintF("%d%%", (int)floor(mg_fFactor*100+0.5f) );
|
|
pdp->PutTextC( strPercentage, pixIR+pixISizeR/2, pixJ+1, col);
|
|
}
|
|
|
|
|
|
void CMGLevelButton::OnActivate(void)
|
|
{
|
|
PlayMenuSound(_psdPress);
|
|
IFeel_PlayEffect("Menu_press");
|
|
_pGame->gam_strCustomLevel = mg_fnmLevel;
|
|
extern void (*_pAfterLevelChosen)(void);
|
|
_pAfterLevelChosen();
|
|
}
|
|
|
|
|
|
void CMGLevelButton::OnSetFocus(void)
|
|
{
|
|
SetThumbnail(mg_fnmLevel);
|
|
CMGButton::OnSetFocus();
|
|
}
|
|
|
|
|
|
|
|
// return slider position on scren
|
|
PIXaabbox2D CMGVarButton::GetSliderBox(void)
|
|
{
|
|
extern CDrawPort *pdp;
|
|
PIXaabbox2D box = FloatBoxToPixBox(pdp, mg_boxOnScreen);
|
|
PIX pixIR = box.Min()(1)+box.Size()(1)*0.55f;
|
|
PIX pixJ = box.Min()(2);
|
|
PIX pixISize = box.Size()(1)*0.13f;
|
|
PIX pixJSize = box.Size()(2);
|
|
return PIXaabbox2D( PIX2D(pixIR, pixJ+1), PIX2D(pixIR+pixISize-4, pixJ+pixJSize-6));
|
|
}
|
|
|
|
extern BOOL _bVarChanged;
|
|
BOOL CMGVarButton::OnKeyDown(int iVKey)
|
|
{
|
|
if (mg_pvsVar==NULL || mg_pvsVar->vs_bSeparator || !mg_pvsVar->Validate() || !mg_bEnabled) {
|
|
return CMenuGadget::OnKeyDown(iVKey);
|
|
}
|
|
|
|
// handle slider
|
|
if( mg_pvsVar->vs_iSlider && !mg_pvsVar->vs_bCustom) {
|
|
// ignore RMB
|
|
if( iVKey==VK_RBUTTON) return TRUE;
|
|
// handle LMB
|
|
if( iVKey==VK_LBUTTON) {
|
|
// get position of slider box on screen
|
|
PIXaabbox2D boxSlider = GetSliderBox();
|
|
// if mouse is within
|
|
if( boxSlider>=PIX2D(_pixCursorPosI, _pixCursorPosJ)) {
|
|
// set new position exactly where mouse pointer is
|
|
mg_pvsVar->vs_iValue = (FLOAT)(_pixCursorPosI-boxSlider.Min()(1))/boxSlider.Size()(1) * (mg_pvsVar->vs_ctValues);
|
|
_bVarChanged = TRUE;
|
|
}
|
|
// handled
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if( iVKey==VK_RETURN) {
|
|
FlushVarSettings(TRUE);
|
|
void MenuGoToParent(void);
|
|
MenuGoToParent();
|
|
return TRUE;
|
|
}
|
|
|
|
if( iVKey==VK_LBUTTON || iVKey==VK_RIGHT) {
|
|
if (mg_pvsVar!=NULL) {
|
|
INDEX iOldValue = mg_pvsVar->vs_iValue;
|
|
mg_pvsVar->vs_iValue++;
|
|
if( mg_pvsVar->vs_iValue>=mg_pvsVar->vs_ctValues) {
|
|
// wrap non-sliders, clamp sliders
|
|
if( mg_pvsVar->vs_iSlider) mg_pvsVar->vs_iValue = mg_pvsVar->vs_ctValues-1L;
|
|
else mg_pvsVar->vs_iValue = 0;
|
|
}
|
|
if( iOldValue != mg_pvsVar->vs_iValue) {
|
|
_bVarChanged = TRUE;
|
|
mg_pvsVar->vs_bCustom = FALSE;
|
|
mg_pvsVar->Validate();
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
if( iVKey==VK_LEFT || iVKey==VK_RBUTTON) {
|
|
if (mg_pvsVar!=NULL) {
|
|
INDEX iOldValue = mg_pvsVar->vs_iValue;
|
|
mg_pvsVar->vs_iValue--;
|
|
if( mg_pvsVar->vs_iValue<0) {
|
|
// wrap non-sliders, clamp sliders
|
|
if( mg_pvsVar->vs_iSlider) mg_pvsVar->vs_iValue = 0;
|
|
else mg_pvsVar->vs_iValue = mg_pvsVar->vs_ctValues-1L;
|
|
}
|
|
if( iOldValue != mg_pvsVar->vs_iValue) {
|
|
_bVarChanged = TRUE;
|
|
mg_pvsVar->vs_bCustom = FALSE;
|
|
mg_pvsVar->Validate();
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// not handled
|
|
return CMenuGadget::OnKeyDown(iVKey);
|
|
}
|
|
|
|
|
|
void CMGVarButton::Render( CDrawPort *pdp)
|
|
{
|
|
if (mg_pvsVar==NULL) {
|
|
return;
|
|
}
|
|
|
|
SetFontMedium(pdp);
|
|
|
|
PIXaabbox2D box = FloatBoxToPixBox(pdp, mg_boxOnScreen);
|
|
PIX pixIL = box.Min()(1)+box.Size()(1)*0.45f;
|
|
PIX pixIR = box.Min()(1)+box.Size()(1)*0.55f;
|
|
PIX pixIC = box.Center()(1);
|
|
PIX pixJ = box.Min()(2);
|
|
|
|
if (mg_pvsVar->vs_bSeparator)
|
|
{
|
|
mg_bEnabled = FALSE;
|
|
COLOR col = LCDGetColor(C_WHITE|255, "separator");
|
|
CTString strText = mg_pvsVar->vs_strName;
|
|
pdp->PutTextC(strText, pixIC, pixJ, col);
|
|
}
|
|
else if (mg_pvsVar->Validate())
|
|
{
|
|
// check whether the variable is disabled
|
|
if( mg_pvsVar->vs_strFilter!="") mg_bEnabled = _pShell->GetINDEX(mg_pvsVar->vs_strFilter);
|
|
COLOR col = GetCurrentColor();
|
|
pdp->PutTextR( mg_pvsVar->vs_strName, pixIL, pixJ, col);
|
|
// custom is by default
|
|
CTString strText = TRANS("Custom");
|
|
if( !mg_pvsVar->vs_bCustom)
|
|
{ // not custom!
|
|
strText = mg_pvsVar->vs_astrTexts[mg_pvsVar->vs_iValue];
|
|
// need slider?
|
|
if( mg_pvsVar->vs_iSlider>0) {
|
|
// draw box around slider
|
|
PIX pixISize = box.Size()(1)*0.13f;
|
|
PIX pixJSize = box.Size()(2);
|
|
LCDDrawBox( 0,-1, PIXaabbox2D( PIX2D(pixIR, pixJ+1), PIX2D(pixIR+pixISize-4, pixJ+pixJSize-6)),
|
|
LCDGetColor(C_GREEN|255, "slider box"));
|
|
// draw filled part of slider
|
|
if( mg_pvsVar->vs_iSlider==1) {
|
|
// fill slider
|
|
FLOAT fFactor = (FLOAT)(mg_pvsVar->vs_iValue+1) / mg_pvsVar->vs_ctValues;
|
|
pdp->Fill( pixIR+1, pixJ+2, (pixISize-6)*fFactor, pixJSize-9, col);
|
|
} else {
|
|
// ratio slider
|
|
ASSERT( mg_pvsVar->vs_iSlider==2);
|
|
FLOAT fUnitWidth = (FLOAT)(pixISize-5) / mg_pvsVar->vs_ctValues;
|
|
pdp->Fill( pixIR+1+(mg_pvsVar->vs_iValue*fUnitWidth), pixJ+2, fUnitWidth, pixJSize-9, col);
|
|
}
|
|
// move text printout to the right of slider
|
|
pixIR += box.Size()(1)*0.15f;
|
|
}
|
|
}
|
|
// write right text
|
|
pdp->PutText(strText, pixIR, pixJ, col);
|
|
}
|
|
}
|
|
|
|
|
|
CMGFileButton::CMGFileButton(void)
|
|
{
|
|
mg_iState = FBS_NORMAL;
|
|
}
|
|
|
|
// refresh current text from description
|
|
void CMGFileButton::RefreshText(void)
|
|
{
|
|
mg_strText = mg_strDes;
|
|
mg_strText.OnlyFirstLine();
|
|
mg_strInfo = mg_strDes;
|
|
mg_strInfo.RemovePrefix(mg_strText);
|
|
mg_strInfo.DeleteChar(0);
|
|
}
|
|
|
|
void CMGFileButton::SaveDescription(void)
|
|
{
|
|
CTFileName fnFileNameDescription = mg_fnm.NoExt()+".des";
|
|
try {
|
|
mg_strDes.Save_t(fnFileNameDescription);
|
|
} catch( char *strError) {
|
|
CPrintF("%s\n", strError);
|
|
}
|
|
}
|
|
|
|
CMGFileButton *_pmgFileToSave = NULL;
|
|
void OnFileSaveOK(void)
|
|
{
|
|
if (_pmgFileToSave!=NULL) {
|
|
_pmgFileToSave->SaveYes();
|
|
}
|
|
}
|
|
|
|
void CMGFileButton::DoSave(void)
|
|
{
|
|
if (FileExistsForWriting(mg_fnm)) {
|
|
_pmgFileToSave = this;
|
|
extern void SaveConfirm(void);
|
|
SaveConfirm();
|
|
} else {
|
|
SaveYes();
|
|
}
|
|
}
|
|
|
|
void CMGFileButton::SaveYes(void)
|
|
{
|
|
ASSERT(gmLoadSaveMenu.gm_bSave);
|
|
// call saving function
|
|
BOOL bSucceeded = gmLoadSaveMenu.gm_pAfterFileChosen(mg_fnm);
|
|
// if saved
|
|
if (bSucceeded) {
|
|
// save the description too
|
|
SaveDescription();
|
|
}
|
|
}
|
|
|
|
void CMGFileButton::DoLoad(void)
|
|
{
|
|
ASSERT(!gmLoadSaveMenu.gm_bSave);
|
|
// if no file
|
|
if(!FileExists(mg_fnm)) {
|
|
// do nothing
|
|
return;
|
|
}
|
|
if (gmLoadSaveMenu.gm_pgmNextMenu!=NULL) {
|
|
gmLoadSaveMenu.gm_pgmParentMenu = gmLoadSaveMenu.gm_pgmNextMenu;
|
|
}
|
|
// call loading function
|
|
BOOL bSucceeded = gmLoadSaveMenu.gm_pAfterFileChosen(mg_fnm);
|
|
ASSERT(bSucceeded);
|
|
}
|
|
|
|
static CTString _strTmpDescription;
|
|
static CTString _strOrgDescription;
|
|
|
|
void CMGFileButton::StartEdit(void)
|
|
{
|
|
CMGEdit::OnActivate();
|
|
}
|
|
|
|
void CMGFileButton::OnActivate(void)
|
|
{
|
|
if (mg_fnm=="") {
|
|
return;
|
|
}
|
|
|
|
PlayMenuSound(_psdPress);
|
|
IFeel_PlayEffect("Menu_press");
|
|
|
|
// if loading
|
|
if (!gmLoadSaveMenu.gm_bSave) {
|
|
// load now
|
|
DoLoad();
|
|
// if saving
|
|
} else {
|
|
// switch to editing mode
|
|
BOOL bWasEmpty = mg_strText==EMPTYSLOTSTRING;
|
|
mg_strDes = gmLoadSaveMenu.gm_strSaveDes;
|
|
RefreshText();
|
|
_strOrgDescription = _strTmpDescription = mg_strText;
|
|
if (bWasEmpty) {
|
|
_strOrgDescription = EMPTYSLOTSTRING;
|
|
}
|
|
mg_pstrToChange = &_strTmpDescription;
|
|
StartEdit();
|
|
mg_iState = FBS_SAVENAME;
|
|
}
|
|
}
|
|
BOOL CMGFileButton::OnKeyDown(int iVKey)
|
|
{
|
|
if (mg_iState == FBS_NORMAL) {
|
|
if (gmLoadSaveMenu.gm_bSave || gmLoadSaveMenu.gm_bManage) {
|
|
if (iVKey == VK_F2) {
|
|
if (FileExistsForWriting(mg_fnm)) {
|
|
// switch to renaming mode
|
|
_strOrgDescription = mg_strText;
|
|
_strTmpDescription = mg_strText;
|
|
mg_pstrToChange = &_strTmpDescription;
|
|
StartEdit();
|
|
mg_iState = FBS_RENAME;
|
|
}
|
|
return TRUE;
|
|
} else if (iVKey == VK_DELETE) {
|
|
if (FileExistsForWriting(mg_fnm)) {
|
|
// delete the file, its description and thumbnail
|
|
RemoveFile(mg_fnm);
|
|
RemoveFile(mg_fnm.NoExt()+".des");
|
|
RemoveFile(mg_fnm.NoExt()+"Tbn.tex");
|
|
// refresh menu
|
|
gmLoadSaveMenu.EndMenu();
|
|
gmLoadSaveMenu.StartMenu();
|
|
OnSetFocus();
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
return CMenuGadget::OnKeyDown(iVKey);
|
|
} else {
|
|
// go out of editing mode
|
|
if(mg_bEditing) {
|
|
if (iVKey==VK_UP || iVKey==VK_DOWN) {
|
|
CMGEdit::OnKeyDown(VK_ESCAPE);
|
|
}
|
|
}
|
|
return CMGEdit::OnKeyDown(iVKey);
|
|
}
|
|
}
|
|
|
|
void CMGFileButton::OnSetFocus(void)
|
|
{
|
|
mg_iState = FBS_NORMAL;
|
|
|
|
if (gmLoadSaveMenu.gm_bAllowThumbnails && mg_bEnabled) {
|
|
SetThumbnail(mg_fnm);
|
|
} else {
|
|
ClearThumbnail();
|
|
}
|
|
pgmCurrentMenu->KillAllFocuses();
|
|
CMGButton::OnSetFocus();
|
|
}
|
|
|
|
void CMGFileButton::OnKillFocus(void)
|
|
{
|
|
// go out of editing mode
|
|
if(mg_bEditing) {
|
|
OnKeyDown(VK_ESCAPE);
|
|
}
|
|
CMGEdit::OnKillFocus();
|
|
}
|
|
|
|
// override from edit gadget
|
|
void CMGFileButton::OnStringChanged(void)
|
|
{
|
|
// if saving
|
|
if (mg_iState == FBS_SAVENAME) {
|
|
// do the save
|
|
mg_strDes = _strTmpDescription+"\n"+mg_strInfo;
|
|
DoSave();
|
|
// if renaming
|
|
} else if (mg_iState == FBS_RENAME) {
|
|
// do the rename
|
|
mg_strDes = _strTmpDescription+"\n"+mg_strInfo;
|
|
SaveDescription();
|
|
// refresh menu
|
|
gmLoadSaveMenu.EndMenu();
|
|
gmLoadSaveMenu.StartMenu();
|
|
OnSetFocus();
|
|
}
|
|
}
|
|
void CMGFileButton::OnStringCanceled(void)
|
|
{
|
|
mg_strText = _strOrgDescription;
|
|
}
|
|
|
|
void CMGFileButton::Render( CDrawPort *pdp)
|
|
{
|
|
// render original gadget first
|
|
CMGEdit::Render(pdp);
|
|
|
|
// if currently selected
|
|
if (mg_bFocused && mg_bEnabled) {
|
|
// add info at the bottom if screen
|
|
SetFontMedium(pdp);
|
|
|
|
PIXaabbox2D box = FloatBoxToPixBox(pdp, BoxSaveLoad(15.0));
|
|
PIX pixI = box.Min()(1);
|
|
PIX pixJ = box.Min()(2);
|
|
|
|
COLOR col = LCDGetColor(C_mlGREEN|255, "file info");
|
|
pdp->PutText( mg_strInfo, pixI, pixJ, col);
|
|
}
|
|
}
|
|
|
|
FLOATaabbox2D GetBoxPartHoriz(const FLOATaabbox2D &box, FLOAT fMin, FLOAT fMax)
|
|
{
|
|
FLOAT fBoxMin = box.Min()(1);
|
|
FLOAT fBoxSize = box.Size()(1);
|
|
|
|
return FLOATaabbox2D(
|
|
FLOAT2D(fBoxMin+fBoxSize*fMin, box.Min()(2)),
|
|
FLOAT2D(fBoxMin+fBoxSize*fMax, box.Max()(2)));
|
|
}
|
|
|
|
void PrintInBox(CDrawPort *pdp, PIX pixI, PIX pixJ, PIX pixSizeI, CTString str, COLOR col)
|
|
{
|
|
str = str.Undecorated();
|
|
PIX pixCharSize = pdp->dp_pixTextCharSpacing+pdp->dp_FontData->fd_pixCharWidth;
|
|
str.TrimRight(pixSizeI/pixCharSize);
|
|
|
|
// print text
|
|
pdp->PutText(str, pixI, pixJ, col);
|
|
}
|
|
|
|
CMGServerList::CMGServerList()
|
|
{
|
|
mg_iSelected = 0;
|
|
mg_iFirstOnScreen = 0;
|
|
mg_ctOnScreen = 10;
|
|
mg_pixMinI = 0;
|
|
mg_pixMaxI = 0;
|
|
mg_pixListMinJ = 0;
|
|
mg_pixListStepJ = 0;
|
|
mg_pixDragJ = -1;
|
|
mg_iDragLine = -1;
|
|
mg_pixMouseDrag = -1;
|
|
// by default, sort by ping, best on top
|
|
mg_iSort = 2;
|
|
mg_bSortDown = FALSE;
|
|
}
|
|
void CMGServerList::AdjustFirstOnScreen(void)
|
|
{
|
|
INDEX ctSessions = _lhServers.Count();
|
|
mg_iSelected = Clamp(mg_iSelected, 0L, ClampDn(ctSessions-1L, 0L));
|
|
mg_iFirstOnScreen = Clamp(mg_iFirstOnScreen, 0L, ClampDn(ctSessions-mg_ctOnScreen, 0L));
|
|
|
|
if (mg_iSelected<mg_iFirstOnScreen) {
|
|
mg_iFirstOnScreen = ClampUp(mg_iSelected, ClampDn(ctSessions-mg_ctOnScreen-1L, 0L));
|
|
} else if (mg_iSelected>=mg_iFirstOnScreen+mg_ctOnScreen) {
|
|
mg_iFirstOnScreen = ClampDn(mg_iSelected-mg_ctOnScreen+1L, 0L);
|
|
}
|
|
}
|
|
|
|
BOOL _iSort = 0;
|
|
BOOL _bSortDown = FALSE;
|
|
|
|
int CompareSessions(const void *pv0, const void *pv1)
|
|
{
|
|
const CNetworkSession &ns0 = **(const CNetworkSession **)pv0;
|
|
const CNetworkSession &ns1 = **(const CNetworkSession **)pv1;
|
|
|
|
int iResult = 0;
|
|
switch(_iSort) {
|
|
case 0: iResult = stricmp(ns0.ns_strSession, ns1.ns_strSession); break;
|
|
case 1: iResult = stricmp(ns0.ns_strWorld, ns1.ns_strWorld); break;
|
|
case 2: iResult = Sgn(ns0.ns_tmPing-ns1.ns_tmPing); break;
|
|
case 3: iResult = Sgn(ns0.ns_ctPlayers-ns1.ns_ctPlayers); break;
|
|
case 4: iResult = stricmp(ns0.ns_strGameType, ns1.ns_strGameType); break;
|
|
case 5: iResult = stricmp(ns0.ns_strMod, ns1.ns_strMod ); break;
|
|
case 6: iResult = stricmp(ns0.ns_strVer, ns1.ns_strVer ); break;
|
|
}
|
|
|
|
if (iResult==0) { // make sure we always have unique order when resorting
|
|
return stricmp(ns0.ns_strAddress, ns1.ns_strAddress);;
|
|
}
|
|
|
|
return _bSortDown?-iResult:iResult;
|
|
}
|
|
|
|
extern CMGButton mgServerColumn[7];
|
|
extern CMGEdit mgServerFilter[7];
|
|
|
|
void SortAndFilterServers(void)
|
|
{
|
|
{FORDELETELIST(CNetworkSession, ns_lnNode, _lhServers, itns) {
|
|
delete &*itns;
|
|
}}
|
|
{FOREACHINLIST(CNetworkSession, ns_lnNode, _pNetwork->ga_lhEnumeratedSessions, itns) {
|
|
CNetworkSession &ns = *itns;
|
|
extern CTString _strServerFilter[7];
|
|
if (_strServerFilter[0]!="" && !ns.ns_strSession.Matches("*"+_strServerFilter[0]+"*")) continue;
|
|
if (_strServerFilter[1]!="" && !ns.ns_strWorld.Matches("*"+_strServerFilter[1]+"*")) continue;
|
|
if (_strServerFilter[2]!="") {
|
|
char strCompare[3] = {0,0,0};
|
|
int iPing = 0;
|
|
_strServerFilter[2].ScanF("%2[<>=]%d", strCompare, &iPing);
|
|
if (strcmp(strCompare, "<" )==0 && !(int(ns.ns_tmPing*1000)< iPing)) continue;
|
|
if (strcmp(strCompare, "<=")==0 && !(int(ns.ns_tmPing*1000)<=iPing)) continue;
|
|
if (strcmp(strCompare, ">" )==0 && !(int(ns.ns_tmPing*1000)> iPing)) continue;
|
|
if (strcmp(strCompare, ">=")==0 && !(int(ns.ns_tmPing*1000)>=iPing)) continue;
|
|
if (strcmp(strCompare, "=" )==0 && !(int(ns.ns_tmPing*1000)==iPing)) continue;
|
|
}
|
|
if (_strServerFilter[3]!="") {
|
|
char strCompare[3] = {0,0,0};
|
|
int iPlayers = 0;
|
|
_strServerFilter[3].ScanF("%2[<>=]%d", strCompare, &iPlayers);
|
|
if (strcmp(strCompare, "<" )==0 && !(ns.ns_ctPlayers< iPlayers)) continue;
|
|
if (strcmp(strCompare, "<=")==0 && !(ns.ns_ctPlayers<=iPlayers)) continue;
|
|
if (strcmp(strCompare, ">" )==0 && !(ns.ns_ctPlayers> iPlayers)) continue;
|
|
if (strcmp(strCompare, ">=")==0 && !(ns.ns_ctPlayers>=iPlayers)) continue;
|
|
if (strcmp(strCompare, "=" )==0 && !(ns.ns_ctPlayers==iPlayers)) continue;
|
|
}
|
|
if (_strServerFilter[4]!="" && !ns.ns_strGameType.Matches("*"+_strServerFilter[4]+"*")) continue;
|
|
if (_strServerFilter[5]!="" && !ns.ns_strMod.Matches("*"+_strServerFilter[5]+"*")) continue;
|
|
if (_strServerFilter[6]!="" && !ns.ns_strVer.Matches("*"+_strServerFilter[6]+"*")) continue;
|
|
|
|
CNetworkSession *pnsNew = new CNetworkSession;
|
|
pnsNew->Copy(*itns);
|
|
_lhServers.AddTail(pnsNew->ns_lnNode);
|
|
}}
|
|
|
|
_lhServers.Sort(CompareSessions, offsetof(CNetworkSession, ns_lnNode));
|
|
}
|
|
|
|
void CMGServerList::Render(CDrawPort *pdp)
|
|
{
|
|
_iSort = mg_iSort ;
|
|
_bSortDown = mg_bSortDown;
|
|
SortAndFilterServers();
|
|
|
|
SetFontSmall(pdp);
|
|
BOOL bFocusedBefore = mg_bFocused;
|
|
mg_bFocused = FALSE;
|
|
|
|
PIXaabbox2D box = FloatBoxToPixBox(pdp, mg_boxOnScreen);
|
|
COLOR col = GetCurrentColor();
|
|
|
|
PIX pixDPSizeI = pdp->GetWidth();
|
|
PIX pixDPSizeJ = pdp->GetHeight();
|
|
PIX pixCharSizeI = pdp->dp_pixTextCharSpacing+pdp->dp_FontData->fd_pixCharWidth;
|
|
PIX pixCharSizeJ = pdp->dp_pixTextLineSpacing+pdp->dp_FontData->fd_pixCharHeight+1;
|
|
PIX pixLineSize = 1;
|
|
PIX pixSliderSizeI = 10;
|
|
PIX pixOuterMargin = 20;
|
|
|
|
INDEX ctSessions = _lhServers.Count();
|
|
INDEX iSession=0;
|
|
|
|
INDEX ctColumns[7];
|
|
{for (INDEX i=0; i<ARRAYCOUNT(ctColumns); i++) {
|
|
ctColumns[i] = mgServerColumn[i].mg_strText.Length()+1;
|
|
}}
|
|
|
|
PIX pixSizePing = Max(PIX(pixCharSizeI*5), pixCharSizeI*ctColumns[2])+pixLineSize*2;
|
|
PIX pixSizePlayerCt = Max(PIX(pixCharSizeI*5),pixCharSizeI*ctColumns[3])+pixLineSize*2;
|
|
PIX pixSizeGameType = Max(Min(PIX(pixCharSizeI*20), PIX(pixDPSizeI*0.2f)), pixCharSizeI*ctColumns[4])+pixLineSize*2;
|
|
PIX pixSizeMapName = Max(PIX(pixDPSizeI*0.25f), pixCharSizeI*ctColumns[1])+pixLineSize*2;
|
|
PIX pixSizeMod = Max(Min(PIX(pixCharSizeI*11), PIX(pixDPSizeI*0.2f)), pixCharSizeI*ctColumns[5])+pixLineSize*2;
|
|
PIX pixSizeVer = Max(PIX(pixCharSizeI*7), pixCharSizeI*ctColumns[6])+pixLineSize*2;
|
|
|
|
PIX apixSeparatorI[9];
|
|
apixSeparatorI[0] = pixOuterMargin;
|
|
apixSeparatorI[8] = pixDPSizeI-pixOuterMargin-pixLineSize;
|
|
apixSeparatorI[7] = apixSeparatorI[8]-pixSliderSizeI-pixLineSize;
|
|
apixSeparatorI[6] = apixSeparatorI[7]-pixSizeVer-pixLineSize;
|
|
apixSeparatorI[5] = apixSeparatorI[6]-pixSizeMod-pixLineSize;
|
|
apixSeparatorI[4] = apixSeparatorI[5]-pixSizeGameType-pixLineSize;
|
|
apixSeparatorI[3] = apixSeparatorI[4]-pixSizePlayerCt-pixLineSize;
|
|
apixSeparatorI[2] = apixSeparatorI[3]-pixSizePing-pixLineSize;
|
|
apixSeparatorI[1] = apixSeparatorI[2]-pixSizeMapName-pixLineSize;
|
|
apixSeparatorI[1] = apixSeparatorI[2]-pixSizeMapName-pixLineSize;
|
|
PIX pixSizeServerName = apixSeparatorI[1]-apixSeparatorI[0]-pixLineSize;
|
|
|
|
PIX pixTopJ = pixDPSizeJ*0.15f;
|
|
PIX pixBottomJ = pixDPSizeJ*0.82f;
|
|
|
|
PIX pixFilterTopJ = pixTopJ+pixLineSize*3+pixCharSizeJ+pixLineSize*3;
|
|
PIX pixListTopJ = pixFilterTopJ+pixLineSize+pixCharSizeJ+pixLineSize;
|
|
INDEX ctSessionsOnScreen = (pixBottomJ-pixListTopJ)/pixCharSizeJ;
|
|
pixBottomJ = pixListTopJ + pixCharSizeJ*ctSessionsOnScreen + pixLineSize*2;
|
|
|
|
mg_pixMinI = apixSeparatorI[0];
|
|
mg_pixMaxI = apixSeparatorI[5];
|
|
mg_pixListMinJ = pixListTopJ;
|
|
mg_pixListStepJ = pixCharSizeJ;
|
|
mg_pixSBMinI = apixSeparatorI[7];
|
|
mg_pixSBMaxI = apixSeparatorI[8];
|
|
mg_pixSBMinJ = pixListTopJ;
|
|
mg_pixSBMaxJ = pixBottomJ;
|
|
mg_pixHeaderMinJ = pixTopJ;
|
|
mg_pixHeaderMidJ = pixTopJ+pixLineSize+pixCharSizeJ;
|
|
mg_pixHeaderMaxJ = pixTopJ+(pixLineSize+pixCharSizeJ)*2;
|
|
memcpy(mg_pixHeaderI, apixSeparatorI, sizeof(mg_pixHeaderI));
|
|
|
|
{for (INDEX i=0; i<ARRAYCOUNT(mgServerFilter); i++) {
|
|
mgServerColumn[i].mg_boxOnScreen = PixBoxToFloatBox(pdp,
|
|
PIXaabbox2D( PIX2D(apixSeparatorI[i]+pixCharSizeI/2,pixTopJ+pixLineSize*4), PIX2D(apixSeparatorI[i+1]-pixCharSizeI/2,pixTopJ+pixLineSize*4+pixCharSizeJ) ));
|
|
mgServerFilter[i].mg_boxOnScreen = PixBoxToFloatBox(pdp,
|
|
PIXaabbox2D( PIX2D(apixSeparatorI[i]+pixCharSizeI/2,pixFilterTopJ), PIX2D(apixSeparatorI[i+1]-pixCharSizeI/2,pixFilterTopJ+pixCharSizeJ) ));
|
|
}}
|
|
|
|
for (INDEX i=0; i<ARRAYCOUNT(apixSeparatorI); i++) {
|
|
pdp->DrawLine(apixSeparatorI[i], pixTopJ, apixSeparatorI[i], pixBottomJ, col|CT_OPAQUE);
|
|
}
|
|
pdp->DrawLine(apixSeparatorI[0], pixTopJ, apixSeparatorI[8], pixTopJ, col|CT_OPAQUE);
|
|
pdp->DrawLine(apixSeparatorI[0], pixListTopJ-pixLineSize, apixSeparatorI[8], pixListTopJ-pixLineSize, col|CT_OPAQUE);
|
|
pdp->DrawLine(apixSeparatorI[0], pixBottomJ, apixSeparatorI[8], pixBottomJ, col|CT_OPAQUE);
|
|
|
|
PIXaabbox2D boxHandle = GetScrollBarHandleBox();
|
|
pdp->Fill(boxHandle.Min()(1)+2, boxHandle.Min()(2)+2, boxHandle.Size()(1)-3, boxHandle.Size()(2)-3, col|CT_OPAQUE);
|
|
|
|
PIX pixJ = pixTopJ+pixLineSize*2+1;
|
|
|
|
mg_ctOnScreen = ctSessionsOnScreen;
|
|
AdjustFirstOnScreen();
|
|
|
|
if (_lhServers.Count()==0) {
|
|
if (_pNetwork->ga_strEnumerationStatus!="") {
|
|
mg_bFocused = TRUE;
|
|
COLOR colItem = GetCurrentColor();
|
|
PrintInBox(pdp, apixSeparatorI[0]+pixCharSizeI, pixListTopJ+pixCharSizeJ+pixLineSize+1, apixSeparatorI[1]-apixSeparatorI[0],
|
|
TRANS("searching..."), colItem);
|
|
}
|
|
} else {
|
|
FOREACHINLIST(CNetworkSession, ns_lnNode, _lhServers, itns) {
|
|
CNetworkSession &ns = *itns;
|
|
|
|
if (iSession<mg_iFirstOnScreen || iSession>=mg_iFirstOnScreen+ctSessionsOnScreen) {
|
|
iSession++;
|
|
continue;
|
|
}
|
|
|
|
PIX pixJ = pixListTopJ+(iSession-mg_iFirstOnScreen)*pixCharSizeJ+pixLineSize+1;
|
|
|
|
mg_bFocused = bFocusedBefore&&iSession==mg_iSelected;
|
|
COLOR colItem = GetCurrentColor();
|
|
|
|
if (ns.ns_strVer!=_SE_VER_STRING) {
|
|
colItem = MulColors(colItem, 0xA0A0A0FF);
|
|
}
|
|
|
|
CTString strPing(0,"%4d", INDEX(ns.ns_tmPing*1000));
|
|
CTString strPlayersCt(0, "%2d/%2d", ns.ns_ctPlayers, ns.ns_ctMaxPlayers);
|
|
CTString strMod = ns.ns_strMod;
|
|
if (strMod=="") {
|
|
strMod = "SeriousSam";
|
|
}
|
|
PrintInBox(pdp, apixSeparatorI[0]+pixCharSizeI/2, pixJ, apixSeparatorI[1]-apixSeparatorI[0]-pixCharSizeI, ns.ns_strSession, colItem);
|
|
PrintInBox(pdp, apixSeparatorI[1]+pixCharSizeI/2, pixJ, apixSeparatorI[2]-apixSeparatorI[1]-pixCharSizeI, TranslateConst(ns.ns_strWorld), colItem);
|
|
PrintInBox(pdp, apixSeparatorI[2]+pixCharSizeI/2, pixJ, apixSeparatorI[3]-apixSeparatorI[2]-pixCharSizeI, strPing, colItem);
|
|
PrintInBox(pdp, apixSeparatorI[3]+pixCharSizeI/2, pixJ, apixSeparatorI[4]-apixSeparatorI[3]-pixCharSizeI, strPlayersCt, colItem);
|
|
PrintInBox(pdp, apixSeparatorI[4]+pixCharSizeI/2, pixJ, apixSeparatorI[5]-apixSeparatorI[4]-pixCharSizeI, TranslateConst(ns.ns_strGameType), colItem);
|
|
PrintInBox(pdp, apixSeparatorI[5]+pixCharSizeI/2, pixJ, apixSeparatorI[6]-apixSeparatorI[5]-pixCharSizeI, TranslateConst(strMod), colItem);
|
|
PrintInBox(pdp, apixSeparatorI[6]+pixCharSizeI/2, pixJ, apixSeparatorI[7]-apixSeparatorI[6]-pixCharSizeI, ns.ns_strVer, colItem);
|
|
|
|
iSession++;
|
|
}
|
|
}
|
|
|
|
mg_bFocused = bFocusedBefore;
|
|
}
|
|
|
|
static INDEX SliderPixToIndex(PIX pixOffset, INDEX iVisible, INDEX iTotal, PIXaabbox2D boxFull)
|
|
{
|
|
FLOAT fSize = ClampUp(FLOAT(iVisible)/iTotal, 1.0f);
|
|
PIX pixFull = boxFull.Size()(2);
|
|
PIX pixSize = PIX(pixFull*fSize);
|
|
if (pixSize>=boxFull.Size()(2)) {
|
|
return 0;
|
|
}
|
|
return (iTotal*pixOffset)/pixFull;
|
|
}
|
|
|
|
static PIXaabbox2D GetSliderBox(INDEX iFirst, INDEX iVisible, INDEX iTotal,
|
|
PIXaabbox2D boxFull)
|
|
{
|
|
if (iTotal<=0) {
|
|
return boxFull;
|
|
}
|
|
FLOAT fSize = ClampUp(FLOAT(iVisible)/iTotal, 1.0f);
|
|
PIX pixFull = boxFull.Size()(2);
|
|
PIX pixSize = PIX(pixFull*fSize);
|
|
pixSize = ClampDn(pixSize, boxFull.Size()(1));
|
|
PIX pixTop = pixFull*(FLOAT(iFirst)/iTotal)+boxFull.Min()(2);
|
|
PIX pixI0 = boxFull.Min()(1);
|
|
PIX pixI1 = boxFull.Max()(1);
|
|
return PIXaabbox2D(PIX2D(pixI0, pixTop), PIX2D(pixI1, pixTop+pixSize));
|
|
}
|
|
|
|
PIXaabbox2D CMGServerList::GetScrollBarFullBox(void)
|
|
{
|
|
return PIXaabbox2D(PIX2D(mg_pixSBMinI, mg_pixSBMinJ), PIX2D(mg_pixSBMaxI, mg_pixSBMaxJ));
|
|
}
|
|
PIXaabbox2D CMGServerList::GetScrollBarHandleBox(void)
|
|
{
|
|
return GetSliderBox(mg_iFirstOnScreen, mg_ctOnScreen, _lhServers.Count(), GetScrollBarFullBox());
|
|
}
|
|
|
|
void CMGServerList::OnMouseOver(PIX pixI, PIX pixJ)
|
|
{
|
|
mg_pixMouseI = pixI;
|
|
mg_pixMouseJ = pixJ;
|
|
|
|
if (!(GetKeyState(VK_LBUTTON)&0x8000)) {
|
|
mg_pixDragJ = -1;
|
|
}
|
|
|
|
BOOL bInSlider = (pixI>=mg_pixSBMinI && pixI<=mg_pixSBMaxI && pixJ>=mg_pixSBMinJ && pixJ<=mg_pixSBMaxJ);
|
|
if (mg_pixDragJ>=0 && bInSlider) {
|
|
PIX pixDelta = pixJ-mg_pixDragJ;
|
|
INDEX ctSessions = _lhServers.Count();
|
|
INDEX iWantedLine = mg_iDragLine+
|
|
SliderPixToIndex(pixDelta, mg_ctOnScreen, ctSessions, GetScrollBarFullBox());
|
|
mg_iFirstOnScreen = Clamp(iWantedLine, 0L, ClampDn(ctSessions-mg_ctOnScreen, 0L));
|
|
mg_iSelected = Clamp(mg_iSelected, mg_iFirstOnScreen, mg_iFirstOnScreen+mg_ctOnScreen-1L);
|
|
// AdjustFirstOnScreen();
|
|
return;
|
|
}
|
|
|
|
// if some server is selected
|
|
if (pixI>=mg_pixMinI && pixI<=mg_pixMaxI) {
|
|
INDEX iOnScreen = (pixJ-mg_pixListMinJ)/mg_pixListStepJ;
|
|
if (iOnScreen>=0 && iOnScreen<mg_ctOnScreen) {
|
|
// put focus on it
|
|
mg_iSelected = mg_iFirstOnScreen+iOnScreen;
|
|
AdjustFirstOnScreen();
|
|
mg_pixMouseDrag = -1;
|
|
}
|
|
} else if (bInSlider) {
|
|
mg_pixMouseDrag = pixJ;
|
|
}
|
|
}
|
|
|
|
BOOL CMGServerList::OnKeyDown(int iVKey)
|
|
{
|
|
switch(iVKey) {
|
|
case VK_UP:
|
|
mg_iSelected-=1;
|
|
AdjustFirstOnScreen();
|
|
break;
|
|
case VK_DOWN:
|
|
mg_iSelected+=1;
|
|
AdjustFirstOnScreen();
|
|
break;
|
|
case VK_PRIOR:
|
|
mg_iSelected-=mg_ctOnScreen-1;
|
|
mg_iFirstOnScreen-=mg_ctOnScreen-1;
|
|
AdjustFirstOnScreen();
|
|
break;
|
|
case VK_NEXT:
|
|
mg_iSelected+=mg_ctOnScreen-1;
|
|
mg_iFirstOnScreen+=mg_ctOnScreen-1;
|
|
AdjustFirstOnScreen();
|
|
break;
|
|
case 11:
|
|
mg_iSelected-=3;
|
|
mg_iFirstOnScreen-=3;
|
|
AdjustFirstOnScreen();
|
|
break;
|
|
case 10:
|
|
mg_iSelected+=3;
|
|
mg_iFirstOnScreen+=3;
|
|
AdjustFirstOnScreen();
|
|
break;
|
|
case VK_LBUTTON:
|
|
/* if (mg_pixMouseJ>=mg_pixHeaderMinJ && mg_pixMouseJ<=mg_pixHeaderMidJ
|
|
&& mg_pixMouseI>=mg_pixHeaderI[0] && mg_pixMouseI<=mg_pixHeaderI[7]) {
|
|
INDEX iNewSort = mg_iSort;
|
|
if (mg_pixMouseI<=mg_pixHeaderI[1]) {
|
|
iNewSort = 0;
|
|
} else if (mg_pixMouseI<=mg_pixHeaderI[2]) {
|
|
iNewSort = 1;
|
|
} else if (mg_pixMouseI<=mg_pixHeaderI[3]) {
|
|
iNewSort = 2;
|
|
} else if (mg_pixMouseI<=mg_pixHeaderI[4]) {
|
|
iNewSort = 3;
|
|
} else if (mg_pixMouseI<=mg_pixHeaderI[5]) {
|
|
iNewSort = 4;
|
|
} else if (mg_pixMouseI<=mg_pixHeaderI[6]) {
|
|
iNewSort = 5;
|
|
} else if (mg_pixMouseI<=mg_pixHeaderI[7]) {
|
|
iNewSort = 6;
|
|
}
|
|
if (iNewSort==mg_iSort) {
|
|
mg_bSortDown = !mg_bSortDown;
|
|
} else {
|
|
mg_bSortDown = FALSE;
|
|
}
|
|
mg_iSort = iNewSort;
|
|
break;
|
|
} else */if (mg_pixMouseDrag>=0) {
|
|
mg_pixDragJ = mg_pixMouseDrag;
|
|
mg_iDragLine = mg_iFirstOnScreen;
|
|
break;
|
|
}
|
|
case VK_RETURN:
|
|
PlayMenuSound(_psdPress);
|
|
IFeel_PlayEffect("Menu_press");
|
|
{INDEX i=0;
|
|
FOREACHINLIST(CNetworkSession, ns_lnNode, _lhServers, itns) {
|
|
if (i==mg_iSelected) {
|
|
|
|
char strAddress[256];
|
|
int iPort;
|
|
itns->ns_strAddress.ScanF("%200[^:]:%d", &strAddress, &iPort);
|
|
_pGame->gam_strJoinAddress = strAddress;
|
|
_pShell->SetINDEX("net_iPort", iPort);
|
|
extern void StartSelectPlayersMenuFromServers(void );
|
|
StartSelectPlayersMenuFromServers();
|
|
return TRUE;
|
|
}
|
|
i++;
|
|
}}
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void CMGServerList::OnSetFocus(void)
|
|
{
|
|
mg_bFocused = TRUE;
|
|
}
|
|
void CMGServerList::OnKillFocus(void)
|
|
{
|
|
mg_bFocused = FALSE;
|
|
}
|
|
|
|
// -------------------------------- Buttons for player selecting implementation
|
|
void CMGChangePlayer::OnActivate(void)
|
|
{
|
|
PlayMenuSound(_psdPress);
|
|
IFeel_PlayEffect("Menu_press");
|
|
_iLocalPlayer = mg_iLocalPlayer;
|
|
if( _pGame->gm_aiMenuLocalPlayers[ mg_iLocalPlayer] < 0)
|
|
_pGame->gm_aiMenuLocalPlayers[ mg_iLocalPlayer] = 0;
|
|
gmPlayerProfile.gm_piCurrentPlayer = &_pGame->gm_aiMenuLocalPlayers[ mg_iLocalPlayer];
|
|
gmPlayerProfile.gm_pgmParentMenu = &gmSelectPlayersMenu;
|
|
extern BOOL _bPlayerMenuFromSinglePlayer;
|
|
_bPlayerMenuFromSinglePlayer = FALSE;
|
|
ChangeToMenu( &gmPlayerProfile);
|
|
}
|
|
|
|
void CMGChangePlayer::SetPlayerText(void)
|
|
{
|
|
INDEX iPlayer = _pGame->gm_aiMenuLocalPlayers[ mg_iLocalPlayer];
|
|
CPlayerCharacter &pc = _pGame->gm_apcPlayers[ iPlayer];
|
|
if (iPlayer<0 || iPlayer>7) {
|
|
mg_strText = "????";
|
|
} else {
|
|
mg_strText.PrintF(TRANS("Player %d: %s\n"), mg_iLocalPlayer+1, pc.GetNameForPrinting());
|
|
}
|
|
}
|
|
|
|
// ------- Key (from customize keyboard) implementation
|
|
|
|
CMGKeyDefinition::CMGKeyDefinition( void)
|
|
{
|
|
mg_iState = DOING_NOTHING;
|
|
}
|
|
|
|
|
|
void CMGKeyDefinition::OnActivate(void)
|
|
{
|
|
PlayMenuSound(_psdPress);
|
|
IFeel_PlayEffect("Menu_press");
|
|
SetBindingNames(/*bDefining=*/TRUE);
|
|
mg_iState = RELEASE_RETURN_WAITING;
|
|
}
|
|
|
|
|
|
BOOL CMGKeyDefinition::OnKeyDown( int iVKey)
|
|
{
|
|
// if waiting for a key definition
|
|
if( mg_iState == PRESS_KEY_WAITING) {
|
|
// do nothing
|
|
return TRUE;
|
|
}
|
|
|
|
// if backspace pressed
|
|
if(iVKey == VK_BACK) {
|
|
// clear both keys
|
|
DefineKey(KID_NONE);
|
|
// message is processed
|
|
return TRUE;
|
|
}
|
|
|
|
return CMenuGadget::OnKeyDown( iVKey);
|
|
}
|
|
|
|
// set names for both key bindings
|
|
void CMGKeyDefinition::SetBindingNames(BOOL bDefining)
|
|
{
|
|
// find the button
|
|
INDEX ict=0;
|
|
INDEX iDik=0;
|
|
FOREACHINLIST( CButtonAction, ba_lnNode, _pGame->gm_ctrlControlsExtra.ctrl_lhButtonActions, itba) {
|
|
if( ict == mg_iControlNumber) {
|
|
CButtonAction &ba = *itba;
|
|
// get the current bindings and names
|
|
INDEX iKey1 = ba.ba_iFirstKey;
|
|
INDEX iKey2 = ba.ba_iSecondKey;
|
|
BOOL bKey1Bound = iKey1!=KID_NONE;
|
|
BOOL bKey2Bound = iKey2!=KID_NONE;
|
|
CTString strKey1 = _pInput->GetButtonTransName(iKey1);
|
|
CTString strKey2 = _pInput->GetButtonTransName(iKey2);
|
|
|
|
// if defining
|
|
if (bDefining) {
|
|
// if only first key is defined
|
|
if (bKey1Bound && !bKey2Bound) {
|
|
// put question mark for second key
|
|
mg_strBinding = strKey1+TRANS(" or ")+"?";
|
|
// otherwise
|
|
} else {
|
|
// put question mark only
|
|
mg_strBinding = "?";
|
|
}
|
|
// if not defining
|
|
} else {
|
|
// if second key is defined
|
|
if (bKey2Bound) {
|
|
// add both
|
|
mg_strBinding = strKey1+TRANS(" or ")+strKey2;
|
|
// if second key is undefined
|
|
} else {
|
|
// display only first one
|
|
mg_strBinding = strKey1;
|
|
}
|
|
}
|
|
return ;
|
|
}
|
|
ict++;
|
|
}
|
|
|
|
// if not found, put errorneous string
|
|
mg_strBinding = "???";
|
|
}
|
|
|
|
void CMGKeyDefinition::Appear(void)
|
|
{
|
|
SetBindingNames(/*bDefining=*/FALSE);
|
|
CMenuGadget::Appear();
|
|
}
|
|
|
|
void CMGKeyDefinition::Disappear(void)
|
|
{
|
|
CMenuGadget::Disappear();
|
|
}
|
|
|
|
void CMGKeyDefinition::DefineKey(INDEX iDik)
|
|
{
|
|
// for each button in controls
|
|
INDEX ict=0;
|
|
FOREACHINLIST(CButtonAction, ba_lnNode, _pGame->gm_ctrlControlsExtra.ctrl_lhButtonActions, itba) {
|
|
CButtonAction &ba = *itba;
|
|
// if it is this one
|
|
if (ict == mg_iControlNumber) {
|
|
// if should clear
|
|
if (iDik == KID_NONE) {
|
|
// unbind both
|
|
ba.ba_iFirstKey = KID_NONE;
|
|
ba.ba_iSecondKey = KID_NONE;
|
|
}
|
|
// if first key is unbound, or both keys are bound
|
|
if (ba.ba_iFirstKey==KID_NONE || ba.ba_iSecondKey!=KID_NONE) {
|
|
// bind first key
|
|
ba.ba_iFirstKey = iDik;
|
|
// clear second key
|
|
ba.ba_iSecondKey = KID_NONE;
|
|
// if only first key bound
|
|
} else {
|
|
// bind second key
|
|
ba.ba_iSecondKey = iDik;
|
|
}
|
|
// if it is not this one
|
|
} else {
|
|
// clear bindings that contain this key
|
|
if (ba.ba_iFirstKey == iDik) {
|
|
ba.ba_iFirstKey = KID_NONE;
|
|
}
|
|
if (ba.ba_iSecondKey == iDik) {
|
|
ba.ba_iSecondKey = KID_NONE;
|
|
}
|
|
}
|
|
ict++;
|
|
}
|
|
|
|
SetBindingNames(/*bDefining=*/FALSE);
|
|
}
|
|
|
|
void CMGKeyDefinition::Think( void)
|
|
{
|
|
if( mg_iState == RELEASE_RETURN_WAITING)
|
|
{
|
|
_bDefiningKey = TRUE;
|
|
extern BOOL _bMouseUsedLast;
|
|
_bMouseUsedLast = FALSE;
|
|
_pInput->SetJoyPolling(TRUE);
|
|
_pInput->GetInput(FALSE);
|
|
if( _pInput->IsInputEnabled() &&
|
|
!_pInput->GetButtonState( KID_ENTER) &&
|
|
!_pInput->GetButtonState( KID_MOUSE1 ) )
|
|
{
|
|
mg_iState = PRESS_KEY_WAITING;
|
|
}
|
|
}
|
|
else if( mg_iState == PRESS_KEY_WAITING)
|
|
{
|
|
_pInput->SetJoyPolling(TRUE);
|
|
_pInput->GetInput(FALSE);
|
|
for( INDEX iDik = 0; iDik<MAX_OVERALL_BUTTONS; iDik++)
|
|
{
|
|
if( _pInput->GetButtonState( iDik))
|
|
{
|
|
// skip keys that cannot be defined
|
|
if (iDik == KID_TILDE) {
|
|
continue;
|
|
}
|
|
// if escape not pressed
|
|
if (iDik != KID_ESCAPE) {
|
|
// define the new key
|
|
DefineKey(iDik);
|
|
// if escape pressed
|
|
} else {
|
|
// undefine the key
|
|
DefineKey(KID_NONE);
|
|
}
|
|
|
|
// end defining loop
|
|
mg_iState = DOING_NOTHING;
|
|
_bDefiningKey = FALSE;
|
|
// refresh all buttons
|
|
pgmCurrentMenu->FillListItems();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMGKeyDefinition::Render( CDrawPort *pdp)
|
|
{
|
|
SetFontMedium(pdp);
|
|
|
|
PIXaabbox2D box = FloatBoxToPixBox(pdp, mg_boxOnScreen);
|
|
PIX pixIL = box.Min()(1)+box.Size()(1)*0.45f;
|
|
PIX pixIR = box.Min()(1)+box.Size()(1)*0.55f;
|
|
PIX pixJ = box.Min()(2);
|
|
|
|
COLOR col = GetCurrentColor();
|
|
pdp->PutTextR( mg_strLabel, pixIL, pixJ, col);
|
|
pdp->PutText( mg_strBinding, pixIR, pixJ, col);
|
|
}
|