2009-05-08 13:28:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 2005 - 2009 , RedWolf Design GmbH , http : //www.clonk.de/
2016-04-03 18:18:29 +00:00
* Copyright ( c ) 2009 - 2016 , The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2009-05-08 13:28:41 +00:00
*/
// Startup screen for non-parameterized engine start: Scenario selection dialog
2016-04-03 18:07:56 +00:00
# include "C4Include.h"
# include "gui/C4StartupScenSelDlg.h"
2009-05-08 13:28:41 +00:00
2016-04-03 18:07:56 +00:00
# include "c4group/C4ComponentHost.h"
# include "c4group/C4Components.h"
2017-04-30 08:49:09 +00:00
# include "game/C4Application.h"
# include "graphics/C4Draw.h"
# include "graphics/C4GraphicsResource.h"
2016-04-03 18:07:56 +00:00
# include "gui/C4FileSelDlg.h"
2017-04-30 08:49:09 +00:00
# include "gui/C4GameDialogs.h"
# include "gui/C4GameOptions.h"
2016-04-03 18:07:56 +00:00
# include "gui/C4MouseControl.h"
2017-04-30 08:49:09 +00:00
# include "gui/C4StartupMainDlg.h"
# include "gui/C4StartupNetDlg.h"
# include "network/C4Network2Dialogs.h"
2009-05-08 13:28:41 +00:00
// singleton
2016-11-02 23:58:02 +00:00
C4StartupScenSelDlg * C4StartupScenSelDlg : : pInstance = nullptr ;
2009-05-08 13:28:41 +00:00
// ----------------------------------------------------------------
// Map folder data
void C4MapFolderData : : Scenario : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
pComp - > Value ( mkNamingAdapt ( sFilename , " File " , StdStrBuf ( ) ) ) ;
pComp - > Value ( mkNamingAdapt ( sBaseImage , " BaseImage " , StdStrBuf ( ) ) ) ;
pComp - > Value ( mkNamingAdapt ( sOverlayImage , " OverlayImage " , StdStrBuf ( ) ) ) ;
2009-05-08 13:28:41 +00:00
pComp - > Value ( mkNamingAdapt ( rcOverlayPos , " Area " , C4Rect ( ) ) ) ;
2010-03-28 18:58:01 +00:00
pComp - > Value ( mkNamingAdapt ( sTitle , " Title " , StdStrBuf ( ) ) ) ;
2009-05-08 13:28:41 +00:00
pComp - > Value ( mkNamingAdapt ( iTitleFontSize , " TitleFontSize " , 20 ) ) ;
pComp - > Value ( mkNamingAdapt ( dwTitleInactClr , " TitleColorInactive " , 0x7fffffffu ) ) ;
pComp - > Value ( mkNamingAdapt ( dwTitleActClr , " TitleColorActive " , 0x0fffffffu ) ) ;
pComp - > Value ( mkNamingAdapt ( iTitleOffX , " TitleOffX " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( iTitleOffY , " TitleOffY " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( byTitleAlign , " TitleAlign " , ACenter ) ) ;
pComp - > Value ( mkNamingAdapt ( fTitleBookFont , " TitleUseBookFont " , true ) ) ;
pComp - > Value ( mkNamingAdapt ( fImgDump , " ImageDump " , false ) ) ; // developer help
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4MapFolderData : : AccessGfx : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
pComp - > Value ( mkNamingAdapt ( sPassword , " Access " , StdStrBuf ( ) ) ) ;
pComp - > Value ( mkNamingAdapt ( sOverlayImage , " OverlayImage " , StdStrBuf ( ) ) ) ;
2009-05-08 13:28:41 +00:00
pComp - > Value ( mkNamingAdapt ( rcOverlayPos , " Area " , C4Rect ( ) ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4MapFolderData : : MapPic : : MapPic ( const FLOAT_RECT & rcfBounds , const C4Facet & rfct ) : C4GUI : : Picture ( C4Rect ( rcfBounds ) , false ) , rcfBounds ( rcfBounds )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// ctor
SetFacet ( rfct ) ;
SetToolTip ( LoadResStr ( " IDS_MSG_MAP_DESC " ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4MapFolderData : : MapPic : : MouseInput ( C4GUI : : CMouse & rMouse , int32_t iButton , int32_t iX , int32_t iY , DWORD dwKeyParam )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
typedef C4GUI : : Picture Parent ;
Parent : : MouseInput ( rMouse , iButton , iX , iY , dwKeyParam ) ;
// input: mouse movement or buttons - deselect everything if clicked
if ( iButton = = C4MC_Button_LeftDown & & C4StartupScenSelDlg : : pInstance )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4StartupScenSelDlg : : pInstance - > DeselectAll ( ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4MapFolderData : : MapPic : : DrawElement ( C4TargetFacet & cgo )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get drawing bounds
float x0 = rcfBounds . left + cgo . TargetX , y0 = rcfBounds . top + cgo . TargetY ;
// draw the image
GetFacet ( ) . DrawXFloat ( cgo . Surface , x0 , y0 , rcfBounds . right - rcfBounds . left , rcfBounds . bottom - rcfBounds . top ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4MapFolderData : : Clear ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
fCoordinatesAdjusted = false ;
fctBackgroundPicture . Clear ( ) ;
2016-11-02 23:58:02 +00:00
pScenarioFolder = nullptr ;
pSelectedEntry = nullptr ;
pSelectionInfoBox = nullptr ;
2009-05-08 13:28:41 +00:00
rcScenInfoArea . Set ( 0 , 0 , 0 , 0 ) ;
MinResX = MinResY = 0 ;
fUseFullscreenMap = false ;
int i ;
for ( i = 0 ; i < iScenCount ; + + i ) delete ppScenList [ i ] ;
iScenCount = 0 ;
2016-11-02 23:58:02 +00:00
delete [ ] ppScenList ; ppScenList = nullptr ;
2009-05-08 13:28:41 +00:00
for ( i = 0 ; i < iAccessGfxCount ; + + i ) delete ppAccessGfxList [ i ] ;
iAccessGfxCount = 0 ;
2016-11-02 23:58:02 +00:00
delete [ ] ppAccessGfxList ; ppAccessGfxList = nullptr ;
pMainDlg = nullptr ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4MapFolderData : : Load ( C4Group & hGroup , C4ScenarioListLoader : : Folder * pScenLoaderFolder )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// clear previous
Clear ( ) ;
// load localization info
C4LangStringTable LangTable ;
2013-10-29 20:32:21 +00:00
bool fHasLangTable = C4Language : : LoadComponentHost ( & LangTable , hGroup , C4CFN_ScriptStringTbl , Config . General . LanguageEx ) ;
2009-05-08 13:28:41 +00:00
// load core data
StdStrBuf Buf ;
2011-03-05 01:44:26 +00:00
if ( ! hGroup . LoadEntryString ( C4CFN_MapFolderData , & Buf ) ) return false ;
2009-05-08 13:28:41 +00:00
if ( fHasLangTable ) LangTable . ReplaceStrings ( Buf ) ;
if ( ! CompileFromBuf_LogWarn < StdCompilerINIRead > ( mkNamingAdapt ( * this , " FolderMap " ) , Buf , C4CFN_MapFolderData ) ) return false ;
// check resolution requirement
if ( MinResX & & MinResX > C4GUI : : GetScreenWdt ( ) ) return false ;
if ( MinResY & & MinResY > C4GUI : : GetScreenHgt ( ) ) return false ;
// load images
2015-09-19 01:10:39 +00:00
if ( ! fctBackgroundPicture . Load ( hGroup , C4CFN_MapFolderBG , C4FCT_Full , C4FCT_Full , false , 0 ) )
2010-03-28 18:58:01 +00:00
{
2017-05-03 18:28:00 +00:00
DebugLogF ( R " (C4MapFolderData::Load(%s): Could not load background graphic " % s " ) " , hGroup . GetName ( ) , C4CFN_MapFolderBG ) ;
2009-05-08 13:28:41 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
int i ;
for ( i = 0 ; i < iScenCount ; + + i )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// init scenario entry stuff
Scenario * pScen = ppScenList [ i ] ;
pScen - > pScenEntry = pScenLoaderFolder - > FindEntryByName ( pScen - > sFilename . getData ( ) ) ;
2016-11-02 23:58:02 +00:00
pScen - > pBtn = nullptr ;
2009-05-08 13:28:41 +00:00
pScen - > sTitle . Replace ( " TITLE " , pScen - > pScenEntry ? pScen - > pScenEntry - > GetName ( ) . getData ( ) : " <c ff0000>ERROR</c> " /* scenario not loaded; title cannot be referenced */ ) ;
// developer image dump
if ( pScen - > fImgDump )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4FacetSurface fctDump ; bool fSuccess = false ;
if ( fctDump . Create ( pScen - > rcOverlayPos . Wdt , pScen - > rcOverlayPos . Hgt , C4FCT_Full , C4FCT_Full ) )
2010-03-28 18:58:01 +00:00
{
2011-10-03 14:30:18 +00:00
pDraw - > Blit ( fctBackgroundPicture . Surface ,
2010-03-28 18:58:01 +00:00
( float ) pScen - > rcOverlayPos . x , ( float ) pScen - > rcOverlayPos . y ,
( float ) pScen - > rcOverlayPos . Wdt , ( float ) pScen - > rcOverlayPos . Hgt ,
fctDump . Surface ,
0 , 0 ,
fctDump . Wdt , fctDump . Hgt ) ;
2015-09-30 00:48:34 +00:00
fSuccess = fctDump . Surface - > SavePNG ( pScen - > sBaseImage . getData ( ) , true , false , false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
if ( ! fSuccess )
2017-05-03 18:28:00 +00:00
DebugLogF ( R " (C4MapFolderData::Load(%s): Could not dump graphic " % s " ) " , hGroup . GetName ( ) , pScen - > sBaseImage . getData ( ) ) ;
2009-05-08 13:28:41 +00:00
continue ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// load images
2015-09-19 01:10:39 +00:00
if ( pScen - > sBaseImage . getLength ( ) > 0 ) if ( ! pScen - > fctBase . Load ( hGroup , pScen - > sBaseImage . getData ( ) , C4FCT_Full , C4FCT_Full , false , 0 ) )
2009-05-08 13:28:41 +00:00
{
2017-05-03 18:28:00 +00:00
DebugLogF ( R " (C4MapFolderData::Load(%s): Could not load base graphic " % s " ) " , hGroup . GetName ( ) , pScen - > sBaseImage . getData ( ) ) ;
2010-03-28 18:58:01 +00:00
return false ;
2009-05-08 13:28:41 +00:00
}
2015-09-19 01:10:39 +00:00
if ( pScen - > sOverlayImage . getLength ( ) > 0 ) if ( ! pScen - > fctOverlay . Load ( hGroup , pScen - > sOverlayImage . getData ( ) , C4FCT_Full , C4FCT_Full , false , 0 ) )
2009-05-08 13:28:41 +00:00
{
2017-05-03 18:28:00 +00:00
DebugLogF ( R " (C4MapFolderData::Load(%s): Could not load graphic " % s " ) " , hGroup . GetName ( ) , pScen - > sOverlayImage . getData ( ) ) ;
2010-03-28 18:58:01 +00:00
return false ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
for ( i = 0 ; i < iAccessGfxCount ; + + i )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
AccessGfx * pGfx = ppAccessGfxList [ i ] ;
2015-09-19 01:10:39 +00:00
if ( pGfx - > sOverlayImage . getLength ( ) > 0 ) if ( ! pGfx - > fctOverlay . Load ( hGroup , pGfx - > sOverlayImage . getData ( ) , C4FCT_Full , C4FCT_Full , false , 0 ) )
2009-05-08 13:28:41 +00:00
{
2017-05-03 18:28:00 +00:00
DebugLogF ( R " (C4MapFolderData::Load(%s): Could not load graphic " % s " ) " , hGroup . GetName ( ) , pGfx - > sOverlayImage . getData ( ) ) ;
2010-03-28 18:58:01 +00:00
return false ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// all loaded
pScenarioFolder = pScenLoaderFolder ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4MapFolderData : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// core values
pComp - > Value ( mkNamingAdapt ( rcScenInfoArea , " ScenInfoArea " , C4Rect ( 0 , 0 , 0 , 0 ) ) ) ;
2010-03-28 18:58:01 +00:00
pComp - > Value ( mkNamingAdapt ( MinResX , " MinResX " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( MinResY , " MinResY " , 0 ) ) ;
2009-05-08 13:28:41 +00:00
pComp - > Value ( mkNamingAdapt ( fUseFullscreenMap , " FullscreenBG " , false ) ) ;
// compile scenario list
int32_t iOldScenCount = iScenCount ;
pComp - > Value ( mkNamingCountAdapt ( iScenCount , " Scenario " ) ) ;
2017-03-11 14:05:41 +00:00
if ( pComp - > isDeserializer ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
while ( iOldScenCount - - ) delete ppScenList [ iOldScenCount ] ;
delete [ ] ppScenList ;
if ( iScenCount )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
ppScenList = new Scenario * [ iScenCount ] ;
2011-03-12 13:59:41 +00:00
memset ( ppScenList , 0 , sizeof ( Scenario * ) * iScenCount ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2016-11-02 23:58:02 +00:00
ppScenList = nullptr ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
if ( iScenCount )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
mkPtrAdaptNoNull ( * ppScenList ) ;
pComp - > Value ( mkNamingAdapt ( mkArrayAdaptMap ( ppScenList , iScenCount , mkPtrAdaptNoNull < Scenario > ) , " Scenario " ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// compile access gfx list
int32_t iOldAccesGfxCount = iAccessGfxCount ;
pComp - > Value ( mkNamingCountAdapt ( iAccessGfxCount , " AccessGfx " ) ) ;
2017-03-11 14:05:41 +00:00
if ( pComp - > isDeserializer ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
while ( iOldAccesGfxCount - - ) delete ppAccessGfxList [ iOldAccesGfxCount ] ;
delete [ ] ppAccessGfxList ;
if ( iAccessGfxCount )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
ppAccessGfxList = new AccessGfx * [ iAccessGfxCount ] ;
2011-03-12 13:59:41 +00:00
memset ( ppAccessGfxList , 0 , sizeof ( AccessGfx * ) * iAccessGfxCount ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2016-11-02 23:58:02 +00:00
ppAccessGfxList = nullptr ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
if ( iAccessGfxCount )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
mkPtrAdaptNoNull ( * ppAccessGfxList ) ;
pComp - > Value ( mkNamingAdapt ( mkArrayAdaptMap ( ppAccessGfxList , iAccessGfxCount , mkPtrAdaptNoNull < AccessGfx > ) , " AccessGfx " ) ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4MapFolderData : : ConvertFacet2ScreenCoord ( const C4Rect & rc , FLOAT_RECT * pfrc , float fBGZoomX , float fBGZoomY , int iOffX , int iOffY )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pfrc - > left = ( fBGZoomX * rc . x ) + iOffX ;
pfrc - > top = ( fBGZoomY * rc . y ) + iOffY ;
pfrc - > right = pfrc - > left + ( fBGZoomX * rc . Wdt ) ;
pfrc - > bottom = pfrc - > top + ( fBGZoomY * rc . Hgt ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4MapFolderData : : ConvertFacet2ScreenCoord ( int32_t * piValue , float fBGZoom , int iOff )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
* piValue = int32_t ( floorf ( fBGZoom * * piValue + 0.5f ) ) + iOff ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4MapFolderData : : ConvertFacet2ScreenCoord ( C4Rect & rcMapArea , bool fAspect )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ! fctBackgroundPicture . Wdt | | ! fctBackgroundPicture . Hgt ) return ; // invalid BG - should not happen
// get zoom of background image
float fBGZoomX = 1.0f , fBGZoomY = 1.0f ; int iOffX = 0 , iOffY = 0 ;
if ( fAspect )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( fctBackgroundPicture . Wdt * rcMapArea . Hgt > rcMapArea . Wdt * fctBackgroundPicture . Hgt )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// background image is limited by width
fBGZoomX = fBGZoomY = ( float ) rcMapArea . Wdt / fctBackgroundPicture . Wdt ;
2015-11-15 12:53:01 +00:00
iOffY = std : : max < int > ( 0 , ( int ) ( rcMapArea . Hgt - ( fBGZoomX * fctBackgroundPicture . Hgt ) ) ) / 2 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// background image is limited by height
fBGZoomX = fBGZoomY = ( float ) rcMapArea . Hgt / fctBackgroundPicture . Hgt ;
2015-11-15 12:53:01 +00:00
iOffX = std : : max < int > ( 0 , ( int ) ( rcMapArea . Wdt - ( fBGZoomY * fctBackgroundPicture . Wdt ) ) ) / 2 ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// do not keep aspect: Independant X and Y zoom
fBGZoomX = ( float ) rcMapArea . Wdt / fctBackgroundPicture . Wdt ; ;
fBGZoomY = ( float ) rcMapArea . Hgt / fctBackgroundPicture . Hgt ; ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
iOffX - = rcMapArea . x ; iOffY - = rcMapArea . y ;
C4Rect rcBG ; rcBG . Set ( 0 , 0 , fctBackgroundPicture . Wdt , fctBackgroundPicture . Hgt ) ;
ConvertFacet2ScreenCoord ( rcBG , & rcfBG , fBGZoomX , fBGZoomY , iOffX , iOffY ) ;
// default for scenario info area: 1/3rd of right area
if ( ! rcScenInfoArea . Wdt )
rcScenInfoArea . Set ( ( int32_t ) ( fctBackgroundPicture . Wdt * 2 / 3 ) , ( int32_t ) ( fctBackgroundPicture . Hgt / 16 ) , ( int32_t ) ( fctBackgroundPicture . Wdt / 3 ) , ( int32_t ) ( fctBackgroundPicture . Hgt * 7 / 8 ) ) ;
// assume all facet coordinates are referring to background image zoom; convert them to screen coordinates by applying zoom and offset
FLOAT_RECT rcfScenInfoArea ;
ConvertFacet2ScreenCoord ( rcScenInfoArea , & rcfScenInfoArea , fBGZoomX , fBGZoomY , iOffX , iOffY ) ;
rcScenInfoArea . x = ( int32_t ) rcfScenInfoArea . left ; rcScenInfoArea . y = ( int32_t ) rcfScenInfoArea . top ;
rcScenInfoArea . Wdt = ( int32_t ) ( rcfScenInfoArea . right - rcfScenInfoArea . left ) ;
rcScenInfoArea . Hgt = ( int32_t ) ( rcfScenInfoArea . bottom - rcfScenInfoArea . top ) ;
int i ;
for ( i = 0 ; i < iScenCount ; + + i )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Scenario * pScen = ppScenList [ i ] ;
ConvertFacet2ScreenCoord ( pScen - > rcOverlayPos , & ( pScen - > rcfOverlayPos ) , fBGZoomX , fBGZoomY , iOffX , iOffY ) ;
// title sizes
ConvertFacet2ScreenCoord ( & ( pScen - > iTitleFontSize ) , fBGZoomY , 0 ) ;
// title position: Relative to title rect; so do not add offset here
ConvertFacet2ScreenCoord ( & ( pScen - > iTitleOffX ) , fBGZoomX , 0 ) ;
ConvertFacet2ScreenCoord ( & ( pScen - > iTitleOffY ) , fBGZoomY , 0 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
for ( i = 0 ; i < iAccessGfxCount ; + + i ) ConvertFacet2ScreenCoord ( ppAccessGfxList [ i ] - > rcOverlayPos , & ( ppAccessGfxList [ i ] - > rcfOverlayPos ) , fBGZoomX , fBGZoomY , iOffX , iOffY ) ;
// done
fCoordinatesAdjusted = true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4MapFolderData : : CreateGUIElements ( C4StartupScenSelDlg * pMainDlg , C4GUI : : Window & rContainer )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
this - > pMainDlg = pMainDlg ;
// convert all coordinates to match the container sizes
// do this only once; assume container won't change between loads
if ( ! fCoordinatesAdjusted )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ! fUseFullscreenMap )
ConvertFacet2ScreenCoord ( rContainer . GetClientRect ( ) , true ) ;
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Rect rcMapRect = pMainDlg - > GetBounds ( ) ;
rContainer . ClientPos2ScreenPos ( rcMapRect . x , rcMapRect . y ) ;
ConvertFacet2ScreenCoord ( rcMapRect , false ) ;
2010-01-25 04:00:59 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// empty any previous stuff in container
while ( rContainer . GetFirst ( ) ) delete rContainer . GetFirst ( ) ;
// create background image
if ( ! fUseFullscreenMap )
rContainer . AddElement ( new MapPic ( rcfBG , fctBackgroundPicture ) ) ;
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pMainDlg - > SetBackground ( & fctBackgroundPicture ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// create mission access overlays
int i ;
for ( i = 0 ; i < iAccessGfxCount ; + + i )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
AccessGfx * pGfx = ppAccessGfxList [ i ] ;
const char * szPassword = pGfx - > sPassword . getData ( ) ;
if ( ! szPassword | | ! * szPassword | | SIsModule ( Config . General . MissionAccess , szPassword ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// ACCESS TO GFX GRANTED: draw it
rContainer . AddElement ( new MapPic ( pGfx - > rcfOverlayPos , pGfx - > fctOverlay ) ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// create buttons for scenarios
2016-11-02 23:58:02 +00:00
C4GUI : : Button * pBtnFirst = nullptr ;
2009-05-08 13:28:41 +00:00
for ( i = 0 ; i < iScenCount ; + + i )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Scenario * pScen = ppScenList [ i ] ;
if ( pScen - > pScenEntry & & ! pScen - > pScenEntry - > HasMissionAccess ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// no access to this scenario: Do not create a button at all; not even base image. The scenario is "invisible".
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4GUI : : CallbackButtonEx < C4StartupScenSelDlg , C4GUI : : FacetButton > * pBtn = new C4GUI : : CallbackButtonEx < C4StartupScenSelDlg , C4GUI : : FacetButton >
2010-03-28 18:58:01 +00:00
( pScen - > fctBase , pScen - > fctOverlay , pScen - > rcfOverlayPos , 0 , pMainDlg , & C4StartupScenSelDlg : : OnButtonScenario ) ;
2009-05-08 13:28:41 +00:00
ppScenList [ i ] - > pBtn = pBtn ;
if ( pScen - > pScenEntry )
pBtn - > SetToolTip ( FormatString ( LoadResStr ( " IDS_MSG_MAP_STARTSCEN " ) , pScen - > pScenEntry - > GetName ( ) . getData ( ) ) . getData ( ) ) ;
if ( pScen - > sTitle . getLength ( ) > 0 )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pBtn - > SetText ( pScen - > sTitle . getData ( ) ) ;
2009-08-23 21:46:56 +00:00
pBtn - > SetTextColors ( pScen - > dwTitleInactClr , pScen - > dwTitleActClr ) ;
2009-05-08 13:28:41 +00:00
pBtn - > SetTextPos ( pScen - > iTitleOffX , pScen - > iTitleOffY , pScen - > byTitleAlign ) ;
CStdFont * pUseFont ; float fFontZoom = 1.0f ;
if ( pScen - > fTitleBookFont )
pUseFont = & ( C4Startup : : Get ( ) - > Graphics . GetBlackFontByHeight ( pScen - > iTitleFontSize , & fFontZoom ) ) ;
else
2010-06-27 00:42:48 +00:00
pUseFont = & ( : : GraphicsResource . GetFontByHeight ( pScen - > iTitleFontSize , & fFontZoom ) ) ;
2009-05-08 13:28:41 +00:00
if ( Inside < float > ( fFontZoom , 0.8f , 1.25f ) ) fFontZoom = 1.0f ; // some tolerance for font zoom
pBtn - > SetTextFont ( pUseFont , fFontZoom ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
rContainer . AddElement ( pBtn ) ;
if ( ! pBtnFirst ) pBtnFirst = pBtn ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// create scenario info listbox
pSelectionInfoBox = new C4GUI : : TextWindow ( rcScenInfoArea ,
2010-03-28 18:58:01 +00:00
C4StartupScenSel_TitlePictureWdt + 2 * C4StartupScenSel_TitleOverlayMargin , C4StartupScenSel_TitlePictureHgt + 2 * C4StartupScenSel_TitleOverlayMargin ,
2016-11-02 23:58:02 +00:00
C4StartupScenSel_TitlePicturePadding , 100 , 4096 , nullptr , true , & C4Startup : : Get ( ) - > Graphics . fctScenSelTitleOverlay , C4StartupScenSel_TitleOverlayMargin ) ;
2009-05-08 13:28:41 +00:00
pSelectionInfoBox - > SetDecoration ( false , false , & C4Startup : : Get ( ) - > Graphics . sfctBookScroll , true ) ;
rContainer . AddElement ( pSelectionInfoBox ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4MapFolderData : : OnButtonScenario ( C4GUI : : Control * pEl )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get associated scenario entry
int i ;
for ( i = 0 ; i < iScenCount ; + + i )
if ( pEl = = ppScenList [ i ] - > pBtn )
break ;
if ( i = = iScenCount ) return ;
// select the associated entry
pSelectedEntry = ppScenList [ i ] - > pScenEntry ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4MapFolderData : : ResetSelection ( )
2010-03-28 18:58:01 +00:00
{
2016-11-02 23:58:02 +00:00
pSelectedEntry = nullptr ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// ----------------------------------------------------------------
// Scenario list loader
// ------------------------------------
// Entry
2016-11-02 23:58:02 +00:00
C4ScenarioListLoader : : Entry : : Entry ( class C4ScenarioListLoader * pLoader , Folder * pParent ) : pLoader ( pLoader ) , pNext ( nullptr ) , pParent ( pParent ) , fBaseLoaded ( false ) , fExLoaded ( false )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// ctor: Put into parent tree node
if ( pParent )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pNext = pParent - > pFirst ;
pParent - > pFirst = this ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
iIconIndex = - 1 ;
iDifficulty = 0 ;
iFolderIndex = 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4ScenarioListLoader : : Entry : : ~ Entry ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// dtor: unlink from parent list (MUST be in there)
if ( pParent )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Entry * * ppCheck = & ( pParent - > pFirst ) ;
while ( * ppCheck ! = this )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
ppCheck = & ( * ppCheck ) - > pNext ;
}
2010-03-28 18:58:01 +00:00
* ppCheck = pNext ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : Entry : : Load ( C4Group * pFromGrp , const StdStrBuf * psFilename , bool fLoadEx )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// nothing to do if already loaded
if ( fBaseLoaded & & ( fExLoaded | | ! fLoadEx ) ) return true ;
C4Group Group ;
// group specified: Load as child
if ( pFromGrp )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
assert ( psFilename ) ;
if ( ! Group . OpenAsChild ( pFromGrp , psFilename - > getData ( ) ) ) return false ;
// set FN by complete entry name
this - > sFilename . Take ( Group . GetFullName ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// set FN by complete entry name
if ( psFilename ) this - > sFilename . Copy ( * psFilename ) ;
// no parent group: Direct load from filename
if ( ! Group . Open ( sFilename . getData ( ) ) ) return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// okay; load standard stuff from group
bool fNameLoaded = false , fIconLoaded = false ;
if ( fBaseLoaded )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
fNameLoaded = fIconLoaded = true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Set default name as filename without extension
sName . Copy ( GetFilename ( sFilename . getData ( ) ) ) ;
char * szBuf = sName . GrabPointer ( ) ;
RemoveExtension ( szBuf ) ;
sName . Take ( szBuf ) ;
// load entry specific stuff that's in the front of the group
if ( ! LoadCustomPre ( Group ) )
return false ;
// Load entry name
C4ComponentHost DefNames ;
2013-10-29 20:32:21 +00:00
if ( C4Language : : LoadComponentHost ( & DefNames , Group , C4CFN_Title , Config . General . LanguageEx ) )
2009-05-08 13:28:41 +00:00
if ( DefNames . GetLanguageString ( Config . General . LanguageEx , sName ) )
fNameLoaded = true ;
// load entry icon
2015-09-19 01:10:39 +00:00
if ( Group . FindEntry ( C4CFN_IconPNG ) & & fctIcon . Load ( Group , C4CFN_IconPNG , C4FCT_Full , C4FCT_Full , false , 0 ) )
2009-05-08 13:28:41 +00:00
fIconLoaded = true ;
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4FacetSurface fctTemp ;
2015-09-19 01:10:39 +00:00
if ( Group . FindEntry ( C4CFN_ScenarioIcon ) & & fctTemp . Load ( Group , C4CFN_ScenarioIcon , C4FCT_Full , C4FCT_Full , true , 0 ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// old style icon: Blit it on a pieace of paper
fctTemp . Surface - > Lock ( ) ;
for ( int y = 0 ; y < fctTemp . Hgt ; + + y )
for ( int x = 0 ; x < fctTemp . Wdt ; + + x )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
uint32_t dwPix = fctTemp . Surface - > GetPixDw ( x , y , false ) ;
// transparency has some tolerance...
if ( Inside < uint8_t > ( dwPix & 0xff , 0xb8 , 0xff ) )
if ( Inside < uint8_t > ( ( dwPix > > 0x08 ) & 0xff , 0x00 , 0x0f ) )
if ( Inside < uint8_t > ( ( dwPix > > 0x10 ) & 0xff , 0xb8 , 0xff ) )
2009-08-23 21:46:56 +00:00
fctTemp . Surface - > SetPixDw ( x , y , 0x00ffffff ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
fctTemp . Surface - > Unlock ( ) ;
int iIconSize = C4Startup : : Get ( ) - > Graphics . fctScenSelIcons . Hgt ;
fctIcon . Create ( iIconSize , iIconSize , C4FCT_Full , C4FCT_Full ) ;
C4Startup : : Get ( ) - > Graphics . fctScenSelIcons . GetPhase ( C4StartupScenSel_DefaultIcon_OldIconBG ) . Draw ( fctIcon ) ;
fctTemp . Draw ( fctIcon . Surface , ( fctIcon . Wdt - fctTemp . Wdt ) / 2 , ( fctIcon . Hgt - fctTemp . Hgt ) / 2 ) ;
fctTemp . Clear ( ) ;
fIconLoaded = true ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// load any entryx-type-specific custom data (e.g. fallbacks for scenario title, and icon)
if ( ! LoadCustom ( Group , fNameLoaded , fIconLoaded ) ) return false ;
fBaseLoaded = true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// load extended stuff: title picture
if ( fLoadEx & & ! fExLoaded )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// load desc
C4ComponentHost DefDesc ;
2013-10-29 20:32:21 +00:00
if ( C4Language : : LoadComponentHost ( & DefDesc , Group , C4CFN_ScenarioDesc , Config . General . LanguageEx ) )
2010-03-28 18:58:01 +00:00
{
2015-12-29 16:51:43 +00:00
sDesc . Copy ( DefDesc . GetData ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// load title
2013-05-25 18:47:17 +00:00
fctTitle . Load ( Group , C4CFN_ScenarioTitle , C4FCT_Full , C4FCT_Full , false , true ) ;
2009-05-08 13:28:41 +00:00
fExLoaded = true ;
// load version
2011-03-05 01:44:26 +00:00
Group . LoadEntryString ( C4CFN_Version , & sVersion ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// done, success
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-03-13 15:38:33 +00:00
// helper func: Recursive check whether a directory contains a .ocs or .ocf file
2009-05-08 13:28:41 +00:00
bool DirContainsScenarios ( const char * szDir )
2010-03-28 18:58:01 +00:00
{
2017-07-12 03:45:57 +00:00
// Ignore object and group folders to avoid descending e.g. deep into unpacked Objects.ocd
if ( WildcardMatch ( C4CFN_DefFiles , szDir ) | | WildcardMatch ( C4CFN_GenericGroupFiles , szDir ) )
{
return false ;
}
2009-05-08 13:28:41 +00:00
// create iterator on free store to avoid stack overflow with deeply recursed folders
DirectoryIterator * pIter = new DirectoryIterator ( szDir ) ;
const char * szChildFilename ;
2010-01-25 04:00:59 +00:00
for ( ; ( szChildFilename = * * pIter ) ; + + * pIter )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Ignore directory navigation entries and CVS folders
2010-04-15 20:24:34 +00:00
if ( C4Group_TestIgnore ( szChildFilename ) ) continue ;
2009-05-08 13:28:41 +00:00
if ( WildcardMatch ( C4CFN_ScenarioFiles , szChildFilename ) | | WildcardMatch ( C4CFN_FolderFiles , szChildFilename ) ) break ;
if ( DirectoryExists ( szChildFilename ) )
if ( DirContainsScenarios ( szChildFilename ) )
break ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
delete pIter ;
// return true if loop was broken, in which case a matching entry was found
return ! ! szChildFilename ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2014-09-24 21:08:40 +00:00
C4ScenarioListLoader : : Entry * C4ScenarioListLoader : : Entry : : CreateEntryForFile ( const StdStrBuf & sFilename , C4ScenarioListLoader * pLoader , Folder * pParent )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// determine entry type by file type
const char * szFilename = sFilename . getData ( ) ;
2016-11-02 23:58:02 +00:00
if ( ! szFilename | | ! * szFilename ) return nullptr ;
2014-09-24 21:08:40 +00:00
if ( WildcardMatch ( C4CFN_ScenarioFiles , sFilename . getData ( ) ) ) return new Scenario ( pLoader , pParent ) ;
if ( WildcardMatch ( C4CFN_FolderFiles , sFilename . getData ( ) ) ) return new SubFolder ( pLoader , pParent ) ;
2009-05-08 13:28:41 +00:00
// regular, open folder (C4Group-packed folders without extensions are not regarded, because they could contain anything!)
const char * szExt = GetExtension ( szFilename ) ;
if ( ( ! szExt | | ! * szExt ) & & DirectoryExists ( sFilename . getData ( ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// open folders only if they contain a scenario or folder
if ( DirContainsScenarios ( szFilename ) )
2014-09-24 21:08:40 +00:00
return new RegularFolder ( pLoader , pParent ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// type not recognized
2016-11-02 23:58:02 +00:00
return nullptr ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : Entry : : RenameTo ( const char * szNewName )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// change name+filename
// some name sanity validation
if ( ! szNewName | | ! * szNewName ) return false ;
if ( SEqual ( szNewName , sName . getData ( ) ) ) return true ;
char fn [ _MAX_PATH + 1 ] ;
SCopy ( szNewName , fn , _MAX_PATH ) ;
// generate new file name
MakeFilenameFromTitle ( fn ) ;
if ( ! * fn ) return false ;
const char * szExt = GetDefaultExtension ( ) ;
if ( szExt ) { SAppend ( " . " , fn , _MAX_PATH ) ; SAppend ( szExt , fn , _MAX_PATH ) ; }
char fullfn [ _MAX_PATH + 1 ] ;
SCopy ( sFilename . getData ( ) , fullfn , _MAX_PATH ) ;
char * fullfn_fn = GetFilename ( fullfn ) ;
SCopy ( fn , fullfn_fn , _MAX_PATH - ( fullfn_fn - fullfn ) ) ;
2010-03-28 18:58:01 +00:00
StdCopyStrBuf strErr ( LoadResStr ( " IDS_FAIL_RENAME " ) ) ;
2009-05-08 13:28:41 +00:00
// check if a rename is due
if ( ! ItemIdentical ( sFilename . getData ( ) , fullfn ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// check for duplicate filename
if ( ItemExists ( fullfn ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
StdStrBuf sMsg ; sMsg . Format ( LoadResStr ( " IDS_ERR_FILEEXISTS " ) , fullfn ) ;
2009-06-05 16:53:56 +00:00
: : pGUI - > ShowMessageModal ( sMsg . getData ( ) , strErr . getData ( ) , C4GUI : : MessageDialog : : btnOK , C4GUI : : Ico_Error ) ;
2009-05-08 13:28:41 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// OK; then rename
if ( ! C4Group_MoveItem ( sFilename . getData ( ) , fullfn , true ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
StdStrBuf sMsg ; sMsg . Format ( LoadResStr ( " IDS_ERR_RENAMEFILE " ) , sFilename . getData ( ) , fullfn ) ;
2009-06-05 16:53:56 +00:00
: : pGUI - > ShowMessageModal ( sMsg . getData ( ) , strErr . getData ( ) , C4GUI : : MessageDialog : : btnOK , C4GUI : : Ico_Error ) ;
2009-05-08 13:28:41 +00:00
return false ;
}
2010-03-28 18:58:01 +00:00
sFilename . Copy ( fullfn ) ;
}
2009-05-08 13:28:41 +00:00
// update real name in group, if this is a group
if ( C4Group_IsGroup ( fullfn ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Group Grp ;
if ( ! Grp . Open ( fullfn ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
StdStrBuf sMsg ; sMsg . Format ( LoadResStr ( " IDS_ERR_OPENFILE " ) , sFilename . getData ( ) , Grp . GetError ( ) ) ;
2009-06-05 16:53:56 +00:00
: : pGUI - > ShowMessageModal ( sMsg . getData ( ) , strErr . getData ( ) , C4GUI : : MessageDialog : : btnOK , C4GUI : : Ico_Error ) ;
2009-05-08 13:28:41 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
if ( ! Grp . Delete ( C4CFN_Title ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
StdStrBuf sMsg ; sMsg . Format ( LoadResStr ( " IDS_ERR_DELOLDTITLE " ) , sFilename . getData ( ) , Grp . GetError ( ) ) ;
2009-06-05 16:53:56 +00:00
: : pGUI - > ShowMessageModal ( sMsg . getData ( ) , strErr . getData ( ) , C4GUI : : MessageDialog : : btnOK , C4GUI : : Ico_Error ) ;
2009-05-08 13:28:41 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
if ( ! SetTitleInGroup ( Grp , szNewName ) ) return false ;
if ( ! Grp . Close ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
StdStrBuf sMsg ; sMsg . Format ( LoadResStr ( " IDS_ERR_WRITENEWTITLE " ) , sFilename . getData ( ) , Grp . GetError ( ) ) ;
2009-06-05 16:53:56 +00:00
: : pGUI - > ShowMessageModal ( sMsg . getData ( ) , strErr . getData ( ) , C4GUI : : MessageDialog : : btnOK , C4GUI : : Ico_Error ) ;
2009-05-08 13:28:41 +00:00
return false ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// update title
sName . Copy ( szNewName ) ;
// done
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : Entry : : SetTitleInGroup ( C4Group & rGrp , const char * szNewTitle )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// default for group files: Create a title text file and set the title in there
// no title needed if filename is sufficient - except for scenarios, where a Scenario.txt could overwrite the title
if ( ! IsScenario ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
StdStrBuf sNameByFile ; sNameByFile . Copy ( GetFilename ( sFilename . getData ( ) ) ) ;
char * szBuf = sNameByFile . GrabPointer ( ) ;
RemoveExtension ( szBuf ) ;
sNameByFile . Take ( szBuf ) ;
if ( SEqual ( szNewTitle , sNameByFile . getData ( ) ) ) return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// okay, make a title
StdStrBuf sTitle ; sTitle . Format ( " %s:%s " , Config . General . Language , szNewTitle ) ;
2009-08-15 18:50:32 +00:00
if ( ! rGrp . Add ( C4CFN_WriteTitle , sTitle , false , true ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
StdStrBuf sMsg ; sMsg . Format ( LoadResStr ( " IDS_ERR_ERRORADDINGNEWTITLEFORFIL " ) , sFilename . getData ( ) , rGrp . GetError ( ) ) ;
2009-06-05 16:53:56 +00:00
: : pGUI - > ShowMessageModal ( sMsg . getData ( ) , LoadResStr ( " IDS_FAIL_RENAME " ) , C4GUI : : MessageDialog : : btnOK , C4GUI : : Ico_Error ) ;
2009-05-08 13:28:41 +00:00
return false ;
}
2010-03-28 18:58:01 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
// ------------------------------------
// Scenario
bool C4ScenarioListLoader : : Scenario : : LoadCustomPre ( C4Group & rGrp )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// load scenario core first
StdStrBuf sFileContents ;
2011-03-05 01:44:26 +00:00
if ( ! rGrp . LoadEntryString ( C4CFN_ScenarioCore , & sFileContents ) ) return false ;
2010-03-28 18:58:01 +00:00
if ( ! CompileFromBuf_LogWarn < StdCompilerINIRead > ( mkParAdapt ( C4S , false ) , sFileContents , ( rGrp . GetFullName ( ) + DirSep C4CFN_ScenarioCore ) . getData ( ) ) )
2009-05-08 13:28:41 +00:00
return false ;
2015-09-25 03:51:16 +00:00
// Mission access
2017-03-23 15:28:28 +00:00
fNoMissionAccess = ( ! C4S . Head . MissionAccess . empty ( ) & & ! SIsModule ( Config . General . MissionAccess , C4S . Head . MissionAccess . c_str ( ) ) ) ;
2014-09-27 14:04:48 +00:00
// Localized parameter definitions. needed for achievements and parameter input boxes.
// Only show them for "real" scenarios
if ( ! C4S . Head . SaveGame & & ! C4S . Head . Replay )
{
2015-09-11 02:32:51 +00:00
// Skipping ahead in regular reading list, so keep other entries in memory
rGrp . PreCacheEntries ( C4CFN_AnyScriptStringTbl , true ) ;
rGrp . PreCacheEntries ( C4CFN_ScenarioParameterDefs , true ) ;
2014-09-27 14:04:48 +00:00
C4LangStringTable ScenarioLangStringTable ;
C4Language : : LoadComponentHost ( & ScenarioLangStringTable , rGrp , C4CFN_ScriptStringTbl , Config . General . LanguageEx ) ;
ParameterDefs . Load ( rGrp , & ScenarioLangStringTable ) ;
2014-10-03 10:06:08 +00:00
// achievement images: Loaded from this entry and parent folder
nAchievements = 0 ;
2016-11-02 23:58:02 +00:00
const C4ScenarioParameterDefs * deflists [ ] = { pParent ? pParent - > GetAchievementDefs ( ) : nullptr , & ParameterDefs } ;
2017-05-03 18:28:00 +00:00
for ( auto deflist : deflists )
2014-10-03 10:06:08 +00:00
{
if ( ! deflist ) continue ;
const C4ScenarioParameterDef * def ; size_t idx = 0 ;
2015-08-29 12:33:00 +00:00
while ( ( def = deflist - > GetParameterDefByIndex ( idx + + ) ) )
2014-09-24 21:08:40 +00:00
{
2014-10-03 10:06:08 +00:00
if ( def - > IsAchievement ( ) )
2014-09-24 21:08:40 +00:00
{
2014-10-03 10:06:08 +00:00
int32_t val = pLoader - > GetAchievements ( ) . GetValueByID ( C4ScenarioParameters : : AddFilename2ID ( rGrp . GetFullName ( ) . getData ( ) , def - > GetID ( ) ) . getData ( ) , def - > GetDefault ( ) ) ;
if ( val )
2014-09-27 14:04:48 +00:00
{
2014-10-03 10:06:08 +00:00
// player has this achievement - find graphics for it
const char * achievement_gfx = def - > GetAchievement ( ) ;
StdStrBuf sAchievementFilename ( C4CFN_Achievements ) ;
sAchievementFilename . Replace ( " * " , achievement_gfx ) ;
// look in scenario
2014-10-03 18:58:49 +00:00
if ( ! fctAchievements [ nAchievements ] . Load ( rGrp , sAchievementFilename . getData ( ) , C4FCT_Height , C4FCT_Full , false , true ) )
2014-10-03 10:06:08 +00:00
{
// look in parent folder
2016-11-02 23:58:02 +00:00
const C4FacetSurface * fct = nullptr ;
2014-10-03 10:06:08 +00:00
const C4AchievementGraphics * parent_achv_gfx ;
if ( pParent & & ( parent_achv_gfx = pParent - > GetAchievementGfx ( ) ) ) fct = parent_achv_gfx - > FindByName ( achievement_gfx ) ;
// look in main gfx group file
if ( ! fct ) fct = : : GraphicsResource . Achievements . FindByName ( achievement_gfx ) ;
if ( ! fct ) continue ; // achievement graphics not found :(
fctAchievements [ nAchievements ] . Set ( ( const C4Facet & ) * fct ) ;
}
// section by achievement index (1-based, since zero means no achievement)
if ( val > 1 ) fctAchievements [ nAchievements ] . X + = fctAchievements [ nAchievements ] . Wdt * ( val - 1 ) ;
// description for this achievement is taken from option
const C4ScenarioParameterDef : : Option * opt = def - > GetOptionByValue ( val ) ;
if ( opt ) sAchievementDescriptions [ nAchievements ] = opt - > Description ;
// keep track of achievement count
+ + nAchievements ;
if ( nAchievements = = C4StartupScenSel_MaxAchievements ) break ;
2014-09-27 14:04:48 +00:00
}
2014-09-24 21:08:40 +00:00
}
}
2014-10-03 10:06:08 +00:00
}
2014-09-27 14:04:48 +00:00
}
2009-05-08 13:28:41 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : Scenario : : LoadCustom ( C4Group & rGrp , bool fNameLoaded , bool fIconLoaded )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// icon fallback: Standard scenario icon
if ( ! fIconLoaded )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
iIconIndex = C4S . Head . Icon ;
fctIcon . Set ( C4Startup : : Get ( ) - > Graphics . fctScenSelIcons . GetSection ( C4S . Head . Icon ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// scenario name fallback to core
if ( ! fNameLoaded )
2017-03-23 15:28:28 +00:00
sName = C4S . Head . Title ;
2009-05-08 13:28:41 +00:00
// difficulty: Set only for regular rounds (not savegame or record) to avoid bogus sorting
if ( ! C4S . Head . SaveGame & & ! C4S . Head . Replay )
iDifficulty = C4S . Head . Difficulty ;
else
iDifficulty = 0 ;
// minimum required player count
iMinPlrCount = C4S . GetMinPlayer ( ) ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2014-09-24 21:08:40 +00:00
bool C4ScenarioListLoader : : Scenario : : GetAchievement ( int32_t idx , C4Facet * out_facet , const char * * out_description )
{
// return true and fill output parameters if player got the indexed achievement
if ( idx < 0 | | idx > = nAchievements ) return false ;
* out_facet = fctAchievements [ idx ] ;
* out_description = sAchievementDescriptions [ idx ] . getData ( ) ;
return true ;
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : Scenario : : Start ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// gogo!
if ( ! ( C4StartupScenSelDlg : : pInstance ) ) return false ;
return ( C4StartupScenSelDlg : : pInstance ) - > StartScenario ( this ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2017-12-28 20:45:20 +00:00
bool C4ScenarioListLoader : : Scenario : : CanOpen ( StdStrBuf & sErrOut , bool & CanHide )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
C4StartupScenSelDlg * pDlg = C4StartupScenSelDlg : : pInstance ;
if ( ! pDlg ) return false ;
// check mission access
2015-09-25 03:51:16 +00:00
if ( ! HasMissionAccess ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
sErrOut . Copy ( LoadResStr ( " IDS_PRC_NOMISSIONACCESS " ) ) ;
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// replay
if ( C4S . Head . Replay )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// replays can currently not be launched in network mode
if ( pDlg - > IsNetworkStart ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
sErrOut . Copy ( LoadResStr ( " IDS_PRC_NONETREPLAY " ) ) ;
return false ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// regular game
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// check player count
int32_t iPlrCount = SModuleCount ( Config . General . Participants ) ;
int32_t iMaxPlrCount = C4S . Head . MaxPlayer ;
if ( C4S . Head . SaveGame )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Some scenarios have adjusted MaxPlayerCount to 0 after starting to prevent future joins
// make sure it's possible to start the savegame anyway
2015-11-15 12:53:01 +00:00
iMaxPlrCount = std : : max < int32_t > ( iMinPlrCount , iMaxPlrCount ) ;
2017-12-28 20:45:20 +00:00
// <Sven2> Savegames store a lot of internal stuff. If you updated clonk in the meantime, many things tend to break
if ( C4S . Head . C4XVer [ 0 ] ! = C4XVER1 | | C4S . Head . C4XVer [ 1 ] ! = C4XVER2 )
{
// Only show a warning to let players try it anyways.
sErrOut . Format ( LoadResStr ( " IDS_MSG_SAVEGAMEVERSIONMISMATCH " ) , C4S . Head . C4XVer [ 0 ] , C4S . Head . C4XVer [ 1 ] ) ;
CanHide = false ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// normal scenarios: At least one player except in network mode, where it is possible to wait for the additional players
// Melees need at least two
if ( ( iPlrCount < iMinPlrCount ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pDlg - > IsNetworkStart ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// network game: Players may yet join in lobby
// only issue a warning for too few players (by setting the error but not returning false here)
sErrOut . Format ( LoadResStr ( " IDS_MSG_TOOFEWPLAYERSNET " ) , ( int ) iMinPlrCount ) ;
2017-12-28 20:45:20 +00:00
CanHide = true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// for regular games, this is a fatal no-start-cause
sErrOut . Format ( LoadResStr ( " IDS_MSG_TOOFEWPLAYERS " ) , ( int ) iMinPlrCount ) ;
return false ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// scenarios (both normal and savegame) may also impose a maximum player restriction
if ( iPlrCount > iMaxPlrCount )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
sErrOut . Format ( LoadResStr ( " IDS_MSG_TOOMANYPLAYERS " ) , ( int ) C4S . Head . MaxPlayer ) ;
return false ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Okay, start!
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
StdStrBuf C4ScenarioListLoader : : Scenario : : GetOpenText ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
return StdCopyStrBuf ( LoadResStr ( " IDS_BTN_STARTGAME " ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
StdStrBuf C4ScenarioListLoader : : Scenario : : GetOpenTooltip ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
return StdCopyStrBuf ( LoadResStr ( " IDS_DLGTIP_SCENSELNEXT " ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// ------------------------------------
// Folder
C4ScenarioListLoader : : Folder : : ~ Folder ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pMapData ) delete pMapData ;
ClearChildren ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : Folder : : Start ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// open as subfolder
if ( ! C4StartupScenSelDlg : : pInstance ) return false ;
return C4StartupScenSelDlg : : pInstance - > OpenFolder ( this ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
int
# ifdef _MSC_VER
__cdecl
# endif
EntrySortFunc ( const void * pEl1 , const void * pEl2 )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4ScenarioListLoader : : Entry * pEntry1 = * ( C4ScenarioListLoader : : Entry * const * ) pEl1 , * pEntry2 = * ( C4ScenarioListLoader : : Entry * const * ) pEl2 ;
// sort folders before scenarios
2010-01-25 04:00:59 +00:00
bool fS1 = ! pEntry1 - > GetIsFolder ( ) , fS2 = ! pEntry2 - > GetIsFolder ( ) ;
if ( fS1 ! = fS2 ) return fS1 - fS2 ;
2009-05-08 13:28:41 +00:00
// sort by folder index (undefined index 0 goes to the end)
if ( ! Config . Startup . AlphabeticalSorting ) if ( pEntry1 - > GetFolderIndex ( ) | | pEntry2 - > GetFolderIndex ( ) )
2010-03-28 18:58:01 +00:00
{
if ( ! pEntry1 - > GetFolderIndex ( ) ) return + 1 ;
if ( ! pEntry2 - > GetFolderIndex ( ) ) return - 1 ;
int32_t iDiff = pEntry1 - > GetFolderIndex ( ) - pEntry2 - > GetFolderIndex ( ) ;
if ( iDiff ) return iDiff ;
}
2009-05-08 13:28:41 +00:00
// sort by numbered standard scenario icons
if ( Inside ( pEntry1 - > GetIconIndex ( ) , 2 , 11 ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t iDiff = pEntry1 - > GetIconIndex ( ) - pEntry2 - > GetIconIndex ( ) ;
if ( iDiff ) return iDiff ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// sort by difficulty (undefined difficulty goes to the end)
if ( ! Config . Startup . AlphabeticalSorting ) if ( pEntry1 - > GetDifficulty ( ) | | pEntry2 - > GetDifficulty ( ) )
2010-03-28 18:58:01 +00:00
{
if ( ! pEntry1 - > GetDifficulty ( ) ) return + 1 ;
if ( ! pEntry2 - > GetDifficulty ( ) ) return - 1 ;
int32_t iDiff = pEntry1 - > GetDifficulty ( ) - pEntry2 - > GetDifficulty ( ) ;
if ( iDiff ) return iDiff ;
}
2009-05-08 13:28:41 +00:00
// otherwise, sort by name
return stricmp ( pEntry1 - > GetName ( ) . getData ( ) , pEntry2 - > GetName ( ) . getData ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
uint32_t C4ScenarioListLoader : : Folder : : GetEntryCount ( ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
uint32_t iCount = 0 ;
for ( Entry * i = pFirst ; i ; i = i - > pNext ) + + iCount ;
return iCount ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4ScenarioListLoader : : Folder : : Sort ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// use C-Library-QSort on a buffer of entry pointers; then re-link list
if ( ! pFirst ) return ;
uint32_t iCount , i ;
Entry * * ppEntries = new Entry * [ i = iCount = GetEntryCount ( ) ] , * * ppI , * pI = pFirst , * * ppIThis ;
for ( ppI = ppEntries ; i - - ; pI = pI - > pNext ) * ppI + + = pI ;
qsort ( ppEntries , iCount , sizeof ( Entry * ) , & EntrySortFunc ) ;
ppIThis = & pFirst ;
2010-03-28 18:58:01 +00:00
for ( ppI = ppEntries ; iCount - - ; ppIThis = & ( ( * ppIThis ) - > pNext ) ) * ppIThis = * ppI + + ;
2016-11-02 23:58:02 +00:00
* ppIThis = nullptr ;
2009-05-08 13:28:41 +00:00
delete [ ] ppEntries ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4ScenarioListLoader : : Folder : : ClearChildren ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// folder deletion: del all the tree non-recursively
Folder * pDelFolder = this , * pCheckFolder ;
2010-03-28 18:58:01 +00:00
for ( ; ; )
{
2009-05-08 13:28:41 +00:00
// delete all children as long as they are not folders
Entry * pChild ;
2010-01-25 04:00:59 +00:00
while ( ( pChild = pDelFolder - > pFirst ) )
if ( ( pCheckFolder = pChild - > GetIsFolder ( ) ) )
2009-05-08 13:28:41 +00:00
// child entry if folder: Continue delete in there
pDelFolder = pCheckFolder ;
else
// regular child entry: del it
// destructor of child will remove it from list
delete pChild ;
// this emptied: Done!
if ( pDelFolder = = this ) break ;
// deepest child recursion reached: Travel up folders
pDelFolder = ( pCheckFolder = pDelFolder ) - > pParent ;
assert ( pDelFolder ) ;
delete pCheckFolder ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : Folder : : LoadContents ( C4ScenarioListLoader * pLoader , C4Group * pFromGrp , const StdStrBuf * psFilename , bool fLoadEx , bool fReload )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// contents already loaded?
if ( fContentsLoaded & & ! fReload ) return true ;
// clear previous
2016-11-02 23:58:02 +00:00
if ( pMapData ) { delete pMapData ; pMapData = nullptr ; }
2009-05-08 13:28:41 +00:00
// if filename is not given, assume it's been loaded in this entry
if ( ! psFilename ) psFilename = & this - > sFilename ; else this - > sFilename = * psFilename ;
// nothing loaded: Load now
if ( ! DoLoadContents ( pLoader , pFromGrp , * psFilename , fLoadEx ) ) return false ;
// sort loaded stuff by name
Sort ( ) ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4ScenarioListLoader : : Entry * C4ScenarioListLoader : : Folder : : FindEntryByName ( const char * szFilename ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// do a case-insensitive filename comparison
for ( Entry * pEntry = pFirst ; pEntry ; pEntry = pEntry - > GetNext ( ) )
if ( SEqualNoCase ( szFilename , GetFilename ( pEntry - > GetEntryFilename ( ) . getData ( ) ) ) )
return pEntry ;
// nothing found
2016-11-02 23:58:02 +00:00
return nullptr ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
StdStrBuf C4ScenarioListLoader : : Folder : : GetOpenText ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
return StdCopyStrBuf ( LoadResStr ( " IDS_BTN_OPEN " ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
StdStrBuf C4ScenarioListLoader : : Folder : : GetOpenTooltip ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
return StdCopyStrBuf ( LoadResStr ( " IDS_DLGTIP_SCENSELNEXT " ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : Folder : : IsGrayed ( )
2010-03-28 18:58:01 +00:00
{
2009-05-09 12:37:20 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : Folder : : LoadCustomPre ( C4Group & rGrp )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// load folder core if available
StdStrBuf sFileContents ;
2011-03-05 01:44:26 +00:00
if ( rGrp . LoadEntryString ( C4CFN_FolderCore , & sFileContents ) )
2009-05-08 13:28:41 +00:00
if ( ! CompileFromBuf_LogWarn < StdCompilerINIRead > ( C4F , sFileContents , ( rGrp . GetFullName ( ) + DirSep C4CFN_FolderCore ) . getData ( ) ) )
return false ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// ------------------------------------
// SubFolder
bool C4ScenarioListLoader : : SubFolder : : LoadCustom ( C4Group & rGrp , bool fNameLoaded , bool fIconLoaded )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// default icon fallback
if ( ! fIconLoaded )
2012-05-22 21:20:01 +00:00
{
if ( WildcardMatch ( C4CFN_Savegames , GetFilename ( sFilename . getData ( ) ) ) ) iIconIndex = C4StartupScenSel_DefaultIcon_SavegamesFolder ;
else iIconIndex = C4StartupScenSel_DefaultIcon_Folder ;
fctIcon . Set ( C4Startup : : Get ( ) - > Graphics . fctScenSelIcons . GetSection ( iIconIndex ) ) ;
}
2009-05-08 13:28:41 +00:00
// folder index
iFolderIndex = C4F . Head . Index ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : SubFolder : : DoLoadContents ( C4ScenarioListLoader * pLoader , C4Group * pFromGrp , const StdStrBuf & sFilename , bool fLoadEx )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
assert ( pLoader ) ;
// clear any previous
ClearChildren ( ) ;
// group specified: Load as child
C4Group Group ;
if ( pFromGrp )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ! Group . OpenAsChild ( pFromGrp , sFilename . getData ( ) ) ) return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
// no parent group: Direct load from filename
if ( ! Group . Open ( sFilename . getData ( ) ) ) return false ;
2014-10-03 10:06:08 +00:00
// Load achievement data contained scenarios can fall back to
C4LangStringTable FolderLangStringTable ;
C4Language : : LoadComponentHost ( & FolderLangStringTable , Group , C4CFN_ScriptStringTbl , Config . General . LanguageEx ) ;
AchievementDefs . Load ( Group , & FolderLangStringTable ) ;
AchievementGfx . Init ( Group ) ;
2009-05-08 13:28:41 +00:00
// get number of entries, to estimate progress
const char * szC4CFN_ScenarioFiles = C4CFN_ScenarioFiles ; // assign values for constant comparison
const char * szSearchMask ; int32_t iEntryCount = 0 ;
for ( szSearchMask = szC4CFN_ScenarioFiles ; szSearchMask ; )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Group . ResetSearch ( ) ;
while ( Group . FindNextEntry ( szSearchMask ) ) + + iEntryCount ;
// next search mask
if ( szSearchMask = = szC4CFN_ScenarioFiles )
szSearchMask = C4CFN_FolderFiles ;
else
2016-11-02 23:58:02 +00:00
szSearchMask = nullptr ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// initial progress estimate
2017-07-12 03:45:19 +00:00
if ( ! pLoader - > DoProcessCallback ( 0 , iEntryCount , nullptr ) ) return false ;
2009-05-08 13:28:41 +00:00
// iterate through group contents
char ChildFilename [ _MAX_FNAME + 1 ] ; StdStrBuf sChildFilename ; int32_t iLoadCount = 0 ;
for ( szSearchMask = szC4CFN_ScenarioFiles ; szSearchMask ; )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Group . ResetSearch ( ) ;
while ( Group . FindNextEntry ( szSearchMask , ChildFilename ) )
2010-03-28 18:58:01 +00:00
{
2017-07-12 03:45:19 +00:00
// mark progress
if ( ! pLoader - > DoProcessCallback ( iLoadCount , iEntryCount , ChildFilename ) ) return false ;
2009-05-08 13:28:41 +00:00
sChildFilename . Ref ( ChildFilename ) ;
// okay; create this item
2014-09-24 21:08:40 +00:00
Entry * pNewEntry = Entry : : CreateEntryForFile ( sChildFilename , pLoader , this ) ;
2009-05-08 13:28:41 +00:00
if ( pNewEntry )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// ...and load it
if ( ! pNewEntry - > Load ( & Group , & sChildFilename , fLoadEx ) )
2010-03-28 18:58:01 +00:00
{
2017-05-03 18:28:00 +00:00
DebugLogF ( R " (Error loading entry " % s " in SubFolder " % s " !) " , sChildFilename . getData ( ) , Group . GetFullName ( ) . getData ( ) ) ;
2009-05-08 13:28:41 +00:00
delete pNewEntry ;
}
2010-03-28 18:58:01 +00:00
}
2017-07-12 03:45:19 +00:00
+ + iLoadCount ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// next search mask
if ( szSearchMask = = szC4CFN_ScenarioFiles )
szSearchMask = C4CFN_FolderFiles ;
else
2016-11-02 23:58:02 +00:00
szSearchMask = nullptr ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// load map folder data
if ( Group . FindEntry ( C4CFN_MapFolderData ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pMapData = new C4MapFolderData ( ) ;
if ( ! pMapData - > Load ( Group , this ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// load error :(
delete pMapData ;
2016-11-02 23:58:02 +00:00
pMapData = nullptr ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// done, success
fContentsLoaded = true ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// ------------------------------------
// RegularFolder
2017-05-03 18:28:00 +00:00
C4ScenarioListLoader : : RegularFolder : : ~ RegularFolder ( ) = default ;
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : RegularFolder : : LoadCustom ( C4Group & rGrp , bool fNameLoaded , bool fIconLoaded )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// default icon fallback
if ( ! fIconLoaded )
fctIcon . Set ( C4Startup : : Get ( ) - > Graphics . fctScenSelIcons . GetSection ( C4StartupScenSel_DefaultIcon_WinFolder ) ) ;
// folder index
iFolderIndex = C4F . Head . Index ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : RegularFolder : : DoLoadContents ( C4ScenarioListLoader * pLoader , C4Group * pFromGrp , const StdStrBuf & sFilename , bool fLoadEx )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// clear any previous
ClearChildren ( ) ;
// regular folders must exist and not be within group!
assert ( ! pFromGrp ) ;
2011-01-06 20:18:13 +00:00
if ( sFilename . getData ( ) & & sFilename [ 0 ] )
2009-05-08 13:28:41 +00:00
Merge ( sFilename . getData ( ) ) ;
// get number of entries, to estimate progress
int32_t iCountLoaded = 0 , iCountTotal = 0 ;
NameList : : iterator it ;
for ( it = contents . begin ( ) ; it ! = contents . end ( ) ; + + it )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ! DirectoryExists ( it - > c_str ( ) ) ) continue ;
DirectoryIterator DirIter ( it - > c_str ( ) ) ;
const char * szChildFilename ;
2010-01-25 04:00:59 +00:00
for ( ; ( szChildFilename = * DirIter ) ; + + DirIter )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ! * szChildFilename | | * GetFilename ( szChildFilename ) = = ' . ' ) continue ;
+ + iCountTotal ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// initial progress estimate
2017-07-12 03:45:19 +00:00
if ( ! pLoader - > DoProcessCallback ( iCountLoaded , iCountTotal , nullptr ) ) return false ;
2009-05-08 13:28:41 +00:00
// do actual loading of files
std : : set < std : : string > names ;
const char * szChildFilename ;
for ( it = contents . begin ( ) ; it ! = contents . end ( ) ; + + it )
2010-03-28 18:58:01 +00:00
{
2017-07-12 03:45:19 +00:00
if ( ! pLoader - > DoProcessCallback ( iCountLoaded , iCountTotal , GetFilename ( it - > c_str ( ) ) ) ) return false ;
2010-01-25 04:00:59 +00:00
for ( DirectoryIterator DirIter ( it - > c_str ( ) ) ; ( szChildFilename = * DirIter ) ; + + DirIter )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
StdStrBuf sChildFilename ( szChildFilename ) ;
szChildFilename = GetFilename ( szChildFilename ) ;
2017-07-12 03:45:19 +00:00
// progress callback
if ( ! pLoader - > DoProcessCallback ( iCountLoaded , iCountTotal , szChildFilename ) ) return false ;
2009-05-08 13:28:41 +00:00
// Ignore directory navigation entries and CVS folders
2010-04-15 20:24:34 +00:00
if ( C4Group_TestIgnore ( szChildFilename ) ) continue ;
2009-05-08 13:28:41 +00:00
if ( names . find ( szChildFilename ) ! = names . end ( ) ) continue ;
names . insert ( szChildFilename ) ;
// filename okay; create this item
2014-09-24 21:08:40 +00:00
Entry * pNewEntry = Entry : : CreateEntryForFile ( sChildFilename , pLoader , this ) ;
2009-05-08 13:28:41 +00:00
if ( pNewEntry )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// ...and load it
2016-11-02 23:58:02 +00:00
if ( ! pNewEntry - > Load ( nullptr , & sChildFilename , fLoadEx ) )
2010-03-28 18:58:01 +00:00
{
2017-05-03 18:28:00 +00:00
DebugLogF ( R " (Error loading entry " % s " in Folder " % s " !) " , szChildFilename , it - > c_str ( ) ) ;
2009-05-08 13:28:41 +00:00
delete pNewEntry ;
}
2010-03-28 18:58:01 +00:00
}
2017-07-12 03:45:19 +00:00
+ + iCountLoaded ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// done, success
fContentsLoaded = true ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4ScenarioListLoader : : RegularFolder : : Merge ( const char * szPath )
2010-03-28 18:58:01 +00:00
{
2017-05-03 18:28:00 +00:00
contents . emplace_back ( szPath ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// ------------------------------------
// C4ScenarioListLoader
2016-11-02 23:58:02 +00:00
C4ScenarioListLoader : : C4ScenarioListLoader ( const C4ScenarioParameters & Achievements ) : Achievements ( Achievements ) , pRootFolder ( nullptr ) , pCurrFolder ( nullptr ) ,
2010-03-28 18:58:01 +00:00
iLoading ( 0 ) , iProgress ( 0 ) , iMaxProgress ( 0 ) , fAbortThis ( false ) , fAbortPrevious ( false )
{
}
2009-05-08 13:28:41 +00:00
C4ScenarioListLoader : : ~ C4ScenarioListLoader ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pRootFolder ) delete pRootFolder ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : BeginActivity ( bool fAbortPrevious )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// if previous activities were running, stop them first if desired
if ( iLoading & & fAbortPrevious )
this - > fAbortPrevious = true ;
// mark this activity
+ + iLoading ;
// progress of activity not yet decided
iProgress = iMaxProgress = 0 ;
2017-07-12 03:45:19 +00:00
current_load_info . Clear ( ) ;
2009-05-08 13:28:41 +00:00
// okay; start activity
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4ScenarioListLoader : : EndActivity ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
assert ( iLoading ) ;
if ( ! - - iLoading )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// last activity done: Reset any flags
fAbortThis = false ;
fAbortPrevious = false ;
iProgress = iMaxProgress = 0 ;
2017-07-12 03:45:19 +00:00
current_load_info . Clear ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// child activity done: Transfer abort flag for next activity
fAbortThis = fAbortPrevious ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2017-07-12 03:45:19 +00:00
bool C4ScenarioListLoader : : DoProcessCallback ( int32_t iProgress , int32_t iMaxProgress , const char * current_load_info )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
this - > iProgress = iProgress ;
this - > iMaxProgress = iMaxProgress ;
2017-07-12 03:45:19 +00:00
this - > current_load_info . Copy ( current_load_info ) ;
2009-05-08 13:28:41 +00:00
// callback to dialog
if ( C4StartupScenSelDlg : : pInstance ) C4StartupScenSelDlg : : pInstance - > ProcessCallback ( ) ;
// process callback - abort at a few ugly circumstances...
2017-07-12 01:24:14 +00:00
// schedule with 1ms delay to force event processing
// (delay 0 would be nice, but isn't supported properly by our Windows implementation of ScheduleProcs)
if ( ! Application . ScheduleProcs ( 1 ) // WM_QUIT message?
2010-03-28 18:58:01 +00:00
| | ! C4StartupScenSelDlg : : pInstance // host dialog removed?
| | ! C4StartupScenSelDlg : : pInstance - > IsShown ( ) // host dialog closed?
) return false ;
2009-05-08 13:28:41 +00:00
// and also abort if flagged
return ! fAbortThis ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : Load ( const StdStrBuf & sRootFolder )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// (unthreaded) loading of all entries in root folder
if ( ! BeginActivity ( true ) ) return false ;
2016-11-02 23:58:02 +00:00
if ( pRootFolder ) { delete pRootFolder ; pRootFolder = nullptr ; }
pCurrFolder = pRootFolder = new RegularFolder ( this , nullptr ) ;
2011-01-06 20:18:13 +00:00
// Load regular game data if no explicit path specified
if ( ! sRootFolder . getData ( ) )
2017-05-03 18:28:00 +00:00
for ( const auto & iter : Reloc )
pRootFolder - > Merge ( iter . strBuf . getData ( ) ) ;
2016-11-02 23:58:02 +00:00
bool fSuccess = pRootFolder - > LoadContents ( this , nullptr , & sRootFolder , false , false ) ;
2009-05-08 13:28:41 +00:00
EndActivity ( ) ;
return fSuccess ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : Load ( Folder * pSpecifiedFolder , bool fReload )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// call safety
if ( ! pRootFolder | | ! pSpecifiedFolder ) return false ;
// set new current and load it
if ( ! BeginActivity ( true ) ) return false ;
pCurrFolder = pSpecifiedFolder ;
2016-11-02 23:58:02 +00:00
bool fSuccess = pCurrFolder - > LoadContents ( this , nullptr , nullptr , false , fReload ) ;
2009-05-08 13:28:41 +00:00
EndActivity ( ) ;
return fSuccess ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : LoadExtended ( Entry * pEntry )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// call safety
if ( ! pRootFolder | | ! pEntry ) return false ;
// load info of selection
if ( ! BeginActivity ( false ) ) return false ;
2016-11-02 23:58:02 +00:00
bool fSuccess = pEntry - > Load ( nullptr , nullptr , true ) ;
2009-05-08 13:28:41 +00:00
EndActivity ( ) ;
return fSuccess ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : FolderBack ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// call safety
if ( ! pRootFolder | | ! pCurrFolder ) return false ;
// already in root: Can't go up
if ( pCurrFolder = = pRootFolder ) return false ;
// otherwise, up one level
return Load ( pCurrFolder - > GetParent ( ) , false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4ScenarioListLoader : : ReloadCurrent ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// call safety
if ( ! pRootFolder | | ! pCurrFolder ) return false ;
// reload current
return Load ( pCurrFolder , true ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// ----------------------------------------------------------------
// Scenario selection GUI
// font clrs
const uint32_t ClrScenarioItem = 0xff000000 ,
2010-03-28 18:58:01 +00:00
ClrScenarioItemXtra = 0x7f000000 ,
ClrScenarioItemDisabled = 0x7f000000 ;
2009-05-08 13:28:41 +00:00
// ------------------------------------------------
// --- C4StartupScenSelDlg::ScenListItem
C4StartupScenSelDlg : : ScenListItem : : ScenListItem ( C4GUI : : ListBox * pForListBox , C4ScenarioListLoader : : Entry * pForEntry , C4GUI : : Element * pInsertBeforeElement )
2016-11-02 23:58:02 +00:00
: pIcon ( nullptr ) , pNameLabel ( nullptr ) , pScenListEntry ( pForEntry )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
assert ( pScenListEntry ) ;
CStdFont & rUseFont = C4Startup : : Get ( ) - > Graphics . BookFont ;
2017-12-28 20:45:20 +00:00
StdStrBuf sIgnore ; bool bIgnore ;
bool fEnabled = pScenListEntry - > CanOpen ( sIgnore , bIgnore ) & & ! pScenListEntry - > IsGrayed ( ) ;
2009-05-08 13:28:41 +00:00
// calc height
int32_t iHeight = rUseFont . GetLineHeight ( ) + 2 * IconLabelSpacing ;
// create subcomponents
pIcon = new C4GUI : : Picture ( C4Rect ( 0 , 0 , iHeight , iHeight ) , true ) ;
pIcon - > SetFacet ( pScenListEntry - > GetIconFacet ( ) ) ;
pNameLabel = new C4GUI : : Label ( pScenListEntry - > GetName ( ) . getData ( ) , iHeight + IconLabelSpacing , IconLabelSpacing , ALeft , fEnabled ? ClrScenarioItem : ClrScenarioItemDisabled , & rUseFont , false , false ) ;
2014-09-24 21:08:40 +00:00
// achievement components
for ( int32_t i = 0 ; i < C4StartupScenSel_MaxAchievements ; + + i )
{
C4Facet fct ; const char * desc ;
if ( pForEntry - > GetAchievement ( i , & fct , & desc ) )
{
ppAchievements [ i ] = new C4GUI : : Picture ( C4Rect ( iHeight * ( i + 2 ) , 0 , iHeight , iHeight ) , true ) ; // position will be adjusted later
ppAchievements [ i ] - > SetFacet ( fct ) ;
ppAchievements [ i ] - > SetToolTip ( desc ) ;
}
else
{
2016-11-02 23:58:02 +00:00
ppAchievements [ i ] = nullptr ;
2014-09-24 21:08:40 +00:00
}
}
2009-05-08 13:28:41 +00:00
// calc own bounds - use icon bounds only, because only the height is used when the item is added
SetBounds ( pIcon - > GetBounds ( ) ) ;
// add components
AddElement ( pIcon ) ; AddElement ( pNameLabel ) ;
2017-05-03 18:28:00 +00:00
for ( auto & ppAchievement : ppAchievements ) if ( ppAchievement ) AddElement ( ppAchievement ) ;
2009-05-08 13:28:41 +00:00
// tooltip by name, so long names can be read via tooltip
SetToolTip ( pScenListEntry - > GetName ( ) . getData ( ) ) ;
// add to listbox (will get resized horizontally and moved) - zero indent; no tree structure in this dialog
pForListBox - > InsertElement ( this , pInsertBeforeElement , 0 ) ;
// update name label width to reflect new horizontal size
// name label width must be set so rename edit will take its size
pNameLabel - > SetAutosize ( false ) ;
C4Rect rcNLB = pNameLabel - > GetBounds ( ) ; rcNLB . Wdt = GetClientRect ( ) . Wdt - rcNLB . x - IconLabelSpacing ;
pNameLabel - > SetBounds ( rcNLB ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : ScenListItem : : UpdateOwnPos ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// parent for client rect
typedef C4GUI : : Window ParentClass ;
ParentClass : : UpdateOwnPos ( ) ;
2014-09-24 21:08:40 +00:00
// reposition achievement items
2009-05-08 13:28:41 +00:00
C4GUI : : ComponentAligner caBounds ( GetContainedClientRect ( ) , IconLabelSpacing , IconLabelSpacing ) ;
2017-05-03 18:28:00 +00:00
for ( auto & ppAchievement : ppAchievements ) if ( ppAchievement )
2014-09-24 21:08:40 +00:00
{
2017-05-03 18:28:00 +00:00
ppAchievement - > SetBounds ( caBounds . GetFromRight ( caBounds . GetHeight ( ) ) ) ;
2014-09-24 21:08:40 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : ScenListItem : : MouseInput ( C4GUI : : CMouse & rMouse , int32_t iButton , int32_t iX , int32_t iY , DWORD dwKeyParam )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// double-click opens/starts item - currently processed by ListBox already!
// inherited processing
typedef C4GUI : : Window BaseClass ;
BaseClass : : MouseInput ( rMouse , iButton , iX , iY , dwKeyParam ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4StartupScenSelDlg : : ScenListItem : : CheckNameHotkey ( const char * c )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// return whether this item can be selected by entering given char:
// first char of name must match
// FIXME: make unicode-ready
if ( ! pScenListEntry ) return false ;
const char * szName = pScenListEntry - > GetName ( ) . getData ( ) ;
return szName & & ( toupper ( * szName ) = = toupper ( c [ 0 ] ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4StartupScenSelDlg : : ScenListItem : : KeyRename ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// rename this entry
C4StartupScenSelDlg : : pInstance - > StartRenaming ( new C4GUI : : CallbackRenameEdit < C4StartupScenSelDlg : : ScenListItem , RenameParams > ( pNameLabel , this , RenameParams ( ) , & C4StartupScenSelDlg : : ScenListItem : : DoRenaming , & C4StartupScenSelDlg : : ScenListItem : : AbortRenaming ) ) ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : ScenListItem : : AbortRenaming ( RenameParams par )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// no renaming
C4StartupScenSelDlg : : pInstance - > SetRenamingDone ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4GUI : : RenameEdit : : RenameResult C4StartupScenSelDlg : : ScenListItem : : DoRenaming ( RenameParams par , const char * szNewName )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// check validity for new name
if ( ! GetEntry ( ) - > RenameTo ( szNewName ) ) return C4GUI : : RenameEdit : : RR_Invalid ;
// rename label
pNameLabel - > SetText ( GetEntry ( ) - > GetName ( ) . getData ( ) ) ;
// main dlg update
C4StartupScenSelDlg : : pInstance - > SetRenamingDone ( ) ;
C4StartupScenSelDlg : : pInstance - > ResortFolder ( ) ;
C4StartupScenSelDlg : : pInstance - > UpdateSelection ( ) ;
C4StartupScenSelDlg : : pInstance - > FocusScenList ( ) ;
// done; rename accepted and control deleted by ResortFolder
return C4GUI : : RenameEdit : : RR_Deleted ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// ------------------------------------------------
// --- C4StartupScenSelDlg
2016-11-02 23:58:02 +00:00
C4StartupScenSelDlg : : C4StartupScenSelDlg ( bool fNetwork ) : C4StartupDlg ( LoadResStrNoAmp ( fNetwork ? " IDS_DLG_NETSTART " : " IDS_DLG_STARTGAME " ) ) , pScenLoader ( nullptr ) , pMapData ( nullptr ) , pfctBackground ( nullptr ) , fIsInitialLoading ( false ) , fStartNetworkGame ( fNetwork ) , pRenameEdit ( nullptr )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// ctor
// assign singleton
pInstance = this ;
// screen calculations
UpdateSize ( ) ;
int32_t iButtonWidth , iCaptionFontHgt ;
int iButtonHeight = C4GUI_ButtonHgt ;
int iBookPageWidth ;
int iExtraHPadding = rcBounds . Wdt > = 700 ? rcBounds . Wdt / 50 : 0 ;
2010-06-27 00:42:48 +00:00
: : GraphicsResource . CaptionFont . GetTextExtent ( " << BACK " , iButtonWidth , iCaptionFontHgt , true ) ;
2009-05-08 13:28:41 +00:00
iButtonWidth * = 3 ;
C4GUI : : ComponentAligner caMain ( GetClientRect ( ) , 0 , 0 , true ) ;
C4GUI : : ComponentAligner caButtonArea ( caMain . GetFromBottom ( caMain . GetHeight ( ) / 8 ) , rcBounds . Wdt / ( rcBounds . Wdt > = 700 ? 128 : 256 ) , 0 ) ;
C4Rect rcMap = caMain . GetCentered ( caMain . GetWidth ( ) , caMain . GetHeight ( ) ) ;
// tabular for different scenario selection designs
pScenSelStyleTabular = new C4GUI : : Tabular ( rcMap , C4GUI : : Tabular : : tbNone ) ;
pScenSelStyleTabular - > SetSheetMargin ( 0 ) ;
2013-05-26 15:51:35 +00:00
pScenSelStyleTabular - > SetGfx ( & C4Startup : : Get ( ) - > Graphics . fctDlgPaper , & C4Startup : : Get ( ) - > Graphics . fctOptionsTabClip , & C4Startup : : Get ( ) - > Graphics . fctOptionsIcons , & C4Startup : : Get ( ) - > Graphics . BookSmallFont , false ) ;
2009-05-08 13:28:41 +00:00
AddElement ( pScenSelStyleTabular ) ;
2016-11-02 23:58:02 +00:00
C4GUI : : Tabular : : Sheet * pSheetBook = pScenSelStyleTabular - > AddSheet ( nullptr ) ;
/* C4GUI::Tabular::Sheet *pSheetMap = */ pScenSelStyleTabular - > AddSheet ( nullptr ) ;
2009-05-08 13:28:41 +00:00
// scenario selection list
2013-05-26 15:51:35 +00:00
C4GUI : : ComponentAligner caBook ( pSheetBook - > GetClientRect ( ) , caMain . GetWidth ( ) / 20 , caMain . GetHeight ( ) / 20 , true ) ;
C4GUI : : ComponentAligner caBookLeft ( caBook . GetFromLeft ( iBookPageWidth = caBook . GetWidth ( ) * 4 / 9 + 4 - iExtraHPadding * 2 ) , 0 , 5 ) ;
2009-05-08 13:28:41 +00:00
CStdFont & rScenSelCaptionFont = C4Startup : : Get ( ) - > Graphics . BookFontTitle ;
pScenSelCaption = new C4GUI : : Label ( " " , caBookLeft . GetFromTop ( rScenSelCaptionFont . GetLineHeight ( ) ) , ACenter , ClrScenarioItem , & rScenSelCaptionFont , false ) ;
pSheetBook - > AddElement ( pScenSelCaption ) ;
pScenSelCaption - > SetToolTip ( LoadResStr ( " IDS_DLGTIP_SELECTSCENARIO " ) ) ;
pScenSelList = new C4GUI : : ListBox ( caBookLeft . GetAll ( ) ) ;
pScenSelList - > SetToolTip ( LoadResStr ( " IDS_DLGTIP_SELECTSCENARIO " ) ) ;
pScenSelList - > SetDecoration ( false , & C4Startup : : Get ( ) - > Graphics . sfctBookScroll , true ) ;
pSheetBook - > AddElement ( pScenSelList ) ;
pScenSelList - > SetSelectionChangeCallbackFn ( new C4GUI : : CallbackHandler < C4StartupScenSelDlg > ( this , & C4StartupScenSelDlg : : OnSelChange ) ) ;
pScenSelList - > SetSelectionDblClickFn ( new C4GUI : : CallbackHandler < C4StartupScenSelDlg > ( this , & C4StartupScenSelDlg : : OnSelDblClick ) ) ;
2017-07-12 03:45:19 +00:00
// scenario selection list progress labels
pScenSelProgressLabel = new C4GUI : : Label ( " " , pScenSelList - > GetBounds ( ) . GetMiddleX ( ) , pScenSelList - > GetBounds ( ) . GetMiddleY ( ) - iCaptionFontHgt , ACenter , ClrScenarioItem , & ( C4Startup : : Get ( ) - > Graphics . BookFontCapt ) , false ) ;
2009-05-08 13:28:41 +00:00
pSheetBook - > AddElement ( pScenSelProgressLabel ) ;
2017-07-12 03:45:19 +00:00
pScenSelProgressInfoLabel = new C4GUI : : Label ( " " , pScenSelList - > GetBounds ( ) . GetMiddleX ( ) , pScenSelList - > GetBounds ( ) . GetMiddleY ( ) , ACenter , ClrScenarioItemXtra , & ( C4Startup : : Get ( ) - > Graphics . BookFontCapt ) , false ) ;
pSheetBook - > AddElement ( pScenSelProgressInfoLabel ) ;
2009-05-08 13:28:41 +00:00
// right side of book: Displaying current selection
2012-10-14 13:58:12 +00:00
C4Rect bounds = caBook . GetFromRight ( iBookPageWidth ) ;
const int32_t AvailWidth = bounds . Wdt ;
2012-10-14 14:24:40 +00:00
const int32_t AvailHeight = 2 * bounds . Hgt / 5 ;
2012-10-14 13:58:12 +00:00
int32_t PictureWidth , PictureHeight ;
if ( AvailWidth * C4StartupScenSel_TitlePictureHgt < AvailHeight * C4StartupScenSel_TitlePictureWdt )
{
PictureWidth = C4StartupScenSel_TitlePictureWdt * AvailWidth / C4StartupScenSel_TitlePictureWdt ;
PictureHeight = C4StartupScenSel_TitlePictureHgt * AvailWidth / C4StartupScenSel_TitlePictureWdt ;
}
else
{
PictureWidth = C4StartupScenSel_TitlePictureWdt * AvailHeight / C4StartupScenSel_TitlePictureHgt ;
PictureHeight = C4StartupScenSel_TitlePictureHgt * AvailHeight / C4StartupScenSel_TitlePictureHgt ;
}
pSelectionInfo = new C4GUI : : TextWindow ( bounds , PictureWidth + 2 * C4StartupScenSel_TitleOverlayMargin , PictureHeight + 2 * C4StartupScenSel_TitleOverlayMargin ,
2016-11-02 23:58:02 +00:00
C4StartupScenSel_TitlePicturePadding , 100 , 4096 , nullptr , true , & C4Startup : : Get ( ) - > Graphics . fctScenSelTitleOverlay , C4StartupScenSel_TitleOverlayMargin ) ;
2009-05-08 13:28:41 +00:00
pSelectionInfo - > SetDecoration ( false , false , & C4Startup : : Get ( ) - > Graphics . sfctBookScroll , true ) ;
pSheetBook - > AddElement ( pSelectionInfo ) ;
2014-09-27 14:04:48 +00:00
// bottom of right side of book: Custom options on selection
// Arbitrary height and invisible by default. Height will be adjusted when options are created.
2014-10-03 19:25:25 +00:00
pSelectionOptions = new C4GameOptionsList ( C4Rect ( bounds . x , bounds . y + bounds . Hgt - 10 , bounds . Wdt , 10 ) , false , fNetwork ? C4GameOptionsList : : GOLS_PreGameNetwork : C4GameOptionsList : : GOLS_PreGameSingle ) ;
2014-09-27 14:04:48 +00:00
pSelectionOptions - > SetDecoration ( false , & C4Startup : : Get ( ) - > Graphics . sfctBookScroll , true ) ;
pSelectionOptions - > SetVisibility ( false ) ;
pSheetBook - > AddElement ( pSelectionOptions ) ;
2009-05-08 13:28:41 +00:00
// back button
C4GUI : : CallbackButton < C4StartupScenSelDlg > * btn ;
AddElement ( btn = new C4GUI : : CallbackButton < C4StartupScenSelDlg > ( LoadResStr ( " IDS_BTN_BACK " ) , caButtonArea . GetFromLeft ( iButtonWidth , iButtonHeight ) , & C4StartupScenSelDlg : : OnBackBtn ) ) ;
btn - > SetToolTip ( LoadResStr ( " IDS_DLGTIP_BACKMAIN " ) ) ;
AddElement ( btn ) ;
// next button
pOpenBtn = new C4GUI : : CallbackButton < C4StartupScenSelDlg > ( LoadResStr ( " IDS_BTN_OPEN " ) , caButtonArea . GetFromRight ( iButtonWidth , iButtonHeight ) , & C4StartupScenSelDlg : : OnNextBtn ) ;
pOpenBtn - > SetToolTip ( LoadResStr ( " IDS_DLGTIP_SCENSELNEXT " ) ) ;
// game options boxes
pGameOptionButtons = new C4GameOptionButtons ( caButtonArea . GetAll ( ) , fNetwork , true , false ) ;
AddElement ( pGameOptionButtons ) ;
// next button adding
AddElement ( pOpenBtn ) ;
// dlg starts with focus on listbox
SetFocus ( pScenSelList , false ) ;
// key bindings
C4CustomKey : : CodeList keys ;
2017-05-03 18:28:00 +00:00
keys . emplace_back ( K_BACK ) ; keys . emplace_back ( K_LEFT ) ;
2009-05-08 13:28:41 +00:00
pKeyBack = new C4KeyBinding ( keys , " StartupScenSelFolderUp " , KEYSCOPE_Gui ,
2010-03-28 18:58:01 +00:00
new C4GUI : : DlgKeyCB < C4StartupScenSelDlg > ( * this , & C4StartupScenSelDlg : : KeyBack ) , C4CustomKey : : PRIO_CtrlOverride ) ;
2009-05-08 13:28:41 +00:00
pKeyRefresh = new C4KeyBinding ( C4KeyCodeEx ( K_F5 ) , " StartupScenSelReload " , KEYSCOPE_Gui ,
2010-03-28 18:58:01 +00:00
new C4GUI : : DlgKeyCB < C4StartupScenSelDlg > ( * this , & C4StartupScenSelDlg : : KeyRefresh ) , C4CustomKey : : PRIO_CtrlOverride ) ;
2009-05-08 13:28:41 +00:00
pKeyForward = new C4KeyBinding ( C4KeyCodeEx ( K_RIGHT ) , " StartupScenSelNext " , KEYSCOPE_Gui ,
2010-03-28 18:58:01 +00:00
new C4GUI : : DlgKeyCB < C4StartupScenSelDlg > ( * this , & C4StartupScenSelDlg : : KeyForward ) , C4CustomKey : : PRIO_CtrlOverride ) ;
2009-05-08 13:28:41 +00:00
pKeyRename = new C4KeyBinding ( C4KeyCodeEx ( K_F2 ) , " StartupScenSelRename " , KEYSCOPE_Gui ,
2010-03-28 18:58:01 +00:00
new C4GUI : : ControlKeyDlgCB < C4StartupScenSelDlg > ( pScenSelList , * this , & C4StartupScenSelDlg : : KeyRename ) , C4CustomKey : : PRIO_CtrlOverride ) ;
2009-05-08 13:28:41 +00:00
pKeyDelete = new C4KeyBinding ( C4KeyCodeEx ( K_DELETE ) , " StartupScenSelDelete " , KEYSCOPE_Gui ,
2010-03-28 18:58:01 +00:00
new C4GUI : : ControlKeyDlgCB < C4StartupScenSelDlg > ( pScenSelList , * this , & C4StartupScenSelDlg : : KeyDelete ) , C4CustomKey : : PRIO_CtrlOverride ) ;
2015-05-22 19:41:34 +00:00
pKeyCheat = new C4KeyBinding ( C4KeyCodeEx ( K_M , KEYS_Control ) , " StartupScenSelCheat " , KEYSCOPE_Gui ,
2010-03-28 18:58:01 +00:00
new C4GUI : : ControlKeyDlgCB < C4StartupScenSelDlg > ( pScenSelList , * this , & C4StartupScenSelDlg : : KeyCheat ) , C4CustomKey : : PRIO_CtrlOverride ) ;
}
2009-05-08 13:28:41 +00:00
C4StartupScenSelDlg : : ~ C4StartupScenSelDlg ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pScenLoader ) delete pScenLoader ;
2016-11-02 23:58:02 +00:00
if ( this = = pInstance ) pInstance = nullptr ;
2009-05-08 13:28:41 +00:00
delete pKeyCheat ;
delete pKeyDelete ;
delete pKeyRename ;
delete pKeyForward ;
delete pKeyRefresh ;
delete pKeyBack ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : DrawElement ( C4TargetFacet & cgo )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// draw background
if ( pfctBackground )
DrawBackground ( cgo , * pfctBackground ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : OnShown ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4StartupDlg : : OnShown ( ) ;
2014-09-24 21:08:40 +00:00
// Collect achievements of all activated players
UpdateAchievements ( ) ;
2009-05-08 13:28:41 +00:00
// init file list
fIsInitialLoading = true ;
2014-09-24 21:08:40 +00:00
if ( ! pScenLoader ) pScenLoader = new C4ScenarioListLoader ( Achievements ) ;
2015-03-25 18:04:04 +00:00
pScenLoader - > Load ( StdStrBuf ( ) ) ;
2009-05-08 13:28:41 +00:00
UpdateList ( ) ;
UpdateSelection ( ) ;
fIsInitialLoading = false ;
// network activation by dialog type
Game . NetworkActive = fStartNetworkGame ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : OnClosed ( bool fOK )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
AbortRenaming ( ) ;
// clear laoded scenarios
if ( pScenLoader )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
delete pScenLoader ;
2016-11-02 23:58:02 +00:00
pScenLoader = nullptr ;
2009-05-08 13:28:41 +00:00
UpdateList ( ) ; // must clear scenario list, because it points to deleted stuff
UpdateSelection ( ) ; // must clear picture facet of selection!
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// dlg abort: return to main screen
if ( ! fOK )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// clear settings: Password
2016-11-02 23:58:02 +00:00
: : Network . SetPassword ( nullptr ) ;
2009-05-08 13:28:41 +00:00
C4Startup : : Get ( ) - > SwitchDialog ( C4Startup : : SDID_Back ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : UpdateList ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
AbortRenaming ( ) ;
// default: Show book (also for loading screen)
2016-11-02 23:58:02 +00:00
pMapData = nullptr ;
2009-05-08 13:28:41 +00:00
pScenSelStyleTabular - > SelectSheet ( ShowStyle_Book , false ) ;
// and delete any stuff from map selection
C4GUI : : Tabular : : Sheet * pMapSheet = pScenSelStyleTabular - > GetSheet ( ShowStyle_Map ) ;
while ( pMapSheet - > GetFirst ( ) ) delete pMapSheet - > GetFirst ( ) ;
2016-11-02 23:58:02 +00:00
pfctBackground = nullptr ;
2009-05-08 13:28:41 +00:00
// for now, all the list is loaded at once anyway
// so just clear and add all loaded items
// remember old selection
C4ScenarioListLoader : : Entry * pOldSelection = GetSelectedEntry ( ) ;
C4GUI : : Element * pEl ;
2010-01-25 04:00:59 +00:00
while ( ( pEl = pScenSelList - > GetFirst ( ) ) ) delete pEl ;
2009-05-08 13:28:41 +00:00
pScenSelCaption - > SetText ( " " ) ;
// scen loader still busy: Nothing to add
if ( ! pScenLoader ) return ;
if ( pScenLoader - > IsLoading ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
StdStrBuf sProgressText ;
sProgressText . Format ( LoadResStr ( " IDS_MSG_SCENARIODESC_LOADING " ) , ( int32_t ) pScenLoader - > GetProgressPercent ( ) ) ;
pScenSelProgressLabel - > SetText ( sProgressText . getData ( ) ) ;
pScenSelProgressLabel - > SetVisibility ( true ) ;
2017-07-12 03:45:19 +00:00
pScenSelProgressInfoLabel - > SetText ( pScenLoader - > GetProgressInfo ( ) ) ;
pScenSelProgressInfoLabel - > SetVisibility ( true ) ;
2009-05-08 13:28:41 +00:00
return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
pScenSelProgressLabel - > SetVisibility ( false ) ;
2017-07-12 03:45:19 +00:00
pScenSelProgressInfoLabel - > SetVisibility ( false ) ;
2009-05-08 13:28:41 +00:00
// is this a map folder? Then show the map instead
C4ScenarioListLoader : : Folder * pFolder = static_cast < C4ScenarioListLoader : : Folder * > ( pScenLoader - > GetCurrFolder ( ) ) ;
2010-01-25 04:00:59 +00:00
if ( ( pMapData = pFolder - > GetMapData ( ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pMapData - > ResetSelection ( ) ;
pMapData - > CreateGUIElements ( this , * pScenSelStyleTabular - > GetSheet ( ShowStyle_Map ) ) ;
pScenSelStyleTabular - > SelectSheet ( ShowStyle_Map , false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// book style selection
// add what has been loaded
for ( C4ScenarioListLoader : : Entry * pEnt = pScenLoader - > GetFirstEntry ( ) ; pEnt ; pEnt = pEnt - > GetNext ( ) )
2010-03-28 18:58:01 +00:00
{
2015-09-25 03:51:16 +00:00
if ( pEnt - > IsHidden ( ) ) continue ; // no UI entry at all for hidden items
2009-05-08 13:28:41 +00:00
ScenListItem * pEntItem = new ScenListItem ( pScenSelList , pEnt ) ;
if ( pEnt = = pOldSelection ) pScenSelList - > SelectEntry ( pEntItem , false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// set title of current folder
// but not root
if ( pFolder & & pFolder ! = pScenLoader - > GetRootFolder ( ) )
pScenSelCaption - > SetText ( pFolder - > GetName ( ) . getData ( ) ) ;
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// special root title
pScenSelCaption - > SetText ( LoadResStr ( " IDS_DLG_SCENARIOS " ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// new list has been loaded: Select first entry if nothing else had been selected
if ( ! pOldSelection ) pScenSelList - > SelectFirstEntry ( false ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : ResortFolder ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// if it's still loading, sorting will be done in the end anyway
if ( ! pScenLoader | | pScenLoader - > IsLoading ( ) ) return ;
C4ScenarioListLoader : : Folder * pFolder = pScenLoader - > GetCurrFolder ( ) ;
if ( ! pFolder ) return ;
pFolder - > Resort ( ) ;
UpdateList ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : UpdateSelection ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
AbortRenaming ( ) ;
if ( ! pScenLoader )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Facet fctNoPic ;
pSelectionInfo - > SetPicture ( fctNoPic ) ;
pSelectionInfo - > ClearText ( false ) ;
SetOpenButtonDefaultText ( ) ;
return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// determine target text box
C4GUI : : TextWindow * pSelectionInfo = pMapData ? pMapData - > GetSelectionInfoBox ( ) : this - > pSelectionInfo ;
// get selected entry
C4ScenarioListLoader : : Entry * pSel = GetSelectedEntry ( ) ;
if ( ! pSel )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// no selection: Display data of current parent folder
pSel = pScenLoader - > GetCurrFolder ( ) ;
// but not root
2016-11-02 23:58:02 +00:00
if ( pSel = = pScenLoader - > GetRootFolder ( ) ) pSel = nullptr ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// get title image and desc of selected entry
C4Facet fctTitle ; StdStrBuf sTitle , sDesc , sVersion , sAuthor ;
if ( pSel )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pScenLoader - > LoadExtended ( pSel ) ; // 2do: Multithreaded
fctTitle = pSel - > GetTitlePicture ( ) ;
sTitle . Ref ( pSel - > GetName ( ) ) ;
sDesc . Ref ( pSel - > GetDesc ( ) ) ;
sVersion . Ref ( pSel - > GetVersion ( ) ) ;
sAuthor . Ref ( pSel - > GetAuthor ( ) ) ;
// never show a pure title string: There must always be some text or an image
if ( ! fctTitle . Surface & & ( ! sDesc | | ! * sDesc . getData ( ) ) )
sTitle . Clear ( ) ;
// selection specific open/start button
pOpenBtn - > SetText ( pSel - > GetOpenText ( ) . getData ( ) ) ;
pOpenBtn - > SetToolTip ( pSel - > GetOpenTooltip ( ) . getData ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
SetOpenButtonDefaultText ( ) ;
// set data in selection component
pSelectionInfo - > ClearText ( false ) ;
pSelectionInfo - > SetPicture ( fctTitle ) ;
2010-12-05 17:57:06 +00:00
if ( sTitle & & ( ! sDesc | | ! * sDesc . getData ( ) ) ) pSelectionInfo - > AddTextLine ( sTitle . getData ( ) , & C4Startup : : Get ( ) - > Graphics . BookFontCapt , ClrScenarioItem , false , false ) ;
if ( sDesc ) pSelectionInfo - > AddTextLine ( sDesc . getData ( ) , & C4Startup : : Get ( ) - > Graphics . BookFont , ClrScenarioItem , false , false , & C4Startup : : Get ( ) - > Graphics . BookFontCapt ) ;
if ( sAuthor ) pSelectionInfo - > AddTextLine ( FormatString ( LoadResStr ( " IDS_CTL_AUTHOR " ) , sAuthor . getData ( ) ) . getData ( ) ,
2010-03-28 18:58:01 +00:00
& C4Startup : : Get ( ) - > Graphics . BookFont , ClrScenarioItemXtra , false , false ) ;
2010-12-05 17:57:06 +00:00
if ( sVersion ) pSelectionInfo - > AddTextLine ( FormatString ( LoadResStr ( " IDS_DLG_VERSION " ) , sVersion . getData ( ) ) . getData ( ) ,
2010-03-28 18:58:01 +00:00
& C4Startup : : Get ( ) - > Graphics . BookFont , ClrScenarioItemXtra , false , false ) ;
2014-09-27 14:04:48 +00:00
// update custom scenario options panel
if ( pSel )
{
pSelectionOptions - > SetParameters ( pSel - > GetParameterDefs ( ) , pSel - > GetParameters ( ) ) ;
pSelectionOptions - > Update ( ) ;
}
else
2016-11-02 23:58:02 +00:00
pSelectionOptions - > SetParameters ( nullptr , nullptr ) ;
2014-09-27 14:04:48 +00:00
// update component heights
C4Rect rcSelBounds = pSelectionInfo - > GetBounds ( ) ;
int32_t ymax = pSelectionOptions - > GetBounds ( ) . GetBottom ( ) ;
C4GUI : : Element * pLastOption = pSelectionOptions - > GetLast ( ) ;
if ( pLastOption )
{
// custom options present: Info box reduced; options box at bottom
// set options box max size to 1/3rd of selection info area
2015-11-15 12:53:01 +00:00
int32_t options_hgt = std : : min < int32_t > ( pLastOption - > GetBounds ( ) . GetBottom ( ) + pSelectionOptions - > GetMarginTop ( ) + pSelectionOptions - > GetMarginTop ( ) , rcSelBounds . Hgt / 3 ) ;
2014-09-27 14:04:48 +00:00
rcSelBounds . Hgt = ymax - options_hgt - rcSelBounds . y ;
pSelectionInfo - > SetBounds ( rcSelBounds ) ;
rcSelBounds . y = ymax - options_hgt ;
rcSelBounds . Hgt = options_hgt ;
pSelectionOptions - > SetBounds ( rcSelBounds ) ;
pSelectionOptions - > SetVisibility ( true ) ;
}
else
{
// custom options absent: Info takes full area
pSelectionOptions - > SetVisibility ( false ) ;
rcSelBounds . Hgt = ymax - rcSelBounds . y ;
pSelectionInfo - > SetBounds ( rcSelBounds ) ;
}
2009-05-08 13:28:41 +00:00
pSelectionInfo - > UpdateHeight ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4StartupScenSelDlg : : ScenListItem * C4StartupScenSelDlg : : GetSelectedItem ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
return static_cast < ScenListItem * > ( pScenSelList - > GetSelectedItem ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4ScenarioListLoader : : Entry * C4StartupScenSelDlg : : GetSelectedEntry ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// map layout: Get selection from map
if ( pMapData ) return pMapData - > GetSelectedEntry ( ) ;
// get selection in listbox
ScenListItem * pSel = static_cast < ScenListItem * > ( pScenSelList - > GetSelectedItem ( ) ) ;
2016-11-02 23:58:02 +00:00
return pSel ? pSel - > GetEntry ( ) : nullptr ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4StartupScenSelDlg : : StartScenario ( C4ScenarioListLoader : : Scenario * pStartScen )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
assert ( pStartScen ) ;
if ( ! pStartScen ) return false ;
// get required object definitions
if ( pStartScen - > GetC4S ( ) . Definitions . AllowUserChange )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get definitions as user selects them
StdStrBuf sDefinitions ;
2011-03-13 15:55:00 +00:00
if ( ! pStartScen - > GetC4S ( ) . Definitions . GetModules ( & sDefinitions ) ) sDefinitions . Copy ( " Objects.ocd " ) ;
2009-05-08 13:28:41 +00:00
if ( ! C4DefinitionSelDlg : : SelectDefinitions ( GetScreen ( ) , & sDefinitions ) )
// user aborted during definition selection
return false ;
2014-09-27 14:04:48 +00:00
SCopy ( sDefinitions . getData ( ) , : : Game . DefinitionFilenames , ( sizeof Game . DefinitionFilenames ) - 1 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
// for no user change, just set default objects. Custom settings will override later anyway
2014-09-27 14:04:48 +00:00
SCopy ( " Objects.ocd " , : : Game . DefinitionFilenames ) ;
2009-05-08 13:28:41 +00:00
// set other default startup parameters
2014-09-27 14:04:48 +00:00
: : Game . fLobby = ! ! : : Game . NetworkActive ; // always lobby in network
: : Game . fObserve = false ;
C4ScenarioParameters * custom_params = pStartScen - > GetParameters ( ) ;
if ( custom_params ) : : Game . StartupScenarioParameters = * custom_params ; else : : Game . StartupScenarioParameters . Clear ( ) ;
2009-05-08 13:28:41 +00:00
// start with this set!
2014-09-27 14:04:48 +00:00
: : Application . OpenGame ( pStartScen - > GetEntryFilename ( ) . getData ( ) ) ;
2009-05-08 13:28:41 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4StartupScenSelDlg : : OpenFolder ( C4ScenarioListLoader : : Folder * pNewFolder )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// open it through loader
if ( ! pScenLoader ) return false ;
bool fSuccess = pScenLoader - > Load ( pNewFolder , false ) ;
UpdateList ( ) ;
UpdateSelection ( ) ;
if ( ! pMapData ) SetFocus ( pScenSelList , false ) ;
return fSuccess ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4StartupScenSelDlg : : DoOK ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
AbortRenaming ( ) ;
// get selected entry
C4ScenarioListLoader : : Entry * pSel = GetSelectedEntry ( ) ;
if ( ! pSel ) return false ;
// check if open is possible
StdStrBuf sError ;
2017-12-28 20:45:20 +00:00
bool CanHide = false ;
if ( ! pSel - > CanOpen ( sError , CanHide ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
GetScreen ( ) - > ShowMessage ( sError . getData ( ) , LoadResStr ( " IDS_MSG_CANNOTSTARTSCENARIO " ) , C4GUI : : Ico_Error ) ;
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// if CanOpen returned true but set an error message, that means it's a warning. Display it!
if ( sError . getLength ( ) )
2010-03-28 18:58:01 +00:00
{
2017-12-28 20:45:20 +00:00
if ( ! GetScreen ( ) - > ShowMessageModal ( sError . getData ( ) , LoadResStrNoAmp ( " IDS_DLG_STARTGAME " ) , C4GUI : : MessageDialog : : btnOKAbort , C4GUI : : Ico_Notify , CanHide ? & Config . Startup . HideMsgStartDedicated : nullptr ) )
2009-05-08 13:28:41 +00:00
// user chose to not start it
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// start it!
return pSel - > Start ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4StartupScenSelDlg : : DoBack ( bool fAllowClose )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
AbortRenaming ( ) ;
// if in a subfolder, try backtrace folders first
if ( pScenLoader & & pScenLoader - > FolderBack ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
UpdateList ( ) ;
UpdateSelection ( ) ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// while this isn't multithreaded, the dialog must not be aborted while initial load...
if ( pScenLoader & & pScenLoader - > IsLoading ( ) ) return false ;
// return to main screen
if ( fAllowClose )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Close ( false ) ;
return true ;
}
2010-03-28 18:58:01 +00:00
return false ;
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : DoRefresh ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pScenLoader & & ! pScenLoader - > IsLoading ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pScenSelList - > SelectNone ( false ) ;
pScenLoader - > ReloadCurrent ( ) ;
UpdateList ( ) ;
UpdateSelection ( ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : SetOpenButtonDefaultText ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pOpenBtn - > SetText ( LoadResStr ( " IDS_BTN_OPEN " ) ) ;
pOpenBtn - > SetToolTip ( LoadResStr ( " IDS_DLGTIP_SCENSELNEXT " ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4StartupScenSelDlg : : KeyRename ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// no rename in map mode
if ( pMapData ) return false ;
// not if renaming already
if ( IsRenaming ( ) ) return false ;
// forward to selected scenario list item
ScenListItem * pSel = GetSelectedItem ( ) ;
if ( ! pSel ) return false ;
return pSel - > KeyRename ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4StartupScenSelDlg : : KeyDelete ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// do not delete from map folder
if ( pMapData ) return false ;
// cancel renaming
AbortRenaming ( ) ;
// delete selected item: Confirmation first
ScenListItem * pSel = GetSelectedItem ( ) ;
if ( ! pSel ) return false ;
C4ScenarioListLoader : : Entry * pEnt = pSel - > GetEntry ( ) ;
StdStrBuf sWarning ;
2016-01-24 05:43:09 +00:00
sWarning . Format ( LoadResStr ( " IDS_MSG_PROMPTDELETE " ) , FormatString ( " %s %s " , pEnt - > GetTypeName ( ) . getData ( ) , pEnt - > GetName ( ) . getData ( ) ) . getData ( ) , pEnt - > GetEntryFilename ( ) . getData ( ) ) ;
2009-05-08 13:28:41 +00:00
GetScreen ( ) - > ShowRemoveDlg ( new C4GUI : : ConfirmationDialog ( sWarning . getData ( ) , LoadResStr ( " IDS_MNU_DELETE " ) ,
2010-03-28 18:58:01 +00:00
new C4GUI : : CallbackHandlerExPar < C4StartupScenSelDlg , ScenListItem * > ( this , & C4StartupScenSelDlg : : DeleteConfirm , pSel ) , C4GUI : : MessageDialog : : btnYesNo ) ) ;
2009-05-08 13:28:41 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : DeleteConfirm ( ScenListItem * pSel )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// deletion confirmed. Do it.
C4ScenarioListLoader : : Entry * pEnt = pSel - > GetEntry ( ) ;
if ( ! C4Group_DeleteItem ( pEnt - > GetEntryFilename ( ) . getData ( ) , true ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
StdStrBuf sMsg ; sMsg . Format ( " %s " , LoadResStr ( " IDS_FAIL_DELETE " ) ) ;
2009-06-05 16:53:56 +00:00
: : pGUI - > ShowMessageModal ( sMsg . getData ( ) , LoadResStr ( " IDS_MNU_DELETE " ) , C4GUI : : MessageDialog : : btnOK , C4GUI : : Ico_Error ) ;
2009-05-08 13:28:41 +00:00
return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// remove from scenario list
pScenSelList - > SelectEntry ( pSel - > GetNext ( ) , false ) ;
delete pEnt ;
delete pSel ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4StartupScenSelDlg : : KeyCheat ( )
2010-03-28 18:58:01 +00:00
{
2009-06-05 16:53:56 +00:00
return : : pGUI - > ShowRemoveDlg ( new C4GUI : : InputDialog ( LoadResStr ( " IDS_TEXT_ENTERMISSIONPASSWORD " ) , LoadResStr ( " IDS_DLG_MISSIONACCESS " ) , C4GUI : : Ico_Options ,
2010-03-28 18:58:01 +00:00
new C4GUI : : InputCallback < C4StartupScenSelDlg > ( this , & C4StartupScenSelDlg : : KeyCheat2 ) ,
false ) ) ;
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : KeyCheat2 ( const StdStrBuf & rsCheatCode )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Special character "-": remove mission password(s)
if ( SEqual2 ( rsCheatCode . getData ( ) , " - " ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
const char * szPass = rsCheatCode . getPtr ( 1 ) ;
if ( szPass & & * szPass )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
SRemoveModules ( Config . General . MissionAccess , szPass , false ) ;
UpdateList ( ) ;
UpdateSelection ( ) ;
return ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// No special character: add mission password(s)
const char * szPass = rsCheatCode . getPtr ( 0 ) ;
if ( szPass & & * szPass )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
SAddModules ( Config . General . MissionAccess , szPass , false ) ;
UpdateList ( ) ;
UpdateSelection ( ) ;
return ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : FocusScenList ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
SetFocus ( pScenSelList , false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : OnButtonScenario ( C4GUI : : Control * pEl )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// map button was clicked: Update selected scenario
if ( ! pMapData | | ! pEl ) return ;
C4ScenarioListLoader : : Entry * pSel = GetSelectedEntry ( ) , * pSel2 ;
pMapData - > OnButtonScenario ( pEl ) ;
pSel2 = GetSelectedEntry ( ) ;
if ( pSel & & pSel = = pSel2 )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// clicking on the selected scenario again starts it
DoOK ( ) ;
return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// the first click selects it
SetFocus ( pEl , false ) ;
UpdateSelection ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : DeselectAll ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Deselect all so current folder info is displayed
2015-12-15 05:25:19 +00:00
if ( GetFocus ( ) ) C4GUI : : GUISound ( " UI::Tick " ) ;
2016-11-02 23:58:02 +00:00
SetFocus ( nullptr , true ) ;
2009-05-08 13:28:41 +00:00
if ( pMapData ) pMapData - > ResetSelection ( ) ;
UpdateSelection ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : StartRenaming ( C4GUI : : RenameEdit * pNewRenameEdit )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pRenameEdit = pNewRenameEdit ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4StartupScenSelDlg : : AbortRenaming ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pRenameEdit ) pRenameEdit - > Abort ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2014-09-24 21:08:40 +00:00
void C4StartupScenSelDlg : : UpdateAchievements ( )
{
// Extract all achievements from activated player files and merge them
Achievements . Clear ( ) ;
char PlayerFilename [ _MAX_FNAME + 1 ] ;
C4Group PlayerGrp ;
for ( int i = 0 ; SCopySegment ( Config . General . Participants , i , PlayerFilename , ' ; ' , _MAX_FNAME , true ) ; i + + )
{
const char * szPlayerFilename = Config . AtUserDataPath ( PlayerFilename ) ;
if ( ! FileExists ( szPlayerFilename ) ) continue ;
if ( ! PlayerGrp . Open ( szPlayerFilename ) ) continue ;
C4PlayerInfoCore nfo ;
if ( ! nfo . Load ( PlayerGrp ) ) continue ;
Achievements . Merge ( nfo . Achievements ) ;
}
}
2014-10-03 12:02:06 +00:00
void C4StartupScenSelDlg : : OnLeagueOptionChanged ( )
{
if ( pSelectionOptions ) pSelectionOptions - > Update ( ) ;
}
2014-09-24 21:08:40 +00:00
// NICHT: 9, 7.2.2, 113-114, 8a
2014-09-27 14:04:48 +00:00