Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
839 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
This document is not UTF8. It was detected as JIS and converted to UTF8 for display.
diff --git a/src/Audio.cpp b/src/Audio.cpp
index 75f63b9..31bd92f 100644
--- a/src/Audio.cpp
+++ b/src/Audio.cpp
@@ -1,322 +1,322 @@
/***************************************************************************
Audio.cpp - description
-------------------
begin : Sat Jul 26 2003
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include "Audio.h"
#include "State.h"
#include "common.h"
#include "SDL_mixer.h"
#include <string>
#include <map>
#include <fstream>
typedef std::map<std::string,Mix_Chunk*> CSampleMap;
typedef std::map<std::string,Mix_Music*> CMusicMap;
typedef CSampleMap::iterator CSampleMapIterator;
typedef CMusicMap::iterator CMusicMapIterator;
COpenMortalAudio* Audio = NULL;
-
-/**
-\ingroup Media
-*/
+
+/**
+\ingroup Media
+*/
class COpenMortalAudioPriv
{
public:
bool m_bAudioOk;
int m_iNumChannels;
CSampleMap m_oSamples;
CMusicMap m_oMusics;
std::string m_sSoundDir;
};
#define SELF (*m_poPriv)
#define CHECKOK if ( ! m_poPriv->m_bAudioOk ) return;
COpenMortalAudio::COpenMortalAudio()
{
Audio = this;
m_poPriv = new COpenMortalAudioPriv;
m_poPriv->m_bAudioOk = false;
m_poPriv->m_iNumChannels = 0;
m_poPriv->m_sSoundDir = DATADIR;
m_poPriv->m_sSoundDir += "/sound/";
SDL_version compile_version;
const SDL_version *link_version;
MIX_VERSION(&compile_version);
debug( "compiled with SDL_mixer version: %d.%d.%d\n",
compile_version.major, compile_version.minor, compile_version.patch);
link_version=Mix_Linked_Version();
debug("running with SDL_mixer version: %d.%d.%d\n",
link_version->major, link_version->minor, link_version->patch);
if ( Mix_OpenAudio( MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT,
2 /*stereo*/, 1024*2 /*chunksize*/ ) < 0 )
{
debug("Mix_OpenAudio: %s\n", Mix_GetError());
SELF.m_bAudioOk = false;
}
else
{
SELF.m_bAudioOk = true;
}
m_poPriv->m_iNumChannels = Mix_AllocateChannels(10);
LoadSampleMap();
}
COpenMortalAudio::~COpenMortalAudio()
{
delete m_poPriv;
m_poPriv = NULL;
}
void COpenMortalAudio::LoadSampleMap()
{
CHECKOK;
std::string sFilename = m_poPriv->m_sSoundDir + "soundmap.txt";
std::ifstream oInput( sFilename.c_str() );
if ( !oInput.is_open() )
{
debug( "File %d could not be read.\n", sFilename.c_str() );
return;
}
std::string sLine;
while ( !oInput.eof() )
{
std::getline( oInput, sLine );
if ( sLine.size() == 0 ) continue;
size_t iFirstChar = sLine.find_first_not_of( " \t\r\n" );
if ( sLine.npos == iFirstChar
|| sLine[iFirstChar] == '#' )
{
// Empty line or comment
continue;
}
size_t iTitleEnd = sLine.find_first_of( " \t\r\n", iFirstChar );
if ( sLine.npos == iTitleEnd )
{
// Bad line
debug( "Bad line in config file: %s\n", sLine.c_str() );
continue;
}
size_t iFilenameStart = sLine.find_first_not_of( " \t\r\n", iTitleEnd );
if ( sLine.npos == iTitleEnd )
{
// Bad line
debug( "Bad line in config file: %s\n", sLine.c_str() );
continue;
}
size_t iFilenameEnd = sLine.find_last_not_of( " \t\r\n" );
std::string sSampleName = sLine.substr( iFirstChar, iTitleEnd-iFirstChar );
std::string sSampleFile = sLine.substr( iFilenameStart, iFilenameEnd - iFilenameStart + 1 );
debug( "MAPPING: '%s' => '%s'\n", sSampleName.c_str(), sSampleFile.c_str() );
LoadSample( sSampleFile.c_str(), sSampleName.c_str() );
}
oInput.close();
}
void COpenMortalAudio::LoadSample( const char* a_pcFilename, const char* a_pcSampleName )
{
CHECKOK;
std::string sSampleName( a_pcSampleName ? a_pcSampleName : a_pcFilename );
std::string sSampleFile = m_poPriv->m_sSoundDir + a_pcFilename;
if ( m_poPriv->m_oSamples.count( sSampleName ) )
{
debug( "Key %s already loaded", a_pcSampleName );
return;
}
Mix_Chunk *poSample;
poSample=Mix_LoadWAV(sSampleFile.c_str());
if(!poSample)
{
debug("Mix_LoadWAV: %s\n", Mix_GetError());
return;
}
m_poPriv->m_oSamples[ sSampleName ] = poSample;
}
void COpenMortalAudio::UnloadSample( const char* a_pcSampleName )
{
CSampleMapIterator it = m_poPriv->m_oSamples.find( a_pcSampleName );
if ( m_poPriv->m_oSamples.end() == it )
{
debug( "UnloadSample: sample %s not found", a_pcSampleName );
return;
}
Mix_FreeChunk( (*it).second );
m_poPriv->m_oSamples.erase( it );
}
void COpenMortalAudio::PlaySample( const char* a_pcSampleName )
{
Mix_Chunk* poSample;
CSampleMapIterator it = m_poPriv->m_oSamples.find(a_pcSampleName);
if ( m_poPriv->m_oSamples.end() == it )
{
// Try to load the sample..
LoadSample( a_pcSampleName );
it = m_poPriv->m_oSamples.find(a_pcSampleName);
if ( m_poPriv->m_oSamples.end() == it )
{
debug( "PlaySample: sample %s not found", a_pcSampleName );
return;
}
}
poSample = (*it).second;
int iVolume = g_oState.m_iSoundVolume * 128 / 100;
if ( poSample->volume != iVolume )
{
Mix_VolumeChunk( poSample, iVolume );
}
if ( -1 == Mix_PlayChannel( -1, poSample, 0 ) )
{
debug( "PlaySample: Mix_PlayChannel: %s\n",Mix_GetError());
}
}
void COpenMortalAudio::PlayFile( const char* a_pcFileName )
{
Mix_Chunk *poSample;
poSample=Mix_LoadWAV("sample.wav");
if(!poSample)
{
debug("Mix_LoadWAV: %s\n", Mix_GetError());
return;
}
if ( -1 == Mix_PlayChannel( -1, poSample, 0 ) )
{
debug( "PlaySample: Mix_PlayChannel: %s\n",Mix_GetError());
}
Mix_FreeChunk( poSample );
}
void COpenMortalAudio::LoadMusic( const char* a_pcFilename, const char* a_pcMusicName )
{
CHECKOK;
std::string sMusicName( a_pcMusicName ? a_pcMusicName : a_pcFilename );
std::string sMusicFile = DATADIR;
sMusicFile += "/sound/";
sMusicFile += a_pcFilename;
if ( m_poPriv->m_oMusics.count( sMusicName ) )
{
debug( "Key %s already loaded", a_pcMusicName );
return;
}
Mix_Music *poMusic;
poMusic=Mix_LoadMUS(sMusicFile.c_str());
if(!poMusic)
{
debug("Mix_LoadMUS: %s\n", Mix_GetError());
return;
}
m_poPriv->m_oMusics[ sMusicName ] = poMusic;
}
void COpenMortalAudio::UnloadMusic( const char* a_pcMusicName )
{
CMusicMapIterator it = m_poPriv->m_oMusics.find( a_pcMusicName );
if ( m_poPriv->m_oMusics.end() == it )
{
debug( "UnloadMusic: music %s not found", a_pcMusicName );
return;
}
Mix_FreeMusic( (*it).second );
m_poPriv->m_oMusics.erase( it );
}
void COpenMortalAudio::PlayMusic( const char* a_pcMusicName )
{
CMusicMapIterator it = m_poPriv->m_oMusics.find( a_pcMusicName );
if ( m_poPriv->m_oMusics.end() == it )
{
debug( "PlayMusic: music %s not found", a_pcMusicName );
return;
}
SetMusicVolume( g_oState.m_iMusicVolume );
//Mix_PlayMusic( (*it).second, -1 );
Mix_FadeInMusic( (*it).second, -1, 100 );
}
void COpenMortalAudio::FadeMusic( int a_iMilliSec )
{
Mix_FadeOutMusic( a_iMilliSec );
}
void COpenMortalAudio::SetMusicVolume( int a_iVolume )
{
Mix_VolumeMusic( a_iVolume * 128 / 100 );
}
void COpenMortalAudio::StopMusic()
{
Mix_HaltMusic();
}
bool COpenMortalAudio::IsMusicPlaying()
{
return Mix_PlayingMusic() != 0;
}
diff --git a/src/Audio.h b/src/Audio.h
index b630c71..d5e8b42 100644
--- a/src/Audio.h
+++ b/src/Audio.h
@@ -1,63 +1,63 @@
/***************************************************************************
Audio.h - description
-------------------
begin : Sat Jul 26 2003
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifndef OPENMORTAL_AUDIO_H
#define OPENMORTAL_AUDIO_H
#ifndef NULL
#define NULL 0
#endif
class COpenMortalAudioPriv;
-/**
-\class COpenMortalAudio
-\brief Audio services for OpenMortal (sound and music).
-\ingroup Media
-
-This class is a wrapper around SDL_Mixer
-*/
+/**
+\class COpenMortalAudio
+\brief Audio services for OpenMortal (sound and music).
+\ingroup Media
+
+This class is a wrapper around SDL_Mixer
+*/
class COpenMortalAudio
{
public:
COpenMortalAudio();
~COpenMortalAudio();
void LoadSampleMap();
public:
// Sample related methods
void LoadSample( const char* a_pcFilename, const char* a_pcSampleName=NULL );
void UnloadSample( const char* a_pcSampleName );
void PlaySample( const char* a_pcSampleName );
void PlayFile( const char* a_pcFilename );
// Music related methods
void LoadMusic( const char* a_pcFilename, const char* a_pcMusicName=NULL );
void UnloadMusic( const char* a_pcMusicName );
void PlayMusic( const char* a_pcMusicName );
void FadeMusic( int a_iMilliSec );
void SetMusicVolume( int a_iVolume );
void StopMusic();
bool IsMusicPlaying();
protected:
// Attributes
COpenMortalAudioPriv* m_poPriv;
};
extern COpenMortalAudio* Audio;
#endif // ifdef OPENMORTAL_AUDIO_H
diff --git a/src/Backend.cpp b/src/Backend.cpp
index 8c00633..ef6c405 100644
--- a/src/Backend.cpp
+++ b/src/Backend.cpp
@@ -1,519 +1,519 @@
/***************************************************************************
Backend.cpp - description
-------------------
begin : Mon Dec 9 2002
copyright : (C) 2002 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include "common.h"
#include "Backend.h"
#include "Audio.h"
#include "State.h"
#include <string>
#include <stdarg.h>
#include "MszPerl.h"
/***************************************************************************
PUBLIC EXPORTED VARIABLES
***************************************************************************/
PerlInterpreter* my_perl;
CBackend g_oBackend;
/***************************************************************************
PRIVATE VARIABLES (perl variable space)
***************************************************************************/
SV
*perl_bgx, *perl_bgy,
*perl_px[MAXPLAYERS], *perl_py[MAXPLAYERS], *perl_pf[MAXPLAYERS],
*perl_ph[MAXPLAYERS], *perl_phreal[MAXPLAYERS],
*perl_gametick, *perl_over, *perl_ko;
SV
*perl_doodad_x, *perl_doodad_y,
*perl_doodad_t, *perl_doodad_f,
*perl_doodad_dir, *perl_doodad_gfxowner,
*perl_doodad_text;
SV
*perl_sound, *perl_Translated;
/***************************************************************************
TRANSLATION SERVICES
***************************************************************************/
const char* Translate( const char* a_pcText )
{
dSP ;
ENTER ;
SAVETMPS ;
PUSHMARK(SP) ;
XPUSHs(sv_2mortal(newSVpv(a_pcText, 0)));
PUTBACK ;
call_pv("Translate", G_DISCARD);
FREETMPS ;
LEAVE ;
if ( NULL == perl_Translated )
{
perl_Translated = get_sv("Translated", TRUE);
}
return SvPV_nolen( perl_Translated );
}
const char* TranslateUTF8( const char* a_pcText )
{
dSP ;
ENTER ;
SAVETMPS ;
PUSHMARK(SP) ;
XPUSHs(sv_2mortal(newSVpv(a_pcText, 0)));
PUTBACK ;
call_pv("Translate", G_DISCARD);
FREETMPS ;
LEAVE ;
if ( NULL == perl_Translated )
{
perl_Translated = get_sv("Translated", TRUE);
}
return SvPVutf8_nolen( perl_Translated );
}
/***************************************************************************
BACKEND CLASS IMPLEMENTATION
***************************************************************************/
#define PERLEVAL(A) eval_pv(A, TRUE);
#define PERLCALL(PROC,A,B) { \
dSP; \
ENTER; \
SAVETMPS; \
PUSHMARK(SP); \
XPUSHs(sv_2mortal(newSViv(A))); \
XPUSHs(sv_2mortal(newSViv(B))); \
PUTBACK ; \
\
call_pv( (PROC), G_DISCARD ); \
\
FREETMPS; \
LEAVE; \
}
CBackend::CBackend()
{
m_iBgX = m_iBgY = 0;
m_iNumDoodads = m_iNumSounds = 0;
for ( int i=0; i<MAXPLAYERS; ++i )
{
m_aoPlayers[i].m_iX = m_aoPlayers[i].m_iY = 0;
m_aoPlayers[i].m_iFrame = 0;
m_aoPlayers[i].m_iHitPoints = 0;
}
}
CBackend::~CBackend()
{
if ( NULL != my_perl )
{
perl_destruct( my_perl );
perl_free( my_perl );
my_perl = NULL;
}
}
bool CBackend::Construct()
{
if ( my_perl != NULL )
{
// Already inited
return false;
}
perl_bgx = NULL;
perl_doodad_x = NULL;
std::string sFileName = DATADIR;
sFileName += "/script";
#ifndef _WINDOWS
chdir( sFileName.c_str() );
#endif
// char *perl_argv[] = {"", "-d:Trace", "Backend.pl"};
// int perl_argc = 3;
char *perl_argv[] = {"", "Backend.pl"};
int perl_argc = 2;
my_perl = perl_alloc();
if ( my_perl == NULL )
{
return false;
}
perl_construct( my_perl );
if ( perl_parse( my_perl, NULL, perl_argc, perl_argv, (char**)NULL ) )
{
char *error = SvPV_nolen(get_sv("@", FALSE));
fprintf( stderr, "%s", error );
return false;
}
if ( perl_run( my_perl ) )
{
char *error = SvPV_nolen(get_sv("@", FALSE));
fprintf( stderr, "%s", error );
return false;
}
return true;
}
const char* CBackend::PerlEvalF( const char* a_pcFormat, ... )
{
va_list ap;
va_start( ap, a_pcFormat );
char acBuffer[1024];
vsnprintf( acBuffer, 1023, a_pcFormat, ap );
acBuffer[1023] = 0;
eval_pv(acBuffer,FALSE);
const char *pcError = SvPV_nolen(get_sv("@", FALSE));
if ( pcError && *pcError )
{
debug( "eval '%s': '%s'\n", acBuffer, pcError );
exit(0);
}
va_end( ap );
return pcError;
}
const char* CBackend::GetPerlString( const char* acScalarName )
{
SV* poScalar = get_sv( acScalarName, FALSE );
if ( NULL == poScalar )
{
return "";
}
return SvPV_nolen( poScalar );
}
int CBackend::GetPerlInt( const char* acScalarName )
{
SV* poScalar = get_sv( acScalarName, FALSE );
if ( NULL == poScalar )
{
return 0;
}
return SvIV( poScalar );
}
/** Returns the total number of registered fighters in the backend.
This may be more than the actual number of playable characters, as
some or many characters may not be ready or installed.
\see GetFighterID
\see GetNumberOfAvailableFighters
*/
int CBackend::GetNumberOfFighters()
{
PerlEvalF( "$::CppNumberOfFighters = scalar keys %%::FighterStats;" );
return GetPerlInt( "CppNumberOfFighters" );
}
/** Returns the ID of a fighter. The index parameter should start from
zero, and be less than the value returned by GetNumberOfFighters().
\see GetNumberOfFighters
*/
FighterEnum CBackend::GetFighterID( int a_iIndex )
{
PerlEvalF( "$::CppFighterID = (sort { $a - $b } keys %%::FighterStats)[%d];", a_iIndex );
return (FighterEnum) GetPerlInt( "CppFighterID" );
}
/** Returns the number of fighters that are locally availaible for play.
This number is smaller or equal to the value returned by GetNumberOfFighters().
Note that the method GetFighterID() returns ID's of non-available
fighters as well, so it can only be used in conjunction with GetNumberOfFighters()
\see GetNumberOfFighters
*/
int CBackend::GetNumberOfAvailableFighters()
{
PerlEvalF( "GetNumberOfAvailableFighters();" ); // Defined in FighterStats.pl
return GetPerlInt( "CppNumberOfAvailableFighters" );
}
-
+
/**
-Makes the perl interpreter advance from the current scene to the next one.
-This should be called a constant number of time per second to make the game
-running seamlessly. Most speedup or slowdown effects are accomplished by
-changing the frequency at which this method is called.
+Makes the perl interpreter advance from the current scene to the next one.
+This should be called a constant number of time per second to make the game
+running seamlessly. Most speedup or slowdown effects are accomplished by
+changing the frequency at which this method is called.
*/
void CBackend::AdvancePerl()
{
PerlEvalF("GameAdvance();");
}
void CBackend::ReadFromPerl()
{
int i;
if ( perl_bgx == NULL )
{
perl_gametick = get_sv("gametick", TRUE);
perl_bgx = get_sv("bgx", TRUE);
perl_bgy = get_sv("bgy", TRUE);
perl_over= get_sv("over", TRUE);
perl_ko = get_sv("ko", TRUE);
char acVarName[128];
for ( i=0; i<MAXPLAYERS; ++i )
{
sprintf( acVarName, "p%dx", i+1 );
perl_px[i] = get_sv(acVarName, TRUE);
sprintf( acVarName, "p%dy", i+1 );
perl_py[i] = get_sv(acVarName, TRUE);
sprintf( acVarName, "p%df", i+1 );
perl_pf[i] = get_sv(acVarName, TRUE);
sprintf( acVarName, "p%dh", i+1 );
perl_ph[i] = get_sv(acVarName, TRUE);
sprintf( acVarName, "p%dhreal", i+1 );
perl_phreal[i] = get_sv(acVarName, TRUE);
}
}
m_iGameTick = SvIV( perl_gametick );
m_iBgX = SvIV( perl_bgx );
m_iBgY = SvIV( perl_bgy );
m_iGameOver = SvIV( perl_over );
m_bKO = SvIV( perl_ko ) != 0;
for ( i=0; i<g_oState.m_iNumPlayers; ++i )
{
m_aoPlayers[i].m_iX = SvIV( perl_px[i] );
m_aoPlayers[i].m_iY = SvIV( perl_py[i] );
m_aoPlayers[i].m_iFrame = SvIV( perl_pf[i] );
m_aoPlayers[i].m_iHitPoints = SvIV( perl_ph[i] ) / 10;
m_aoPlayers[i].m_iRealHitPoints = SvIV( perl_phreal[i] );
}
// READ DOODAD DATA
if ( perl_doodad_x == NULL )
{
perl_doodad_x = get_sv("doodad_x", TRUE);
perl_doodad_y = get_sv("doodad_y", TRUE);
perl_doodad_t = get_sv("doodad_t", TRUE);
perl_doodad_f = get_sv("doodad_f", TRUE);
perl_doodad_dir = get_sv("doodad_dir", TRUE);
perl_doodad_gfxowner = get_sv("doodad_gfxowner", TRUE);
perl_doodad_text = get_sv("doodad_text", TRUE);
}
for ( m_iNumDoodads=0; m_iNumDoodads<MAXDOODADS; ++m_iNumDoodads )
{
PERLEVAL("GetNextDoodadData();");
SDoodad& oDoodad = m_aoDoodads[m_iNumDoodads];
oDoodad.m_iType = SvIV(perl_doodad_t);
if ( oDoodad.m_iType < 0 )
{
break;
}
oDoodad.m_iX = SvIV(perl_doodad_x);
oDoodad.m_iY = SvIV(perl_doodad_y);
oDoodad.m_iFrame = SvIV(perl_doodad_f);
oDoodad.m_iDir = SvIV(perl_doodad_dir);
oDoodad.m_iGfxOwner = SvIV(perl_doodad_gfxowner);
if ( oDoodad.m_iType == 0 )
{
oDoodad.m_sText = SvPV_nolen(perl_doodad_text);
}
else
{
oDoodad.m_sText = "";
}
}
// READ SOUND DATA
if ( perl_sound == NULL )
{
perl_sound = get_sv("sound", TRUE);
}
for ( m_iNumSounds=0; m_iNumSounds<MAXSOUNDS; ++m_iNumSounds )
{
PERLEVAL("GetNextSoundData();");
const char* pcSound = SvPV_nolen(perl_sound);
if ( NULL == pcSound
|| 0 == *pcSound )
{
break;
}
m_asSounds[ m_iNumSounds ] = pcSound;
//Audio->PlaySample( pcSound );
}
}
bool CBackend::IsDead( int a_iPlayer )
{
return m_aoPlayers[ a_iPlayer ].m_iRealHitPoints <= 0;
}
void CBackend::PlaySounds()
{
for ( int i=0; i<m_iNumSounds; ++i )
{
Audio->PlaySample( m_asSounds[i].c_str() );
}
}
/***************************************************************************
PLAYBACK STRING CONVERSION ROUTINES
***************************************************************************/
void CBackend::WriteToString( std::string& a_rsOutString )
{
char acBuffer[2048];
int iNumChars = sprintf( acBuffer, "%d %d %d %d %d %d %d %d %d %d %d ",
m_iBgX, m_iBgY,
m_aoPlayers[0].m_iX, m_aoPlayers[0].m_iY, m_aoPlayers[0].m_iFrame, m_aoPlayers[0].m_iHitPoints,
m_aoPlayers[1].m_iX, m_aoPlayers[1].m_iY, m_aoPlayers[1].m_iFrame, m_aoPlayers[1].m_iHitPoints,
m_iNumDoodads );
int i;
for ( i = 0; i<m_iNumDoodads; ++i )
{
SDoodad& roDoodad = m_aoDoodads[i];
iNumChars += sprintf( acBuffer+iNumChars, "%d %d %d %d %d %d %d %s ",
roDoodad.m_iX, roDoodad.m_iY, roDoodad.m_iType, roDoodad.m_iFrame,
roDoodad.m_iDir, roDoodad.m_iGfxOwner,
roDoodad.m_sText.size(), roDoodad.m_sText.c_str() );
}
iNumChars += sprintf( acBuffer+iNumChars, "%d ", m_iNumSounds );
for ( i = 0; i<m_iNumSounds; ++i )
{
iNumChars += sprintf( acBuffer+iNumChars, " %d %s",
m_asSounds[i].size(), m_asSounds[i].c_str() );
}
// debug( "Frame: '%s'\n", acBuffer );
a_rsOutString = acBuffer;
}
void CBackend::ReadFromString( const std::string& a_rsString )
{
ReadFromString( a_rsString.c_str() );
}
void CBackend::ReadFromString( const char* a_pcBuffer )
{
if ( strlen( a_pcBuffer ) < 10 )
{
m_iNumDoodads = m_iNumSounds = 0;
return;
}
int iNumMatches;
int iOffset, iTotal;
iNumMatches = sscanf( a_pcBuffer, "%d %d %d %d %d %d %d %d %d %d %d%n",
&m_iBgX, &m_iBgY,
&m_aoPlayers[0].m_iX, &m_aoPlayers[0].m_iY, &m_aoPlayers[0].m_iFrame, &m_aoPlayers[0].m_iHitPoints,
&m_aoPlayers[1].m_iX, &m_aoPlayers[1].m_iY, &m_aoPlayers[1].m_iFrame, &m_aoPlayers[1].m_iHitPoints,
&m_iNumDoodads, &iTotal );
if ( m_iNumDoodads > MAXDOODADS )
{
m_iNumDoodads = m_iNumSounds = 0;
return;
}
int i, j;
for ( i=0; i<m_iNumDoodads; ++i )
{
SDoodad& roDoodad = m_aoDoodads[i];
iNumMatches += sscanf( a_pcBuffer+iTotal, "%d %d %d %d %d %d %d %n",
&roDoodad.m_iX, &roDoodad.m_iY, &roDoodad.m_iType, &roDoodad.m_iFrame,
&roDoodad.m_iDir, &roDoodad.m_iGfxOwner,
&j, &iOffset );
iTotal += iOffset;
roDoodad.m_sText.assign( a_pcBuffer + iTotal, j );
iTotal += j;
}
iNumMatches += sscanf( a_pcBuffer + iTotal, "%d%n",
&m_iNumSounds, &iOffset );
if ( m_iNumSounds > MAXSOUNDS )
{
m_iNumSounds = 0;
return;
}
iTotal += iOffset;
for ( i=0; i<m_iNumSounds; ++i )
{
iNumMatches += sscanf( a_pcBuffer+iTotal, "%d %n",
&j, &iOffset );
iTotal += iOffset;
m_asSounds[i].assign( a_pcBuffer + iTotal, j );
iTotal += j;
}
}
diff --git a/src/Backend.h b/src/Backend.h
index 11d2dfa..e4d3533 100644
--- a/src/Backend.h
+++ b/src/Backend.h
@@ -1,105 +1,105 @@
/***************************************************************************
Backend.h - description
-------------------
begin : Sun Dec 8 2002
copyright : (C) 2002 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifndef BACKEND_H
#define BACKEND_H
#include <string>
#include "FighterEnum.h"
class CRlePack;
#define MAXDOODADS 20
#define MAXSOUNDS 20
-
-/**
-\class CBackend
-\ingroup GameLogic
-\brief The CBackend class provides access to the perl game engine.
-
-The backend maintains just about all game-relevant data, such as fighters,
-player information, doodads, current game state, and so forth. CBackend
-provides access for the frontend to the backend's variables and functions.
-Some of this is done via custom methods (such as GetNumberOfFighters()),
-but certain functions are only available via the "generic" perl interface,
-PerlEvalF().
-
-It is the CBackend's job to provide variables which describe the current
-\i scene to the frontend. The backend can
-
-\li Read the scene from the Perl backend.
-\li Write the scene into a string
-\li Read the scene from a string.
-
-The string conversion routines are used for saving replays and instant
-playback.
-*/
+
+/**
+\class CBackend
+\ingroup GameLogic
+\brief The CBackend class provides access to the perl game engine.
+
+The backend maintains just about all game-relevant data, such as fighters,
+player information, doodads, current game state, and so forth. CBackend
+provides access for the frontend to the backend's variables and functions.
+Some of this is done via custom methods (such as GetNumberOfFighters()),
+but certain functions are only available via the "generic" perl interface,
+PerlEvalF().
+
+It is the CBackend's job to provide variables which describe the current
+\i scene to the frontend. The backend can
+
+\li Read the scene from the Perl backend.
+\li Write the scene into a string
+\li Read the scene from a string.
+
+The string conversion routines are used for saving replays and instant
+playback.
+*/
class CBackend
{
public:
// Lifecycle
CBackend();
~CBackend();
bool Construct();
// Miscellaneous
const char* PerlEvalF( const char* a_pcFormat, ... );
const char* GetPerlString( const char* a_pcScalarName );
int GetPerlInt( const char* a_pcScalarName );
// Fighter enumeration
int GetNumberOfFighters();
FighterEnum GetFighterID( int a_iIndex );
int GetNumberOfAvailableFighters();
// Game data
void AdvancePerl();
void ReadFromPerl();
bool IsDead( int a_iPlayer );
void PlaySounds();
void WriteToString( std::string& a_rsOutString );
void ReadFromString( const std::string& a_rsString );
void ReadFromString( const char* a_pcBuffer );
public:
int m_iGameTick;
int m_iGameOver;
bool m_bKO;
int m_iBgX, m_iBgY;
int m_iNumDoodads;
int m_iNumSounds;
struct SPlayer
{
int m_iX, m_iY, m_iFrame, m_iHitPoints, m_iRealHitPoints;
} m_aoPlayers[MAXPLAYERS];
struct SDoodad
{
int m_iX, m_iY, m_iType, m_iFrame;
int m_iDir, m_iGfxOwner;
std::string m_sText;
} m_aoDoodads[ MAXDOODADS ];
std::string m_asSounds[ MAXSOUNDS ];
};
extern CBackend g_oBackend;
#endif
diff --git a/src/Background.cpp b/src/Background.cpp
index 5a3df8f..f84eda8 100644
--- a/src/Background.cpp
+++ b/src/Background.cpp
@@ -1,167 +1,167 @@
/***************************************************************************
Background.cpp - description
-------------------
begin : Sun Jan 11 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
#include "Background.h"
#include "SDL.h"
#include "sge_surface.h"
#include "gfx.h"
#include "common.h"
#include <string>
#include <fstream>
/* Calculating background distance:
BW: background width
SW: screen width (640)
AW: arena width (1920)
D: distance
(AW - SW) * D = BW - SW
D = (BW - SW) / (AW - SW)
D = (BW - 640) / 1280
*/
CBackground::CBackground()
{
m_bOK = false;
m_iNumber = 0;
m_iFirstExtraLayer = 0;
}
CBackground::~CBackground()
{
Clear();
}
void CBackground::Clear()
{
for( CLayerIterator it=m_aLayers.begin(); it!=m_aLayers.end(); ++it )
{
SBackgroundLayer& roLayer = *it;
if ( roLayer.m_poSurface )
{
SDL_FreeSurface( roLayer.m_poSurface );
roLayer.m_poSurface = NULL;
}
}
m_aLayers.clear();
m_bOK = false;
m_iNumber = 0;
m_iFirstExtraLayer = 0;
}
void CBackground::Load( int a_iBackgroundNumber )
{
char acFilename[FILENAME_MAX+1];
// 1. Try loading a description-based background.
sprintf( acFilename, "%s/gfx/level%d.desc", DATADIR, a_iBackgroundNumber );
std::ifstream oInput( acFilename );
if ( !oInput.is_open() )
{
// Description-based background not found. Try simple image-based
// background.
sprintf( acFilename, "level%d.jpg", a_iBackgroundNumber );
SDL_Surface* poImage = LoadBackground( acFilename, 64 );
if ( NULL == poImage )
{
// Couldn't load background.
return;
}
SBackgroundLayer oLayer;
oLayer.m_poSurface = poImage;
oLayer.m_iXOffset = 0;
oLayer.m_iYOffset = 0;
oLayer.m_dDistance = 1.0;
m_aLayers.push_back( oLayer );
m_iNumber = a_iBackgroundNumber;
m_iFirstExtraLayer = m_aLayers.size();
m_bOK = true;
return;
}
// 2. Parse description.
int iNumLayers;
oInput >> iNumLayers;
for ( int i=0; i<iNumLayers; ++i )
{
SBackgroundLayer oLayer;
std::string sFilename;
oInput >> sFilename >> oLayer.m_iXOffset >> oLayer.m_iYOffset >> oLayer.m_dDistance;
oLayer.m_poSurface = LoadBackground( sFilename.c_str(), 64, 0 );
if ( NULL == oLayer.m_poSurface )
{
continue;
}
m_aLayers.push_back( oLayer );
}
m_iFirstExtraLayer = m_aLayers.size();
m_bOK = m_aLayers.size() > 0;
m_iNumber = m_bOK ? a_iBackgroundNumber : 0;
}
/** Adds a layer to the background.
The background object will assume ownership of the given structure, including
the surface within.
*/
void CBackground::AddExtraLayer( const SBackgroundLayer& a_roLayer )
{
m_aLayers.push_back( a_roLayer );
}
void CBackground::DeleteExtraLayers()
{
- while ( m_aLayers.size() > m_iFirstExtraLayer )
+ while ( (int)m_aLayers.size() > m_iFirstExtraLayer )
{
SDL_FreeSurface( m_aLayers.back().m_poSurface );
m_aLayers.pop_back();
}
}
bool CBackground::IsOK()
{
return m_bOK;
}
void CBackground::Draw( int a_iXPosition, int a_iYPosition, int a_iYOffset )
{
for ( CLayerIterator it = m_aLayers.begin(); it != m_aLayers.end(); ++it )
{
SBackgroundLayer& roLayer = *it;
sge_Blit( roLayer.m_poSurface, gamescreen,
0, 0, // source position
roLayer.m_iXOffset - (int)( ((double)a_iXPosition) * roLayer.m_dDistance ),
roLayer.m_iYOffset - (int)( ((double)a_iYPosition) * roLayer.m_dDistance ) + a_iYOffset,
gamescreen->w*3 + 100, gamescreen->h + 100 );
}
}
diff --git a/src/Background.h b/src/Background.h
index 22c5c26..8d07fef 100644
--- a/src/Background.h
+++ b/src/Background.h
@@ -1,67 +1,67 @@
/***************************************************************************
Background.h - description
-------------------
begin : Sun Jan 11 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
#ifndef __BACKGROUND_H
#define __BACKGROUND_H
#include <vector>
-struct SDL_Surface;
-
-/**
-\class CBackground
-\ingroup GameLogic
-\brief The CBackground class draws the multi-layered background of each arena.
-
-The backgrounds are identified by their number. Single-layer backgrounds do
-not have description files. Multi-layer backgrounds have a description file
-which has the following format:
-\li First line: number of layers(int)
-\li For each layer: First line: filename (relative to gfx directory)
-\li For each layer: Second line: x-displacement(int) y-displacement(int) distance(double)
-
-Extra layers can be added to the background. These are for dead fighters in
-team game mode.
+struct SDL_Surface;
+
+/**
+\class CBackground
+\ingroup GameLogic
+\brief The CBackground class draws the multi-layered background of each arena.
+
+The backgrounds are identified by their number. Single-layer backgrounds do
+not have description files. Multi-layer backgrounds have a description file
+which has the following format:
+\li First line: number of layers(int)
+\li For each layer: First line: filename (relative to gfx directory)
+\li For each layer: Second line: x-displacement(int) y-displacement(int) distance(double)
+
+Extra layers can be added to the background. These are for dead fighters in
+team game mode.
*/
class CBackground
{
-public:
- struct SBackgroundLayer
- {
- SDL_Surface* m_poSurface;
- int m_iXOffset;
- int m_iYOffset;
- double m_dDistance;
- };
-
-private:
- typedef std::vector<SBackgroundLayer> CLayerVector;
- typedef CLayerVector::iterator CLayerIterator;
-
- void Clear();
-
+public:
+ struct SBackgroundLayer
+ {
+ SDL_Surface* m_poSurface;
+ int m_iXOffset;
+ int m_iYOffset;
+ double m_dDistance;
+ };
+
+private:
+ typedef std::vector<SBackgroundLayer> CLayerVector;
+ typedef CLayerVector::iterator CLayerIterator;
+
+ void Clear();
+
public:
CBackground();
~CBackground();
void Load( int a_iBackgroundNumber );
void AddExtraLayer( const SBackgroundLayer& a_roLayer );
void DeleteExtraLayers();
bool IsOK();
void Draw( int a_iXPosition, int a_iYPosition, int a_iYOffset );
protected:
int m_iNumber;
int m_iFirstExtraLayer;
bool m_bOK;
CLayerVector m_aLayers;
};
#endif // __BACKGROUND_H
diff --git a/src/Chooser.h b/src/Chooser.h
index 3c63d12..c632f25 100644
--- a/src/Chooser.h
+++ b/src/Chooser.h
@@ -1,77 +1,77 @@
/***************************************************************************
Chooser.h - description
-------------------
begin : Tue Jan 27 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
#ifndef CHOOSER_H
#define CHOOSER_H
#include "FighterEnum.h"
#include "common.h"
#include "SDL.h"
-/**
-CChooser is a control for choosing fighters.
-It is used on the fighter selection screens.
-\ingroup PlayerSelect
+/**
+CChooser is a control for choosing fighters.
+It is used on the fighter selection screens.
+\ingroup PlayerSelect
*/
class CChooser
{
public:
CChooser();
~CChooser();
void Start( SDL_Surface* m_poScreen );
void Stop();
void Resize( int x1, int y1, int x2, int y2 );
void Draw();
void MarkFighter( FighterEnum a_enFighter, Uint32 a_iColor );
SDL_Surface* GetPortrait( FighterEnum a_enFighter );
void DrawPortrait( FighterEnum a_enFighter, SDL_Surface* a_poScreen, const SDL_Rect& a_roRect );
FighterEnum GetCurrentFighter( int a_iPlayer );
void MoveRectangle( int a_iPlayer, int a_iDirection );
void SetRectangle( int a_iPlayer, FighterEnum a_enFighter );
void SetRectangleVisible( int a_iPlayer, bool a_bVisible );
bool IsRectangleVisible( int a_iPlayer );
void DrawRectangles( int a_iStartingWith );
SDL_Rect GetFighterRect( FighterEnum a_enFighter );
protected:
void Init();
int FighterToPosition( FighterEnum a_enFighter );
FighterEnum PositionToFighter( int a_iPosition );
SDL_Rect GetRect( int a_iPosition );
void ClearRectangle( int a_iPlayer );
void DrawRectangle( int a_iPlayer );
void DrawRectangle( int a_iPosition, Uint32 a_iColor );
protected:
SDL_Surface* m_poScreen;
FighterEnum m_aenFighters[100];
SDL_Surface* m_apoPortraits[100];
bool m_abRectangleVisible[MAXPLAYERS];
int m_aiPlayerPosition[MAXPLAYERS];
Uint32 m_aiColors[MAXPLAYERS];
int x1, y1, x2, y2;
int m_iNumberOfFighters;
int m_iRows;
int m_iCols;
};
extern CChooser g_oChooser;
#endif // CHOOSER_H
diff --git a/src/Demo.cpp b/src/Demo.cpp
index 8d6ec9a..56822f2 100644
--- a/src/Demo.cpp
+++ b/src/Demo.cpp
@@ -1,510 +1,510 @@
/***************************************************************************
Demo.cpp - description
-------------------
begin : Wed Aug 16 22:18:47 CEST 2003
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include "FlyingChars.h"
#include "SDL.h"
#include "State.h"
#include "gfx.h"
#include "common.h"
#include "Backend.h"
#include "RlePack.h"
#include "FighterStats.h" // #includes Demo.h
#include "Event.h"
#include "config.h"
CDemo::CDemo()
{
m_poFlyingChars = NULL;
m_bAdvanceGame = false;
}
CDemo::~CDemo()
{
delete m_poFlyingChars;
m_poFlyingChars = NULL;
}
int CDemo::Advance( int a_iNumFrames, bool a_bFlip )
{
int iRetVal = 1;
if ( a_iNumFrames > 5 )
a_iNumFrames = 5;
if ( m_poBackground )
{
SDL_BlitSurface( m_poBackground, NULL, gamescreen, NULL );
}
if ( m_poFlyingChars )
{
iRetVal &= AdvanceFlyingChars( a_iNumFrames );
m_poFlyingChars->Draw();
}
if ( m_bAdvanceGame )
{
iRetVal &= AdvanceGame( a_iNumFrames );
//@ DRAW GAME?
}
if ( a_bFlip )
{
SDL_Flip( gamescreen );
}
return iRetVal;
}
int CDemo::AdvanceFlyingChars( int a_iNumFrames )
{
m_poFlyingChars->Advance( a_iNumFrames );
return ( m_poFlyingChars->IsDone() ? 1 : 0 );
}
int CDemo::AdvanceGame( int a_iNumFrames )
{
for ( int i=0; i<a_iNumFrames; ++i )
{
g_oBackend.AdvancePerl();
}
return 0;
}
int CDemo::Run()
{
SState::TGameMode enOriginalGameMode = g_oState.m_enGameMode;
int thisTick, lastTick, firstTick, gameSpeed;
gameSpeed = 12;
/*
if ( m_poBackground )
{
DrawTextMSZ( "Press Escape for the menu", impactFont, 10, 450, UseShadow, C_WHITE, m_poBackground );
}
*/
thisTick = SDL_GetTicks() / gameSpeed;
lastTick = thisTick - 1;
firstTick = SDL_GetTicks() / gameSpeed;
while ( 1 )
{
// 1. Wait for the next tick (on extremely fast machines..)
while (1)
{
thisTick = SDL_GetTicks() / gameSpeed;
if ( thisTick==lastTick )
{
SDL_Delay(1);
}
else
{
break;
}
}
// 2. Call ADVANCE.
int iRetVal = Advance(thisTick-lastTick, true);
lastTick = thisTick;
if ( iRetVal )
{
return 0;
}
// 3. Handle events.
SDL_Event oSdlEvent;
SMortalEvent oEvent;
while ( SDL_PollEvent(&oSdlEvent) )
{
TranslateEvent( &oSdlEvent, &oEvent );
switch (oEvent.m_enType)
{
case Me_QUIT:
g_oState.m_bQuitFlag = true;
break;
case Me_MENU:
OnMenu();
break;
case Me_PLAYERKEYDOWN:
if ( oEvent.m_iKey < 4 )
break;
if ( SState::IN_DEMO == g_oState.m_enGameMode )
{
OnMenu();
}
else
{
return 0;
}
break;
case Me_SKIP:
return 0;
case Me_NOTHING:
if ( SDL_KEYDOWN == oSdlEvent.type && SState::IN_DEMO == g_oState.m_enGameMode )
{
OnMenu();
continue;
}
break;
case Me_PLAYERKEYUP:
break;
} // switch
} // while MortalPollEvent
if ( g_oState.m_enGameMode != enOriginalGameMode
|| g_oState.m_bQuitFlag )
{
return 1;
}
} // while 1;
}
void CDemo::OnMenu()
{
::DoMenu();
}
-/**
-\ingroup Demo
-*/
+/**
+\ingroup Demo
+*/
class CCreditsDemo: public CDemo
{
public:
CCreditsDemo()
{
m_poBackground = LoadBackground( "Credits.jpg", 240 );
SDL_UnlockSurface( m_poBackground );
DrawGradientText( "Credits", titleFont, 20, m_poBackground );
SDL_Flip( m_poBackground );
SDL_Rect oRect;
oRect.x = 110; oRect.w = gamescreen->w - 220;
oRect.y = 100; oRect.h = 350;
m_poFlyingChars = new CFlyingChars( creditsFont, oRect );
m_sText1 = Translate( "CreditsText1" );
m_sText2 = Translate( "CreditsText2" );
m_sText3 = Translate( "CreditsText3" );
m_poFlyingChars->AddText( m_sText1.c_str(), CFlyingChars::FC_AlignCenter, true );
m_poFlyingChars->AddText( m_sText2.c_str(), CFlyingChars::FC_AlignJustify, true );
m_poFlyingChars->AddText( m_sText3.c_str(), CFlyingChars::FC_AlignCenter, true );
m_poFlyingChars->AddText( "\n\n\n\n\n\n:)", CFlyingChars::FC_AlignRight, true );
}
protected:
std::string m_sText1;
std::string m_sText2;
std::string m_sText3;
};
-/**
-\ingroup Demo
-*/
+/**
+\ingroup Demo
+*/
class CEuDemo: public CDemo
{
public:
CEuDemo()
{
m_poBackground = LoadBackground( "eu.jpg", 240 );
SDL_UnlockSurface( m_poBackground );
SDL_Rect oRect;
oRect.x = 50; oRect.w = gamescreen->w - 100;
oRect.y = 50; oRect.h = gamescreen->h - 100;
m_poFlyingChars = new CFlyingChars( storyFont, oRect, -1 );
m_sText1 = "This version of OpenMortal was released on 2004-05-01, the day that Hungary "
"along with 9 other countries joined the European Union.\n\n\n\n\n\n\n\n\n";
m_poFlyingChars->AddText( m_sText1.c_str(), CFlyingChars::FC_AlignJustify, true );
}
protected:
std::string m_sText1;
};
-/**
-\ingroup Demo
-*/
+/**
+\ingroup Demo
+*/
class CStory1Demo: public CDemo
{
public:
CStory1Demo()
{
m_poBackground = LoadBackground( "Story1.jpg", 240 );
SDL_UnlockSurface( m_poBackground );
SDL_Rect oRect;
oRect.x = 50; oRect.w = gamescreen->w - 100;
oRect.y = 50; oRect.h = gamescreen->h - 100;
m_poFlyingChars = new CFlyingChars( storyFont, oRect, -1 );
m_sText1 = Translate( "Story1Text" );
m_poFlyingChars->AddText( m_sText1.c_str(), CFlyingChars::FC_AlignJustify, true );
}
protected:
std::string m_sText1;
};
-/**
-\ingroup Demo
-*/
+/**
+\ingroup Demo
+*/
class CStory2Demo: public CDemo
{
public:
CStory2Demo()
{
m_poBackground = LoadBackground( "Story2.jpg", 240 );
SDL_UnlockSurface( m_poBackground );
SDL_Rect oRect;
oRect.x = 50; oRect.w = gamescreen->w - 100;
oRect.y = 50; oRect.h = gamescreen->h - 100;
m_poFlyingChars = new CFlyingChars( storyFont, oRect, -1 );
m_sText1 = Translate( "Story2Text" );
m_poFlyingChars->AddText( m_sText1.c_str(), CFlyingChars::FC_AlignJustify, true );
}
protected:
std::string m_sText1;
};
-/**
-\ingroup Demo
-*/
+/**
+\ingroup Demo
+*/
class CMainScreenDemo: public CDemo
{
public:
CMainScreenDemo()
{
i = 0;
m_iTimeLeft = 50;
m_poBackground = LoadBackground( "Mortal.jpg", 240 );
DrawTextMSZ( "Version " VERSION " ゥ 2003-2004 by UPi", inkFont, 320, 430, UseShadow | AlignHCenter, C_WHITE, m_poBackground, false );
std::string sStaffFilename = DATADIR;
sStaffFilename += "/characters/STAFF.DAT";
m_poPack = new CRlePack( sStaffFilename.c_str(), 255 );
m_poPack->ApplyPalette();
SDL_BlitSurface( m_poBackground, NULL, gamescreen, NULL );
SDL_Flip( gamescreen );
int j, k, l;
for ( j=0; j<14; ++j )
{
m_aiOrder[j] = j;
m_bShown[j] = false;
}
for ( j=0; j<14; ++j )
{
k = rand() % 14;
l = m_aiOrder[j]; m_aiOrder[j] = m_aiOrder[k]; m_aiOrder[k] = l;
}
}
~CMainScreenDemo()
{
delete m_poPack;
m_poPack = NULL;
}
int Advance( int a_iNumFrames, bool a_bFlip )
{
static int x[14] = {
0, 26, 67, 125, 159, 209,
249, 289, 358, 397, 451, 489, 532, 161 };
static int y[14] = {
5, 4, 5, 5, 5, 7,
4, 0, 7, 5, 5, 6, 5, 243 };
m_iTimeLeft -= a_iNumFrames;
if ( m_iTimeLeft <= 0
&& i >= 14 )
{
return 1;
}
if ( m_iTimeLeft <= 0 )
{
m_bShown[ m_aiOrder[i] ] = true;
for ( int j=0; j<=14; ++j )
{
if ( m_bShown[j] )
{
m_poPack->Draw( j, x[j], y[j], false );
}
}
SDL_Flip( gamescreen );
++i;
m_iTimeLeft += 20;
if ( i >= 14 )
{
m_iTimeLeft += 50;
}
}
return 0;
}
protected:
CRlePack* m_poPack;
int m_iTimeLeft;
int i;
int m_aiOrder[14];
bool m_bShown[14];
};
void DoReplayDemo()
{
static int aiOrder[6] = {-1, -1, -1, -1, -1, -1};
static int iNext = 0;
if ( aiOrder[0]<0 )
{
// shuffle
int i, j, k;
for ( i=0; i<6; ++i ) aiOrder[i]=i;
for ( i=0; i<6; ++i )
{
j = rand() % 6;
k = aiOrder[i];
aiOrder[i] = aiOrder[j];
aiOrder[j] = k;
}
iNext = 0;
}
char acFilename[1024];
#if defined (MACOSX)
//[segabor] path fix.
sprintf( acFilename, "%s/demo%d.om", DATADIR, aiOrder[iNext] );
#else
sprintf( acFilename, DATADIR "/demo%d.om", aiOrder[iNext] );
#endif
// DoGame( acFilename, true, false );
iNext = ( iNext + 1 ) % 6;
}
static bool g_bFirstTime = true;
void DoDemos()
{
#define DoDemos_BREAKONEND \
if ( g_oState.m_enGameMode != SState::IN_DEMO \
|| g_oState.m_bQuitFlag ) \
return;
if ( g_bFirstTime )
{
g_bFirstTime = false;
}
else
{
CMainScreenDemo oDemo;
oDemo.Run();
}
while (1)
{
DoDemos_BREAKONEND;
{
CEuDemo oDemo;
oDemo.Run();
}
DoDemos_BREAKONEND;
DoReplayDemo();
DoDemos_BREAKONEND;
{
CStory1Demo oDemo;
oDemo.Run();
}
DoDemos_BREAKONEND;
DoReplayDemo();
DoDemos_BREAKONEND;
{
CFighterStatsDemo oDemo;
oDemo.Run();
}
DoDemos_BREAKONEND;
DoReplayDemo();
DoDemos_BREAKONEND;
{
CStory2Demo oDemo;
oDemo.Run();
}
DoDemos_BREAKONEND;
{
CFighterStatsDemo oDemo;
oDemo.Run();
}
DoDemos_BREAKONEND;
DoReplayDemo();
DoDemos_BREAKONEND;
{
CCreditsDemo oDemo;
oDemo.Run();
}
DoDemos_BREAKONEND;
{
CMainScreenDemo oDemo;
oDemo.Run();
}
DoDemos_BREAKONEND;
}
}
diff --git a/src/Demo.h b/src/Demo.h
index c29f24d..10e78f6 100644
--- a/src/Demo.h
+++ b/src/Demo.h
@@ -1,54 +1,54 @@
/***************************************************************************
Demo.h - description
-------------------
begin : Wed Aug 16 22:18:47 CEST 2003
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifndef DEMO_H
-#define DEMO_H
-
-/**
-\defgroup Demo Demos and special screens
+#define DEMO_H
+
+/**
+\defgroup Demo Demos and special screens
*/
class CFlyingChars;
struct SDL_Surface;
-
-/**
-\class CDemo
-\ingroup Demo
-\brief CDemo is the base class for every specific demo.
-
-The demos are played by the DoDemos() function in a predefined order.
+
+/**
+\class CDemo
+\ingroup Demo
+\brief CDemo is the base class for every specific demo.
+
+The demos are played by the DoDemos() function in a predefined order.
*/
class CDemo
{
public:
CDemo();
virtual ~CDemo();
virtual int Run();
protected:
virtual int Advance( int a_iNumFrames, bool a_bFlip );
virtual int AdvanceFlyingChars( int a_iNumFrames );
virtual int AdvanceGame( int a_iNumFrames );
virtual void OnMenu();
protected:
CFlyingChars* m_poFlyingChars;
bool m_bAdvanceGame;
SDL_Surface* m_poBackground;
};
#endif // DEMO_H
diff --git a/src/DrawRle.h b/src/DrawRle.h
index 12e9a0a..aa5bd0c 100644
--- a/src/DrawRle.h
+++ b/src/DrawRle.h
@@ -1,347 +1,347 @@
-// This is not a real include file. It is used byt RlePack.cpp
-
+// This is not a real include file. It is used byt RlePack.cpp
+
// At this point the following methods should be defined:
// METHODNAME: The name of the drawing method
// METHODNAME_FLIPT: The name of the flipped drawing method
// PIXEL_PTR: type of pointer to the target surface pixels
// PUT_PIXEL(p,c): Draw pixel of color c to pixel ptr type p
// PITCH: This added to PIXEL_PTR type will result in the next scanline
void METHODNAME_FLIP( SRleSprite* src, int dx, int dy )
{
#define RLE_PTR signed char*
#define RLE_IS_EOL(c) ((c) == 0)
//#define PIXEL_PTR unsigned char*
#define OFFSET_PIXEL_PTR(p,x) ((PIXEL_PTR) (p) + (x))
#define INC_PIXEL_PTR(p) ((p)++)
#define DEC_PIXEL_PTR(p) ((p)--)
//#define PUT_PIXEL(p,c) (*((unsigned char *)(p)) = (c))
int x, y, w, h; // width and height of visible area
int dxbeg, dybeg; // beginning in destination
int sxbeg, sybeg; // beginning in source
RLE_PTR s;
SDL_Surface* dst = gamescreen;
// Clip to dst->clip_rect
int dst_cl = dst->clip_rect.x;
int dst_cr = dst->clip_rect.w + dst_cl - 1;
int dst_ct = dst->clip_rect.y;
int dst_cb = dst->clip_rect.h + dst_ct;
// if (dst->clip)
if (1)
{
int tmp;
dxbeg = dx;
if ( dst_cl > dx ) dxbeg = dst_cl;
tmp = dx + src->w - dst_cr;
sxbeg = ((tmp < 0) ? 0 : tmp);
tmp = dx + src->w;
if (tmp > dst_cr ) tmp = dst_cr;
w = tmp - dxbeg;
if (w <= 0)
return;
tmp = dst_ct - dy;
sybeg = ((tmp < 0) ? 0 : tmp);
dybeg = sybeg + dy;
tmp = dst_cb - dy;
h = ((tmp > src->h) ? src->h : tmp) - sybeg;
if (h <= 0)
return;
}
else {
w = src->w;
h = src->h;
sxbeg = 0;
sybeg = 0;
dxbeg = dx;
dybeg = dy;
}
s = (RLE_PTR) (src->dat);
dxbeg += w;
// Clip top.
for (y = sybeg - 1; y >= 0; y--)
{
long c = *s++;
while (!RLE_IS_EOL(c))
{
if (c > 0)
s += c;
c = *s++;
}
}
//@@@ bmp_select(dst);
/* Visible part. */
for (y = 0; y < h; y++)
{
//@@@ PIXEL_PTR d = OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y), dxbeg);
PIXEL_PTR d = (PIXEL_PTR) dst->pixels;
d += (dybeg+y)*PITCH;
d = OFFSET_PIXEL_PTR( d, dxbeg );
long c = *s++;
// Clip left.
for (x = sxbeg; x > 0; )
{
if (RLE_IS_EOL(c))
goto next_line;
else if (c > 0)
{
// Run of solid pixels.
if ((x - c) >= 0)
{
// Fully clipped.
x -= c;
s += c;
}
else
{
// Visible on the right.
c -= x;
s += x;
break;
}
}
else
{
// Run of transparent pixels.
if ((x + c) >= 0) {
// Fully clipped.
x += c;
}
else {
// Visible on the right.
c += x;
break;
}
}
c = *s++;
}
/* Visible part. */
for (x = w; x > 0; )
{
if (RLE_IS_EOL(c))
goto next_line;
else if (c > 0)
{
/* Run of solid pixels. */
if ((x - c) >= 0)
{
/* Fully visible. */
x -= c;
for (c--; c >= 0; s++, DEC_PIXEL_PTR(d), c--)
{
unsigned long col = (unsigned char) (*s);
PUT_PIXEL(d, col);
}
}
else
{
/* Clipped on the right. */
c -= x;
for (x--; x >= 0; s++, DEC_PIXEL_PTR(d), x--)
{
unsigned long col = (unsigned char) (*s);
PUT_PIXEL(d, col);
}
break;
}
}
else
{
/* Run of transparent pixels. */
x += c;
d = OFFSET_PIXEL_PTR(d, c);
}
c = *s++;
}
/* Clip right. */
while (!RLE_IS_EOL(c))
{
if (c > 0)
s += c;
c = *s++;
}
next_line: ;
}
//@@@bmp_unwrite_line(dst);
}
void METHODNAME( SRleSprite* src, int dx, int dy )
{
#define RLE_PTR signed char*
#define RLE_IS_EOL(c) ((c) == 0)
//#define PIXEL_PTR unsigned char*
#define OFFSET_PIXEL_PTR(p,x) ((PIXEL_PTR) (p) + (x))
#define INC_PIXEL_PTR(p) ((p)++)
#define DEC_PIXEL_PTR(p) ((p)--)
//#define PUT_PIXEL(p,c) (*((unsigned char *)(p)) = (c))
//#define PUT_PIXEL(p,c) bmp_write8((unsigned long) (p), (c))
int x, y, w, h; // width and height of visible area
int dxbeg, dybeg; // beginning in destination
int sxbeg, sybeg; // beginning in source
RLE_PTR s;
SDL_Surface* dst = gamescreen;
// Clip to dst->clip_rect
int dst_cl = dst->clip_rect.x;
int dst_cr = dst->clip_rect.w + dst_cl;
int dst_ct = dst->clip_rect.y;
int dst_cb = dst->clip_rect.h + dst_ct;
// if (dst->clip)
if (1)
{
int tmp;
tmp = dst_cl - dx;
sxbeg = ((tmp < 0) ? 0 : tmp);
dxbeg = sxbeg + dx;
tmp = dst_cr - dx;
w = ((tmp > src->w) ? src->w : tmp) - sxbeg;
if ( w<=0 ) return;
tmp = dst_ct - dy;
sybeg = ((tmp < 0) ? 0 : tmp);
dybeg = sybeg + dy;
tmp = dst_cb - dy;
h = ((tmp > src->h) ? src->h : tmp) - sybeg;
if ( h<=0 ) return;
}
else
{
w = src->w;
h = src->h;
sxbeg = 0;
sybeg = 0;
dxbeg = dx;
dybeg = dy;
}
s = (RLE_PTR) (src->dat);
/* Clip top. */
for (y = sybeg - 1; y >= 0; y--)
{
long c = *s++;
while (!RLE_IS_EOL(c))
{
if (c > 0)
s += c;
c = *s++;
}
}
//@@@ bmp_select(dst);
/* Visible part. */
for (y = 0; y < h; y++)
{
//@@@ PIXEL_PTR d = OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y), dxbeg);
PIXEL_PTR d = (PIXEL_PTR) dst->pixels;
d += (dybeg+y)*PITCH;
d = OFFSET_PIXEL_PTR( d, dxbeg );
long c = *s++;
/* Clip left. */
for (x = sxbeg; x > 0; ) {
if (RLE_IS_EOL(c))
goto next_line;
else if (c > 0) {
/* Run of solid pixels. */
if ((x - c) >= 0) {
/* Fully clipped. */
x -= c;
s += c;
}
else {
/* Visible on the right. */
c -= x;
s += x;
break;
}
}
else {
/* Run of transparent pixels. */
if ((x + c) >= 0) {
/* Fully clipped. */
x += c;
}
else {
/* Visible on the right. */
c += x;
break;
}
}
c = *s++;
}
/* Visible part. */
for (x = w; x > 0; ) {
if (RLE_IS_EOL(c))
goto next_line;
else if (c > 0) {
/* Run of solid pixels. */
if ((x - c) >= 0) {
/* Fully visible. */
x -= c;
for (c--; c >= 0; s++, INC_PIXEL_PTR(d), c--) {
unsigned long col = (unsigned char) (*s);
PUT_PIXEL(d, col);
}
}
else {
/* Clipped on the right. */
c -= x;
for (x--; x >= 0; s++, INC_PIXEL_PTR(d), x--) {
unsigned long col = (unsigned char) (*s);
PUT_PIXEL(d, col);
}
break;
}
}
else {
/* Run of transparent pixels. */
x += c;
d = OFFSET_PIXEL_PTR(d, -c);
}
c = *s++;
}
/* Clip right. */
while (!RLE_IS_EOL(c)) {
if (c > 0)
s += c;
c = *s++;
}
next_line: ;
}
//@@@bmp_unwrite_line(dst);
}
diff --git a/src/Event.h b/src/Event.h
index 160ea95..e5d3fcb 100644
--- a/src/Event.h
+++ b/src/Event.h
@@ -1,54 +1,54 @@
/***************************************************************************
Event.h - description
-------------------
begin : Sat Feb 14 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
#ifndef EVENT_H
#define EVENT_H
enum TMortalEventEnum
{
Me_NOTHING,
Me_QUIT,
Me_MENU,
Me_SKIP,
Me_PLAYERKEYDOWN,
Me_PLAYERKEYUP,
};
enum TMortalKeysEnum
{
Mk_UP = 0,
Mk_DOWN = 1,
Mk_LEFT = 2,
Mk_RIGHT = 3,
Mk_BLOCK = 4,
Mk_LPUNCH = 5,
Mk_HPUNCH = 6,
Mk_LKICK = 7,
Mk_HKICK = 8,
};
-
-/**
-\ingroup GameLogic
+
+/**
+\ingroup GameLogic
*/
struct SMortalEvent
{
TMortalEventEnum m_enType;
int m_iPlayer;
int m_iKey;
};
bool TranslateEvent( const SDL_Event* a_poInSDLEvent, SMortalEvent* a_poOutEvent );
bool MortalPollEvent( SMortalEvent& a_roOutEvent );
void MortalWaitEvent( SMortalEvent& a_roOutEvent );
#endif
diff --git a/src/FighterEnum.h b/src/FighterEnum.h
index c300e64..85e0957 100644
--- a/src/FighterEnum.h
+++ b/src/FighterEnum.h
@@ -1,65 +1,65 @@
/***************************************************************************
FighterEnum.h - description
-------------------
begin : 2003-09-03
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifndef FIGHTERENUM_H
#define FIGHTERENUM_H
/// FIGHTER ENUMERABLE
-/**
-\ingroup GameLogic
-*/
+/**
+\ingroup GameLogic
+*/
enum FighterEnum {
UNKNOWN = 0, ///< Must be the first element, must be 0 (used by iterations)
ULMAR,
UPI,
ZOLI,
CUMI,
SIRPI,
MACI,
BENCE,
GRIZLI,
DESCANT,
SURBA,
AMBRUS,
DANI,
KINGA,
MISI,
LASTFIGHTER, ///< This must terminate the list, iterations use it.
};
/** The TintEnum contains values that can be passed to CRlePack::SetTint.
The tint is some modification of the original palette of an CRlePack. This
is used for two things:
\li In case both players choose the same fighter, player 2's fighter is
tinted so they won't get confused.
\li Some special effects (e.g. frozen) make the fighter tinted as well.
The Tint of players is stored by PlayerSelect and applied by CRlePack::SetTint().
*/
enum TintEnum {
NO_TINT = 0,
ZOMBIE_TINT,
GRAY_TINT,
DARK_TINT,
INVERTED_TINT,
FROZEN_TINT,
};
#endif // FIGHTERENUM_H
diff --git a/src/FighterStats.cpp b/src/FighterStats.cpp
index e479f07..0ca3770 100644
--- a/src/FighterStats.cpp
+++ b/src/FighterStats.cpp
@@ -1,240 +1,240 @@
/***************************************************************************
FighterStats.cpp - description
-------------------
begin : Tue Dec 10 2002
copyright : (C) 2002 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include <stdio.h>
#include <string>
#include "PlayerSelect.h"
#include "FlyingChars.h"
#include "SDL.h"
#include "SDL_video.h"
#include "SDL_image.h"
#include "sge_tt_text.h"
#include "common.h"
#include "gfx.h"
#include "RlePack.h"
#include "Backend.h"
#include "State.h"
#include "FighterStats.h"
#include "MszPerl.h"
extern PerlInterpreter* my_perl;
#define LEFTMARGIN 160
#define TOPMARGIN 70
#define RIGHTMARGIN 630
#define LINEHEIGHT 35
#define GAPWIDTH 20
#define DESCMARGIN 50
#define LEFTMARGIN2 ((LEFTMARGIN+RIGHTMARGIN+GAPWIDTH)/2)
/*
void DrawMultiLineText( const char* text, _sge_TTFont* font, int x, int y,
int fg, SDL_Surface* target )
{
const char* s1, * s2;
char line[1024];
s1 = s2 = text;
while (1)
{
while ( isspace(*s2) ) s2++;
if ( !*s2 )
break;
s1 = s2; // s1: start of line.
while ( (*s2 != '\n') && *s2 ) s2++;
strncpy( line, s1, s2-s1 );
line[s2-s1] = 0;
DrawTextMSZ( line, font, x, y, 0, fg, target );
y += sge_TTF_FontLineSkip( font );
}
}
*/
int CFighterStatsDemo::mg_iLastFighter = -1;
FighterEnum CFighterStatsDemo::mg_aenFighterOrder[LASTFIGHTER-1];
CFighterStatsDemo::CFighterStatsDemo( FighterEnum a_iFighter )
{
m_iTimeLeft = 500;
m_poStaff = NULL;
m_poBackground = LoadBackground( "FighterStats.jpg", 64 );
DrawGradientText( "Fighter Stats", titleFont, 10, m_poBackground );
SDL_BlitSurface( m_poBackground, NULL, gamescreen, NULL );
SDL_Flip( gamescreen );
if ( mg_iLastFighter < 0 )
{
// First run; create shuffled array of fighters.
mg_iLastFighter = 0;
int i, j;
FighterEnum k;
for ( i=0; i<LASTFIGHTER-1; ++i )
{
mg_aenFighterOrder[i] = (FighterEnum)(i+1);
}
for ( i=0; i<LASTFIGHTER-1; ++i )
{
j = rand() % (LASTFIGHTER-1);
k = mg_aenFighterOrder[i];
mg_aenFighterOrder[i] = mg_aenFighterOrder[j];
mg_aenFighterOrder[j] = k;
}
}
if ( a_iFighter <= UNKNOWN )
{
mg_iLastFighter = (mg_iLastFighter+1) % (LASTFIGHTER-1);
m_enFighter = mg_aenFighterOrder[mg_iLastFighter];
}
else
{
m_enFighter = a_iFighter;
}
if ( g_oPlayerSelect.IsFighterAvailable( m_enFighter ) )
{
g_oPlayerSelect.SetPlayer( 0, m_enFighter );
g_oBackend.PerlEvalF( "SelectStart(%d);", 2 );
}
else
{
std::string sStaffFilename = DATADIR;
sStaffFilename += "/characters/STAFF.DAT";
m_poStaff = new CRlePack( sStaffFilename.c_str(), 255 );
}
g_oBackend.PerlEvalF("GetFighterStats(%d);", m_enFighter );
_sge_TTFont* font = impactFont;
int y = TOPMARGIN;
AV *StatTags = get_av( "StatTags", FALSE );
char *s, *sTag;
s = SvPV_nolen(get_sv("Name", FALSE));
DrawTextMSZ( s, inkFont, (LEFTMARGIN + RIGHTMARGIN)/2, y, AlignHCenter, C_WHITE, m_poBackground );
y+= 10;
s = SvPV_nolen(get_sv("Team", FALSE ));
sTag = SvPV_nolen( *av_fetch( StatTags, 1, false ) );
int i = DrawTextMSZ( sTag, font, LEFTMARGIN, y+=LINEHEIGHT, 0, C_YELLOW, m_poBackground );
DrawTextMSZ( s, font, LEFTMARGIN+i, y, 0, C_ORANGE, m_poBackground, false );
s = SvPV_nolen(get_sv("Style", FALSE ));
sTag = SvPV_nolen( *av_fetch( StatTags, 2, false ) );
i = DrawTextMSZ( sTag, font, LEFTMARGIN2, y, 0, C_YELLOW, m_poBackground );
DrawTextMSZ( s, font, LEFTMARGIN2+i, y, 0, C_ORANGE, m_poBackground, false );
s = SvPV_nolen(get_sv("Age", FALSE ));
sTag = SvPV_nolen( *av_fetch( StatTags, 3, false ) );
i = DrawTextMSZ( sTag, font, LEFTMARGIN, y+=LINEHEIGHT, 0, C_YELLOW, m_poBackground );
DrawTextMSZ( s, font, LEFTMARGIN+i, y, 0, C_ORANGE, m_poBackground, false );
s = SvPV_nolen(get_sv("Weight", FALSE ));
sTag = SvPV_nolen( *av_fetch( StatTags, 4, false ) );
i = DrawTextMSZ( sTag, font, LEFTMARGIN2, y, 0, C_YELLOW, m_poBackground );
DrawTextMSZ( s, font, LEFTMARGIN2+i, y, 0, C_ORANGE, m_poBackground, false );
s = SvPV_nolen(get_sv("Height", FALSE ));
sTag = SvPV_nolen( *av_fetch( StatTags, 5, false ) );
i = DrawTextMSZ( sTag, font, LEFTMARGIN, y+=LINEHEIGHT, 0, C_YELLOW, m_poBackground );
DrawTextMSZ( s, font, LEFTMARGIN+i, y, 0, C_ORANGE, m_poBackground, false );
s = SvPV_nolen(get_sv("Shoe", FALSE ));
sTag = SvPV_nolen( *av_fetch( StatTags, 6, false ) );
i = DrawTextMSZ( sTag, font, LEFTMARGIN2, y, 0, C_YELLOW, m_poBackground );
DrawTextMSZ( s, font, LEFTMARGIN2+i, y, 0, C_ORANGE, m_poBackground, false );
m_sStory = SvPV_nolen(get_sv("Story", FALSE ));
SDL_Rect oFlyingRect;
oFlyingRect.x = LEFTMARGIN;
oFlyingRect.y = y+DESCMARGIN;
oFlyingRect.w = gamescreen->w - oFlyingRect.x - 20;
oFlyingRect.h = gamescreen->h - oFlyingRect.y - 10;
m_poFlyingChars = new CFlyingChars( creditsFont, oFlyingRect );
m_poFlyingChars->AddText( m_sStory.c_str(), CFlyingChars::FC_AlignJustify, false );
if ( g_oPlayerSelect.IsFighterAvailable( m_enFighter ) )
{
m_sKeys = SvPV_nolen(get_sv("Keys", TRUE ));
m_poFlyingChars->AddText( "\n\nKEYS\n", CFlyingChars::FC_AlignCenter, true );
m_poFlyingChars->AddText( m_sKeys.c_str(), CFlyingChars::FC_AlignCenter, true );
}
else
{
m_sKeys = Translate("Unfortunately this fighter is not yet playable.");
m_poFlyingChars->AddText( m_sKeys.c_str(), CFlyingChars::FC_AlignLeft, true );
}
}
CFighterStatsDemo::~CFighterStatsDemo()
{
delete m_poStaff;
}
int CFighterStatsDemo::Advance( int a_iNumFrames, bool a_bFlip )
{
if ( a_iNumFrames > 5 ) a_iNumFrames = 5;
if ( m_poFlyingChars->IsDone() )
{
m_iTimeLeft -= a_iNumFrames;
}
AdvanceFlyingChars( a_iNumFrames );
SDL_BlitSurface( m_poBackground, NULL, gamescreen, NULL );
m_poFlyingChars->Draw();
// 2. Advance as many ticks as necessary..
if ( g_oPlayerSelect.IsFighterAvailable( m_enFighter ) )
{
for (int i=0; i<a_iNumFrames; ++i )
{
g_oBackend.AdvancePerl();
}
int p1x = SvIV(get_sv("p1x", TRUE));
int p1y = SvIV(get_sv("p1y", TRUE));
int p1f = SvIV(get_sv("p1f", TRUE));
- if (p1f) g_oPlayerSelect.GetPlayerInfo(0).m_poPack->Draw( ABS(p1f)-1, p1x, p1y, p1f<0 );
+ if (p1f) g_oPlayerSelect.GetPlayerInfo(0).m_poPack->Draw( omABS(p1f)-1, p1x, p1y, p1f<0 );
}
if ( SState::IN_DEMO != g_oState.m_enGameMode )
{
sge_BF_textout( gamescreen, fastFont, Translate("Press F1 to skip..."), 230, 450 );
}
SDL_Flip( gamescreen );
return (m_iTimeLeft > 0) ? 0 : 1;
}
diff --git a/src/FighterStats.h b/src/FighterStats.h
index f61f295..d568a27 100644
--- a/src/FighterStats.h
+++ b/src/FighterStats.h
@@ -1,43 +1,43 @@
/***************************************************************************
FighterStats.h - description
-------------------
begin : Sun Jan 25 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
#ifndef FIGHTERSTATS_H
#define FIGHTERSTATS_H
#include "Demo.h"
#include <string>
-
-/**
-\class CFighterStatDemo
-\ingroup Demo
-\brief This is a specialized CDemo which displays the stats of a fighter.
-
-The fighter is either random, or the winner of the last game.
-*/
+
+/**
+\class CFighterStatDemo
+\ingroup Demo
+\brief This is a specialized CDemo which displays the stats of a fighter.
+
+The fighter is either random, or the winner of the last game.
+*/
class CFighterStatsDemo: public CDemo
{
public:
CFighterStatsDemo( FighterEnum a_iFighter = UNKNOWN );
virtual ~CFighterStatsDemo();
int Advance( int a_iNumFrames, bool a_bFlip );
protected:
int m_iTimeLeft;
FighterEnum m_enFighter;
CRlePack* m_poStaff;
std::string m_sKeys;
std::string m_sStory;
static int mg_iLastFighter; // index of the last fighter in the fighter order
static FighterEnum mg_aenFighterOrder[LASTFIGHTER-1];
};
#endif // FIGHTERSTATS_H
diff --git a/src/FlyingChars.h b/src/FlyingChars.h
index 1103861..3fb247a 100644
--- a/src/FlyingChars.h
+++ b/src/FlyingChars.h
@@ -1,95 +1,95 @@
/***************************************************************************
FlyingChars.h - description
-------------------
begin : Mon Aug 12 2003
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifndef FLYINGCHARS_H
#define FLYINGCHARS_H
#include "sge_bm_text.h"
#include <vector>
#include <list>
-
-/**
-\class CFlyingChars
-\brief Characters jumping onto the screen to form the text in demos
-
-\ingroup Media
+
+/**
+\class CFlyingChars
+\brief Characters jumping onto the screen to form the text in demos
+
+\ingroup Media
*/
class CFlyingChars
{
-
- struct SFlyingLetter
- {
- int m_iX, m_iY;
- int m_iSX, m_iSY;
- int m_iDX, m_iDY;
- int m_iDelay;
- int m_iTime;
- unsigned char m_cLetter;
- };
-
+
+ struct SFlyingLetter
+ {
+ int m_iX, m_iY;
+ int m_iSX, m_iSY;
+ int m_iDX, m_iDY;
+ int m_iDelay;
+ int m_iTime;
+ unsigned char m_cLetter;
+ };
+
public:
enum TextAlignmentEnum {
FC_AlignLeft,
FC_AlignRight,
FC_AlignCenter,
FC_AlignJustify,
};
public:
CFlyingChars( sge_bmpFont* a_poFont, const SDL_Rect& a_roRect, int a_iFontDisplacement = 0 );
~CFlyingChars();
void AddText( const char* a_pcText, TextAlignmentEnum a_enAlignment, bool bOneByOne );
void Advance( int a_iNumFrames );
void Draw();
bool IsDone();
int GetCount();
protected:
void AddNextLine();
int GetCharWidth( unsigned char a_cChar );
void DequeueText();
protected:
struct SEnqueuedText
{
const char* m_pcText;
TextAlignmentEnum m_enAlignment;
};
std::list<SEnqueuedText> m_oEnqueuedTexts;
bool m_bDone;
bool m_bScrolling;
double m_dScrollupRate;
double m_dScrollup;
typedef std::vector<SFlyingLetter> CFlyingLetterList;
typedef CFlyingLetterList::iterator CFlyingLetterIterator;
sge_bmpFont* m_poFont;
int m_iFontDisplacement;
CFlyingLetterList m_oLetters;
int m_iTimeToNextLine;
SDL_Rect m_oRect;
const unsigned char* m_pcText;
TextAlignmentEnum m_enAlignment;
int m_iTextOffset;
int m_iLastLineY;
int m_iDelay;
};
#endif // FLYINGCHARS_H
diff --git a/src/Game.cpp b/src/Game.cpp
index e30ae39..5eef6e2 100644
--- a/src/Game.cpp
+++ b/src/Game.cpp
@@ -1,1211 +1,1211 @@
/***************************************************************************
Game.cpp - description
-------------------
begin : Mon Sep 24 2001
copyright : (C) 2001 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include <string.h>
#include <stdio.h>
#include "SDL_image.h"
#include "sge_surface.h"
#include "sge_primitives.h"
#include "sge_bm_text.h"
#include "SDL_events.h"
#include "SDL_keysym.h"
#include <fstream>
#include "Event.h"
#include "PlayerSelect.h"
#include "Background.h"
#include "common.h"
#include "gfx.h"
#include "Backend.h"
#include "RlePack.h"
#include "State.h"
#include "Game.h"
#include "Audio.h"
#include "MortalNetwork.h"
#include "MszPerl.h"
extern PerlInterpreter* my_perl;
int CGame::mg_iBackgroundNumber = 1;
/*
GAME PALETTE
From To Num Desc
---------------------------------------
0 .. 63 64 Background
64 .. 111 48 Doodads
112 .. 175 64 1st Fighter
176 .. 239 64 2nd Fighter
240 .. 255 16 basic colors
*/
#define MAXFRAMESKIP 5
/***************************************************************************
SFpsCounter CLASS
***************************************************************************/
/**
-\ingroup GameLogic
+\ingroup GameLogic
*/
struct SFpsCounter
{
int m_iLastCheck; // Last second then Tick() was called
int m_iFrames; // The number of frames in this second so far
int m_iFps; // The number of frames in the last second
void Reset()
{
m_iLastCheck = m_iFrames = m_iFps = 0;
}
void Tick()
{
int iSecond = SDL_GetTicks() / 1000;
if ( iSecond > m_iLastCheck )
{
m_iLastCheck = iSecond;
m_iFps = m_iFrames;
m_iFrames = 0;
// fprintf( stderr, "%d ", m_iFps);
}
++m_iFrames;
}
} oFpsCounter;
/***************************************************************************
CKeyQueue CLASS
***************************************************************************/
CKeyQueue::CKeyQueue()
{
Reset();
}
CKeyQueue::~CKeyQueue() {}
void CKeyQueue::Reset()
{
m_oKeys.clear();
}
void CKeyQueue::EnqueueKey( int a_iAtTime, int a_iPlayer, int a_iKey, bool a_bDown )
{
debug( "EnqueueKey( %d, %d, %d, %d ) at %d\n", a_iAtTime, a_iPlayer, a_iKey, a_bDown, g_oBackend.m_iGameTick );
SEnqueuedKey oKey;
oKey.iTime = a_iAtTime;
oKey.iPlayer = a_iPlayer;
oKey.iKey = a_iKey;
oKey.bDown = a_bDown;
if ( m_oKeys.size() == 0 )
{
m_oKeys.push_front( oKey );
return;
}
// Try to find the appropriate time in the list
// We maintain the list so that it is sorted in a descending time
// order. This means that usually we enqueue keys at the front and
// dequeue them at the end, but sometimes a key is inserted in mid-queue.
TEnqueuedKeyList::iterator it;
for ( it=m_oKeys.begin(); it!=m_oKeys.end(); ++it )
{
if ( it->iTime <= a_iAtTime )
{
m_oKeys.insert( it, oKey );
return;
}
}
// a_iAtTime is smaller than any time in the queue, so it goes to the end.
m_oKeys.push_back( oKey );
}
/**
If
*/
void CKeyQueue::DequeueKeys( int a_iToTime )
{
while ( m_oKeys.size() > 0
&& m_oKeys.back().iTime <= a_iToTime )
{
SEnqueuedKey& roKey = m_oKeys.back();
debug( "Dequeued key at %d tick: %d time, %d player, %d key, %d down\n", a_iToTime, roKey.iTime, roKey.iPlayer, roKey.iKey, roKey.bDown );
g_oBackend.PerlEvalF( roKey.bDown ? "KeyDown(%d,%d);" : "KeyUp(%d,%d);", roKey.iPlayer, roKey.iKey );
m_oKeys.pop_back();
}
}
/***************************************************************************
GAME PUBLIC METHODS
***************************************************************************/
CGame::CGame( bool a_bIsReplay, bool a_bWide, bool a_bDebug)
{
m_bIsReplay = a_bIsReplay;
m_bWide = a_bWide;
m_bDebug = a_bDebug;
m_enInitialGameMode = g_oState.m_enGameMode;
if ( IsNetworkGame() )
{
mg_iBackgroundNumber = g_poNetwork->GetGameParams().iBackgroundNumber;
}
m_poBackground = new CBackground();
m_poBackground->Load(mg_iBackgroundNumber++);
if ( !m_poBackground->IsOK() )
{
m_poBackground->Load(1);
mg_iBackgroundNumber = 1;
}
m_poDoodads = LoadBackground( "Doodads.png", 48, 64, true );
int i;
for ( i=0; i<g_oState.m_iNumPlayers; ++i )
{
m_aiRoundsWonByPlayer[i] = 0;
m_aiHitPointDisplayX[i] = 4 + ((i%2) * 396) + (m_bWide ? 130 : 0);
m_aiHitPointDisplayY[i] = 10 + (i/2) * 45;
m_abHitPointDisplayLeft[i] = ! (i%2);
}
m_iNumberOfRounds = 0;
SDL_EnableUNICODE( 0 );
m_iEnqueueDelay = 10;
}
CGame::~CGame()
{
delete m_poBackground;
m_poBackground = NULL;
SDL_FreeSurface( m_poDoodads );
m_poDoodads = NULL;
}
/** Runs a whole game, with two or three rounds.
\retval 0 if player 1 has won.
\retval 1 if player 2 has won.
\retval -1 if the game was a draw.
*/
int CGame::Run()
{
while (1)
{
// 1. START A ROUND
// This will update m_iNumberOfRounds and m_aiRoundsWonByPlayer[]
m_sReplayString = "";
m_aReplayOffsets.clear();
DoOneRound();
if ( g_oState.m_bQuitFlag
|| m_enInitialGameMode != g_oState.m_enGameMode )
{
return -1;
}
// 2. CHECK FOR END-OF-MATCH CONDITIONS
int i;
for ( i=0; i<g_oState.m_iNumPlayers; ++i )
{
if ( m_aiRoundsWonByPlayer[i] >= 2 ) {
return i;
}
}
if ( m_iNumberOfRounds > g_oState.m_iNumPlayers )
{
return -1;
}
}
}
/** Returns the replay string of the last round.
*/
std::string& CGame::GetReplay()
{
return m_sReplayString;
}
/***************************************************************************
GAME DRAWING METHODS
***************************************************************************/
void CGame::DrawHitPointDisplay( int a_iPlayer )
{
int iX = m_aiHitPointDisplayX[a_iPlayer];
int iY = m_aiHitPointDisplayY[a_iPlayer];
bool bLeft = m_abHitPointDisplayLeft[a_iPlayer];
int iHp = g_oBackend.m_aoPlayers[a_iPlayer].m_iHitPoints;
SDL_Rect oSrcRect, oDstRect;
// The green part
oSrcRect.x = bLeft ? 0 : (100-iHp)*2;
oSrcRect.y = 154;
oSrcRect.h = 20;
oSrcRect.w = iHp * 2;
oDstRect.y = iY + m_iYOffset;
oDstRect.x = iX + oSrcRect.x + (bLeft ? 36 : 0 );
SDL_BlitSurface( m_poDoodads, &oSrcRect, gamescreen, &oDstRect );
// The red part
if ( bLeft )
oDstRect.x += iHp * 2;
else
oDstRect.x = iX;
oSrcRect.x = (100+iHp) * 2;
oSrcRect.w = (100-iHp) * 2;
SDL_BlitSurface( m_poDoodads, &oSrcRect, gamescreen, &oDstRect );
// The "won" icon
oSrcRect.x = 0;
oSrcRect.y = 276;
oSrcRect.w = 32;
oSrcRect.h = 32;
if ( m_aiRoundsWonByPlayer[a_iPlayer] > 0 )
{
oDstRect.x = iX + (bLeft ? 0 : 204);
oDstRect.y = iY-4 + m_iYOffset;
SDL_BlitSurface( m_poDoodads, &oSrcRect , gamescreen, &oDstRect );
}
int iTextW = g_oPlayerSelect.GetFighterNameWidth(a_iPlayer);
int iTextX = bLeft ? iX + 230 - iTextW : iX + 10 ;
if ( iTextX + iTextW + 5 > gamescreen->w ) iTextX = gamescreen->w - iTextW - 5;
if ( iTextX < iX + 5 ) iTextX = iX + 5;
sge_BF_textout( gamescreen, fastFont, g_oPlayerSelect.GetFighterName(a_iPlayer),
iTextX, iY/*+ 38*/ + m_iYOffset );
}
/** Draws the hitpoint bars that are displayed on the top of the screen.
Also draws the fighter names below the bars.
Input variables:
\li g_oBackend.m_aoPlayers[x].m_iHitPoints
\li g_oPlayerSelect.GetFighterName
*/
void CGame::DrawHitPointDisplays()
{
for ( int i=0; i<g_oState.m_iNumPlayers; ++i )
{
DrawHitPointDisplay(i);
}
}
/** Draws the background, using the m_poBackground object.
*/
void CGame::DrawBackground()
{
m_poBackground->Draw( g_oBackend.m_iBgX, g_oBackend.m_iBgY, m_iYOffset );
}
void CGame::AddBodyToBackground( int a_iPlayer )
{
CBackend::SPlayer& roPlayer = g_oBackend.m_aoPlayers[a_iPlayer];
CBackground::SBackgroundLayer oLayer;
CRlePack* poPack = g_oPlayerSelect.GetPlayerInfo(a_iPlayer).m_poPack;
oLayer.m_iXOffset = roPlayer.m_iX + g_oBackend.m_iBgX;
oLayer.m_iYOffset = roPlayer.m_iY;
oLayer.m_dDistance = 1.0;
- oLayer.m_poSurface = poPack->CreateSurface( ABS(roPlayer.m_iFrame)-1, roPlayer.m_iFrame<0 );
+ oLayer.m_poSurface = poPack->CreateSurface( omABS(roPlayer.m_iFrame)-1, roPlayer.m_iFrame<0 );
m_poBackground->AddExtraLayer( oLayer );
}
/** In debug mode, this method is used to draw the frame of the fighters.
\param a_pcName The name of the polygon (in the perl namespace)
\param a_iColor The game color to draw the polygon with.
*/
void CGame::DrawPoly( const char* a_pcName, int a_iColor )
{
AV *poList;
int n;
poList = get_av( a_pcName, FALSE );
if ( poList == NULL )
{
return;
}
n = av_len( poList ) + 1;
if ( n< 2 )
{
return;
}
for ( int i=0; i<n; i += 2 )
{
int j = (i+2) % n;
int x1 = SvIV( *av_fetch( poList, i, false) );
int y1 = SvIV( *av_fetch( poList, i+1, false) );
int x2 = SvIV( *av_fetch( poList, j, false) );
int y2 = SvIV( *av_fetch( poList, j+1, false) );
sge_Line( gamescreen, x1, y1 + m_iYOffset, x2, y2 + m_iYOffset, a_iColor ) ;
}
}
/** Draws every doodad that is currently defined in the backend.
*/
void CGame::DrawDoodads()
{
for ( int i=0; i<g_oBackend.m_iNumDoodads; ++i )
{
CBackend::SDoodad& roDoodad = g_oBackend.m_aoDoodads[i];
if ( 0 == roDoodad.m_iType )
{
// Handle text doodads
const char *s = roDoodad.m_sText.c_str();
int iWidth = sge_BF_TextSize(fastFont, s).w;
int iDoodadX = roDoodad.m_iX - iWidth/2;
if ( iDoodadX + iWidth > gamescreen->w ) iDoodadX = gamescreen->w - iWidth;
if ( iDoodadX < 0 ) iDoodadX = 0;
int iDoodadY = roDoodad.m_iY;
sge_BF_textout( gamescreen, fastFont, s, iDoodadX, iDoodadY + m_iYOffset );
continue;
}
if ( roDoodad.m_iGfxOwner >= 0 )
{
g_oPlayerSelect.GetPlayerInfo(roDoodad.m_iGfxOwner).m_poPack->Draw(
roDoodad.m_iFrame, roDoodad.m_iX, roDoodad.m_iY + m_iYOffset, roDoodad.m_iDir < 1 );
continue;
}
SDL_Rect rsrc, rdst;
int w, h, y0;
rdst.x = roDoodad.m_iX;
rdst.y = roDoodad.m_iY + m_iYOffset;
if ( 5 == roDoodad.m_iType )
{
y0 = 308;
w = h = 24;
}
else
{
y0 = 0;
w = h = 64;
}
rsrc.x = w * roDoodad.m_iFrame;
rsrc.y = y0;
rsrc.w = w;
rsrc.h = h;
SDL_BlitSurface( m_poDoodads, &rsrc, gamescreen, &rdst );
//debug( "Doodad x: %d, y: %d, t: %d, f: %d\n", dx, dy, dt, df );
}
}
/** Draws the entire game screen:
\li First, the background.
\li The players.
\li The debug wireframes (if debugging is turned on)
\li The doodads.
\li The hitpoint display.
\li The gametime display.
\li The FPS display.
\li The "Round x" text during Ph_Start
Input:
\li m_enGamePhase
\li g_oBackend.m_iRoundLength
\li m_iNumberOfRounds
\li oFpsCounter
*/
void CGame::Draw()
{
#define GROUNDZERO (440 + m_iYOffset)
m_iYOffset = ( gamescreen->h - 480 ) / 2;
if ( m_iYOffset )
{
SDL_Rect oRect;
oRect.x = 0;
oRect.w = gamescreen->w;
oRect.y = m_iYOffset;
oRect.h = 480;
SDL_SetClipRect( gamescreen, &oRect );
}
else
{
SDL_SetClipRect( gamescreen, NULL );
}
DrawBackground();
// DRAW THE SHADOWS
int i;
for ( i=0; i<g_oState.m_iNumPlayers; ++i )
{
CBackend::SPlayer& roPlayer = g_oBackend.m_aoPlayers[i];
int iFrame = roPlayer.m_iFrame;
if ( iFrame == 0 )
continue;
CRlePack* poPack = g_oPlayerSelect.GetPlayerInfo(i).m_poPack;
- int w = poPack->GetWidth( ABS(iFrame)-1 );
- int h = poPack->GetHeight( ABS(iFrame)-1 );
+ int w = poPack->GetWidth( omABS(iFrame)-1 );
+ int h = poPack->GetHeight( omABS(iFrame)-1 );
h = GROUNDZERO - ( h + roPlayer.m_iY ); // Distance of feet from ground
if ( h < 0 ) h = 0;
if ( h > 500 ) h = 500;
h = 500 - h;
int h2 = 15 * h / 500;
h = ( w / 2 ) * h / 500;
if ( gamescreen->format->BitsPerPixel <= 8 )
{
sge_FilledEllipse( gamescreen, g_oBackend.m_aoPlayers[i].m_iX + w/2, GROUNDZERO,
h, h2, C_BLACK );
}
else
{
sge_FilledEllipseAlpha( gamescreen, g_oBackend.m_aoPlayers[i].m_iX + w/2, GROUNDZERO,
h, h2, C_BLACK, 128 );
}
}
for ( i=0; i<g_oState.m_iNumPlayers; ++i )
{
CBackend::SPlayer& roPlayer = g_oBackend.m_aoPlayers[i];
int iFrame = roPlayer.m_iFrame;
if ( iFrame == 0 )
continue;
CRlePack* poPack = g_oPlayerSelect.GetPlayerInfo(i).m_poPack;
- poPack->Draw( ABS(iFrame)-1, roPlayer.m_iX, roPlayer.m_iY + m_iYOffset, iFrame<0 );
+ poPack->Draw( omABS(iFrame)-1, roPlayer.m_iX, roPlayer.m_iY + m_iYOffset, iFrame<0 );
}
if ( m_bDebug )
{
DrawPoly( "p1head", C_LIGHTRED );
DrawPoly( "p1body", C_LIGHTGREEN );
DrawPoly( "p1legs", C_LIGHTBLUE );
DrawPoly( "p1hit", C_YELLOW );
DrawPoly( "p2head", C_LIGHTRED );
DrawPoly( "p2body", C_LIGHTGREEN );
DrawPoly( "p2legs", C_LIGHTBLUE );
DrawPoly( "p2hit", C_YELLOW );
}
DrawDoodads();
DrawHitPointDisplays();
if ( Ph_NORMAL == m_enGamePhase )
{
char s[100];
sprintf( s, "%d", m_iGameTime ); // m_iGameTime is maintained by DoGame
DrawTextMSZ( s, inkFont, 320, 10 + m_iYOffset, AlignHCenter, C_LIGHTCYAN, gamescreen, false );
}
else if ( Ph_START == m_enGamePhase )
{
char s[100];
const char* format = Translate( "Round %d" );
sprintf( s, format, m_iNumberOfRounds+1 );
DrawTextMSZ( s, inkFont, 320, 200 + m_iYOffset, AlignHCenter, C_WHITE, gamescreen, false );
}
else if ( Ph_REWIND == m_enGamePhase )
{
DrawTextMSZ( "REW", inkFont, 320, 10 + m_iYOffset, AlignHCenter, C_WHITE, gamescreen );
sge_BF_textout( gamescreen, fastFont, Translate("Press F1 to skip..."), 230, 450 + m_iYOffset );
}
else if ( Ph_SLOWFORWARD == m_enGamePhase )
{
DrawTextMSZ( "REPLAY", inkFont, 320, 10 + m_iYOffset, AlignHCenter, C_WHITE, gamescreen );
sge_BF_textout( gamescreen, fastFont, Translate("Press F1 to skip..."), 230, 450 + m_iYOffset );
}
else if ( Ph_REPLAY == m_enGamePhase )
{
DrawTextMSZ( "DEMO", inkFont, 320, 10 + m_iYOffset, AlignHCenter, C_WHITE, gamescreen );
}
if ( oFpsCounter.m_iFps > 0 )
{
sge_BF_textoutf( gamescreen, fastFont, 2, 455 + m_iYOffset, "%d fps", oFpsCounter.m_iFps );
}
SDL_Flip( gamescreen );
}
/***************************************************************************
GAME PROTECTED METHODS
***************************************************************************/
bool CGame::IsTeamMode()
{
return SState::Team_ONE_VS_ONE != g_oState.m_enTeamMode;
}
bool CGame::IsNetworkGame()
{
return SState::IN_NETWORK == g_oState.m_enGameMode;
}
/** Returns true if we control our own data, or false if the network supplies
us with game data. */
bool CGame::IsMaster()
{
return !IsNetworkGame() || g_poNetwork->IsMaster();
}
/**
This method reads and updates the game's variables. In replay mode,
this is done by parsing the replay string. Otherwise the perl
backend is advanced the given number of steps.
Whichever the case, the variables will be available in g_oBackend.
Only the backend-driven variables are modified, the GamePhase and
GameTime remain unchanged; these are up for DoOneRound and friends
to modify.
*/
void CGame::Advance( int a_iNumFrames )
{
if ( m_bIsReplay )
{
// Replay mode...
m_iFrame += a_iNumFrames;
if ( m_iFrame >= ((int)m_aReplayOffsets.size())-1 ) m_iFrame = m_aReplayOffsets.size() - 2;
if ( m_iFrame <= 0 ) m_iFrame = 0;
std::string sFrameDesc = m_sReplayString.substr(
m_aReplayOffsets[m_iFrame],
m_aReplayOffsets[m_iFrame+1] - m_aReplayOffsets[m_iFrame] );
g_oBackend.ReadFromString( sFrameDesc );
return;
}
static std::string sFrameDesc;
if ( IsNetworkGame() )
{
g_poNetwork->SendGameTick( g_oBackend.m_iGameTick );
g_poNetwork->Update();
int i = 0;
while ( g_poNetwork->GetGameTick() + m_iEnqueueDelay < g_oBackend.m_iGameTick + a_iNumFrames )
{
++i;
if ( i > 300 ) {
// Waited for too long..
g_poNetwork->Stop();
}
// The remote side is lagging behind.. Wait for it.
SDL_Delay( 10 );
g_poNetwork->Update();
if ( m_enInitialGameMode != g_oState.m_enGameMode ) {
return;
}
}
int iTime;
int iKey;
bool bPressed;
while ( g_poNetwork->GetKeystroke( iTime, iKey, bPressed ) )
{
debug( "Got GetKeystroke: %d, %d, %d at %d\n", iTime, iKey, bPressed, g_oBackend.m_iGameTick );
// g_oBackend.PerlEvalF( bPressed ? "KeyDown(%d,%d);" : "KeyUp(%d,%d);", 1, iKey );
m_oKeyQueue.EnqueueKey( iTime, IsMaster() ? 1 : 0, iKey, bPressed );
if ( iTime <= g_oBackend.m_iGameTick )
{
debug( "KEY ARRIVED TOO LATE!!!\n" );
}
}
}
while ( a_iNumFrames > 0 )
{
-- a_iNumFrames;
g_oBackend.AdvancePerl();
g_oBackend.ReadFromPerl();
g_oBackend.PlaySounds();
m_oKeyQueue.DequeueKeys( g_oBackend.m_iGameTick );
g_oBackend.WriteToString( sFrameDesc );
m_sReplayString += sFrameDesc;
m_sReplayString += '\n';
m_aReplayOffsets.push_back( m_sReplayString.size() );
}
}
/** A helper method of ProcessEvents; it manages keypresses and releases of
players. It is only called when keypresses are actually relevant for the
backend (not during instant replay, etc).
*/
void CGame::HandleKey( int a_iPlayer, int a_iKey, bool a_bDown )
{
int iCurrentTick = g_oBackend.m_iGameTick + m_iEnqueueDelay;
if ( IsNetworkGame() )
{
a_iPlayer = IsMaster() ? 0 : 1;
g_poNetwork->SendKeystroke( iCurrentTick, a_iKey, a_bDown );
}
m_oKeyQueue.EnqueueKey( iCurrentTick, a_iPlayer, a_iKey, a_bDown );
}
/** ProcessEvents reads events from the SDL event system.
Relevant key events are fed to the backend.
Esc brings up the menu.
Returns 1 on quit event (e.g. if the current game or replay should be aborted), 0 otherwise.
*/
int CGame::ProcessEvents()
{
SMortalEvent oEvent;
while (MortalPollEvent(oEvent))
{
switch (oEvent.m_enType)
{
case Me_QUIT:
g_oState.m_bQuitFlag = true;
return 1;
case Me_MENU:
if ( Ph_REWIND == m_enGamePhase
|| Ph_SLOWFORWARD == m_enGamePhase )
{
// Menu counts as 'skip' during instant replay
return 1;
}
if ( !IsNetworkGame() )
{
SState::TGameMode enMode = g_oState.m_enGameMode;
::DoMenu();
return g_oState.m_enGameMode == enMode ? 0 : 1;
}
break;
case Me_SKIP:
return 1;
case Me_PLAYERKEYDOWN:
case Me_PLAYERKEYUP:
{
if ( Ph_NORMAL != m_enGamePhase &&
Ph_REPLAY != m_enGamePhase )
break;
HandleKey( oEvent.m_iPlayer, oEvent.m_iKey, Me_PLAYERKEYDOWN == oEvent.m_enType );
break;
}
case Me_NOTHING:
break;
} // End of switch
} // End of while polling events;
return 0;
}
void CGame::HandleKO()
{
}
void CGame::HurryUp()
{
Audio->PlaySample( "GAME_HURRYUP" );
DrawGradientText( "HURRY UP!", titleFont, 200, gamescreen );
SDL_Delay( 1000 );
Audio->PlaySample( "GAME_HURRYUP_ENDS" );
}
void CGame::TimeUp()
{
DrawGradientText( "TIME IS UP!", titleFont, 200, gamescreen );
SDL_Delay( 1000 );
}
/** This methods starts and runs the "instant replay" mode that is done
at the end of a game round. This means doing phases Ph_REWIND and Ph_SLOWFORWARD.
Rewind will go back in time 200 ticks before the parameter a_iKoAt.
*/
void CGame::InstantReplay( int a_iKoAt )
{
int iCurrentFrame = m_aReplayOffsets.size() - 200;
int iThisTick, iLastTick, iGameSpeed;
m_enGamePhase = Ph_REWIND;
iGameSpeed = 8;
iThisTick = SDL_GetTicks() / iGameSpeed;
iLastTick = iThisTick - 1;
while ( iCurrentFrame < (int)m_aReplayOffsets.size() - 150 )
{
// 1. Wait for the next tick (on extremely fast machines..)
while (iThisTick == iLastTick)
{
iThisTick = SDL_GetTicks() / iGameSpeed;
if ( iThisTick==iLastTick ) SDL_Delay(1);
}
// 2. Advance as many ticks as necessary..
int iNumTicks = iThisTick - iLastTick;
if ( iNumTicks > 10 ) iNumTicks = 10;
if ( iNumTicks < 0 ) iNumTicks = 0;
iCurrentFrame += ( Ph_REWIND == m_enGamePhase ) ? -iNumTicks : +iNumTicks ;
if ( Ph_REWIND == m_enGamePhase
&& ( iCurrentFrame < a_iKoAt - 200 || iCurrentFrame <= 0 )
)
{
m_enGamePhase = Ph_SLOWFORWARD;
iGameSpeed = 16;
SDL_Delay(500);
}
iLastTick = iThisTick;
if ( iCurrentFrame < 0 ) iCurrentFrame = 0;
m_iFrame = iCurrentFrame;
if ( m_iFrame >= ((int)m_aReplayOffsets.size())-1 ) m_iFrame = m_aReplayOffsets.size() - 2;
if ( m_iFrame <= 0 ) m_iFrame = 0;
std::string sFrameDesc = m_sReplayString.substr(
m_aReplayOffsets[m_iFrame],
m_aReplayOffsets[m_iFrame+1] - m_aReplayOffsets[m_iFrame] );
//debug( "PB: Frame %d ofs %d-%d; data: '%s'\n", m_iFrame,
// m_aReplayOffsets[m_iFrame], m_aReplayOffsets[m_iFrame+1], sFrameDesc.c_str() );
g_oBackend.ReadFromString( sFrameDesc );
if ( ProcessEvents() )
{
break;
}
oFpsCounter.Tick();
// 3. Draw the next game screen..
Draw();
if ( g_oState.m_bQuitFlag
|| SState::IN_DEMO == g_oState.m_enGameMode )
{
break;
}
}
}
/** This methods executes one round of gameplay.
The game progresses through phases Ph_START, Ph_NORMAL, and
Ph_KO. If a KO happened, it will invoke InstantReplay. At the end of
the round m_aiRoundsWonByPlayer[x] will be incremented depending on the
outcome. m_iNumberOfRounds will also increase by 1.
*/
void CGame::DoOneRound()
{
m_enGamePhase = Ph_START;
m_poBackground->DeleteExtraLayers();
int iTeamSize = (SState::Team_ONE_VS_ONE==g_oState.m_enTeamMode) ?
1 : g_oPlayerSelect.GetPlayerInfo(0).m_aenTeam.size();
int aiTeamNumber[MAXPLAYERS];
for ( int i=0; i<g_oState.m_iNumPlayers; ++i )
{
aiTeamNumber[i] = 0;
}
if ( IsTeamMode() )
{
for ( int i=0; i<g_oState.m_iNumPlayers; ++i )
{
g_oPlayerSelect.SetPlayer( i, g_oPlayerSelect.GetPlayerInfo(i).m_aenTeam[aiTeamNumber[i]] );
}
}
g_oBackend.PerlEvalF( "GameStart(%d,%d,%d,%d,%d);",
IsMaster() ? g_oState.m_iHitPoints : g_poNetwork->GetGameParams().iHitPoints,
g_oState.m_iNumPlayers,
iTeamSize,
m_bWide,
m_bDebug );
g_oBackend.ReadFromPerl();
if ( IsNetworkGame() )
{
g_poNetwork->SynchStartRound();
g_poNetwork->SendGameTick( g_oBackend.m_iGameTick-1 );
}
int iKoFrame = -1;
double dGameTime = 2 * 1000; // Only for the "greeting phase", the real gametime will be set after.
int iThisTick, iLastTick, iGameSpeed;
bool bHurryUp = false;
bool bReplayAfter = true;
iGameSpeed = IsMaster() ? g_oState.m_iGameSpeed : g_poNetwork->GetGameParams().iGameSpeed;
iThisTick = SDL_GetTicks() / iGameSpeed;
iLastTick = iThisTick - 1;
m_oKeyQueue.Reset();
oFpsCounter.Reset();
// 1. DO THE NORMAL GAME ROUND (START, NORMAL, KO, TIMEUP)
while ( dGameTime >= 0 )
{
if ( m_enInitialGameMode != g_oState.m_enGameMode )
{
return;
}
// 1. Wait for the next tick (on extremely fast machines..)
while (iThisTick == iLastTick)
{
iThisTick = SDL_GetTicks() / iGameSpeed;
if ( iThisTick==iLastTick ) SDL_Delay(1);
}
// 2. Advance as many ticks as necessary..
int iNumTicks = iThisTick - iLastTick;
if ( iNumTicks > MAXFRAMESKIP ) iNumTicks = MAXFRAMESKIP;
Advance( iNumTicks );
dGameTime -= iNumTicks * iGameSpeed;
// 3. Check for state transitions and game time.
// START -> NORMAL
// NORMAL -> KO
// NORMAL -> TIMEUP
// bHurryUp flag can be set during NORMAL phase
if ( Ph_START == m_enGamePhase ) // Check for the end of the START phase
{
if ( dGameTime <= 0 )
{
m_enGamePhase = Ph_NORMAL;
dGameTime = (IsMaster() ? g_oState.m_iRoundLength : g_poNetwork->GetGameParams().iRoundLength) * 1000;
}
}
else if ( Ph_NORMAL == m_enGamePhase ) // Check for the end of the NORMAL phase
{
if ( dGameTime < 10 * 1000
&& !bHurryUp )
{
bHurryUp = true;
g_poNetwork->SendHurryup( 1 );
HurryUp();
iGameSpeed = iGameSpeed * 3 / 4;
}
if ( g_oBackend.m_bKO )
{
m_enGamePhase = Ph_KO;
dGameTime = 10 * 1000;
iKoFrame = m_aReplayOffsets.size();
}
else if ( dGameTime <= 0 )
{
m_enGamePhase = Ph_TIMEUP;
g_poNetwork->SendHurryup( 2 );
TimeUp();
break;
}
}
m_iGameTime = (int) ((dGameTime + 500.0) / 1000.0);
iLastTick = iThisTick;
// ProcessEvents will read keyboard/gamepad input
// It will also transmit them to the remote side in a network game.
if ( ProcessEvents() || g_oState.m_bQuitFlag )
{
bReplayAfter = false;
break;
}
oFpsCounter.Tick();
// 3. Draw the next game screen..
Draw();
// 4. Check 'end of round' condition.
for ( int i=0; i<g_oState.m_iNumPlayers; ++i )
{
if ( g_oBackend.m_aoPlayers[i].m_iRealHitPoints <= -10000 )
{
// We have a dead player here.
if ( aiTeamNumber[i] < iTeamSize-1 )
{
++aiTeamNumber[i];
AddBodyToBackground( i );
FighterEnum enFighter = g_oPlayerSelect.GetPlayerInfo(i).m_aenTeam[ aiTeamNumber[i] ];
g_oPlayerSelect.SetPlayer( i, enFighter );
g_oBackend.PerlEvalF( "NextTeamMember(%d,%d);", i, enFighter );
}
}
}
if ( g_oBackend.m_iGameOver )
{
break;
}
if ( !IsMaster() )
{
if ( g_poNetwork->IsRoundOver() )
{
break;
}
}
}
int p1h = g_oBackend.m_aoPlayers[0].m_iRealHitPoints;
int p2h = g_oBackend.m_aoPlayers[1].m_iRealHitPoints;
// 3. DO THE REPLAY (IF THERE WAS A KO)
if ( iKoFrame>0 && bReplayAfter && !IsNetworkGame() )
{
InstantReplay( iKoFrame );
}
// 4. END OF ROUND
debug( "Game over; p1h = %d; p2h = %d\n", p1h, p2h );
if ( IsMaster() )
{
int iWhoWon = -1;
if ( p1h > p2h ) { ++m_aiRoundsWonByPlayer[0]; iWhoWon = 0; }
if ( p2h > p1h ) { ++m_aiRoundsWonByPlayer[1]; iWhoWon = 1; }
if ( IsNetworkGame() )
{
g_poNetwork->SendGameTick( g_oBackend.m_iGameTick + m_iEnqueueDelay * 100 );
g_poNetwork->SendRoundOver( iWhoWon, m_iNumberOfRounds > 0 );
}
}
else
{
int iWhoWon = g_poNetwork->GetWhoWon();
if ( iWhoWon>=0 )
{
++m_aiRoundsWonByPlayer[iWhoWon];
}
}
++m_iNumberOfRounds;
}
void CGame::DoReplay( const char* a_pcReplayFile )
{
std::ifstream oInput( a_pcReplayFile );
int iPlayer1, iPlayer2;
oInput >> iPlayer1 >> iPlayer2;
std::string sLine;
std::getline( oInput, sLine );
g_oPlayerSelect.SetPlayer( 0, (FighterEnum) iPlayer1 );
g_oPlayerSelect.SetPlayer( 1, (FighterEnum) iPlayer2 );
int iThisTick, iLastTick, iGameSpeed;
m_enGamePhase = Ph_REPLAY;
iGameSpeed = 12;
iThisTick = SDL_GetTicks() / iGameSpeed;
iLastTick = iThisTick - 1;
while ( !oInput.eof() )
{
// 1. Wait for the next tick (on extremely fast machines..)
while (iThisTick == iLastTick)
{
iThisTick = SDL_GetTicks() / iGameSpeed;
if ( iThisTick==iLastTick ) SDL_Delay(1);
}
// 2. Advance as many ticks as necessary..
int iNumTicks = iThisTick - iLastTick;
if ( iNumTicks > 5 ) iNumTicks = 5;
for ( int i=0; i< iNumTicks; ++i )
{
std::getline( oInput, sLine );
}
if ( 0 == sLine.size() )
{
break;
}
iLastTick = iThisTick;
g_oBackend.ReadFromString( sLine );
if ( ProcessEvents() )
{
break;
}
oFpsCounter.Tick();
// 3. Draw the next game screen..
Draw();
if ( g_oState.m_bQuitFlag )
{
break;
}
}
}
// TODO move the backgroundnumber to SState
int CGame::GetBackgroundNumber() //static
{
return mg_iBackgroundNumber;
}
/** Public static function.
Other parts of OpenMortal need not include "Game.h" so long as they have
the definition of this method (defined in "common.h"). The method runs
a cycle of the game (either a normal game, or replay).
In replay mode, DoReplay() is called, and the replay file is required.
In normal mode, Run() is called. The replay file is recorded, if it is not NULL.
*/
int DoGame( char* a_pcReplayFile, bool a_bIsReplay, bool a_bDebug )
{
bool bWide = g_oState.m_iNumPlayers > 2;
// CVideoModeChange oVideoMode( bWide );
CGame oGame( a_bIsReplay, bWide, a_bDebug );
if ( a_bIsReplay )
{
if ( NULL == a_pcReplayFile )
{
return 0;
}
oGame.DoReplay( a_pcReplayFile );
return 0;
}
else
{
int iRetval = oGame.Run();
if ( NULL != a_pcReplayFile )
{
std::ofstream oOutput( a_pcReplayFile );
oOutput <<
g_oPlayerSelect.GetPlayerInfo(0).m_enFighter << ' ' <<
g_oPlayerSelect.GetPlayerInfo(1).m_enFighter << '\n' << oGame.GetReplay();
}
return iRetval;
}
}
int GetBackgroundNumber()
{
return CGame::GetBackgroundNumber();
}
diff --git a/src/Game.h b/src/Game.h
index 19ef5f9..6cb33e3 100644
--- a/src/Game.h
+++ b/src/Game.h
@@ -1,155 +1,155 @@
/***************************************************************************
Game.h - description
-------------------
begin : Mon Aug 27 2003
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifndef GAME_H
-#define GAME_H
-
-/**
-\defgroup GameLogic Game logic (frontend + backend connection)
-
-This group of classes implement the frontend part of the game logic,
-including the game object itself, menus, and connection to the backend.
+#define GAME_H
+
+/**
+\defgroup GameLogic Game logic (frontend + backend connection)
+
+This group of classes implement the frontend part of the game logic,
+including the game object itself, menus, and connection to the backend.
*/
#include <string>
#include <vector>
#include <list>
struct SDL_Surface;
class Background;
-/**
+/**
\ingroup GameLogic
CKeyQueue is used to introduce a certain amount of negative or positive
lag to keystrokes.
The keys are sent to the backend and the remote site set to a future time.
The time is measured in the backend's game ticks. So if the current key
is pressed at game time 80, and enqueued to game time 90, there will be an
artificial lag of 10 game ticks.
The actual length of game ticks depends on the game speed (set in the menu),
for a normal game its 1000/80 = 12.5 ms. This artificial lag is useful for
network games.
*/
class CKeyQueue
{
public:
CKeyQueue();
~CKeyQueue();
void Reset();
void EnqueueKey( int a_iAtTime, int a_iPlayer, int a_iKey, bool a_bDown );
void DequeueKeys( int a_iToTime );
protected:
struct SEnqueuedKey
{
int iTime;
int iPlayer;
int iKey;
bool bDown;
};
typedef std::list<SEnqueuedKey> TEnqueuedKeyList;
TEnqueuedKeyList m_oKeys;
};
-/**
-\ingroup GameLogic
+/**
+\ingroup GameLogic
The CGame class is for running the frontend of a game.
This involves reading the game state data from a source (be it a replay
file or the backend), handling the keystrokes and network, etc.
*/
class CGame
{
public:
CGame( bool a_bIsReplay, bool m_bWide, bool a_bDebug );
~CGame();
int Run();
std::string& GetReplay();
void DoReplay( const char* a_pcReplayFile );
static int GetBackgroundNumber();
protected:
void Draw();
void DrawHitPointDisplay( int a_iPlayer);
void DrawHitPointDisplays();
void DrawBackground();
void DrawDoodads();
void DrawPoly( const char* a_pcName, int a_iColor );
void AddBodyToBackground( int a_iPlayer );
void DoOneRound();
void Advance( int a_iNumFrames );
int ProcessEvents();
void HandleKey( int a_iPlayer, int a_iKey, bool a_bDown );
void HandleKO();
void HurryUp();
void TimeUp();
void InstantReplay( int a_iKoAt );
bool IsTeamMode();
bool IsNetworkGame();
bool IsMaster();
void ReadKeysFromNetwork();
protected:
static int mg_iBackgroundNumber;
bool m_bIsReplay;
bool m_bWide; ///< 800 or 640 pixel width.
int m_iYOffset; ///< For wide mode.
bool m_bDebug;
CBackground* m_poBackground;
SDL_Surface* m_poDoodads;
int m_aiHitPointDisplayX[MAXPLAYERS];
int m_aiHitPointDisplayY[MAXPLAYERS];
bool m_abHitPointDisplayLeft[MAXPLAYERS];
int m_aiRoundsWonByPlayer[MAXPLAYERS];
int m_iNumberOfRounds;
int m_iFrame;
int m_iGameTime;
CKeyQueue m_oKeyQueue;
int m_iEnqueueDelay;
std::string m_sReplayString;
std::vector<int> m_aReplayOffsets;
enum TGamePhaseEnum // This enum assumes its values during DoOneRound
{
Ph_START, // "Round X" displayed, fighters getting ready
Ph_NORMAL, // During the fight
Ph_TIMEUP, // Time is up, no KO, no replay.
Ph_KO, // There is a KO, forward until the guy is down
Ph_REWIND, // There was a KO, rewinding until before the KO
Ph_SLOWFORWARD, // Playing back the KO
Ph_REPLAY, // Replay mode
} m_enGamePhase;
SState::TGameMode m_enInitialGameMode; // must make sure it's still the same.
};
#endif
diff --git a/src/GameOver.cpp b/src/GameOver.cpp
index e9a8de5..3108335 100644
--- a/src/GameOver.cpp
+++ b/src/GameOver.cpp
@@ -1,218 +1,218 @@
/***************************************************************************
GameOver.cpp - description
-------------------
begin : Wed Aug 21 20:25:30 CEST 2003
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include "PlayerSelect.h"
#include "SDL.h"
#include "gfx.h"
#include "Backend.h"
#include "common.h"
#include "State.h"
#include "RlePack.h"
#include "Audio.h"
#include "Event.h"
#include <stdio.h>
void DrawPlayer( int i )
{
int iFrame = g_oBackend.m_aoPlayers[i].m_iFrame;
if ( 0 != iFrame )
{
g_oPlayerSelect.GetPlayerInfo(i).m_poPack->Draw(
- ABS(iFrame)-1,
+ omABS(iFrame)-1,
g_oBackend.m_aoPlayers[i].m_iX,
g_oBackend.m_aoPlayers[i].m_iY - 15,
iFrame<0 );
}
}
void GameOver( int a_iPlayerWon )
{
SDL_Surface* poBackground = LoadBackground( "GameOver.jpg", 112 );
DrawGradientText( "Final Judgement", titleFont, 20, poBackground );
DrawTextMSZ( "Continue?", inkFont, 320, 100, AlignHCenter, C_LIGHTCYAN, poBackground );
SDL_Surface* poFoot = LoadBackground( "Foot.jpg", 112, 0, true );
SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
g_oBackend.PerlEvalF( "JudgementStart(%d);", a_iPlayerWon );
int thisTick, lastTick, firstTick, iGameSpeed;
iGameSpeed = 14 ;
firstTick = thisTick = SDL_GetTicks() / iGameSpeed;
lastTick = thisTick - 1;
char acString[100];
int iTimeLeft = 8000 / iGameSpeed;
int FOOTHEIGHT = poFoot->h;
int GROUNDLEVEL = 440;
int iFootY = -FOOTHEIGHT;
bool bTimeUp = false;
bool bKeyPressed = false;
int iCounter = -1;
while (1)
{
// 1. Wait for the next tick (on extremely fast machines..)
while (1)
{
thisTick = SDL_GetTicks() / iGameSpeed;
if ( thisTick==lastTick )
{
SDL_Delay(1);
}
else
{
break;
}
}
// 2. Advance as many ticks as necessary..
if ( thisTick - lastTick > 5 )
{
iTimeLeft -= 5;
}
else
{
iTimeLeft = iTimeLeft - thisTick + lastTick;
}
if ( iTimeLeft < 0 && !bTimeUp )
{
bTimeUp = true;
Audio->FadeMusic( 1500 );
}
if ( bTimeUp )
{
iFootY += 12 * (thisTick - lastTick );
if ( iFootY > GROUNDLEVEL - FOOTHEIGHT )
{
break;
}
}
int iNumFrames = thisTick - lastTick;
for ( int i=0; i<iNumFrames; ++i )
{
g_oBackend.AdvancePerl();
};
lastTick = thisTick;
SMortalEvent oEvent;
while (MortalPollEvent(oEvent))
{
switch (oEvent.m_enType)
{
case Me_QUIT:
g_oState.m_bQuitFlag = true;
break;
case Me_MENU:
DoMenu();
break;
case Me_PLAYERKEYDOWN:
if ( 1-a_iPlayerWon == oEvent.m_iPlayer
&& oEvent.m_iKey>= 4 )
{
bKeyPressed = true;
}
break;
case Me_NOTHING:
case Me_PLAYERKEYUP:
case Me_SKIP:
break;
} // switch statement
} // Polling events
g_oBackend.ReadFromPerl();
SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
DrawPlayer( a_iPlayerWon );
if ( bTimeUp )
{
SDL_Rect oRect;
oRect.x = 0;
oRect.y = iFootY + FOOTHEIGHT - 10;
oRect.w = gamescreen->w;
oRect.h = gamescreen->h - oRect.y;
SDL_SetClipRect(gamescreen, &oRect);
}
DrawPlayer( 1-a_iPlayerWon );
SDL_SetClipRect( gamescreen, NULL );
if ( !bTimeUp )
{
int iNewCounter = iTimeLeft * iGameSpeed / 1000;
sprintf( acString, "%d", iNewCounter );
DrawTextMSZ( acString, inkFont, 320, 130, AlignHCenter, C_LIGHTCYAN, gamescreen );
if ( iNewCounter != iCounter )
{
Audio->PlaySample( "GAME_OVER_COUNTDOWN" );
iCounter = iNewCounter;
}
}
else
{
SDL_Rect oRect;
oRect.x = 40;
oRect.y = iFootY;
SDL_BlitSurface( poFoot, NULL, gamescreen, &oRect );
}
SDL_Flip( gamescreen );
if ( g_oState.m_bQuitFlag ||
SState::IN_DEMO == g_oState.m_enGameMode ||
bKeyPressed )
{
break;
}
}
if ( g_oState.m_bQuitFlag ||
SState::IN_DEMO == g_oState.m_enGameMode )
{
SDL_FreeSurface( poBackground );
return;
}
SDL_FillRect( gamescreen, NULL, C_BLACK );
if ( bTimeUp )
{
SDL_UnlockSurface( gamescreen );
DrawGradientText( "SPLAT!", titleFont, 220, gamescreen );
Audio->PlaySample( "GAME_OVER_SPLAT" );
SDL_Flip( gamescreen );
SDL_Delay( 1500 );
g_oState.m_enGameMode = SState::IN_DEMO;
}
else
{
SDL_Flip( gamescreen );
}
SDL_FreeSurface( poBackground );
return;
}
diff --git a/src/Joystick.h b/src/Joystick.h
index 289cd76..0c67ecf 100644
--- a/src/Joystick.h
+++ b/src/Joystick.h
@@ -1,50 +1,50 @@
/***************************************************************************
Joystick.h - description
-------------------
begin : Sat Feb 14 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
#ifndef JOYSTICK_H
#define JOYSTICK_H
#include "SDL.h"
struct SMortalEvent;
-
-/**
-\ingroup Media
+
+/**
+\ingroup Media
*/
class CJoystick
{
public:
CJoystick();
~CJoystick();
int Init();
bool TranslateEvent( const SDL_Event* a_poInEvent, SMortalEvent* a_poOutEvent );
const char* GetJoystickName( int a_iJoystickNumber );
protected:
int AxisWorkaround( const SDL_JoyAxisEvent& a_roEvent );
enum {
mg_iMaxJoysticks = 32,
};
int m_iNumJoysticks;
SDL_Joystick* m_apoJoysticks[mg_iMaxJoysticks];
const char* m_apcJoystickNames[mg_iMaxJoysticks];
bool m_abWorkaround[mg_iMaxJoysticks];
int m_aiHorizontalAxis[mg_iMaxJoysticks];
int m_aiVerticalAxis[mg_iMaxJoysticks];
};
extern CJoystick g_oJoystick;
#endif // JOYSTICK_H
diff --git a/src/MortalNetwork.h b/src/MortalNetwork.h
index 034de27..4dbeee8 100644
--- a/src/MortalNetwork.h
+++ b/src/MortalNetwork.h
@@ -1,136 +1,136 @@
/***************************************************************************
MortalNetwork.h - description
-------------------
begin : Sun Jan 25 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
#ifndef MORTALNETWORK_H
#define MORTALNETWORK_H
#include "FighterEnum.h"
#include "SDL_types.h"
-
-/**
-\defgroup Network Networking layer
-Classes related to networking (MortalNet and internet game)
-*/
+
+/**
+\defgroup Network Networking layer
+Classes related to networking (MortalNet and internet game)
+*/
/** Mortal Network messages:
\ingroup Network
TYPICAL MESSAGE FLOW:
<connection is established>
Introduction messages are sent (version checking, usernames)
<players go to the character selection screen>
1. F <number> messages go both ways as players choose their characters.
2. R message goes in both direction when players have finished choosing.
<both sides go to the game screen>
In odd rounds, the "server" if the "master" and the "client" is the "slave"
In even rounds, the "client" if the "master" and the "server" is the "slave"
Both the master and the slave send an S message to synchronize the game start.
The master sends G <text> messages to update the backend on the slave side.
The slave sends K <number> <bool> messages to communicate keystrokes to the master side.
The master sends O <number> <bool> message when the round is over.
Back to game start synchronization.
<both sides go to final judgement - may disconnect the game>
<both sides go back to the character selection screen>
OTHERS:
Msgs can be send on the character selection screen with M <text>.
The connection can be broken at any time. IsConnectionAlive() must be called
periodically.
The "server" is always appears as player 1, the "client" is always player 2.
However, they both use the "Player 1" keys.
*/
class CMortalNetwork
{
public:
struct SGameParams
{
Uint32 iRoundLength;
Uint32 iGameSpeed;
Uint32 iHitPoints;
Uint32 iBackgroundNumber;
};
public:
static void Create();
// Connection's lifecycle
virtual bool Start( const char* a_pcServerName ) = 0; // Accept connection, or connect to given server
virtual void Stop() = 0; // Disconnect
virtual bool IsConnectionAlive() = 0; // Is the connection still good?
virtual void Update() = 0; // Read network traffic. Might get disconnected...
virtual const char* GetLastError() = 0;
virtual bool IsMaster() = 0; // Am I Master or Slave?
// Msg related methods
virtual const char* GetRemoteUsername() = 0; // This is the name that is passed upon connection.
virtual void SendMsg( const char* a_rsMsg ) = 0; // Prompt the user for a line of chat text
virtual bool IsMsgAvailable() = 0; // Returns true is a chatline has arrived
virtual const char* GetMsg() = 0; // The next chatline, or NULL if there are no more.
// Charater Selection methods
virtual bool IsRemoteFighterAvailable( FighterEnum a_enFighter ) = 0; // Does the other computer have fighter X installed?
virtual FighterEnum GetRemoteFighter() = 0; // Returns the latest fighter chosen by the remote side.
virtual bool IsRemoteSideReady() = 0; // The other player is finished choosing.
virtual void SendFighter( FighterEnum a_enFighter ) = 0; // Let the other side know that I switched to fighter X.
virtual void SendReady() = 0; // Let the other side know that I am ready.
virtual void SendGameParams( int a_iGameSpeed, int a_iRoundLength, int a_iHitPoints, int a_iBackgroundNumber ) = 0;
virtual SGameParams GetGameParams() = 0;
// Game methods
virtual bool SynchStartRound() = 0;
virtual void SendGameData( const char* a_pcGameData ) = 0;
virtual const char* GetLatestGameData() = 0;
virtual void SendKeystroke( int a_iTime, int a_iKey, bool a_bPressed ) = 0;
virtual bool GetKeystroke( int& a_riOutTime, int& a_riOutKey, bool& a_rbPressed ) = 0;
virtual void SendGameTick( int a_iGameTick ) = 0;
virtual int GetGameTick() = 0;
virtual void SendHurryup( int a_iHurryUpCode ) = 0;
virtual int GetHurryup() = 0;
virtual void SendRoundOver( int a_iWhoWon, bool a_bGameOver ) = 0;
virtual bool IsRoundOver() = 0;
virtual bool IsGameOver() = 0;
virtual int GetWhoWon() = 0;
};
extern CMortalNetwork* g_poNetwork;
#endif // MORTALNETWORK_H
diff --git a/src/MortalNetworkImpl.h b/src/MortalNetworkImpl.h
index 7b93c0f..88af205 100644
--- a/src/MortalNetworkImpl.h
+++ b/src/MortalNetworkImpl.h
@@ -1,166 +1,166 @@
/***************************************************************************
MortalNetworkImpl.h - description
-------------------
begin : Sun Jan 25 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
#ifndef MORTALNETWORKIMPL_H
#define MORTALNETWORKIMPL_H
#include "MortalNetwork.h"
#include "SDL_net.h"
#include <string>
#include <list>
typedef std::list<int> TIntList;
typedef std::list<std::string> TStringList;
-/**
+/**
\ingroup Network
Implementation of the CMortalNetwork interface.
SUMMARY OF MESSAGES:
I <version> <username> - Introduction sent both ways on connection.
U <text> - Remote user's name
M <text> - Incoming Msg text.
S - Ready for the next round (synch).
G <text> - Update on the game backend data.
T <number> <number> - Update the game time and game phase.
K <number> <bool> - Key # up/down
H <number> - Hurryup and other special messages
O <number> <bool> - The round is over (who won, are there more rounds).
F <number> - I have switched to fighter X.
R - I have chosen a fighter.
Q <number> - Is fighter X available?
A <number> - Fighter A is available.
P <number> x3 - Game parameters
*/
class CMortalNetworkImpl: public CMortalNetwork
{
public:
CMortalNetworkImpl();
virtual ~CMortalNetworkImpl();
// Connection's lifecycle
bool Start( const char* a_pcServerName );
void Stop(); // Disconnect
bool IsConnectionAlive(); // Is the connection still good?
void Update(); // Read network traffic. Might get disconnected...
const char* GetLastError();
bool IsMaster(); // Am I Master or Slave?
// Msg related methods
const char* GetRemoteUsername(); // This is the name that is passed upon connection.
void SendMsg( const char* a_pcMsg ); // Prompt the user for a line of chat text
bool IsMsgAvailable(); // Returns true is a chatline has arrived
const char* GetMsg(); // The next chatline, or NULL if there are no more.
// Charater Selection methods
bool IsRemoteFighterAvailable( FighterEnum a_enFighter ); // Does the other computer have fighter X installed?
FighterEnum GetRemoteFighter(); // Returns the latest fighter chosen by the remote side.
bool IsRemoteSideReady(); // The other player is finished choosing.
void SendFighter( FighterEnum a_enFighter ); // Let the other side know that I switched to fighter X.
void SendReady(); // Let the other side know that I am ready.
void SendGameParams( int a_iGameSpeed, int a_iRoundLength, int a_iHitPoints, int a_iBackgroundNumber );
SGameParams GetGameParams();
// Game methods
bool SynchStartRound();
void SendGameData( const char* a_pcGameData );
const char* GetLatestGameData();
void SendKeystroke( int a_iTime, int a_iKey, bool a_bPressed );
bool GetKeystroke( int& a_riOutTime, int& a_riOutKey, bool& a_rbPressed );
void SendGameTick( int a_iGameTick );
int GetGameTick();
void SendHurryup( int a_iHurryUpCode );
int GetHurryup() ;
void SendRoundOver( int a_iWhoWon, bool a_bGameOver );
int GetWhoWon();
bool IsRoundOver();
bool IsGameOver();
protected:
void SendRawData( char a_cID, const void* a_pData, int a_iLength );
void ReceiveMsg( void* a_pData, int a_iLength );
void ReceiveRemoteUserName( void* a_pData, int a_iLength );
void ReceiveGameData( void* a_pData, int a_iLength );
void ReceiveKeystroke( void* a_pData, int a_iLength );
void ReceiveFighter( void* a_pData, int a_iLength );
void ReceiveReady( void* a_pData, int a_iLength );
void ReceiveRoundOver( void* a_pData, int a_iLength );
void ReceiveGameTick( void* a_pData, int a_iLength );
void ReceiveHurryup( void* a_pData, int a_iLength );
void ReceiveRemoteFighterAvailable( void* a_pData, int a_iLength );
void ReceiveRemoteFighterQuery( void* a_pData, int a_iLength );
void ReceiveGameParams( void* a_pData, int a_iLength );
protected:
enum TNetworkState
{
NS_DISCONNECTED,
NS_CHARACTER_SELECTION,
NS_IN_GAME,
};
// Network METADATA
bool m_bNetworkAvailable; ///< Is the networking API initialized correctly?
TNetworkState m_enState; ///< The current state
bool m_bServer; ///< We are the server side.
bool m_bMaster; ///< We are the master side. (Initially the server side)
TCPsocket m_poSocket; ///< The TCP/IP network socket.
SDLNet_SocketSet m_poSocketSet; ///< SDLNet construct for watching the socket.
char m_acIncomingBuffer[2048]; ///< Received data goes here.
int m_iIncomingBufferSize; ///< How much of the buffer is filled?
std::string m_sLastError; ///< The last error message from SDLNet
TStringList m_asMsgs; ///< Incoming chatlines
// GAME DATA
std::string m_sRemoteUserName;
TIntList m_aiAvailableRemoteFighters;
FighterEnum m_enRemoteFighter;
bool m_bRemoteReady;
SGameParams m_oGameParams;
std::string m_sLatestGameData;
TIntList m_aiKeyTimes;
TIntList m_aiKeystrokes;
TIntList m_abKeystrokes;
bool m_bRoundOver;
int m_iWhoWon;
bool m_bGameOver;
int m_iGameTick;
int m_iHurryupCode;
// REMOTE QUERY RESPONSES
bool m_bSynchQueryResponse;
};
#endif // MORTALNETWORKIMPL_H
diff --git a/src/MszPerl.h b/src/MszPerl.h
index 923c220..38f5faf 100644
--- a/src/MszPerl.h
+++ b/src/MszPerl.h
@@ -1,32 +1,32 @@
/***************************************************************************
MszPerl.h - description
-------------------
begin : Mon Jan 5 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
-/**
-\file MszPerl.h
-\ingroup GameLogic
+/**
+\file MszPerl.h
+\ingroup GameLogic
This file helps include perl.h
The windows version of perl.h contains a lot of stupid #defines, this
file helps undefine them.
*/
#ifndef __MSZPERL_H
#define __MSZPERL_H
#include <EXTERN.h>
#include <perl.h>
#ifdef _WINDOWS
#undef bool
#undef chdir
#undef close
#undef eof
#define vsnprintf _vsnprintf
#endif
#endif // __MSZPERL_H
diff --git a/src/OnlineChat.cpp b/src/OnlineChat.cpp
index 822dbc3..d951d18 100644
--- a/src/OnlineChat.cpp
+++ b/src/OnlineChat.cpp
@@ -1,754 +1,754 @@
/***************************************************************************
OnlineChat.cpp - description
-------------------
begin : Fri Jan 30 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
#include "OnlineChat.h"
#include "TextArea.h"
#include "State.h"
#include "menu.h"
#include "Audio.h"
#include "sge_tt_text.h"
#include "gfx.h"
#include "common.h"
#include "config.h"
#include "Event.h"
//#include "SDL_video.h"
#define MORTALNETSERVER "apocalypse.game-host.org"
#define MORTALNETWORKPORT 0x3A23
// Layout
#define READLINE_Y 440
#define NICKLIST_X 500
void MortalNetworkResetMessages( bool a_bClear );
void MortalNetworkMessage( const char* format, ... );
bool MortalNetworkCheckKey();
/*************************************************************************
CHAT / CHALLENGE MENUS
*************************************************************************/
enum
{
MENU_DISCONNECT = 100,
MENU_CHALLENGE,
MENU_CHANGENICK,
MENU_OK,
MENU_ACCEPTCHALLENGE,
MENU_REJECTHALLENGE,
};
-
-/**
-\ingroup Network
-Displays the 'you have been challenged' screen.
-*/
+
+/**
+\ingroup Network
+Displays the 'you have been challenged' screen.
+*/
class CChallengeMenu: public CMenu
{
public:
CChallengeMenu::CChallengeMenu( std::string a_sChallenger )
: CMenu( "You have been challenged!" ),
m_sChallenger( a_sChallenger )
{
m_bAccepted = false;
AddTextMenuItem( "ACCEPT CHALLENGE FROM ", m_sChallenger.c_str(), MENU_ACCEPTCHALLENGE );
AddMenuItem( "NO, I'M REALLY SCARED", SDLK_UNKNOWN, MENU_REJECTHALLENGE );
}
~CChallengeMenu() {}
bool GetAccepted()
{
return m_bAccepted;
}
void ItemActivated( int a_iItemCode, CMenuItem* a_poMenuItem )
{
switch ( a_iItemCode )
{
case MENU_ACCEPTCHALLENGE:
m_bAccepted = true;
// intentional fall through
case MENU_REJECTHALLENGE:
m_iReturnCode = 100;
m_bDone = true;
break;
}
}
protected:
std::string m_sChallenger;
bool m_bAccepted;
};
-/**
-\ingroup Network
-
-The Chat menu is displayed instead of the regular CMenu when the user is
-connected to MortalNet. The Chat menu has a different set of operations.
-*/
-
+/**
+\ingroup Network
+
+The Chat menu is displayed instead of the regular CMenu when the user is
+connected to MortalNet. The Chat menu has a different set of operations.
+*/
+
class CChatMenu: public CMenu
{
public:
CChatMenu( const TNickMap& a_roNicks )
: CMenu( "MortalNet Menu" ),
m_roNicks( a_roNicks )
{
int i=0;
TNickMap::const_iterator it;
for ( it=m_roNicks.begin();
it != m_roNicks.end() && i < 1023;
++it, ++i )
{
if ( it->first == g_oState.m_acNick )
{
--i;
continue;
}
m_apcNicks[i] = (it->first).c_str();
m_aiNicks[i] = i;
}
m_apcNicks[i] = NULL;
m_sNick = g_oState.m_acNick;
AddMenuItem( "DISCONNECT", SDLK_UNKNOWN, MENU_DISCONNECT );
if ( i > 0 )
{
AddEnumMenuItem( "CHALLENGE USER: ", 0, m_apcNicks, m_aiNicks, MENU_CHALLENGE );
}
m_poNickMenuItem = AddTextMenuItem( "Nickname: ", g_oState.m_acNick, MENU_CHANGENICK );
AddMenuItem( "~OPTIONS", SDLK_o, MENU_OPTIONS );
AddMenuItem( "QUIT", SDLK_UNKNOWN, MENU_QUIT );
AddOkCancel( MENU_OK );
}
virtual ~CChatMenu() {}
std::string GetNick()
{
return m_sNick;
}
std::string GetChallengedNick()
{
return m_sChallengedNick;
}
void ItemActivated( int a_iItemCode, CMenuItem* a_poMenuItem )
{
switch ( a_iItemCode )
{
case MENU_DISCONNECT:
g_oState.m_enGameMode = SState::IN_DEMO;
m_bDone = true;
m_iReturnCode = -1;
break;
case MENU_CHANGENICK:
{
EnterName( "Nickname: ", m_sNick, m_poNickMenuItem, 12 );
break;
}
case MENU_CHALLENGE:
{
m_sChallengedNick = ((CEnumMenuItem*)a_poMenuItem)->GetCurrentText();
m_bDone = true;
m_iReturnCode = 100;
break;
}
case MENU_OK:
{
m_bDone = true;
m_iReturnCode = -1;
break;
}
default:
CMenu::ItemActivated( a_iItemCode, a_poMenuItem );
} // end of switch statement
}
protected:
std::string m_sChallengedNick;
std::string m_sNick;
const TNickMap& m_roNicks;
const char* m_apcNicks[1024];
int m_aiNicks[1024];
CTextMenuItem* m_poNickMenuItem;
};
/*************************************************************************
CHAT CONNECT/DISCONNECT
*************************************************************************/
COnlineChat::COnlineChat()
{
m_poScreen = gamescreen;
m_poBackground = NULL;
m_poSocket = NULL;
m_poSocketSet = NULL;
m_iIncomingBufferSize = 0;
m_poReadline = NULL;
m_poTextArea = NULL;
}
COnlineChat::~COnlineChat()
{
Stop();
if ( m_poBackground )
{
SDL_FreeSurface( m_poBackground );
m_poBackground = NULL;
}
}
#define CHECKCONNECTION if ( m_poSocket == NULL ) return;
bool COnlineChat::Start()
{
if ( m_poSocket != NULL )
{
return true; // Already connected.
}
#define RETURNNOERROR { \
debug( "%s\n", m_sLastError.c_str() ); \
return false; }
#define RETURNWITHERROR { \
m_sLastError = SDLNet_GetError(); \
debug( "%s\n", m_sLastError.c_str() ); \
return false; }
#define RETURNWITHADDITIONALERROR { \
m_sLastError += SDLNet_GetError(); \
debug( "%s\n", m_sLastError.c_str() ); \
return false; }
m_poBackground = LoadBackground( "FighterStats.jpg", 64 );
if ( NULL == m_poBackground )
{
return false; // Should carp
}
SDL_BlitSurface( m_poBackground, NULL, m_poScreen, NULL );
SDL_Flip( m_poScreen );
MortalNetworkResetMessages( false );
MortalNetworkMessage( Translate("Resolving hostname (%s)..."), MORTALNETSERVER );
IPaddress oAddress;
int iResult = SDLNet_ResolveHost( &oAddress, MORTALNETSERVER, MORTALNETWORKPORT );
if ( iResult )
{
m_sLastError = Translate( "Couldn't resolve host." );
RETURNNOERROR;
}
debug( "IP Address of server is 0x%x\n", oAddress.host );
Uint32 ipaddr=SDL_SwapBE32(oAddress.host);
MortalNetworkMessage("Connecting to %d.%d.%d.%d port %d",
ipaddr>>24, (ipaddr>>16)&0xff, (ipaddr>>8)&0xff, ipaddr&0xff, oAddress.port);
MortalNetworkMessage ( Translate("Waiting for connection... (press any key to abort)") );
while (1)
{
m_poSocket = SDLNet_TCP_Open( &oAddress );
if ( m_poSocket ) break;
if ( MortalNetworkCheckKey() ) break;
SDL_Delay( 100 );
}
if ( NULL == m_poSocket )
{
RETURNWITHERROR;
}
// CONNECTION ESTABLISHED. SEND INTRO PACKETS
MortalNetworkMessage( Translate("Connection established.") );
m_poSocketSet = SDLNet_AllocSocketSet( 1 );
SDLNet_TCP_AddSocket( m_poSocketSet, m_poSocket ); // Check for errors?
m_iIncomingBufferSize = 0;
m_bMyNickIsOk = false;
m_asNicks.clear();
SendRawData( 'N', g_oState.m_acNick );
return ( m_poSocket != NULL );
}
void COnlineChat::Stop()
{
if ( m_poSocketSet )
{
SDLNet_FreeSocketSet( m_poSocketSet );
m_poSocketSet = NULL;
}
if ( m_poSocket )
{
SDLNet_TCP_Close( m_poSocket );
m_poSocket = NULL;
}
m_bMyNickIsOk = false;
m_asNicks.clear();
if ( g_oState.m_enGameMode == SState::IN_CHAT )
{
g_oState.m_enGameMode = SState::IN_DEMO;
}
}
/*************************************************************************
SENDING / RECEIVING CHAT DATA
*************************************************************************/
void COnlineChat::SendRawData( char a_cID, const std::string& a_rsData )
{
CHECKCONNECTION;
SDLNet_TCP_Send( m_poSocket, &a_cID, 1 );
SDLNet_TCP_Send( m_poSocket, (void*) a_rsData.c_str(), a_rsData.length() );
char cNL = '\n';
SDLNet_TCP_Send( m_poSocket, &cNL, 1 );
}
void COnlineChat::Update()
{
CHECKCONNECTION;
// 1. CHECK FOR STUFF TO READ
int iRetval = SDLNet_CheckSockets( m_poSocketSet, 0 );
if ( iRetval <= 0 )
{
return;
}
// 2. APPEND AT MOST 1024 bytes TO THE END OF THE INCOMING BUFFER
// CHECK FOR BUFFER OVERFLOW HERE.
if ( m_iIncomingBufferSize >= 1024*3 )
{
m_acIncomingBuffer[m_iIncomingBufferSize] = '\n';
m_acIncomingBuffer[m_iIncomingBufferSize+1] = 'x';
m_iIncomingBufferSize += 1;
}
else
{
iRetval = SDLNet_TCP_Recv( m_poSocket, m_acIncomingBuffer + m_iIncomingBufferSize, 1024 );
if ( iRetval <= 0 )
{
m_sLastError = SDLNet_GetError();
Stop();
return;
}
m_iIncomingBufferSize += iRetval;
}
// 3. CONSUME THE INCOMING BUFFER.
// We always make sure the incoming buffer starts with a package header.
int iOffset = 0;
m_acIncomingBuffer[ m_iIncomingBufferSize ] = 0;
bool bRedraw = false;
while ( iOffset < m_iIncomingBufferSize )
{
// 3.1. Find the end of the line.
char* pcLineEnd = strchr( m_acIncomingBuffer + iOffset, '\n' );
if ( NULL == pcLineEnd )
{
// The buffer doesn't have the end of the line (yet)
debug( "Buffer doesn't have the NL (%d buffer, %d offset)\n", m_iIncomingBufferSize, iOffset );
break;
}
*pcLineEnd = 0;
debug( "Receiving message: %d ('%c') type, %d length, %d offset, %d in buffer.\n",
m_acIncomingBuffer[iOffset], m_acIncomingBuffer[iOffset],
pcLineEnd - m_acIncomingBuffer - iOffset, iOffset, m_iIncomingBufferSize );
// 3.2. Receive the data.
switch ( m_acIncomingBuffer[iOffset] )
{
case 'M':
case 'S':
ReceiveMsg( m_acIncomingBuffer[iOffset], m_acIncomingBuffer + iOffset + 1 ); bRedraw = true; break;
case 'J':
case 'L':
case 'N':
case 'Y':
case 'W':
case 'C':
ReceiveUser( m_acIncomingBuffer[iOffset], m_acIncomingBuffer + iOffset + 1 ); bRedraw = true; break;
}
CHECKCONNECTION;
iOffset = pcLineEnd - m_acIncomingBuffer + 1;
}
// 4. MOVE LEFTOVER DATA TO THE BEGINNING OF THE INCOMING BUFFER
// The leftover data starts at iOffset, and is (m_iIncomingBufferSize-iOffset) long.
memmove( m_acIncomingBuffer, m_acIncomingBuffer + iOffset, m_iIncomingBufferSize-iOffset );
m_iIncomingBufferSize -= iOffset;
if ( bRedraw && m_poTextArea )
{
Audio->PlaySample( "NETWORK_MESSAGE" );
m_poTextArea->Redraw();
}
}
/*************************************************************************
INCOMING MESSAGES METHODS
*************************************************************************/
void COnlineChat::ReceiveMsg( char a_cID, char* a_pcData )
{
debug( "Received message %c, content is '%s'\n", a_cID, a_pcData );
if ( m_poTextArea )
{
m_poTextArea->AddString( a_pcData, a_cID == 'M' ? C_YELLOW : C_WHITE );
}
}
void COnlineChat::ReceiveUser( char a_cID, char* a_pcData )
{
debug( "Received user %c, content is '%s'\n", a_cID, a_pcData );
// Split up the data.
int iNumWords = 1;
char* pcFirstWord = a_pcData;
char* pcSecondWord = strchr( a_pcData, ' ' );
if ( pcSecondWord )
{
iNumWords = 2;
*pcSecondWord = 0;
++pcSecondWord;
}
int iColor = C_WHITE;
char acMsg[1024];
acMsg[0] = 0;
switch ( a_cID )
{
case 'J':
sprintf( acMsg, "*** %s has joined MortalChat from %s.", pcFirstWord, pcSecondWord );
if ( strcmp( pcFirstWord, g_oState.m_acNick ) != 0 )
{
m_asNicks[ pcFirstWord ] = pcSecondWord;
}
break;
case 'L':
{
sprintf( acMsg, "*** %s has left MortalChat.", pcFirstWord );
iColor = C_LIGHTRED;
m_asNicks.erase( pcFirstWord );
debug( "# of Nicks: %d\n", m_asNicks.size() );
break;
}
case 'N':
{
sprintf( acMsg, "%s is now known as %s", pcFirstWord, pcSecondWord );
iColor = C_LIGHTGRAY;
std::string sHost = m_asNicks[pcFirstWord];
m_asNicks.erase( pcFirstWord );
m_asNicks[ pcSecondWord ] = sHost;
break;
}
case 'Y':
sprintf( acMsg, "You are now known as %s", pcFirstWord );
iColor = C_LIGHTCYAN;
m_bMyNickIsOk = true;
m_asNicks.erase( g_oState.m_acNick );
m_asNicks[ pcFirstWord ] = "";
strncpy( g_oState.m_acNick, pcFirstWord, 127 );
g_oState.m_acNick[127] = 0;
break;
case 'W':
sprintf( acMsg, "%s is hailing from %s", pcFirstWord, pcSecondWord );
iColor = C_LIGHTGRAY;
m_asNicks[ pcFirstWord ] = pcSecondWord;
break;
case 'C':
CChallengeMenu oMenu( pcFirstWord );
DoMenu( oMenu );
if ( oMenu.GetAccepted() )
{
MortalNetworkResetMessages( true );
Connect( m_asNicks[pcFirstWord].c_str() );
}
Redraw();
break;
}
if ( m_poTextArea && m_bMyNickIsOk )
{
m_poTextArea->AddString( acMsg, iColor );
DrawNickList();
}
}
/*************************************************************************
DRAWING THE SCREEN
*************************************************************************/
void COnlineChat::Redraw()
{
SDL_BlitSurface( m_poBackground, NULL, m_poScreen, NULL );
m_poReadline->Redraw();
m_poTextArea->Redraw();
DrawNickList();
SDL_Flip( m_poScreen );
}
void COnlineChat::DrawNickList()
{
SDL_Rect oNickListRect;
oNickListRect.x = NICKLIST_X;
oNickListRect.y = 10;
oNickListRect.w = gamescreen->w - oNickListRect.x - 10;
oNickListRect.h = READLINE_Y - oNickListRect.y - 10;
SDL_Rect oOldClipRect;
SDL_GetClipRect( m_poScreen, &oOldClipRect );
SDL_SetClipRect( m_poScreen, &oNickListRect );
SDL_BlitSurface( m_poBackground, &oNickListRect, m_poScreen, &oNickListRect );
int y = oNickListRect.y + sge_TTF_FontAscent( chatFont );
int yEnd = oNickListRect.y + oNickListRect.h - sge_TTF_FontDescent( chatFont );
TNickMap::const_iterator it;
for ( it = m_asNicks.begin();
it != m_asNicks.end() && y <= yEnd;
++it , y += sge_TTF_FontHeight( chatFont ) )
{
int iColor = (it->first) == g_oState.m_acNick ? C_LIGHTCYAN : C_WHITE;
sge_tt_textout( m_poScreen, chatFont, (it->first).c_str(), oNickListRect.x, y, iColor, C_BLACK, 255 );
}
SDL_UpdateRect( m_poScreen, oNickListRect.x, oNickListRect.y, oNickListRect.w, oNickListRect.h );
SDL_SetClipRect( m_poScreen, NULL );
}
extern int g_iMessageY;
void COnlineChat::DoOnlineChat()
{
if ( !Start() )
{
if ( !g_oState.m_bQuitFlag )
{
DrawTextMSZ( "Couldn't connect", inkFont, 320, g_iMessageY, AlignHCenter|UseShadow, C_LIGHTRED, gamescreen );
DrawTextMSZ( m_sLastError.c_str(), impactFont, 320, g_iMessageY + 40, AlignHCenter|UseShadow, C_LIGHTRED, gamescreen, false );
GetKey( true );
}
return;
}
// CREATE USER INTERFACE ELEMENTS
char acMsg[256];
SDL_Event event;
SDL_BlitSurface( m_poBackground, NULL, m_poScreen, NULL );
SDL_Flip( m_poScreen );
m_poTextArea = new CTextArea( m_poScreen, chatFont, 10, 10, NICKLIST_X-20, READLINE_Y-20 );
m_poTextArea->TintBackground( C_DARKGRAY, 128 );
m_poReadline = new CReadline( m_poScreen, chatFont,
acMsg, 0, 255,
10, READLINE_Y + sge_TTF_FontAscent(chatFont), 620, C_LIGHTCYAN, C_BLACK, 255 );
while (1)
{
if ( g_oState.m_enGameMode != SState::IN_CHAT ) break;
if ( NULL == m_poSocket ) break;
Update();
if ( NULL == m_poSocket ) break;
SDL_Delay( 10 );
if ( g_oState.m_bQuitFlag ) break;
while (SDL_PollEvent(&event))
{
if ( SDL_KEYDOWN != event.type )
{
SMortalEvent oEvent;
TranslateEvent( &event, &oEvent );
switch (oEvent.m_enType)
{
case Me_MENU:
Menu();
break;
case Me_QUIT:
g_oState.m_bQuitFlag = true;
break;
default:
break;
}
continue;
}
// HANDLE SCROLLING THE TEXT AREA
if ( event.type == SDL_KEYDOWN )
{
SDLKey enKey = event.key.keysym.sym;
if ( enKey == SDLK_PAGEUP || enKey == SDLK_KP9 )
{
m_poTextArea->ScrollUp();
continue;
}
if ( enKey == SDLK_PAGEDOWN || enKey == SDLK_KP3 )
{
m_poTextArea->ScrollDown();
continue;
}
if ( enKey == SDLK_ESCAPE )
{
Menu();
continue;
}
}
m_poReadline->HandleKeyEvent( event );
int iResult = m_poReadline->GetResult();
if ( iResult > 0 )
{
if ( strlen( acMsg ) )
{
SendRawData( 'M', acMsg );
std::string sMsg = std::string("<") + g_oState.m_acNick + "> " + acMsg;
m_poTextArea->AddString( sMsg.c_str(), C_LIGHTCYAN );
m_poTextArea->Redraw();
}
m_poReadline->Clear();
acMsg[0] = 0;
m_poReadline->Restart( acMsg, strlen(acMsg), 256, C_LIGHTCYAN, C_BLACK, 255 );
}
}
}
if ( NULL == m_poSocket
&& !g_oState.m_bQuitFlag )
{
DrawTextMSZ( "Connection closed.", inkFont, 320, 210, AlignHCenter | UseShadow, C_WHITE, m_poScreen );
DrawTextMSZ( m_sLastError.c_str(), impactFont, 320, 250, AlignHCenter | UseShadow, C_WHITE, m_poScreen );
SDL_Delay( 1000 );
GetKey( true );
}
delete m_poReadline;
m_poReadline = NULL;
delete m_poTextArea;
m_poTextArea = NULL;
Stop();
}
void COnlineChat::Menu()
{
CChatMenu oMenu( m_asNicks );
DoMenu( oMenu );
if ( !g_oState.m_bQuitFlag )
{
if ( oMenu.GetNick() != g_oState.m_acNick )
{
SendRawData( 'N', oMenu.GetNick() );
}
if ( oMenu.GetChallengedNick().length() )
{
SendRawData( 'C', oMenu.GetChallengedNick() );
MortalNetworkResetMessages( true );
Connect( NULL );
}
Redraw();
}
}
/** Static global entry point for chatting. */
void DoOnlineChat()
{
g_oState.m_enGameMode = SState::IN_CHAT;
COnlineChat oChat;
oChat.DoOnlineChat();
}
diff --git a/src/OnlineChat.h b/src/OnlineChat.h
index 0ef7c65..2679869 100644
--- a/src/OnlineChat.h
+++ b/src/OnlineChat.h
@@ -1,95 +1,95 @@
/***************************************************************************
OnlineChat.h - description
-------------------
begin : Thu Jan 29 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
#ifndef ONLINECHAT_H
#define ONLINECHAT_H
-/**
-\class COnlineChat
-\ingroup Network
-The "mortal.net" chat protocol should be simple enough...
+/**
+\class COnlineChat
+\ingroup Network
+The "mortal.net" chat protocol should be simple enough...
[LOGGING IN]
Server: <greeting msg>
Client: N <version> <nickname>
Server: OK <actual nickname>
[CHATTING]
Server: J <user> <IP> - User joins.
Server: L <user> - User leaves.
Server: N <user> <newnick> - Nick change.
Server: W <user> <IP> - Whois response
Server: Y <num> - You are now known as...
Server: C <user> - Someone has challenged you!
Server: M <user> <text> - Public message.
Server: S <text> - Server message.
Client: M <text> - Send message.
Client: W <user> - WHOIS query
Client: L - Quit
Client: C <user> - Challenge a user
*/
#include "SDL_net.h"
#include <string>
#include <map>
class CReadline;
class CTextArea;
struct SDL_Surface;
typedef std::map<std::string,std::string> TNickMap;
class COnlineChat
{
public:
COnlineChat();
~COnlineChat();
bool Start();
void Stop();
void DoOnlineChat();
protected:
void Redraw();
void Update(); // Read network traffic. Might get disconnected...
void SendRawData( char a_cID, const std::string& a_rsData );
void ReceiveMsg( char a_cID, char* a_pcData );
void ReceiveUser( char a_cID, char* a_pcData );
void DrawNickList();
void Menu();
protected:
TCPsocket m_poSocket; ///< The TCP/IP network socket.
SDLNet_SocketSet m_poSocketSet; ///< SDLNet construct for watching the socket.
char m_acIncomingBuffer[4096]; ///< Received data goes here.
int m_iIncomingBufferSize; ///< How much of the buffer is filled?
std::string m_sLastError; ///< The last error message from SDLNet
SDL_Surface* m_poScreen;
SDL_Surface* m_poBackground;
CReadline* m_poReadline;
CTextArea* m_poTextArea;
bool m_bMyNickIsOk;
TNickMap m_asNicks;
};
#endif // ONLINECHAT_H
diff --git a/src/OnlineChatBE.cpp b/src/OnlineChatBE.cpp
index afa3746..4f49684 100755
--- a/src/OnlineChatBE.cpp
+++ b/src/OnlineChatBE.cpp
@@ -1,75 +1,75 @@
//
// C++ Implementation: onlinechatbe
//
// Description:
//
//
// Author: upi <upi@feel>, (C) 2004
//
// Copyright: See COPYING file that comes with this distribution
//
//
-/*
-#include "OnlineChatBE.h"
-#include "common.h"
-#include "SDL_net.h"
-
-class COnlineChatBEImpl: public IOnlineChatBE
-{
-protected:
- ConnectionStateEnum m_enConnectionState;
-
-public:
- // Lifecycle control
- COnlineChatBEImpl();
- virtual ~COnlineChatBEImpl() {}
-
- // Connection
-
- virtual void connect( std::string a_sNick );
- virtual void disconnect();
- virtual ConnectionStateEnum getConnectionState() const;
-
- // Getting/setting my connection parameters
-
- virtual std::string getMyNick() const;
- virtual void setMyNick( std::string a_sNick );
- virtual ClientModeEnum getMyClientMode() const;
- virtual void setMyClientMode( ClientModeEnum a_enClientMode );
- virtual const UserInfo& getMyUserInfo() const; ///< Same as getUserInfo(0)
-
- // User control
-
- virtual int getUserCount() const;
- virtual const UserInfo& getUserInfo( int a_iUserNumber ) const;
- virtual ClientModeEnum getClientMode() const;
- virtual void setClientMode( ClientModeEnum a_newMode );
-
- // Event sinks
-
- virtual void addEventSink( IOnlineEventSink* a_poSink );
- virtual void removeEventSink( IOnlineEventSink* a_poSink );
- virtual void removeAllEventSinks();
-};
-
-COnlineChatBEImpl::COnlineChatBEImpl()
-{
- m_enConnectionState = CS_Disconnected;
-}
-
-void COnlineChatBEImpl::connect( std::string a_sNick )
-{
- if ( m_enConnectionState != CS_Disconnected )
- {
- debug( "COnlineChatBEImpl::connect: Not in disconnected state!\n" );
- return;
- }
- m_enConnectionState = CS_Connecting;
-
-
-}
-
-void COnlineChatBEImpl::disconnect()
-{
-}
+/*
+#include "OnlineChatBE.h"
+#include "common.h"
+#include "SDL_net.h"
+
+class COnlineChatBEImpl: public IOnlineChatBE
+{
+protected:
+ ConnectionStateEnum m_enConnectionState;
+
+public:
+ // Lifecycle control
+ COnlineChatBEImpl();
+ virtual ~COnlineChatBEImpl() {}
+
+ // Connection
+
+ virtual void connect( std::string a_sNick );
+ virtual void disconnect();
+ virtual ConnectionStateEnum getConnectionState() const;
+
+ // Getting/setting my connection parameters
+
+ virtual std::string getMyNick() const;
+ virtual void setMyNick( std::string a_sNick );
+ virtual ClientModeEnum getMyClientMode() const;
+ virtual void setMyClientMode( ClientModeEnum a_enClientMode );
+ virtual const UserInfo& getMyUserInfo() const; ///< Same as getUserInfo(0)
+
+ // User control
+
+ virtual int getUserCount() const;
+ virtual const UserInfo& getUserInfo( int a_iUserNumber ) const;
+ virtual ClientModeEnum getClientMode() const;
+ virtual void setClientMode( ClientModeEnum a_newMode );
+
+ // Event sinks
+
+ virtual void addEventSink( IOnlineEventSink* a_poSink );
+ virtual void removeEventSink( IOnlineEventSink* a_poSink );
+ virtual void removeAllEventSinks();
+};
+
+COnlineChatBEImpl::COnlineChatBEImpl()
+{
+ m_enConnectionState = CS_Disconnected;
+}
+
+void COnlineChatBEImpl::connect( std::string a_sNick )
+{
+ if ( m_enConnectionState != CS_Disconnected )
+ {
+ debug( "COnlineChatBEImpl::connect: Not in disconnected state!\n" );
+ return;
+ }
+ m_enConnectionState = CS_Connecting;
+
+
+}
+
+void COnlineChatBEImpl::disconnect()
+{
+}
*/
\ No newline at end of file
diff --git a/src/OnlineChatBE.h b/src/OnlineChatBE.h
index acd45c4..f76b392 100755
--- a/src/OnlineChatBE.h
+++ b/src/OnlineChatBE.h
@@ -1,142 +1,142 @@
//
// C++ Interface: onlinechatbe
//
// Description:
//
//
// Author: upi <upi@apocalypse.rulez.org>, (C) 2004
//
// Copyright: See COPYING file that comes with this distribution
//
//
#ifndef ONLINECHATBE_H
#define ONLINECHATBE_H
#include <string>
class IOnlineEventSink;
struct SOnlineChatBE_P;
/**
This is a backend class which implements communication services with the MortalNet backend.
The backend doesn't provide any frontend or interactivity and is meant to run independently in its own thread.
-\author upi
+\author upi
\ingroup Network
*/
class IOnlineChatBE
{
public:
enum ConnectionStateEnum
{
CS_Disconnected, ///< The backend is not connected to the server.
CS_Connecting, ///< The backend is trying to connect to the server.
CS_Connected, ///< Connected.
CS_Disconnecting,
};
enum ClientModeEnum
{
CM_Chatroom, ///< The user is rotting away in the chatroom
CM_Game, ///< The user is playing a game. He'll be back.
CM_Away, ///< The user is not at all here, he just left his client running
CM_WaitingForChallenge, ///< The user is not running the game, but is waiting for a challenge.
};
enum ChatEventEnum
{
CE_Nothing,
CE_MyNick, ///< You are now known as...
CE_Challenge, ///< Challenged by user X
CE_Message, ///< Message from user X
CE_Joins, ///< User X has joined MortalNet
CE_Leaves, ///< User X has left MortalNet
CE_NickChange, ///< User X is now known as Y
CE_ServerMessage, ///< Miscellaneous info from server
};
struct UserInfo
{
std::string m_sNick; ///< The name of the user
ClientModeEnum m_enClientMode; ///< The client mode of the user
std::string m_sHostName; ///< The hostname that is displayed for the user (reverse lookup by MortalNet)
std::string m_sHostAddress; ///< The host address string of the user (IPV4 or IPV6 number).
UserInfo();
UserInfo( const UserInfo& a_roRhs );
UserInfo& operator=( const UserInfo& a_roRhs );
};
struct SChatEvent
{
ChatEventEnum m_enEvent;
UserInfo m_sUser;
std::string m_sMessage;
};
protected:
// Lifecycle control
IOnlineChatBE() {}
virtual ~IOnlineChatBE() {}
public:
static void create();
// Connection
virtual void connect( std::string a_sNick ) = 0;
virtual void disconnect() = 0;
virtual ConnectionStateEnum getConnectionState() const = 0;
// Getting/setting my connection parameters
virtual std::string getMyNick() const = 0;
virtual void setMyNick( std::string a_sNick ) = 0;
virtual ClientModeEnum getMyClientMode() const = 0;
virtual void setMyClientMode( ClientModeEnum a_enClientMode ) = 0;
virtual const UserInfo& getMyUserInfo() const = 0; ///< Same as getUserInfo(0)
// User control
virtual int getUserCount() const = 0;
virtual const UserInfo& getUserInfo( int a_iUserNumber ) const = 0;
virtual ClientModeEnum getClientMode() const = 0;
virtual void setClientMode( ClientModeEnum a_newMode ) = 0;
// Event sinks
virtual void addEventSink( IOnlineEventSink* a_poSink ) = 0;
virtual void removeEventSink( IOnlineEventSink* a_poSink ) = 0;
virtual void removeAllEventSinks() = 0;
};
extern IOnlineChatBE* g_poChatBE;
/** IBackendEventSink is an interface for receiving events from IOnlineChatBE.
Every backend event sink which is registered to g_poChatBE will be notified of
chat events as they occur. This is done with the receiveEvent() method.
*/
class IOnlineEventSink
{
public:
IOnlineEventSink() {}
virtual ~IOnlineEventSink() {}
virtual void receiveEvent( const IOnlineChatBE::SChatEvent& a_roEvent ) = 0;
virtual void connectionStateChange( IOnlineChatBE::ConnectionStateEnum a_enOldState,
IOnlineChatBE::ConnectionStateEnum a_enNewState,
const std::string& a_rsMessage ) = 0;
};
#endif
diff --git a/src/PlayerSelect.cpp b/src/PlayerSelect.cpp
index 4a1b381..2117b7d 100644
--- a/src/PlayerSelect.cpp
+++ b/src/PlayerSelect.cpp
@@ -1,254 +1,254 @@
/***************************************************************************
PlayerSelect.cpp - description
-------------------
begin : Sun Dec 8 2002
copyright : (C) 2002 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include <stdio.h>
#include "PlayerSelect.h"
#include "PlayerSelectController.h"
#include "SDL.h"
#include "SDL_video.h"
#include "SDL_image.h"
#include "sge_primitives.h"
#include "sge_surface.h"
#include "common.h"
#include "Audio.h"
#include "sge_bm_text.h"
#include "gfx.h"
#include "RlePack.h"
#include "Backend.h"
#include "State.h"
#include "MortalNetwork.h"
#include "Chooser.h"
#include "sge_tt_text.h"
#include "TextArea.h"
#include "Event.h"
#ifndef NULL
#define NULL 0
#endif
/***************************************************************************
PUBLIC EXPORTED VARIABLES
***************************************************************************/
CPlayerSelect g_oPlayerSelect;
CPlayerSelect::CPlayerSelect()
{
for ( int i=0; i<MAXPLAYERS; ++i )
{
m_aoPlayers[i].m_enFighter = UNKNOWN;
m_aoPlayers[i].m_enTint = NO_TINT;
m_aoPlayers[i].m_poPack = NULL;
}
}
/*************************************************************************
GENERAL PLAYER INFO
*************************************************************************/
-
-/**
-Returns the info of a given player. The most important piece in the info
-is the player's CRlePack which is used for drawing the player in the Game,
-the GameOver and the FighterInfo screens.
-*/
+
+/**
+Returns the info of a given player. The most important piece in the info
+is the player's CRlePack which is used for drawing the player in the Game,
+the GameOver and the FighterInfo screens.
+*/
const SPlayerInfo& CPlayerSelect::GetPlayerInfo( int a_iPlayer )
{
return m_aoPlayers[ a_iPlayer ];
}
SPlayerInfo& CPlayerSelect::EditPlayerInfo( int a_iPlayer )
{
return m_aoPlayers[ a_iPlayer ];
}
const char* CPlayerSelect::GetFighterName( int a_iPlayer )
{
return m_aoPlayers[ a_iPlayer ].m_sFighterName.c_str();
}
int CPlayerSelect::GetFighterNameWidth( int a_iPlayer )
{
return m_aiFighterNameWidth[ a_iPlayer ];
}
-
-/**
-Returns true if the given fighter can be used.
-Some fighters are just not in the data files yet, or not installed.
+
+/**
+Returns true if the given fighter can be used.
+Some fighters are just not in the data files yet, or not installed.
*/
bool CPlayerSelect::IsFighterAvailable( FighterEnum a_enFighter )
{
if ( a_enFighter <= UNKNOWN )
{
return false;
}
bool bLocalAvailable = IsLocalFighterAvailable( a_enFighter );
if ( SState::IN_NETWORK != g_oState.m_enGameMode || !bLocalAvailable )
{
return bLocalAvailable;
}
// Check the remote site
return g_poNetwork->IsRemoteFighterAvailable( a_enFighter );
}
bool CPlayerSelect::IsLocalFighterAvailable( FighterEnum a_enFighter )
{
if ( a_enFighter <= UNKNOWN )
{
return false;
}
g_oBackend.PerlEvalF("GetFighterStats(%d);", a_enFighter);
const char* pcDatafile = g_oBackend.GetPerlString("Datafile");
return pcDatafile && *pcDatafile;
}
bool CPlayerSelect::IsFighterInTeam( FighterEnum a_enFighter )
{
std::vector<FighterEnum>::const_iterator it;
for ( int i=0; i<g_oState.m_iNumPlayers; ++i )
{
std::vector<FighterEnum>& roTeam = m_aoPlayers[i].m_aenTeam;
for ( it=roTeam.begin(); it!=roTeam.end(); ++it )
{
if ( a_enFighter == *it )
{
return true;
}
}
}
return false;
}
/** LoadFighter simply looks up the filename associated with the given
fighter, loads it, and returns the CRlePack.
\return The freshly loaded CRlePack, or NULL if it could not be loaded.
*/
CRlePack* CPlayerSelect::LoadFighter( FighterEnum m_enFighter ) // static
{
char a_pcFilename[FILENAME_MAX+1];
const char* s;
g_oBackend.PerlEvalF( "GetFighterStats(%d);", m_enFighter );
s = g_oBackend.GetPerlString( "Datafile" );
strcpy( a_pcFilename, DATADIR );
strcat( a_pcFilename, "/characters/" );
strcat( a_pcFilename, s );
CRlePack* pack = new CRlePack( a_pcFilename, COLORSPERPLAYER );
if ( pack->Count() <= 0 )
{
debug( "Couldn't load CRlePack: '%s'\n", a_pcFilename );
delete pack;
return NULL;
}
return pack;
}
/** SetPlayer loads the given fighter for the given player.
The CRlePack is loaded first. If that succeeds, then the perl backend is
set too. The tint and palette of both players are set. */
void CPlayerSelect::SetPlayer( int a_iPlayer, FighterEnum a_enFighter )
{
if ( m_aoPlayers[a_iPlayer].m_enFighter == a_enFighter )
{
if ( m_aoPlayers[a_iPlayer].m_poPack )
{
m_aoPlayers[a_iPlayer].m_poPack->ApplyPalette();
}
return;
}
if ( !IsFighterAvailable( a_enFighter ) )
{
return;
}
int iOffset = COLOROFFSETPLAYER1 + a_iPlayer*64;
CRlePack* poPack = LoadFighter( a_enFighter );
poPack->OffsetSprites( iOffset );
if ( NULL == poPack )
{
debug( "SetPlayer(%d,%d): Couldn't load CRlePack\n", a_iPlayer, a_enFighter );
return;
}
delete m_aoPlayers[a_iPlayer].m_poPack;
m_aoPlayers[a_iPlayer].m_poPack = poPack;
m_aoPlayers[a_iPlayer].m_enFighter = a_enFighter;
g_oBackend.PerlEvalF( "SetPlayerNumber(%d,%d);", a_iPlayer, a_enFighter );
m_aoPlayers[a_iPlayer].m_sFighterName = g_oBackend.GetPerlString( "PlayerName" );
m_aiFighterNameWidth[a_iPlayer] = sge_BF_TextSize( fastFont, GetFighterName(a_iPlayer) ).w;
TintEnum enTint = NO_TINT;
//@ CLASHES WITH OTHER PLAYERS NEED TO BE HANDLED
if ( m_aoPlayers[0].m_enFighter == m_aoPlayers[1].m_enFighter )
{
enTint = TintEnum( (rand() % 4) + 1 );
}
SetTint( 1, enTint );
m_aoPlayers[a_iPlayer].m_poPack->ApplyPalette();
}
void CPlayerSelect::SetTint( int a_iPlayer, TintEnum a_enTint )
{
m_aoPlayers[a_iPlayer].m_enTint = a_enTint;
if ( m_aoPlayers[a_iPlayer].m_poPack )
{
m_aoPlayers[a_iPlayer].m_poPack->SetTint( a_enTint );
m_aoPlayers[a_iPlayer].m_poPack->ApplyPalette();
}
}
-
+
void CPlayerSelect::DoPlayerSelect()
{
CPlayerSelectController oController( SState::IN_NETWORK == g_oState.m_enGameMode );
oController.DoPlayerSelect();
}
diff --git a/src/PlayerSelect.h b/src/PlayerSelect.h
index 391970d..62f671e 100644
--- a/src/PlayerSelect.h
+++ b/src/PlayerSelect.h
@@ -1,102 +1,102 @@
/***************************************************************************
PlayerSelect.h - description
-------------------
begin : 2003-09-05
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifndef PLAYERSELECT_H
#define PLAYERSELECT_H
#define COLORSPERPLAYER 64
#define COLOROFFSETPLAYER1 112
#define COLOROFFSETPLAYER2 (COLOROFFSETPLAYER1+64)
-/**
-\defgroup PlayerSelect Fighter selection
-This module runs the fighter selection part of the game.
-*/
+/**
+\defgroup PlayerSelect Fighter selection
+This module runs the fighter selection part of the game.
+*/
#include "FighterEnum.h"
#include "common.h"
#include <string>
#include <vector>
class CRlePack;
struct SDL_Surface;
class CTextArea;
class CReadline;
-
-
+
+
/** PlayerInfo structure stores information about a PLAYER.
In OpenMortal, the term PLAYER refers to one of the two guys playing the
game, as opposed to FIGHTER, which refers to one of the many playable
characters.
PlayerInfo stores: the player's selected fighter, the fighters tint and
-CRlePack.
-\ingroup PlayerSelect
+CRlePack.
+\ingroup PlayerSelect
*/
struct SPlayerInfo
{
FighterEnum m_enFighter;
TintEnum m_enTint;
CRlePack* m_poPack;
std::string m_sFighterName;
std::vector<FighterEnum> m_aenTeam;
};
-/** This class implements services that allows players to select their fighters.
-
+/** This class implements services that allows players to select their fighters.
+
It also stores info about which fighter is available, and
allows other parts of the program to programmatically assign a fighter
to a player, and set fighter tints (this is used by e.g. the "frozen"
-effect.)
-
-This is the model part model-view-controller architecture of the player selection.
-
-
-\ingroup PlayerSelect
+effect.)
+
+This is the model part model-view-controller architecture of the player selection.
+
+
+\ingroup PlayerSelect
*/
class CPlayerSelect
{
public:
CPlayerSelect();
const SPlayerInfo& GetPlayerInfo( int a_iPlayer );
SPlayerInfo& EditPlayerInfo( int a_iPlayer );
const char* GetFighterName( int a_iPlayer );
int GetFighterNameWidth( int a_iPlayer );
void DoPlayerSelect();
void SetPlayer( int a_iPlayer, FighterEnum a_enFighter );
void SetTint( int a_iPlayer, TintEnum a_enFighter );
bool IsFighterAvailable( FighterEnum a_enFighter );
bool IsLocalFighterAvailable( FighterEnum a_enFighter );
bool IsFighterInTeam( FighterEnum a_enFighter );
protected:
static CRlePack* LoadFighter( FighterEnum m_enFighter );
protected:
SPlayerInfo m_aoPlayers[MAXPLAYERS];
int m_aiFighterNameWidth[MAXPLAYERS];
};
extern CPlayerSelect g_oPlayerSelect;
#endif // PLAYERSELECT_H
diff --git a/src/PlayerSelectController.cpp b/src/PlayerSelectController.cpp
index d9cef95..5b4cca7 100644
--- a/src/PlayerSelectController.cpp
+++ b/src/PlayerSelectController.cpp
@@ -1,505 +1,505 @@
-#include "PlayerSelectController.h"
-#include "PlayerSelectView.h"
-#include "PlayerSelect.h"
-#include "Chooser.h"
-#include "MortalNetwork.h"
-#include "State.h"
-#include "Backend.h"
-#include "Event.h"
-#include "Audio.h"
-
-#include "TextArea.h"
-#include "sge_tt_text.h"
-#include "common.h"
-
-
-
-int GetBackgroundNumber();
-
-
-
-CPlayerSelectController::CPlayerSelectController( bool a_bNetworkGame )
-{
- m_bNetworkGame = a_bNetworkGame;
- m_bTeamMode = SState::Team_CUSTOM == g_oState.m_enTeamMode;
- m_poView = new CPlayerSelectView( a_bNetworkGame, m_bTeamMode );
-}
-
-
-CPlayerSelectController::~CPlayerSelectController()
-{
- delete m_poView;
- m_poView = NULL;
-}
-
-
-
-void CPlayerSelectController::GetThisTick()
-{
- m_iLastTick = m_iThisTick;
-
- while (1)
- {
- m_iThisTick = SDL_GetTicks() / m_iGameSpeed;
- if ( m_iThisTick==m_iLastTick )
- {
- SDL_Delay(1);
- }
- else
- {
- break;
- }
- }
-}
-
-
-
-bool CPlayerSelectController::HandleChatKey( SDL_Event& a_roEvent )
-{
- if ( !m_bNetworkGame )
- {
- return false;
- }
-
- SDLKey enKey = a_roEvent.key.keysym.sym;
-
- if ( enKey == SDLK_PAGEUP || enKey == SDLK_KP9 )
- {
- m_poView->GetTextArea()->ScrollUp();
- return true;
- }
- if ( enKey == SDLK_PAGEDOWN || enKey == SDLK_KP3 )
- {
- m_poView->GetTextArea()->ScrollDown();
- return true;
- }
-
- if ( !m_bChatActive && ( SDLK_TAB == enKey
- || SDLK_RETURN == enKey || SDLK_KP_ENTER == enKey ) )
- {
- // Activate chat.
- m_acChatMsg[0] = 0;
- m_poView->GetReadline()->Clear();
- m_poView->GetReadline()->Restart( m_acChatMsg, strlen(m_acChatMsg), 256, C_LIGHTCYAN, C_BLACK, 255 );
- m_bChatActive = true;
- return true;
- }
-
- if ( !m_bChatActive )
- {
- return false;
- }
-
- if ( SDLK_ESCAPE == enKey || SDLK_TAB == enKey )
- {
- // Deactivate chat.
- m_poView->GetReadline()->Clear();
- m_bChatActive = false;
- return true;
- }
-
- // other keys..
-
- m_poView->GetReadline()->HandleKeyEvent( a_roEvent );
- int iResult = m_poView->GetReadline()->GetResult();
-
- if ( iResult < 0 )
- {
- // Escape was pressed?
- m_poView->GetReadline()->Clear();
- m_bChatActive = false;
- }
- if ( iResult > 0 )
- {
- if ( strlen( m_acChatMsg ) )
- {
- g_poNetwork->SendMsg( m_acChatMsg );
- std::string sMsg = std::string("<") + g_oState.m_acNick + "> " + m_acChatMsg;
- m_poView->GetTextArea()->AddString( sMsg.c_str(), C_LIGHTCYAN );
- m_poView->GetTextArea()->Redraw();
-
- m_acChatMsg[0] = 0;
- m_poView->GetReadline()->Clear();
- m_poView->GetReadline()->Restart( m_acChatMsg, strlen(m_acChatMsg), 256, C_LIGHTCYAN, C_BLACK, 255 );
- }
- else
- {
- m_poView->GetReadline()->Clear();
- m_bChatActive = false;
- }
- }
-
- return true;
-}
-
-
-
-void CPlayerSelectController::HandleEvents()
-{
- SDL_Event oSdlEvent;
- while (SDL_PollEvent(&oSdlEvent))
- {
- if ( m_bNetworkGame
- && SDL_KEYDOWN == oSdlEvent.type )
- {
- if (HandleChatKey( oSdlEvent ))
- {
- continue;
- }
- }
-
- if ( m_bNetworkGame
- && SDL_KEYDOWN == oSdlEvent.type
- && (oSdlEvent.key.keysym.sym == SDLK_RETURN || oSdlEvent.key.keysym.sym==SDLK_KP_ENTER) )
- {
- m_bChatActive = true;
- continue;
- }
-
- SMortalEvent oEvent;
- TranslateEvent( &oSdlEvent, &oEvent );
-
- switch ( oEvent.m_enType )
- {
- case Me_QUIT:
- g_oState.m_bQuitFlag = true;
- break;
-
- case Me_MENU:
- DoMenu();
- if ( m_bNetworkGame && g_poNetwork->IsMaster() )
- {
- g_poNetwork->SendGameParams( g_oState.m_iGameSpeed, g_oState.m_iRoundLength, g_oState.m_iHitPoints, GetBackgroundNumber() );
- }
- break;
-
- case Me_PLAYERKEYDOWN:
- HandleKey( oEvent.m_iPlayer, oEvent.m_iKey );
- break;
-
- case Me_NOTHING:
- case Me_SKIP:
- case Me_PLAYERKEYUP:
- break;
- } // end of switch statement
- }
-}
-
-
-
-void CPlayerSelectController::HandleKey( int a_iPlayer, int a_iKey )
-{
- if ( m_bNetworkGame )
- {
- a_iPlayer = g_poNetwork->IsMaster() ? 0 : 1;
- }
-
- if ( !m_abPlayerActive[a_iPlayer] )
- {
- return;
- }
-
- int iSetPlayer = a_iPlayer;
- if ( m_bTeamMode && !g_oState.m_bTeamMultiselect )
- {
- iSetPlayer = 0;
- }
-
- // MOVE THE CURSOR
-
- if ( a_iKey < 4 )
- {
- g_oChooser.MoveRectangle( a_iPlayer, a_iKey );
- FighterEnum enNewFighter = g_oChooser.GetCurrentFighter( a_iPlayer );
- if ( enNewFighter != g_oPlayerSelect.GetPlayerInfo( iSetPlayer ).m_enFighter )
- {
- Audio->PlaySample("PLAYER_SELECTION_CHANGES");
- if ( IsFighterSelectable(enNewFighter) )
- {
- if ( m_bNetworkGame )
- {
- g_poNetwork->SendFighter( enNewFighter );
- }
-
- g_oPlayerSelect.SetPlayer( iSetPlayer, enNewFighter );
- }
- }
- return;
- }
-
- // SELECT THE CURRENT FIGHTER
-
- FighterEnum enFighter = g_oChooser.GetCurrentFighter( a_iPlayer );
- if ( !IsFighterSelectable( enFighter ) )
- {
- // Current fighter cannot be selected.
- return;
- }
-
- Audio->PlaySample("PLAYER_SELECTED");
- g_oBackend.PerlEvalF( "PlayerSelected(%d);", iSetPlayer );
- if ( m_bNetworkGame )
- {
- g_poNetwork->SendFighter( enFighter );
- g_poNetwork->SendReady();
- }
-
- bool bKeepPlayerActive = false;
-
- SPlayerInfo& roInfo = g_oPlayerSelect.EditPlayerInfo(a_iPlayer);
- const SPlayerInfo& roOtherInfo = g_oPlayerSelect.GetPlayerInfo(1-a_iPlayer);
- int iTeamSize = roInfo.m_aenTeam.size() + 1;
- int iOtherTeamSize = roOtherInfo.m_aenTeam.size();
-
- if ( m_bTeamMode )
- {
- m_poView->AddFighterToTeam( a_iPlayer, enFighter );
- roInfo.m_aenTeam.push_back( enFighter );
-
- if ( g_oState.m_bTeamMultiselect )
- {
- SetPlayerActive( a_iPlayer, iTeamSize < g_oState.m_iTeamSize );
- }
- else
- {
- --m_iNumberOfSelectableFighters;
- g_oChooser.MarkFighter( enFighter, a_iPlayer ? C_LIGHTMAGENTA : C_LIGHTGREEN );
- ActivateNextPlayer( a_iPlayer );
- }
- }
- else
- {
- roInfo.m_aenTeam.clear();
- roInfo.m_aenTeam.push_back( enFighter );
- SetPlayerActive( a_iPlayer, false );
- }
-
-}
-
-
-void CPlayerSelectController::HandleNetwork()
-{
- g_poNetwork->Update();
-
- // 1. READ CHAT MESSAGES
-
- bool bUpdateText = false;
- while ( g_poNetwork->IsMsgAvailable() )
- {
- const char* pcMsg = g_poNetwork->GetMsg();
- int iColor = C_YELLOW;
- if ( pcMsg[0] == '*' && pcMsg[1] == '*' && pcMsg[2] == '*' ) iColor = C_WHITE;
- m_poView->GetTextArea()->AddString( pcMsg, iColor );
- bUpdateText = true;
- }
- if ( bUpdateText )
- {
- Audio->PlaySample("NETWORK_MESSAGE");
- m_poView->GetTextArea()->Redraw();
- }
-
- // 2. READ PLAYER SELECTION ACTIONS
-
- bool bMaster = g_poNetwork->IsMaster();
- int iPlayer = bMaster ? 1 : 0;
-
- if ( !m_abPlayerActive[iPlayer] )
- {
- return;
- }
-
- FighterEnum enOldFighter = g_oPlayerSelect.GetPlayerInfo(iPlayer).m_enFighter;
- FighterEnum enRemoteFighter = g_poNetwork->GetRemoteFighter();
-
- if ( enOldFighter != enRemoteFighter
- && enRemoteFighter != UNKNOWN )
- {
- Audio->PlaySample("PLAYER_SELECTION_CHANGES");
- g_oPlayerSelect.SetPlayer( iPlayer, enRemoteFighter );
- g_oChooser.SetRectangle( iPlayer, enRemoteFighter );
- }
-
- bool bDone = g_poNetwork->IsRemoteSideReady();
- if ( bDone )
- {
- m_abPlayerActive[iPlayer] = false;
- Audio->PlaySample("PLAYER_SELECTED");
- g_oBackend.PerlEvalF( "PlayerSelected(%d);", iPlayer );
-
- SPlayerInfo& roInfo = g_oPlayerSelect.EditPlayerInfo( iPlayer );
-
- roInfo.m_aenTeam.clear();
- roInfo.m_aenTeam.push_back( enRemoteFighter );
- SetPlayerActive( iPlayer, false );
- }
-}
-
-
-
-void CPlayerSelectController::MarkFighters()
-{
- int iNumberOfFighters = g_oBackend.GetNumberOfFighters();
- int i;
-
- for ( i=0; i<iNumberOfFighters; ++i )
- {
- FighterEnum enFighter = g_oBackend.GetFighterID( i );
- if ( !g_oPlayerSelect.IsLocalFighterAvailable( enFighter ) )
- {
- g_oChooser.MarkFighter( enFighter, C_LIGHTRED );
- }
- else if ( !g_oPlayerSelect.IsFighterAvailable( enFighter ) )
- {
- g_oChooser.MarkFighter( enFighter, C_LIGHTBLUE );
- }
- }
-}
-
-
-
-void CPlayerSelectController::SetPlayerActive( int a_iPlayer, bool a_bActive )
-{
- m_abPlayerActive[a_iPlayer] = a_bActive;
- g_oChooser.SetRectangleVisible( a_iPlayer, a_bActive );
-}
-
-
-/** This method finds the next player and lets him choose a fighter.
-This only should be called in team mode without multiselect.
-*/
-
-void CPlayerSelectController::ActivateNextPlayer( int a_iCurrentPlayer )
-{
- // Go in the following order:
- // 1 2 3 4 4 3 2 1 1 2 3 4 ...
-
- int iNextPlayer = a_iCurrentPlayer;
-
- if ( m_iNumberOfSelectableFighters <= 0 )
- {
- SetPlayerActive( a_iCurrentPlayer, false );
- return;
- }
-
- if ( a_iCurrentPlayer == 0 )
- {
- iNextPlayer = 1;
- }
- else if ( g_oState.m_iNumPlayers-1 == a_iCurrentPlayer )
- {
- iNextPlayer = a_iCurrentPlayer - 1;
- }
- else
- {
- iNextPlayer = GetTeamSize(a_iCurrentPlayer-1) > GetTeamSize(a_iCurrentPlayer+1) ?
- a_iCurrentPlayer+1 : a_iCurrentPlayer-1;
- }
-
- if ( GetTeamSize(a_iCurrentPlayer) <= GetTeamSize(iNextPlayer) )
- {
- iNextPlayer = a_iCurrentPlayer;
- }
-
- if ( iNextPlayer != a_iCurrentPlayer )
- {
- SetPlayerActive( a_iCurrentPlayer, false );
- }
- SetPlayerActive( iNextPlayer, GetTeamSize(iNextPlayer) < g_oState.m_iTeamSize );
-}
-
-
-int CPlayerSelectController::GetTeamSize( int a_iPlayer )
-{
- return g_oPlayerSelect.GetPlayerInfo( a_iPlayer ).m_aenTeam.size();
-}
-
-
-
-bool CPlayerSelectController::IsFighterSelectable( FighterEnum a_enFighter )
-{
- if ( !g_oPlayerSelect.IsFighterAvailable( a_enFighter ) )
- {
- return false;
- }
-
- if ( m_bTeamMode && !g_oState.m_bTeamMultiselect && g_oPlayerSelect.IsFighterInTeam(a_enFighter) )
- {
- return false;
- }
-
- return true;
-}
-
-
-
-void CPlayerSelectController::DoPlayerSelect()
-{
-
- // 1. INITIALIZE
-
- if ( SState::IN_NETWORK == g_oState.m_enGameMode )
- {
- g_oState.m_enTeamMode = SState::Team_ONE_VS_ONE;
- g_oState.m_iNumPlayers = 2;
- }
-
- int i;
- for ( i=0; i<g_oState.m_iNumPlayers; ++i )
- {
- g_oPlayerSelect.SetPlayer( i, g_oChooser.GetCurrentFighter(i) );
- SetPlayerActive( i, !m_bTeamMode || g_oState.m_bTeamMultiselect || 0 == i );
- }
- m_iNumberOfSelectableFighters = g_oBackend.GetNumberOfAvailableFighters();
- MarkFighters();
-
- if ( m_bTeamMode )
- {
- for ( int i=0; i<g_oState.m_iNumPlayers; ++i )
- {
- g_oPlayerSelect.EditPlayerInfo(i).m_aenTeam.clear();
- }
- }
-
- if ( m_bNetworkGame && g_poNetwork->IsMaster() )
- {
- g_poNetwork->SendGameParams( g_oState.m_iGameSpeed, g_oState.m_iRoundLength, g_oState.m_iHitPoints, GetBackgroundNumber() );
- }
-
- g_oBackend.PerlEvalF( "SelectStart(%d);", g_oState.m_iNumPlayers );
-
- m_bChatActive = false;
-
- m_iGameSpeed = 12 ;
- m_iThisTick = SDL_GetTicks() / m_iGameSpeed;
- m_iLastTick = m_iThisTick - 1;
-
- // 2. RUN THE PLAYER SELECTION LOOP
-
- while (1)
- {
- // 2.1. Wait for the next tick (on extremely fast machines..)
- GetThisTick();
- int iAdvance = m_iThisTick - m_iLastTick;
- if ( iAdvance > 5 )
- iAdvance = 5;
-
- // 2.2. Handle events
- HandleEvents();
- if ( m_bNetworkGame )
- {
- HandleNetwork();
- }
-
- // 2.3. Update the view
- m_poView->Advance( iAdvance );
- m_poView->Draw();
-
- if ( g_oState.m_bQuitFlag || SState::IN_DEMO == g_oState.m_enGameMode)
- break;
-
- //@ FIX THIS
-
- if ( !m_abPlayerActive[0] && !m_abPlayerActive[1] && m_poView->IsOver() )
- break;
- }
-}
+#include "PlayerSelectController.h"
+#include "PlayerSelectView.h"
+#include "PlayerSelect.h"
+#include "Chooser.h"
+#include "MortalNetwork.h"
+#include "State.h"
+#include "Backend.h"
+#include "Event.h"
+#include "Audio.h"
+
+#include "TextArea.h"
+#include "sge_tt_text.h"
+#include "common.h"
+
+
+
+int GetBackgroundNumber();
+
+
+
+CPlayerSelectController::CPlayerSelectController( bool a_bNetworkGame )
+{
+ m_bNetworkGame = a_bNetworkGame;
+ m_bTeamMode = SState::Team_CUSTOM == g_oState.m_enTeamMode;
+ m_poView = new CPlayerSelectView( a_bNetworkGame, m_bTeamMode );
+}
+
+
+CPlayerSelectController::~CPlayerSelectController()
+{
+ delete m_poView;
+ m_poView = NULL;
+}
+
+
+
+void CPlayerSelectController::GetThisTick()
+{
+ m_iLastTick = m_iThisTick;
+
+ while (1)
+ {
+ m_iThisTick = SDL_GetTicks() / m_iGameSpeed;
+ if ( m_iThisTick==m_iLastTick )
+ {
+ SDL_Delay(1);
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+
+
+bool CPlayerSelectController::HandleChatKey( SDL_Event& a_roEvent )
+{
+ if ( !m_bNetworkGame )
+ {
+ return false;
+ }
+
+ SDLKey enKey = a_roEvent.key.keysym.sym;
+
+ if ( enKey == SDLK_PAGEUP || enKey == SDLK_KP9 )
+ {
+ m_poView->GetTextArea()->ScrollUp();
+ return true;
+ }
+ if ( enKey == SDLK_PAGEDOWN || enKey == SDLK_KP3 )
+ {
+ m_poView->GetTextArea()->ScrollDown();
+ return true;
+ }
+
+ if ( !m_bChatActive && ( SDLK_TAB == enKey
+ || SDLK_RETURN == enKey || SDLK_KP_ENTER == enKey ) )
+ {
+ // Activate chat.
+ m_acChatMsg[0] = 0;
+ m_poView->GetReadline()->Clear();
+ m_poView->GetReadline()->Restart( m_acChatMsg, strlen(m_acChatMsg), 256, C_LIGHTCYAN, C_BLACK, 255 );
+ m_bChatActive = true;
+ return true;
+ }
+
+ if ( !m_bChatActive )
+ {
+ return false;
+ }
+
+ if ( SDLK_ESCAPE == enKey || SDLK_TAB == enKey )
+ {
+ // Deactivate chat.
+ m_poView->GetReadline()->Clear();
+ m_bChatActive = false;
+ return true;
+ }
+
+ // other keys..
+
+ m_poView->GetReadline()->HandleKeyEvent( a_roEvent );
+ int iResult = m_poView->GetReadline()->GetResult();
+
+ if ( iResult < 0 )
+ {
+ // Escape was pressed?
+ m_poView->GetReadline()->Clear();
+ m_bChatActive = false;
+ }
+ if ( iResult > 0 )
+ {
+ if ( strlen( m_acChatMsg ) )
+ {
+ g_poNetwork->SendMsg( m_acChatMsg );
+ std::string sMsg = std::string("<") + g_oState.m_acNick + "> " + m_acChatMsg;
+ m_poView->GetTextArea()->AddString( sMsg.c_str(), C_LIGHTCYAN );
+ m_poView->GetTextArea()->Redraw();
+
+ m_acChatMsg[0] = 0;
+ m_poView->GetReadline()->Clear();
+ m_poView->GetReadline()->Restart( m_acChatMsg, strlen(m_acChatMsg), 256, C_LIGHTCYAN, C_BLACK, 255 );
+ }
+ else
+ {
+ m_poView->GetReadline()->Clear();
+ m_bChatActive = false;
+ }
+ }
+
+ return true;
+}
+
+
+
+void CPlayerSelectController::HandleEvents()
+{
+ SDL_Event oSdlEvent;
+ while (SDL_PollEvent(&oSdlEvent))
+ {
+ if ( m_bNetworkGame
+ && SDL_KEYDOWN == oSdlEvent.type )
+ {
+ if (HandleChatKey( oSdlEvent ))
+ {
+ continue;
+ }
+ }
+
+ if ( m_bNetworkGame
+ && SDL_KEYDOWN == oSdlEvent.type
+ && (oSdlEvent.key.keysym.sym == SDLK_RETURN || oSdlEvent.key.keysym.sym==SDLK_KP_ENTER) )
+ {
+ m_bChatActive = true;
+ continue;
+ }
+
+ SMortalEvent oEvent;
+ TranslateEvent( &oSdlEvent, &oEvent );
+
+ switch ( oEvent.m_enType )
+ {
+ case Me_QUIT:
+ g_oState.m_bQuitFlag = true;
+ break;
+
+ case Me_MENU:
+ DoMenu();
+ if ( m_bNetworkGame && g_poNetwork->IsMaster() )
+ {
+ g_poNetwork->SendGameParams( g_oState.m_iGameSpeed, g_oState.m_iRoundLength, g_oState.m_iHitPoints, GetBackgroundNumber() );
+ }
+ break;
+
+ case Me_PLAYERKEYDOWN:
+ HandleKey( oEvent.m_iPlayer, oEvent.m_iKey );
+ break;
+
+ case Me_NOTHING:
+ case Me_SKIP:
+ case Me_PLAYERKEYUP:
+ break;
+ } // end of switch statement
+ }
+}
+
+
+
+void CPlayerSelectController::HandleKey( int a_iPlayer, int a_iKey )
+{
+ if ( m_bNetworkGame )
+ {
+ a_iPlayer = g_poNetwork->IsMaster() ? 0 : 1;
+ }
+
+ if ( !m_abPlayerActive[a_iPlayer] )
+ {
+ return;
+ }
+
+ int iSetPlayer = a_iPlayer;
+ if ( m_bTeamMode && !g_oState.m_bTeamMultiselect )
+ {
+ iSetPlayer = 0;
+ }
+
+ // MOVE THE CURSOR
+
+ if ( a_iKey < 4 )
+ {
+ g_oChooser.MoveRectangle( a_iPlayer, a_iKey );
+ FighterEnum enNewFighter = g_oChooser.GetCurrentFighter( a_iPlayer );
+ if ( enNewFighter != g_oPlayerSelect.GetPlayerInfo( iSetPlayer ).m_enFighter )
+ {
+ Audio->PlaySample("PLAYER_SELECTION_CHANGES");
+ if ( IsFighterSelectable(enNewFighter) )
+ {
+ if ( m_bNetworkGame )
+ {
+ g_poNetwork->SendFighter( enNewFighter );
+ }
+
+ g_oPlayerSelect.SetPlayer( iSetPlayer, enNewFighter );
+ }
+ }
+ return;
+ }
+
+ // SELECT THE CURRENT FIGHTER
+
+ FighterEnum enFighter = g_oChooser.GetCurrentFighter( a_iPlayer );
+ if ( !IsFighterSelectable( enFighter ) )
+ {
+ // Current fighter cannot be selected.
+ return;
+ }
+
+ Audio->PlaySample("PLAYER_SELECTED");
+ g_oBackend.PerlEvalF( "PlayerSelected(%d);", iSetPlayer );
+ if ( m_bNetworkGame )
+ {
+ g_poNetwork->SendFighter( enFighter );
+ g_poNetwork->SendReady();
+ }
+
+ bool bKeepPlayerActive = false;
+
+ SPlayerInfo& roInfo = g_oPlayerSelect.EditPlayerInfo(a_iPlayer);
+ const SPlayerInfo& roOtherInfo = g_oPlayerSelect.GetPlayerInfo(1-a_iPlayer);
+ int iTeamSize = roInfo.m_aenTeam.size() + 1;
+ int iOtherTeamSize = roOtherInfo.m_aenTeam.size();
+
+ if ( m_bTeamMode )
+ {
+ m_poView->AddFighterToTeam( a_iPlayer, enFighter );
+ roInfo.m_aenTeam.push_back( enFighter );
+
+ if ( g_oState.m_bTeamMultiselect )
+ {
+ SetPlayerActive( a_iPlayer, iTeamSize < g_oState.m_iTeamSize );
+ }
+ else
+ {
+ --m_iNumberOfSelectableFighters;
+ g_oChooser.MarkFighter( enFighter, a_iPlayer ? C_LIGHTMAGENTA : C_LIGHTGREEN );
+ ActivateNextPlayer( a_iPlayer );
+ }
+ }
+ else
+ {
+ roInfo.m_aenTeam.clear();
+ roInfo.m_aenTeam.push_back( enFighter );
+ SetPlayerActive( a_iPlayer, false );
+ }
+
+}
+
+
+void CPlayerSelectController::HandleNetwork()
+{
+ g_poNetwork->Update();
+
+ // 1. READ CHAT MESSAGES
+
+ bool bUpdateText = false;
+ while ( g_poNetwork->IsMsgAvailable() )
+ {
+ const char* pcMsg = g_poNetwork->GetMsg();
+ int iColor = C_YELLOW;
+ if ( pcMsg[0] == '*' && pcMsg[1] == '*' && pcMsg[2] == '*' ) iColor = C_WHITE;
+ m_poView->GetTextArea()->AddString( pcMsg, iColor );
+ bUpdateText = true;
+ }
+ if ( bUpdateText )
+ {
+ Audio->PlaySample("NETWORK_MESSAGE");
+ m_poView->GetTextArea()->Redraw();
+ }
+
+ // 2. READ PLAYER SELECTION ACTIONS
+
+ bool bMaster = g_poNetwork->IsMaster();
+ int iPlayer = bMaster ? 1 : 0;
+
+ if ( !m_abPlayerActive[iPlayer] )
+ {
+ return;
+ }
+
+ FighterEnum enOldFighter = g_oPlayerSelect.GetPlayerInfo(iPlayer).m_enFighter;
+ FighterEnum enRemoteFighter = g_poNetwork->GetRemoteFighter();
+
+ if ( enOldFighter != enRemoteFighter
+ && enRemoteFighter != UNKNOWN )
+ {
+ Audio->PlaySample("PLAYER_SELECTION_CHANGES");
+ g_oPlayerSelect.SetPlayer( iPlayer, enRemoteFighter );
+ g_oChooser.SetRectangle( iPlayer, enRemoteFighter );
+ }
+
+ bool bDone = g_poNetwork->IsRemoteSideReady();
+ if ( bDone )
+ {
+ m_abPlayerActive[iPlayer] = false;
+ Audio->PlaySample("PLAYER_SELECTED");
+ g_oBackend.PerlEvalF( "PlayerSelected(%d);", iPlayer );
+
+ SPlayerInfo& roInfo = g_oPlayerSelect.EditPlayerInfo( iPlayer );
+
+ roInfo.m_aenTeam.clear();
+ roInfo.m_aenTeam.push_back( enRemoteFighter );
+ SetPlayerActive( iPlayer, false );
+ }
+}
+
+
+
+void CPlayerSelectController::MarkFighters()
+{
+ int iNumberOfFighters = g_oBackend.GetNumberOfFighters();
+ int i;
+
+ for ( i=0; i<iNumberOfFighters; ++i )
+ {
+ FighterEnum enFighter = g_oBackend.GetFighterID( i );
+ if ( !g_oPlayerSelect.IsLocalFighterAvailable( enFighter ) )
+ {
+ g_oChooser.MarkFighter( enFighter, C_LIGHTRED );
+ }
+ else if ( !g_oPlayerSelect.IsFighterAvailable( enFighter ) )
+ {
+ g_oChooser.MarkFighter( enFighter, C_LIGHTBLUE );
+ }
+ }
+}
+
+
+
+void CPlayerSelectController::SetPlayerActive( int a_iPlayer, bool a_bActive )
+{
+ m_abPlayerActive[a_iPlayer] = a_bActive;
+ g_oChooser.SetRectangleVisible( a_iPlayer, a_bActive );
+}
+
+
+/** This method finds the next player and lets him choose a fighter.
+This only should be called in team mode without multiselect.
+*/
+
+void CPlayerSelectController::ActivateNextPlayer( int a_iCurrentPlayer )
+{
+ // Go in the following order:
+ // 1 2 3 4 4 3 2 1 1 2 3 4 ...
+
+ int iNextPlayer = a_iCurrentPlayer;
+
+ if ( m_iNumberOfSelectableFighters <= 0 )
+ {
+ SetPlayerActive( a_iCurrentPlayer, false );
+ return;
+ }
+
+ if ( a_iCurrentPlayer == 0 )
+ {
+ iNextPlayer = 1;
+ }
+ else if ( g_oState.m_iNumPlayers-1 == a_iCurrentPlayer )
+ {
+ iNextPlayer = a_iCurrentPlayer - 1;
+ }
+ else
+ {
+ iNextPlayer = GetTeamSize(a_iCurrentPlayer-1) > GetTeamSize(a_iCurrentPlayer+1) ?
+ a_iCurrentPlayer+1 : a_iCurrentPlayer-1;
+ }
+
+ if ( GetTeamSize(a_iCurrentPlayer) <= GetTeamSize(iNextPlayer) )
+ {
+ iNextPlayer = a_iCurrentPlayer;
+ }
+
+ if ( iNextPlayer != a_iCurrentPlayer )
+ {
+ SetPlayerActive( a_iCurrentPlayer, false );
+ }
+ SetPlayerActive( iNextPlayer, GetTeamSize(iNextPlayer) < g_oState.m_iTeamSize );
+}
+
+
+int CPlayerSelectController::GetTeamSize( int a_iPlayer )
+{
+ return g_oPlayerSelect.GetPlayerInfo( a_iPlayer ).m_aenTeam.size();
+}
+
+
+
+bool CPlayerSelectController::IsFighterSelectable( FighterEnum a_enFighter )
+{
+ if ( !g_oPlayerSelect.IsFighterAvailable( a_enFighter ) )
+ {
+ return false;
+ }
+
+ if ( m_bTeamMode && !g_oState.m_bTeamMultiselect && g_oPlayerSelect.IsFighterInTeam(a_enFighter) )
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+
+void CPlayerSelectController::DoPlayerSelect()
+{
+
+ // 1. INITIALIZE
+
+ if ( SState::IN_NETWORK == g_oState.m_enGameMode )
+ {
+ g_oState.m_enTeamMode = SState::Team_ONE_VS_ONE;
+ g_oState.m_iNumPlayers = 2;
+ }
+
+ int i;
+ for ( i=0; i<g_oState.m_iNumPlayers; ++i )
+ {
+ g_oPlayerSelect.SetPlayer( i, g_oChooser.GetCurrentFighter(i) );
+ SetPlayerActive( i, !m_bTeamMode || g_oState.m_bTeamMultiselect || 0 == i );
+ }
+ m_iNumberOfSelectableFighters = g_oBackend.GetNumberOfAvailableFighters();
+ MarkFighters();
+
+ if ( m_bTeamMode )
+ {
+ for ( int i=0; i<g_oState.m_iNumPlayers; ++i )
+ {
+ g_oPlayerSelect.EditPlayerInfo(i).m_aenTeam.clear();
+ }
+ }
+
+ if ( m_bNetworkGame && g_poNetwork->IsMaster() )
+ {
+ g_poNetwork->SendGameParams( g_oState.m_iGameSpeed, g_oState.m_iRoundLength, g_oState.m_iHitPoints, GetBackgroundNumber() );
+ }
+
+ g_oBackend.PerlEvalF( "SelectStart(%d);", g_oState.m_iNumPlayers );
+
+ m_bChatActive = false;
+
+ m_iGameSpeed = 12 ;
+ m_iThisTick = SDL_GetTicks() / m_iGameSpeed;
+ m_iLastTick = m_iThisTick - 1;
+
+ // 2. RUN THE PLAYER SELECTION LOOP
+
+ while (1)
+ {
+ // 2.1. Wait for the next tick (on extremely fast machines..)
+ GetThisTick();
+ int iAdvance = m_iThisTick - m_iLastTick;
+ if ( iAdvance > 5 )
+ iAdvance = 5;
+
+ // 2.2. Handle events
+ HandleEvents();
+ if ( m_bNetworkGame )
+ {
+ HandleNetwork();
+ }
+
+ // 2.3. Update the view
+ m_poView->Advance( iAdvance );
+ m_poView->Draw();
+
+ if ( g_oState.m_bQuitFlag || SState::IN_DEMO == g_oState.m_enGameMode)
+ break;
+
+ //@ FIX THIS
+
+ if ( !m_abPlayerActive[0] && !m_abPlayerActive[1] && m_poView->IsOver() )
+ break;
+ }
+}
diff --git a/src/PlayerSelectController.h b/src/PlayerSelectController.h
index 0f59912..c545125 100644
--- a/src/PlayerSelectController.h
+++ b/src/PlayerSelectController.h
@@ -1,54 +1,54 @@
-#ifndef PLAYERSELECTCONTROLLER_H
-#define PLAYERSELECTCONTROLLER_H
-
-#include "SDL.h"
-#include "FighterEnum.h"
-#include "common.h"
-
-class CPlayerSelectView;
-
-/**
-Controller part model-view-controller architecture of the player selection.
-\ingroup PlayerSelect
-*/
-
-class CPlayerSelectController
-{
-public:
- CPlayerSelectController( bool a_bNetworkGame );
- ~CPlayerSelectController();
-
- void DoPlayerSelect();
-
-protected:
- void HandleEvents();
- void HandleKey( int a_iPlayer, int a_iKey );
- bool HandleChatKey( SDL_Event& a_roEvent );
- void HandleNetwork();
- void GetThisTick();
- void MarkFighters();
-
- void SetPlayerActive( int a_iPlayer, bool a_bActive );
- void ActivateNextPlayer( int a_iCurrentPlayer );
- int GetTeamSize( int a_iPlayer );
-
- bool IsFighterSelectable( FighterEnum a_enFighter );
-
-
-protected:
- CPlayerSelectView* m_poView;
- bool m_bNetworkGame;
- bool m_bTeamMode;
- bool m_bChatActive;
- char m_acChatMsg[256];
- int m_iNumberOfSelectableFighters;
-
- bool m_abPlayerActive[MAXPLAYERS];
-
- int m_iGameSpeed;
- int m_iThisTick;
- int m_iLastTick;
-};
-
-
-#endif // PLAYERSELECTCONTROLLER_H
+#ifndef PLAYERSELECTCONTROLLER_H
+#define PLAYERSELECTCONTROLLER_H
+
+#include "SDL.h"
+#include "FighterEnum.h"
+#include "common.h"
+
+class CPlayerSelectView;
+
+/**
+Controller part model-view-controller architecture of the player selection.
+\ingroup PlayerSelect
+*/
+
+class CPlayerSelectController
+{
+public:
+ CPlayerSelectController( bool a_bNetworkGame );
+ ~CPlayerSelectController();
+
+ void DoPlayerSelect();
+
+protected:
+ void HandleEvents();
+ void HandleKey( int a_iPlayer, int a_iKey );
+ bool HandleChatKey( SDL_Event& a_roEvent );
+ void HandleNetwork();
+ void GetThisTick();
+ void MarkFighters();
+
+ void SetPlayerActive( int a_iPlayer, bool a_bActive );
+ void ActivateNextPlayer( int a_iCurrentPlayer );
+ int GetTeamSize( int a_iPlayer );
+
+ bool IsFighterSelectable( FighterEnum a_enFighter );
+
+
+protected:
+ CPlayerSelectView* m_poView;
+ bool m_bNetworkGame;
+ bool m_bTeamMode;
+ bool m_bChatActive;
+ char m_acChatMsg[256];
+ int m_iNumberOfSelectableFighters;
+
+ bool m_abPlayerActive[MAXPLAYERS];
+
+ int m_iGameSpeed;
+ int m_iThisTick;
+ int m_iLastTick;
+};
+
+
+#endif // PLAYERSELECTCONTROLLER_H
diff --git a/src/PlayerSelectView.cpp b/src/PlayerSelectView.cpp
index 574b136..8f24837 100644
--- a/src/PlayerSelectView.cpp
+++ b/src/PlayerSelectView.cpp
@@ -1,598 +1,598 @@
-#include "sge_tt_text.h"
-#include "sge_bm_text.h"
-#include "sge_primitives.h"
-#include "RlePack.h"
-
-#include "PlayerSelectView.h"
-#include "PlayerSelect.h"
-
-#include "Chooser.h"
-#include "TextArea.h"
-#include "Backend.h"
-#include "State.h"
-#include "gfx.h"
-#include "common.h"
-
-
-
-
-/**
-Displays teams in the player selection screen for CPlayerSelectView.
-\ingroup PlayerSelect
-*/
-
-class CTeamDisplay
-{
-public:
- CTeamDisplay( int a_iPlayer, SDL_Surface* a_poScreen, const SDL_Rect& a_roRect );
- ~CTeamDisplay();
-
- void DrawTitle( Uint32 a_iColor );
- void DrawQuestionMark( Uint32 a_iColor, int a_iNumber=-1 );
- void AddFighter( FighterEnum a_enFighter );
- void DrawFighter( FighterEnum a_enFighter, int a_iNumber );
- SDL_Rect GetRect( int a_iNumber=-1 );
- int GetCount() { return m_iCount; }
-
-protected:
- int m_iPlayer;
- SDL_Surface* m_poScreen;
- SDL_Rect m_oRect;
- int m_iTitleX;
-
- int m_iCount;
- int m_iMax;
-};
-
-
-CTeamDisplay::CTeamDisplay( int a_iPlayer, SDL_Surface* a_poScreen, const SDL_Rect& a_roRect )
-{
- m_iPlayer = a_iPlayer;
- m_poScreen = a_poScreen;
- m_oRect = a_roRect;
- m_iCount = 0;
- m_iMax = g_oState.m_iTeamSize;
- m_iTitleX = m_oRect.x;
-
- const char* pcFormat = Translate("Team %d");
- SDL_Rect oTextSize = sge_TTF_TextSize( impactFont, pcFormat );
- int w = oTextSize.w;
- m_oRect.w -= w;
- m_oRect.x += w;
-
- DrawTitle( C_WHITE );
-
- for ( int i=0; i< m_iMax; ++i )
- {
- DrawQuestionMark( C_WHITE, i );
- }
-}
-
-
-CTeamDisplay::~CTeamDisplay() {}
-
-
-void CTeamDisplay::DrawTitle( Uint32 a_iColor )
-{
- char acBuffer[128];
- const char* pcFormat = Translate("Team %d");
-
- sprintf( acBuffer, pcFormat, m_iPlayer+1 );
- DrawTextMSZ( acBuffer, impactFont, m_iTitleX, m_oRect.y+m_oRect.h/2,
- AlignVCenter|UseShadow, a_iColor, m_poScreen, false );
-}
-
-
-void CTeamDisplay::DrawQuestionMark( Uint32 a_iColor, int a_iNumber )
-{
- if ( a_iNumber < 0 ) a_iNumber = m_iCount;
- if ( a_iNumber >= m_iMax ) return;
-
- SDL_Rect oRect = GetRect( a_iNumber );
- sge_Rect( m_poScreen, oRect.x, oRect.y, oRect.x+oRect.w, oRect.y+oRect.h, C_WHITE );
- DrawTextMSZ( "?", impactFont, oRect.x+oRect.w/2, oRect.y+oRect.h/2, AlignCenter, a_iColor, m_poScreen, false );
-}
-
-
-void CTeamDisplay::AddFighter( FighterEnum a_enFighter )
-{
- DrawQuestionMark( C_WHITE );
- ++m_iCount;
-}
-
-
-void CTeamDisplay::DrawFighter( FighterEnum a_enFighter, int a_iNumber )
-{
- SDL_Rect oRect = GetRect( a_iNumber );
- g_oChooser.DrawPortrait( a_enFighter, m_poScreen, oRect );
- sge_Rect( m_poScreen, oRect.x, oRect.y, oRect.x+oRect.w, oRect.y+oRect.h, C_WHITE );
-}
-
-
-SDL_Rect CTeamDisplay::GetRect( int a_iNumber )
-{
- if ( a_iNumber < 0 ) a_iNumber = m_iCount;
- if ( m_oRect.h > 75 )
- {
- m_oRect.y += (m_oRect.h - 75) / 2;
- m_oRect.h = 75;
- }
-
- int iGap = 5;
- int iWidth = m_oRect.w / m_iMax;
- if ( iWidth > m_oRect.h + iGap ) iWidth = m_oRect.h + iGap;
-
- SDL_Rect oRect;
- oRect.y = m_oRect.y;
- oRect.h = m_oRect.h;
- oRect.x = m_oRect.x + iWidth * a_iNumber;
- oRect.w = iWidth - iGap;
-
- return oRect;
-}
-
-
-
-IViewElement::IViewElement( CPlayerSelectView* a_poView, int a_iPriority )
-{
- m_poView = a_poView;
- m_iPriority = a_iPriority;
-
- m_poView->AddViewElement( this, m_iPriority );
-}
-
-
-IViewElement::~IViewElement()
-{
-}
-
-
-int IViewElement::GetPriority() const
-{
- return m_iPriority;
-}
-
-
-/**
-Flying portrait element for CPlayerSelectView.
-The portrait of a given fighter will gracefully fly from the chooser
-to a team display. The view element will delete itself afterwards.
-\ingroup PlayerSelect
-*/
-
-class CFlyingPortraitViewElement: public IViewElement
-{
-public:
- CFlyingPortraitViewElement( CPlayerSelectView* a_poView, CTeamDisplay* a_poTeamDisplay,
- FighterEnum a_enFighter, const SDL_Rect& a_oSrcRect, const SDL_Rect& a_oDstRect )
- : IViewElement( a_poView, 0 )
- {
- m_poTeamDisplay = a_poTeamDisplay;
- m_iTeamNumber = m_poTeamDisplay->GetCount();
- m_enFighter = a_enFighter;
- m_oRect = a_oSrcRect;
- m_oDstRect = a_oDstRect;
-
- m_dX = m_oRect.x + m_oRect.w / 2;
- m_dY = m_oRect.y + m_oRect.h / 2;
- m_dSize = MIN( m_oRect.w, m_oRect.h );
-
- m_dSpeedX = 0.0;
- m_dSpeedY = - m_dY / 15;
- m_dSpeedSize= 0.0;
-
- m_dTargetX = m_oDstRect.x + m_oDstRect.w / 2;
- m_dTargetY = m_oDstRect.y + m_oDstRect.h / 2;
- m_dTargetSize = MIN( m_oDstRect.w, m_oDstRect.h);
-
- m_iTotalTime = 70 + m_dY / 7.5;
- m_iTime = m_iTotalTime;
-
- }
-
- ~CFlyingPortraitViewElement() {}
-
- void Advance( int a_iNumFrames )
- {
- if ( m_dX + m_dSpeedX * 0.5 * m_iTime > m_dTargetX ) m_dSpeedX -= a_iNumFrames * 0.5; else m_dSpeedX += a_iNumFrames * 0.5;
- if ( m_dY + m_dSpeedY * 0.5 * m_iTime > m_dTargetY ) m_dSpeedY -= a_iNumFrames * 0.5; else m_dSpeedY += a_iNumFrames * 0.5;
-
- m_dX += m_dSpeedX * a_iNumFrames;
- m_dY += m_dSpeedY * a_iNumFrames;
-
- double dTargetSize = (m_iTime > m_iTotalTime/2) ? 75.0 : m_dTargetSize;
- int iTargetTime = (m_iTime > m_iTotalTime/2) ? m_iTime : ( m_iTotalTime/2-m_iTime );
- if ( m_dSize + m_dSpeedSize * iTargetTime > dTargetSize ) m_dSpeedSize -= a_iNumFrames * 0.3; else m_dSpeedSize += a_iNumFrames * 0.3;
-
- m_dSize += m_dSpeedSize * a_iNumFrames;
-
- m_oRect.x = int( m_dX - m_dSize / 2 );
- m_oRect.y = int( m_dY - m_dSize / 2 );
- m_oRect.w = m_oRect.h = (int)m_dSize;
-
- m_iTime -= a_iNumFrames;
- if ( m_iTime < 0 )
- {
- m_poTeamDisplay->DrawFighter( m_enFighter, m_iTeamNumber );
- m_poView->RemoveViewElement( this );
- delete( this );
- }
- }
-
- void Draw()
- {
- g_oChooser.DrawPortrait( m_enFighter, gamescreen, m_oRect );
- }
-
-protected:
- CTeamDisplay* m_poTeamDisplay;
- int m_iTeamNumber;
- FighterEnum m_enFighter;
- double m_dX, m_dY, m_dSize;
- double m_dSpeedX, m_dSpeedY, m_dSpeedSize;
- double m_dTargetX, m_dTargetY, m_dTargetSize;
- int m_iTotalTime;
- int m_iTime;
- SDL_Rect m_oDstRect;
- SDL_Rect m_oRect;
- int m_iNumber;
-};
-
-/**
-This view element implements the "opening courtain" effect at the start
-of the player selection routine.
-It removes itself when the effect is
-finished.
-\ingroup PlayerSelect
-*/
-
-class CCourtainViewElement: public IViewElement
-{
-public:
- CCourtainViewElement( CPlayerSelectView* a_poView ) : IViewElement( a_poView, 0 )
- {
- m_iCourtain = 0;
- m_iCourtainSpeed = 0;
- m_iCourtainTime = 80;
- }
-
- ~CCourtainViewElement() {}
-
- void Advance( int a_iNumFrames )
- {
- if ( a_iNumFrames > 5 ) a_iNumFrames = 5;
-
- if ( m_iCourtainTime <= 0 )
- {
- SDL_SetClipRect( gamescreen, NULL );
- m_poView->RemoveViewElement( this );
- delete( this );
- }
-
- if ( m_iCourtain + m_iCourtainSpeed * m_iCourtainTime /2 < 320 * 4 )
- m_iCourtainSpeed += a_iNumFrames;
- else
- m_iCourtainSpeed -= a_iNumFrames;
-
- m_iCourtain += m_iCourtainSpeed * a_iNumFrames;
- m_iCourtainTime -= a_iNumFrames;
-
- if ( m_iCourtainTime > 0 )
- {
- SDL_Rect oRect;
- oRect.x = 320 - m_iCourtain/4; oRect.y = 0;
- oRect.w = m_iCourtain / 2; oRect.h = gamescreen->h;
- if ( oRect.x < 0 ) oRect.x = 0;
- if ( oRect.w > gamescreen->w ) oRect.w = gamescreen->w;
- SDL_SetClipRect( gamescreen, &oRect );
- }
- }
-
- void Draw()
- {
- }
-
-protected:
- int m_iCourtain;
- int m_iCourtainSpeed;
- int m_iCourtainTime;
-
-};
-
-
-
-/**
-This view element flashes the title and '?' mark of active teams.
-\ingroup PlayerSelect
-*/
-
-class CTeamFlashViewElement: public IViewElement
-{
-public:
- CTeamFlashViewElement( CPlayerSelectView* a_poView, int a_iPriority )
- : IViewElement( a_poView, a_iPriority )
- {
- for ( int i=0; i<MAXPLAYERS; ++i )
- {
- m_bActive[i] = false;
- }
- }
-
- ~CTeamFlashViewElement() {}
-
- void Advance( int a_iNumFrames )
- {
- m_iCycle = (m_iCycle + a_iNumFrames*10) % 512;
- }
-
- void Draw()
- {
- int iLum = m_iCycle < 256 ? m_iCycle : 511-m_iCycle;
-
- for ( int i=0; i<g_oState.m_iNumPlayers; ++i )
- {
- if ( g_oChooser.IsRectangleVisible( i ) )
- {
- SDL_Color oColor;
- switch (i)
- {
- case 0: oColor.r = 85; oColor.g = 255; oColor.b = 85; break;
- case 1: oColor.r = 255; oColor.g = 85; oColor.b = 255; break;
- case 2: oColor.r = 255; oColor.g = 255; oColor.b = 85; break;
- default: oColor.r = 85; oColor.g = 85; oColor.b = 255; break;
- }
- Uint32 iColor = SDL_MapRGB( gamescreen->format, oColor.r*iLum/256, oColor.g*iLum/256, oColor.b*iLum/256 );
- m_poView->GetTeamDisplay(i)->DrawTitle( iColor );
- m_poView->GetTeamDisplay(i)->DrawQuestionMark( iColor );
- m_bActive[i] = true;
- }
- else if ( m_bActive[i] )
- {
- m_poView->GetTeamDisplay(i)->DrawTitle( C_WHITE );
- m_bActive[i] = false;
- }
- }
- }
-
-protected:
- int m_iCycle;
- bool m_bActive[MAXPLAYERS];
-};
-
-
-
-
-
-/*************************************************************************
- CPLAYERSELECTVIEW CLASS
-*************************************************************************/
-
-CPlayerSelectView::CPlayerSelectView( bool a_bNetworkGame, bool a_bTeamMode )
-{
- m_bOver = false;
- m_bNetworkGame = a_bNetworkGame;
- m_bTeamMode = a_bTeamMode;
- m_bTeamMultiselect = g_oState.m_bTeamMultiselect > 0;
- m_poReadline = NULL;
- m_poTextArea = NULL;
- m_iTime = 0;
-
- int i;
- for ( i=0; i<MAXPLAYERS; ++i ) m_apoTeamDisplays[i] = NULL;
-
- SDL_FillRect( gamescreen, NULL, C_BLACK );
- SDL_Flip( gamescreen );
- m_poBackground = LoadBackground( "FighterStats.jpg", 64 ); //m_bNetworkGame ? "PlayerSelect_chat.png" : "PlayerSelect.png", 111 );
- if ( m_poBackground ) SDL_SetColorKey( m_poBackground, 0, 0 );
-
- new CCourtainViewElement(this);
-
- if ( m_bTeamMode )
- {
- new CTeamFlashViewElement(this, 0);
- SDL_Rect oRect;
- oRect.x = 10; oRect.w = 620;
- oRect.y = 380; oRect.h = 40;
- m_apoTeamDisplays[0] = new CTeamDisplay( 0, m_poBackground, oRect );
- oRect.y = 430; oRect.h = 40;
- m_apoTeamDisplays[1] = new CTeamDisplay( 1, m_poBackground, oRect );
- if ( g_oState.m_iNumPlayers >= 3 )
- {
- oRect.y = 330;
- m_apoTeamDisplays[2] = new CTeamDisplay( 2, m_poBackground, oRect );
- }
-
- if ( g_oState.m_iNumPlayers >= 4 )
- {
- oRect.y = 280;
- m_apoTeamDisplays[3] = new CTeamDisplay( 3, m_poBackground, oRect );
- }
-
- if ( m_bTeamMultiselect )
- {
- m_iChooserTop = 25;
- m_iChooserHeight = 80 * 4;
- m_iChooserLeft = 158;
- m_iChooserWidth = 64*5;
- }
- else
- {
- DrawGradientText( "Choose A Fighter Dammit", titleFont, 10, m_poBackground );
- m_iChooserTop = 75;
- m_iChooserHeight = 80 * 4 - 50;
- m_iChooserLeft = 180;
- m_iChooserWidth = 430;
- }
- m_iFighterYOffset = -100;
- m_iFighterNameYOffset = -95;
- }
- else if ( m_bNetworkGame )
- {
- m_iChooserLeft = 158;
- m_iChooserTop = 26;
- m_iChooserWidth = 64 * 5;
- m_iChooserHeight = 64 * 4;
- m_iFighterYOffset = -130;
- m_iFighterNameYOffset = -170;
- }
- else
- {
- m_iChooserLeft = 158;
- m_iChooserTop = 74;
- m_iChooserWidth = 80*4;
- m_iChooserHeight = 80*5;
- m_iFighterYOffset = 0;
- m_iFighterNameYOffset = 0;
- }
-
- g_oChooser.Start( m_poBackground );
- g_oChooser.Resize( m_iChooserLeft, m_iChooserTop, m_iChooserLeft+m_iChooserWidth, m_iChooserTop+m_iChooserHeight );
- g_oChooser.Draw();
-
- if ( !m_bNetworkGame && !m_bTeamMode )
- {
- DrawGradientText( "Choose A Fighter Dammit", titleFont, 10, m_poBackground );
- }
-
- if ( m_bNetworkGame )
- {
- char acMsg[256];
- sprintf( acMsg, "Press Enter to chat, Page Up/Page Down to scroll..." );
-
- if ( m_bNetworkGame )
- {
- m_poReadline = new CReadline( m_bNetworkGame ? m_poBackground : NULL, chatFont,
- acMsg, strlen(acMsg), 256, 15, 465, 610, C_LIGHTCYAN, C_BLACK, 255 );
- m_poTextArea = new CTextArea( m_poBackground, chatFont, 15, 313, 610, 32*4 );
- }
- }
-
-}
-
-
-CPlayerSelectView::~CPlayerSelectView()
-{
- delete m_apoTeamDisplays[0]; m_apoTeamDisplays[0] = NULL;
- delete m_apoTeamDisplays[1]; m_apoTeamDisplays[1] = NULL;
-
- TViewElements::iterator it;
- for ( it=m_apoElements.begin(); it!= m_apoElements.end(); ++it )
- {
- delete *it;
- }
- m_apoElements.clear();
-
- delete m_poTextArea;
- delete m_poReadline;
- SDL_FreeSurface( m_poBackground );
-}
-
-
-void CPlayerSelectView::Advance( int a_iNumFrames )
-{
- m_iTime += a_iNumFrames;
-
- for ( int i=0; i<a_iNumFrames; ++i )
- {
- g_oBackend.AdvancePerl();
-
- TViewElements::iterator it;
- }
-
- TViewElements::iterator it;
- TViewElements::iterator itNext;
- for ( it = m_apoElements.begin(); it != m_apoElements.end(); )
- {
- itNext = it;
- ++itNext;
- (*it)->Advance( a_iNumFrames );
- it = itNext;
- }
-}
-
-
-void CPlayerSelectView::Draw()
-{
- TViewElements::iterator it;
-
- g_oBackend.ReadFromPerl();
- m_bOver = g_oBackend.m_iGameOver > 0;
-
- g_oChooser.DrawRectangles(m_iTime);
- SDL_BlitSurface( m_poBackground, NULL, gamescreen, NULL );
-
- for ( it = m_apoElements.begin(); it != m_apoElements.end(); ++it )
- {
- (*it)->Draw();
- }
-
- for ( int i=0; i<g_oState.m_iNumPlayers; ++i )
- {
- if ( m_bTeamMode && 1==i && !m_bTeamMultiselect ) continue;
-
- const SPlayerInfo& roPlayerInfo = g_oPlayerSelect.GetPlayerInfo( i );
- int iPlayerNameWidth = g_oPlayerSelect.GetFighterNameWidth( i );
-
- if ( g_oBackend.m_aoPlayers[i].m_iFrame )
- {
- roPlayerInfo.m_poPack->Draw(
- ABS(g_oBackend.m_aoPlayers[i].m_iFrame)-1,
- g_oBackend.m_aoPlayers[i].m_iX, g_oBackend.m_aoPlayers[i].m_iY + m_iFighterYOffset,
- g_oBackend.m_aoPlayers[i].m_iFrame < 0 );
- }
- int x = ( m_iChooserLeft - iPlayerNameWidth ) / 2;
- if ( x<10 ) x = 10;
- if ( i ) x = gamescreen->w - x - iPlayerNameWidth;
-
- sge_BF_textout( gamescreen, fastFont, g_oPlayerSelect.GetFighterName(i),
- x, gamescreen->h - 40 + m_iFighterNameYOffset );
- }
-
- SDL_Flip( gamescreen );
-}
-
-
-CReadline* CPlayerSelectView::GetReadline()
-{
- return m_poReadline;
-}
-
-
-CTextArea* CPlayerSelectView::GetTextArea()
-{
- return m_poTextArea;
-}
-
-
-void CPlayerSelectView::AddViewElement( IViewElement* a_poElement, int a_iPriority )
-{
-
- m_apoElements.push_back( a_poElement );
-}
-
-
-void CPlayerSelectView::RemoveViewElement( IViewElement* a_poElement )
-{
- m_apoElements.remove( a_poElement );
-}
-
-
-void CPlayerSelectView::AddFighterToTeam( int a_iPlayer, FighterEnum a_enFighter )
-{
- new CFlyingPortraitViewElement( this, m_apoTeamDisplays[a_iPlayer], a_enFighter,
- g_oChooser.GetFighterRect( a_enFighter ),
- m_apoTeamDisplays[a_iPlayer]->GetRect() );
- m_apoTeamDisplays[a_iPlayer]->AddFighter( a_enFighter );
-}
-
-
-bool CPlayerSelectView::IsOver()
-{
- return m_bOver;
-}
-
-
-CTeamDisplay* CPlayerSelectView::GetTeamDisplay( int a_iPlayer )
-{
- return m_apoTeamDisplays[a_iPlayer];
-}
+#include "sge_tt_text.h"
+#include "sge_bm_text.h"
+#include "sge_primitives.h"
+#include "RlePack.h"
+
+#include "PlayerSelectView.h"
+#include "PlayerSelect.h"
+
+#include "Chooser.h"
+#include "TextArea.h"
+#include "Backend.h"
+#include "State.h"
+#include "gfx.h"
+#include "common.h"
+
+
+
+
+/**
+Displays teams in the player selection screen for CPlayerSelectView.
+\ingroup PlayerSelect
+*/
+
+class CTeamDisplay
+{
+public:
+ CTeamDisplay( int a_iPlayer, SDL_Surface* a_poScreen, const SDL_Rect& a_roRect );
+ ~CTeamDisplay();
+
+ void DrawTitle( Uint32 a_iColor );
+ void DrawQuestionMark( Uint32 a_iColor, int a_iNumber=-1 );
+ void AddFighter( FighterEnum a_enFighter );
+ void DrawFighter( FighterEnum a_enFighter, int a_iNumber );
+ SDL_Rect GetRect( int a_iNumber=-1 );
+ int GetCount() { return m_iCount; }
+
+protected:
+ int m_iPlayer;
+ SDL_Surface* m_poScreen;
+ SDL_Rect m_oRect;
+ int m_iTitleX;
+
+ int m_iCount;
+ int m_iMax;
+};
+
+
+CTeamDisplay::CTeamDisplay( int a_iPlayer, SDL_Surface* a_poScreen, const SDL_Rect& a_roRect )
+{
+ m_iPlayer = a_iPlayer;
+ m_poScreen = a_poScreen;
+ m_oRect = a_roRect;
+ m_iCount = 0;
+ m_iMax = g_oState.m_iTeamSize;
+ m_iTitleX = m_oRect.x;
+
+ const char* pcFormat = Translate("Team %d");
+ SDL_Rect oTextSize = sge_TTF_TextSize( impactFont, pcFormat );
+ int w = oTextSize.w;
+ m_oRect.w -= w;
+ m_oRect.x += w;
+
+ DrawTitle( C_WHITE );
+
+ for ( int i=0; i< m_iMax; ++i )
+ {
+ DrawQuestionMark( C_WHITE, i );
+ }
+}
+
+
+CTeamDisplay::~CTeamDisplay() {}
+
+
+void CTeamDisplay::DrawTitle( Uint32 a_iColor )
+{
+ char acBuffer[128];
+ const char* pcFormat = Translate("Team %d");
+
+ sprintf( acBuffer, pcFormat, m_iPlayer+1 );
+ DrawTextMSZ( acBuffer, impactFont, m_iTitleX, m_oRect.y+m_oRect.h/2,
+ AlignVCenter|UseShadow, a_iColor, m_poScreen, false );
+}
+
+
+void CTeamDisplay::DrawQuestionMark( Uint32 a_iColor, int a_iNumber )
+{
+ if ( a_iNumber < 0 ) a_iNumber = m_iCount;
+ if ( a_iNumber >= m_iMax ) return;
+
+ SDL_Rect oRect = GetRect( a_iNumber );
+ sge_Rect( m_poScreen, oRect.x, oRect.y, oRect.x+oRect.w, oRect.y+oRect.h, C_WHITE );
+ DrawTextMSZ( "?", impactFont, oRect.x+oRect.w/2, oRect.y+oRect.h/2, AlignCenter, a_iColor, m_poScreen, false );
+}
+
+
+void CTeamDisplay::AddFighter( FighterEnum a_enFighter )
+{
+ DrawQuestionMark( C_WHITE );
+ ++m_iCount;
+}
+
+
+void CTeamDisplay::DrawFighter( FighterEnum a_enFighter, int a_iNumber )
+{
+ SDL_Rect oRect = GetRect( a_iNumber );
+ g_oChooser.DrawPortrait( a_enFighter, m_poScreen, oRect );
+ sge_Rect( m_poScreen, oRect.x, oRect.y, oRect.x+oRect.w, oRect.y+oRect.h, C_WHITE );
+}
+
+
+SDL_Rect CTeamDisplay::GetRect( int a_iNumber )
+{
+ if ( a_iNumber < 0 ) a_iNumber = m_iCount;
+ if ( m_oRect.h > 75 )
+ {
+ m_oRect.y += (m_oRect.h - 75) / 2;
+ m_oRect.h = 75;
+ }
+
+ int iGap = 5;
+ int iWidth = m_oRect.w / m_iMax;
+ if ( iWidth > m_oRect.h + iGap ) iWidth = m_oRect.h + iGap;
+
+ SDL_Rect oRect;
+ oRect.y = m_oRect.y;
+ oRect.h = m_oRect.h;
+ oRect.x = m_oRect.x + iWidth * a_iNumber;
+ oRect.w = iWidth - iGap;
+
+ return oRect;
+}
+
+
+
+IViewElement::IViewElement( CPlayerSelectView* a_poView, int a_iPriority )
+{
+ m_poView = a_poView;
+ m_iPriority = a_iPriority;
+
+ m_poView->AddViewElement( this, m_iPriority );
+}
+
+
+IViewElement::~IViewElement()
+{
+}
+
+
+int IViewElement::GetPriority() const
+{
+ return m_iPriority;
+}
+
+
+/**
+Flying portrait element for CPlayerSelectView.
+The portrait of a given fighter will gracefully fly from the chooser
+to a team display. The view element will delete itself afterwards.
+\ingroup PlayerSelect
+*/
+
+class CFlyingPortraitViewElement: public IViewElement
+{
+public:
+ CFlyingPortraitViewElement( CPlayerSelectView* a_poView, CTeamDisplay* a_poTeamDisplay,
+ FighterEnum a_enFighter, const SDL_Rect& a_oSrcRect, const SDL_Rect& a_oDstRect )
+ : IViewElement( a_poView, 0 )
+ {
+ m_poTeamDisplay = a_poTeamDisplay;
+ m_iTeamNumber = m_poTeamDisplay->GetCount();
+ m_enFighter = a_enFighter;
+ m_oRect = a_oSrcRect;
+ m_oDstRect = a_oDstRect;
+
+ m_dX = m_oRect.x + m_oRect.w / 2;
+ m_dY = m_oRect.y + m_oRect.h / 2;
+ m_dSize = omMIN( m_oRect.w, m_oRect.h );
+
+ m_dSpeedX = 0.0;
+ m_dSpeedY = - m_dY / 15;
+ m_dSpeedSize= 0.0;
+
+ m_dTargetX = m_oDstRect.x + m_oDstRect.w / 2;
+ m_dTargetY = m_oDstRect.y + m_oDstRect.h / 2;
+ m_dTargetSize = omMIN( m_oDstRect.w, m_oDstRect.h);
+
+ m_iTotalTime = 70 + m_dY / 7.5;
+ m_iTime = m_iTotalTime;
+
+ }
+
+ ~CFlyingPortraitViewElement() {}
+
+ void Advance( int a_iNumFrames )
+ {
+ if ( m_dX + m_dSpeedX * 0.5 * m_iTime > m_dTargetX ) m_dSpeedX -= a_iNumFrames * 0.5; else m_dSpeedX += a_iNumFrames * 0.5;
+ if ( m_dY + m_dSpeedY * 0.5 * m_iTime > m_dTargetY ) m_dSpeedY -= a_iNumFrames * 0.5; else m_dSpeedY += a_iNumFrames * 0.5;
+
+ m_dX += m_dSpeedX * a_iNumFrames;
+ m_dY += m_dSpeedY * a_iNumFrames;
+
+ double dTargetSize = (m_iTime > m_iTotalTime/2) ? 75.0 : m_dTargetSize;
+ int iTargetTime = (m_iTime > m_iTotalTime/2) ? m_iTime : ( m_iTotalTime/2-m_iTime );
+ if ( m_dSize + m_dSpeedSize * iTargetTime > dTargetSize ) m_dSpeedSize -= a_iNumFrames * 0.3; else m_dSpeedSize += a_iNumFrames * 0.3;
+
+ m_dSize += m_dSpeedSize * a_iNumFrames;
+
+ m_oRect.x = int( m_dX - m_dSize / 2 );
+ m_oRect.y = int( m_dY - m_dSize / 2 );
+ m_oRect.w = m_oRect.h = (int)m_dSize;
+
+ m_iTime -= a_iNumFrames;
+ if ( m_iTime < 0 )
+ {
+ m_poTeamDisplay->DrawFighter( m_enFighter, m_iTeamNumber );
+ m_poView->RemoveViewElement( this );
+ delete( this );
+ }
+ }
+
+ void Draw()
+ {
+ g_oChooser.DrawPortrait( m_enFighter, gamescreen, m_oRect );
+ }
+
+protected:
+ CTeamDisplay* m_poTeamDisplay;
+ int m_iTeamNumber;
+ FighterEnum m_enFighter;
+ double m_dX, m_dY, m_dSize;
+ double m_dSpeedX, m_dSpeedY, m_dSpeedSize;
+ double m_dTargetX, m_dTargetY, m_dTargetSize;
+ int m_iTotalTime;
+ int m_iTime;
+ SDL_Rect m_oDstRect;
+ SDL_Rect m_oRect;
+ int m_iNumber;
+};
+
+/**
+This view element implements the "opening courtain" effect at the start
+of the player selection routine.
+It removes itself when the effect is
+finished.
+\ingroup PlayerSelect
+*/
+
+class CCourtainViewElement: public IViewElement
+{
+public:
+ CCourtainViewElement( CPlayerSelectView* a_poView ) : IViewElement( a_poView, 0 )
+ {
+ m_iCourtain = 0;
+ m_iCourtainSpeed = 0;
+ m_iCourtainTime = 80;
+ }
+
+ ~CCourtainViewElement() {}
+
+ void Advance( int a_iNumFrames )
+ {
+ if ( a_iNumFrames > 5 ) a_iNumFrames = 5;
+
+ if ( m_iCourtainTime <= 0 )
+ {
+ SDL_SetClipRect( gamescreen, NULL );
+ m_poView->RemoveViewElement( this );
+ delete( this );
+ }
+
+ if ( m_iCourtain + m_iCourtainSpeed * m_iCourtainTime /2 < 320 * 4 )
+ m_iCourtainSpeed += a_iNumFrames;
+ else
+ m_iCourtainSpeed -= a_iNumFrames;
+
+ m_iCourtain += m_iCourtainSpeed * a_iNumFrames;
+ m_iCourtainTime -= a_iNumFrames;
+
+ if ( m_iCourtainTime > 0 )
+ {
+ SDL_Rect oRect;
+ oRect.x = 320 - m_iCourtain/4; oRect.y = 0;
+ oRect.w = m_iCourtain / 2; oRect.h = gamescreen->h;
+ if ( oRect.x < 0 ) oRect.x = 0;
+ if ( oRect.w > gamescreen->w ) oRect.w = gamescreen->w;
+ SDL_SetClipRect( gamescreen, &oRect );
+ }
+ }
+
+ void Draw()
+ {
+ }
+
+protected:
+ int m_iCourtain;
+ int m_iCourtainSpeed;
+ int m_iCourtainTime;
+
+};
+
+
+
+/**
+This view element flashes the title and '?' mark of active teams.
+\ingroup PlayerSelect
+*/
+
+class CTeamFlashViewElement: public IViewElement
+{
+public:
+ CTeamFlashViewElement( CPlayerSelectView* a_poView, int a_iPriority )
+ : IViewElement( a_poView, a_iPriority )
+ {
+ for ( int i=0; i<MAXPLAYERS; ++i )
+ {
+ m_bActive[i] = false;
+ }
+ }
+
+ ~CTeamFlashViewElement() {}
+
+ void Advance( int a_iNumFrames )
+ {
+ m_iCycle = (m_iCycle + a_iNumFrames*10) % 512;
+ }
+
+ void Draw()
+ {
+ int iLum = m_iCycle < 256 ? m_iCycle : 511-m_iCycle;
+
+ for ( int i=0; i<g_oState.m_iNumPlayers; ++i )
+ {
+ if ( g_oChooser.IsRectangleVisible( i ) )
+ {
+ SDL_Color oColor;
+ switch (i)
+ {
+ case 0: oColor.r = 85; oColor.g = 255; oColor.b = 85; break;
+ case 1: oColor.r = 255; oColor.g = 85; oColor.b = 255; break;
+ case 2: oColor.r = 255; oColor.g = 255; oColor.b = 85; break;
+ default: oColor.r = 85; oColor.g = 85; oColor.b = 255; break;
+ }
+ Uint32 iColor = SDL_MapRGB( gamescreen->format, oColor.r*iLum/256, oColor.g*iLum/256, oColor.b*iLum/256 );
+ m_poView->GetTeamDisplay(i)->DrawTitle( iColor );
+ m_poView->GetTeamDisplay(i)->DrawQuestionMark( iColor );
+ m_bActive[i] = true;
+ }
+ else if ( m_bActive[i] )
+ {
+ m_poView->GetTeamDisplay(i)->DrawTitle( C_WHITE );
+ m_bActive[i] = false;
+ }
+ }
+ }
+
+protected:
+ int m_iCycle;
+ bool m_bActive[MAXPLAYERS];
+};
+
+
+
+
+
+/*************************************************************************
+ CPLAYERSELECTVIEW CLASS
+*************************************************************************/
+
+CPlayerSelectView::CPlayerSelectView( bool a_bNetworkGame, bool a_bTeamMode )
+{
+ m_bOver = false;
+ m_bNetworkGame = a_bNetworkGame;
+ m_bTeamMode = a_bTeamMode;
+ m_bTeamMultiselect = g_oState.m_bTeamMultiselect > 0;
+ m_poReadline = NULL;
+ m_poTextArea = NULL;
+ m_iTime = 0;
+
+ int i;
+ for ( i=0; i<MAXPLAYERS; ++i ) m_apoTeamDisplays[i] = NULL;
+
+ SDL_FillRect( gamescreen, NULL, C_BLACK );
+ SDL_Flip( gamescreen );
+ m_poBackground = LoadBackground( "FighterStats.jpg", 64 ); //m_bNetworkGame ? "PlayerSelect_chat.png" : "PlayerSelect.png", 111 );
+ if ( m_poBackground ) SDL_SetColorKey( m_poBackground, 0, 0 );
+
+ new CCourtainViewElement(this);
+
+ if ( m_bTeamMode )
+ {
+ new CTeamFlashViewElement(this, 0);
+ SDL_Rect oRect;
+ oRect.x = 10; oRect.w = 620;
+ oRect.y = 380; oRect.h = 40;
+ m_apoTeamDisplays[0] = new CTeamDisplay( 0, m_poBackground, oRect );
+ oRect.y = 430; oRect.h = 40;
+ m_apoTeamDisplays[1] = new CTeamDisplay( 1, m_poBackground, oRect );
+ if ( g_oState.m_iNumPlayers >= 3 )
+ {
+ oRect.y = 330;
+ m_apoTeamDisplays[2] = new CTeamDisplay( 2, m_poBackground, oRect );
+ }
+
+ if ( g_oState.m_iNumPlayers >= 4 )
+ {
+ oRect.y = 280;
+ m_apoTeamDisplays[3] = new CTeamDisplay( 3, m_poBackground, oRect );
+ }
+
+ if ( m_bTeamMultiselect )
+ {
+ m_iChooserTop = 25;
+ m_iChooserHeight = 80 * 4;
+ m_iChooserLeft = 158;
+ m_iChooserWidth = 64*5;
+ }
+ else
+ {
+ DrawGradientText( "Choose A Fighter Dammit", titleFont, 10, m_poBackground );
+ m_iChooserTop = 75;
+ m_iChooserHeight = 80 * 4 - 50;
+ m_iChooserLeft = 180;
+ m_iChooserWidth = 430;
+ }
+ m_iFighterYOffset = -100;
+ m_iFighterNameYOffset = -95;
+ }
+ else if ( m_bNetworkGame )
+ {
+ m_iChooserLeft = 158;
+ m_iChooserTop = 26;
+ m_iChooserWidth = 64 * 5;
+ m_iChooserHeight = 64 * 4;
+ m_iFighterYOffset = -130;
+ m_iFighterNameYOffset = -170;
+ }
+ else
+ {
+ m_iChooserLeft = 158;
+ m_iChooserTop = 74;
+ m_iChooserWidth = 80*4;
+ m_iChooserHeight = 80*5;
+ m_iFighterYOffset = 0;
+ m_iFighterNameYOffset = 0;
+ }
+
+ g_oChooser.Start( m_poBackground );
+ g_oChooser.Resize( m_iChooserLeft, m_iChooserTop, m_iChooserLeft+m_iChooserWidth, m_iChooserTop+m_iChooserHeight );
+ g_oChooser.Draw();
+
+ if ( !m_bNetworkGame && !m_bTeamMode )
+ {
+ DrawGradientText( "Choose A Fighter Dammit", titleFont, 10, m_poBackground );
+ }
+
+ if ( m_bNetworkGame )
+ {
+ char acMsg[256];
+ sprintf( acMsg, "Press Enter to chat, Page Up/Page Down to scroll..." );
+
+ if ( m_bNetworkGame )
+ {
+ m_poReadline = new CReadline( m_bNetworkGame ? m_poBackground : NULL, chatFont,
+ acMsg, strlen(acMsg), 256, 15, 465, 610, C_LIGHTCYAN, C_BLACK, 255 );
+ m_poTextArea = new CTextArea( m_poBackground, chatFont, 15, 313, 610, 32*4 );
+ }
+ }
+
+}
+
+
+CPlayerSelectView::~CPlayerSelectView()
+{
+ delete m_apoTeamDisplays[0]; m_apoTeamDisplays[0] = NULL;
+ delete m_apoTeamDisplays[1]; m_apoTeamDisplays[1] = NULL;
+
+ TViewElements::iterator it;
+ for ( it=m_apoElements.begin(); it!= m_apoElements.end(); ++it )
+ {
+ delete *it;
+ }
+ m_apoElements.clear();
+
+ delete m_poTextArea;
+ delete m_poReadline;
+ SDL_FreeSurface( m_poBackground );
+}
+
+
+void CPlayerSelectView::Advance( int a_iNumFrames )
+{
+ m_iTime += a_iNumFrames;
+
+ for ( int i=0; i<a_iNumFrames; ++i )
+ {
+ g_oBackend.AdvancePerl();
+
+ TViewElements::iterator it;
+ }
+
+ TViewElements::iterator it;
+ TViewElements::iterator itNext;
+ for ( it = m_apoElements.begin(); it != m_apoElements.end(); )
+ {
+ itNext = it;
+ ++itNext;
+ (*it)->Advance( a_iNumFrames );
+ it = itNext;
+ }
+}
+
+
+void CPlayerSelectView::Draw()
+{
+ TViewElements::iterator it;
+
+ g_oBackend.ReadFromPerl();
+ m_bOver = g_oBackend.m_iGameOver > 0;
+
+ g_oChooser.DrawRectangles(m_iTime);
+ SDL_BlitSurface( m_poBackground, NULL, gamescreen, NULL );
+
+ for ( it = m_apoElements.begin(); it != m_apoElements.end(); ++it )
+ {
+ (*it)->Draw();
+ }
+
+ for ( int i=0; i<g_oState.m_iNumPlayers; ++i )
+ {
+ if ( m_bTeamMode && 1==i && !m_bTeamMultiselect ) continue;
+
+ const SPlayerInfo& roPlayerInfo = g_oPlayerSelect.GetPlayerInfo( i );
+ int iPlayerNameWidth = g_oPlayerSelect.GetFighterNameWidth( i );
+
+ if ( g_oBackend.m_aoPlayers[i].m_iFrame )
+ {
+ roPlayerInfo.m_poPack->Draw(
+ omABS(g_oBackend.m_aoPlayers[i].m_iFrame)-1,
+ g_oBackend.m_aoPlayers[i].m_iX, g_oBackend.m_aoPlayers[i].m_iY + m_iFighterYOffset,
+ g_oBackend.m_aoPlayers[i].m_iFrame < 0 );
+ }
+ int x = ( m_iChooserLeft - iPlayerNameWidth ) / 2;
+ if ( x<10 ) x = 10;
+ if ( i ) x = gamescreen->w - x - iPlayerNameWidth;
+
+ sge_BF_textout( gamescreen, fastFont, g_oPlayerSelect.GetFighterName(i),
+ x, gamescreen->h - 40 + m_iFighterNameYOffset );
+ }
+
+ SDL_Flip( gamescreen );
+}
+
+
+CReadline* CPlayerSelectView::GetReadline()
+{
+ return m_poReadline;
+}
+
+
+CTextArea* CPlayerSelectView::GetTextArea()
+{
+ return m_poTextArea;
+}
+
+
+void CPlayerSelectView::AddViewElement( IViewElement* a_poElement, int a_iPriority )
+{
+
+ m_apoElements.push_back( a_poElement );
+}
+
+
+void CPlayerSelectView::RemoveViewElement( IViewElement* a_poElement )
+{
+ m_apoElements.remove( a_poElement );
+}
+
+
+void CPlayerSelectView::AddFighterToTeam( int a_iPlayer, FighterEnum a_enFighter )
+{
+ new CFlyingPortraitViewElement( this, m_apoTeamDisplays[a_iPlayer], a_enFighter,
+ g_oChooser.GetFighterRect( a_enFighter ),
+ m_apoTeamDisplays[a_iPlayer]->GetRect() );
+ m_apoTeamDisplays[a_iPlayer]->AddFighter( a_enFighter );
+}
+
+
+bool CPlayerSelectView::IsOver()
+{
+ return m_bOver;
+}
+
+
+CTeamDisplay* CPlayerSelectView::GetTeamDisplay( int a_iPlayer )
+{
+ return m_apoTeamDisplays[a_iPlayer];
+}
diff --git a/src/PlayerSelectView.h b/src/PlayerSelectView.h
index 4901d44..c9cba6d 100644
--- a/src/PlayerSelectView.h
+++ b/src/PlayerSelectView.h
@@ -1,82 +1,82 @@
-#ifndef PLAYERSELECTVIEW_H
-#define PLAYERSELECTVIEW_H
-
-#include "FighterEnum.h"
-#include "State.h"
-#include <list>
-
-struct SDL_Surface;
-class CTextArea;
-class CReadline;
-class CPlayerSelectView;
-class CTeamDisplay;
-
-
-/**
-A visual element that runs independently within CPlayerSelectView
-\ingroup PlayerSelect
-*/
-
-class IViewElement
-{
-public:
- IViewElement( CPlayerSelectView* a_poView, int a_iPriority );
- virtual ~IViewElement();
-
- int GetPriority() const;
- virtual void Advance( int a_iNumFrames ) = 0;
- virtual void Draw() = 0;
-
-protected:
- CPlayerSelectView* m_poView;
- int m_iPriority;
-};
-
-
-
-/**
-View part model-view-controller architecture of the player selection.
-\ingroup PlayerSelect
-*/
-
-class CPlayerSelectView
-{
-public:
- CPlayerSelectView( bool a_bNetworkGame, bool a_bTeamMode );
- ~CPlayerSelectView();
-
- void Advance( int a_iNumFrames );
- void Draw();
- CTextArea* GetTextArea();
- CReadline* GetReadline();
-
- void AddViewElement( IViewElement* a_poElement, int a_iPriority );
- void RemoveViewElement( IViewElement* a_poElement );
- void AddFighterToTeam( int a_iPlayer, FighterEnum a_enFighter );
- bool IsOver();
-
- CTeamDisplay* GetTeamDisplay( int a_iPlayer );
-
-protected:
- bool m_bTeamMode;
- bool m_bTeamMultiselect;
- bool m_bNetworkGame;
- SDL_Surface* m_poBackground;
- CTextArea* m_poTextArea;
- CReadline* m_poReadline;
- bool m_bOver;
-
- int m_iChooserTop;
- int m_iChooserLeft;
- int m_iChooserHeight;
- int m_iChooserWidth;
- int m_iFighterYOffset;
- int m_iFighterNameYOffset;
-
- int m_iTime;
- typedef std::list<IViewElement*> TViewElements;
- TViewElements m_apoElements;
- CTeamDisplay* m_apoTeamDisplays[MAXPLAYERS];
-};
-
-#endif // PLAYERSELECTVIEW_H
+#ifndef PLAYERSELECTVIEW_H
+#define PLAYERSELECTVIEW_H
+
+#include "FighterEnum.h"
+#include "State.h"
+#include <list>
+
+struct SDL_Surface;
+class CTextArea;
+class CReadline;
+class CPlayerSelectView;
+class CTeamDisplay;
+
+
+/**
+A visual element that runs independently within CPlayerSelectView
+\ingroup PlayerSelect
+*/
+
+class IViewElement
+{
+public:
+ IViewElement( CPlayerSelectView* a_poView, int a_iPriority );
+ virtual ~IViewElement();
+
+ int GetPriority() const;
+ virtual void Advance( int a_iNumFrames ) = 0;
+ virtual void Draw() = 0;
+
+protected:
+ CPlayerSelectView* m_poView;
+ int m_iPriority;
+};
+
+
+
+/**
+View part model-view-controller architecture of the player selection.
+\ingroup PlayerSelect
+*/
+
+class CPlayerSelectView
+{
+public:
+ CPlayerSelectView( bool a_bNetworkGame, bool a_bTeamMode );
+ ~CPlayerSelectView();
+
+ void Advance( int a_iNumFrames );
+ void Draw();
+ CTextArea* GetTextArea();
+ CReadline* GetReadline();
+
+ void AddViewElement( IViewElement* a_poElement, int a_iPriority );
+ void RemoveViewElement( IViewElement* a_poElement );
+ void AddFighterToTeam( int a_iPlayer, FighterEnum a_enFighter );
+ bool IsOver();
+
+ CTeamDisplay* GetTeamDisplay( int a_iPlayer );
+
+protected:
+ bool m_bTeamMode;
+ bool m_bTeamMultiselect;
+ bool m_bNetworkGame;
+ SDL_Surface* m_poBackground;
+ CTextArea* m_poTextArea;
+ CReadline* m_poReadline;
+ bool m_bOver;
+
+ int m_iChooserTop;
+ int m_iChooserLeft;
+ int m_iChooserHeight;
+ int m_iChooserWidth;
+ int m_iFighterYOffset;
+ int m_iFighterNameYOffset;
+
+ int m_iTime;
+ typedef std::list<IViewElement*> TViewElements;
+ TViewElements m_apoElements;
+ CTeamDisplay* m_apoTeamDisplays[MAXPLAYERS];
+};
+
+#endif // PLAYERSELECTVIEW_H
diff --git a/src/Pragma.h b/src/Pragma.h
new file mode 100644
index 0000000..239fa7b
--- /dev/null
+++ b/src/Pragma.h
@@ -0,0 +1 @@
+#pragma warning( disable : 4786 )
diff --git a/src/RlePack.cpp b/src/RlePack.cpp
index 4aff488..1d19b74 100644
--- a/src/RlePack.cpp
+++ b/src/RlePack.cpp
@@ -1,679 +1,679 @@
/***************************************************************************
RlePack.cpp - description
-------------------
begin : Mon Sep 24 2001
copyright : (C) 2001 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include "RlePack.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL.h"
#include "gfx.h"
#include "common.h"
/// Sanity: This is the maximal number of entries in a .DAT file.
#define MAXDATACOUNT 65530
inline void ChangeEndian32( Uint32& a_riArg )
{
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
char* pcArg = (char*)&a_riArg;
char cTemp;
cTemp = pcArg[0]; pcArg[0] = pcArg[3]; pcArg[3] = cTemp;
cTemp = pcArg[1]; pcArg[1] = pcArg[2]; pcArg[2] = cTemp;
#endif
}
inline void ChangeEndian16( Uint16& a_riArg )
{
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
char* pcArg = (char*)&a_riArg;
char cTemp;
cTemp = pcArg[0]; pcArg[0] = pcArg[1]; pcArg[1] = cTemp;
#endif
}
inline Uint32 ConvertEndian32( Uint32 a_iArg )
{
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
char* pcArg = (char*)&a_iArg;
char cTemp;
cTemp = pcArg[0]; pcArg[0] = pcArg[3]; pcArg[3] = cTemp;
cTemp = pcArg[1]; pcArg[1] = pcArg[2]; pcArg[2] = cTemp;
#endif
return a_iArg;
}
inline Uint16 ConvertEndian16( Uint16 a_iArg )
{
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
char* pcArg = (char*)&a_iArg;
char cTemp;
cTemp = pcArg[0]; pcArg[0] = pcArg[1]; pcArg[1] = cTemp;
#endif
return a_iArg;
}
-
-/**
-\ingroup Media
-\brief CRleSprite is a runlength encoded sprite that can be blitted flipped.
-
-CRleSprite originally comes from Allegro. I use it in OpenMortal because
-it is relatively fast to blit and is economical on the memory too.
+
+/**
+\ingroup Media
+\brief CRleSprite is a runlength encoded sprite that can be blitted flipped.
+
+CRleSprite originally comes from Allegro. I use it in OpenMortal because
+it is relatively fast to blit and is economical on the memory too.
*/
struct SRleSprite
{
Uint16 dummy; // For better alignment... NASTY NASTY HACK!!
Uint16 color_depth; /* color depth of the image */
Uint16 w, h; /* width and height in pixels */
Uint32 size;
signed char dat[0];
};
-
-/**
-\ingroup Media
-\brief Internal data of CRlePack
+
+/**
+\ingroup Media
+\brief Internal data of CRlePack
*/
struct CRlePack_P
{
SDL_Color m_aoPalette[256];
SDL_Color m_aoTintedPalette[256];
TintEnum m_enTint;
int m_iCount;
int m_iArraysize;
SRleSprite** m_pSprites;
void* m_pData;
int m_iColorCount;
int m_iColorOffset;
Uint32 m_aiRGBPalette[256];
void draw_rle_sprite8( SRleSprite* a_poSprite, int a_dx, int a_dy );
void draw_rle_sprite_v_flip8( SRleSprite* a_poSprite, int a_dx, int a_dy );
void draw_rle_sprite16( SRleSprite* a_poSprite, int a_dx, int a_dy );
void draw_rle_sprite_v_flip16( SRleSprite* a_poSprite, int a_dx, int a_dy );
void draw_rle_sprite24( SRleSprite* a_poSprite, int a_dx, int a_dy );
void draw_rle_sprite_v_flip24( SRleSprite* a_poSprite, int a_dx, int a_dy );
void draw_rle_sprite32( SRleSprite* a_poSprite, int a_dx, int a_dy );
void draw_rle_sprite_v_flip32( SRleSprite* a_poSprite, int a_dx, int a_dy );
};
CRlePack::CRlePack( const char* a_pcFilename, int a_iNumColors )
{
p = new CRlePack_P;
p->m_enTint = NO_TINT;
p->m_iCount = 0;
p->m_iArraysize = 0;
p->m_pSprites = NULL;
p->m_pData = NULL;
p->m_iColorCount = 0;
p->m_iColorOffset = 0;
// Load file and stuff
LoadFile( a_pcFilename, a_iNumColors );
}
CRlePack::~CRlePack()
{
if (!p)
return;
if (p->m_pSprites)
{
delete[] p->m_pSprites;
p->m_pSprites = NULL;
}
free( p->m_pData );
delete( p );
p = NULL;
}
void CRlePack::Clear()
{
if ( p && p->m_pSprites )
{
delete[] p->m_pSprites;
p->m_pSprites = NULL;
}
}
int CRlePack::LoadFile( const char* a_pcFilename, int a_iNumColors )
{
FILE* f;
f = fopen( a_pcFilename, "rb" );
if (f==NULL)
{
debug( "Can't open file '%s'.\n", a_pcFilename );
return -1;
}
fseek( f, 0, SEEK_END );
long iFileSize = ftell ( f );
p->m_pData = malloc( iFileSize );
if ( NULL == p->m_pData )
{
fclose( f );
return -1;
}
fseek( f, 0, SEEK_SET );
int iRead = fread( p->m_pData, 1, iFileSize, f );
fclose( f );
p->m_iColorCount = gamescreen->format->BitsPerPixel == 8 ? a_iNumColors : 256;
if ( iFileSize != iRead )
{
debug( "Warning CRlePack(): iFileSize=%d, iRead=%d\n", iFileSize, iRead );
}
struct SHeader
{
char acDummy[8];
Uint32 iDatacount;
} *poHeader = (SHeader*) p->m_pData;
ChangeEndian32( poHeader->iDatacount );
debug( "File '%s' contains %d entries.\n", a_pcFilename, poHeader->iDatacount );
if (poHeader->iDatacount>MAXDATACOUNT) poHeader->iDatacount = MAXDATACOUNT; // Sanity
p->m_iArraysize = poHeader->iDatacount;
p->m_pSprites = new SRleSprite*[ poHeader->iDatacount ];
char* pcNext = ((char*)p->m_pData) + sizeof(SHeader);
char* pcEnd = ((char*)p->m_pData) + iFileSize;
while ( pcNext < pcEnd - 4 )
{
if ( 0 == strncmp( pcNext, "prop", 4 ) )
{
struct SProperty
{
char acName[4];
Uint32 iSize;
} *poProperty = (SProperty*) (pcNext+4);
ChangeEndian32( poProperty->iSize );
pcNext += 4 + sizeof(SProperty) + poProperty->iSize;
}
else if ( 0 == strncmp( pcNext, "RLE ", 4 ) )
{
struct SRLE
{
SRleSprite oSprite;
} *poRle = (SRLE*) (pcNext+10);
poRle->oSprite.color_depth = ConvertEndian16(poRle->oSprite.color_depth);
poRle->oSprite.w = ConvertEndian16(poRle->oSprite.w);
poRle->oSprite.h = ConvertEndian16(poRle->oSprite.h);
poRle->oSprite.size = ConvertEndian32(poRle->oSprite.size);
p->m_pSprites[p->m_iCount] = &(poRle->oSprite);
p->m_iCount++;
pcNext += 10 + sizeof( SRLE ) + poRle->oSprite.size;
}
else if ( 0 == strncmp( pcNext, "PAL ", 4 ) )
{
struct SPAL
{
Uint32 iLength1;
Uint32 iLength;
SDL_Color aoColors[256];
} *poPal = (SPAL*) (pcNext+4);
ChangeEndian32( poPal->iLength );
int iNumColors = poPal->iLength>1024 ? 1024 : poPal->iLength;
iNumColors /= 4;
for (int i=0; i< iNumColors; i++)
{
p->m_aoPalette[i].r = poPal->aoColors[i].r*4;
p->m_aoPalette[i].g = poPal->aoColors[i].g*4;
p->m_aoPalette[i].b = poPal->aoColors[i].b*4;
p->m_aoPalette[i].unused = 0;
p->m_aoTintedPalette[i] = p->m_aoPalette[i];
}
pcNext += 4 + 8 + poPal->iLength;
}
else
{
struct SUnknown
{
Uint32 iSize;
} *poUnknown = (SUnknown*) (pcNext+4);
ChangeEndian32( poUnknown->iSize );
debug( "Unknown: '%4s', size: %d\n", pcNext, poUnknown->iSize );
pcNext += 4 + sizeof(SUnknown) + poUnknown->iSize;
}
}
return p->m_iCount;
#if 0
// #
// # Here's the old implementation or read, left here for reference only.
// #
int datacount;
#define READDW(I) { \
unsigned char data[4]; \
fread( data, 4, 1, f ); \
(I) = (data[0]<<24) + (data[1]<<16) + (data[2]<<8) + data[3]; }
#define READW(I) { \
unsigned char data[2]; \
fread( data, 2, 1, f ); \
(I) = (data[0]<<8) + data[1]; }
#define READCH(S,C) { \
fread( S, C, 1, f ); S[C] = 0; }
fseek( f, 8, SEEK_SET ); // Skip header
READDW( datacount );
debug( "File '%s' contains %d entries.\n", filename, datacount );
if (datacount>500) datacount = 500; // Sanity
p->arraysize = datacount;
p->sprites = new SRleSprite*[ datacount ];
while( (!feof(f)) && (!ferror(f)) && (datacount>0) )
{
char s[10];
READCH( s, 4 );
if ( !strcmp( s, "prop" )) // Found a property
{
fseek( f, 4, SEEK_CUR );
unsigned int propsize;
READDW( propsize );
fseek( f, propsize, SEEK_CUR );
}
else if (!strcmp( s, "RLE " )) // Found an SRleSprite
{
datacount--;
unsigned int length, bpp, width, height, size;
READDW( length );
READDW( length );
READW( bpp );
READW( width );
READW( height );
READDW( size );
SRleSprite* sprite = (SRleSprite*) malloc( sizeof(SRleSprite) + size );
p->sprites[ p->count ] = sprite;
(p->count)++;
sprite->w = width;
sprite->h = height;
sprite->color_depth = bpp;
sprite->size = size;
fread( sprite->dat, 1, size, f );
}
else if (!strcmp( s, "PAL ")) // Found a palette
{
datacount--;
unsigned int length, pallength;
READDW( length );
READDW( length );
pallength = length>1024 ? 1024 : length;
pallength /= 4;
for (unsigned int i=0; i< pallength; i++)
{
char c[4];
fread( c, 4, 1, f );
p->palette[i].r = c[0]*4;
p->palette[i].g = c[1]*4;
p->palette[i].b = c[2]*4;
p->palette[i].unused = 0;
}
fseek( f, length - pallength*4, SEEK_CUR );
}
else // Found something else
{
debug( "Unknown: %s.", s );
datacount--;
unsigned int length;
READDW( length );
READDW( length );
fseek( f, length, SEEK_CUR );
}
}
fclose( f );
#endif
}
int CRlePack::Count()
{
return p->m_iCount;
}
/** Worker method of CRlePack::OffsetSprites() .*/
void OffsetRLESprite( SRleSprite* spr, int offset ) // Static method
{
if (!spr || !offset) return;
signed char *s = spr->dat;
signed char c;
int y;
for (y=0; y<spr->h; y++)
{
c = *s++;
while (c)
{
// For positive c: solid pixels.
for ( ; c>0; c-- )
{
*s = (*s) + offset;
s++;
}
c = *s++;
}
}
}
/** Offsets the sprites "logical" palette values by the given offset.
This is only relevant in 8BPP mode; in other color depths this is a
no-op.
Explanation: RlePacks have an internal palette which contains up to 256
colors. These colors are always indexed from 0 up. However, if you load
two RlePacks with different palettes, the palettes will collide, and one
CRlePack will be displayed with an incorrect palette.
To work around this, you can offset one of the sprites palette. For example,
you might load an CRlePack with 16 colors, and another with 64 colors. You
can offset the second CRlePack by 16 colors; the total effect is that the
two RlePacks now use 80 colors of the available 256 colors, the first using
colors 0-15, the second using colors 16-79.
*/
void CRlePack::OffsetSprites( int a_iOffset )
{
if ( (a_iOffset<=0) || (a_iOffset>255) || (8!=gamescreen->format->BitsPerPixel) )
return;
p->m_iColorOffset = a_iOffset;
int i;
// Offset every SRleSprite
for ( i=0; i<p->m_iCount; ++i )
{
OffsetRLESprite( p->m_pSprites[i], a_iOffset );
}
}
void CRlePack::SetTint( TintEnum a_enTint )
{
int i;
switch( a_enTint )
{
case ZOMBIE_TINT:
{
for ( i=0; i<p->m_iColorCount; ++i )
{
p->m_aoTintedPalette[i].r = 0;
p->m_aoTintedPalette[i].g = p->m_aoPalette[i].g;
p->m_aoTintedPalette[i].b = 0;
}
break;
}
case GRAY_TINT:
{
int j;
for ( i=0; i<p->m_iColorCount; ++i )
{
j = (p->m_aoPalette[i].r + p->m_aoPalette[i].g + p->m_aoPalette[i].b)/4;
p->m_aoTintedPalette[i].r = j;
p->m_aoTintedPalette[i].g = j;
p->m_aoTintedPalette[i].b = j;
}
break;
}
case DARK_TINT:
{
for ( i=0; i<p->m_iColorCount; ++i )
{
p->m_aoTintedPalette[i].r = int(p->m_aoPalette[i].r) * 2 / 3;
p->m_aoTintedPalette[i].g = int(p->m_aoPalette[i].g) * 2 / 3;
p->m_aoTintedPalette[i].b = int(p->m_aoPalette[i].b) * 2 / 3;
}
break;
}
case INVERTED_TINT:
{
for ( i=0; i<p->m_iColorCount; ++i )
{
p->m_aoTintedPalette[i].r = 255 - p->m_aoPalette[i].r;
p->m_aoTintedPalette[i].g = 255 - p->m_aoPalette[i].g;
p->m_aoTintedPalette[i].b = 255 - p->m_aoPalette[i].b;
}
break;
}
case NO_TINT:
default:
{
for ( i=0; i<p->m_iColorCount; ++i )
{
p->m_aoTintedPalette[i] = p->m_aoPalette[i];
}
break;
}
} // end of switch( a_enTint )
}
/** Loads the palette of the CRlePack to the gamescreen.
This only works in 8BPP mode; in other modes the palette is always considered
to be loaded, and this is a no-operation.
*/
void CRlePack::ApplyPalette()
{
if ( 8 == gamescreen->format->BitsPerPixel )
{
SDL_SetColors( gamescreen, p->m_aoTintedPalette, p->m_iColorOffset, p->m_iColorCount );
}
else
{
// Now is the time to compile m_aiRGBPalette
for ( int i=0; i<p->m_iColorCount; ++i )
{
SDL_Color& roColor = p->m_aoTintedPalette[i];
p->m_aiRGBPalette[i] = SDL_MapRGB( gamescreen->format, roColor.r, roColor.g, roColor.b );
}
}
}
/** Returns the width of a given sprite in pixels.
\param a_iIndex The index of the sprite, 0 <= a_iIndex < Count()
*/
int CRlePack::GetWidth( int a_iIndex )
{
if ( (a_iIndex<0) || (a_iIndex>=p->m_iCount) )
return -1;
SRleSprite* poSprite = p->m_pSprites[a_iIndex];
if (!poSprite)
return -1;
return poSprite->w;
}
/** Returns the height of a given sprite in pixels.
\param a_iIndex The index of the sprite, 0 <= a_iIndex < Count()
*/
int CRlePack::GetHeight( int a_iIndex )
{
if ( (a_iIndex<0) || (a_iIndex>=p->m_iCount) )
return -1;
SRleSprite* poSprite = p->m_pSprites[a_iIndex];
if (!poSprite)
return -1;
return poSprite->h;
}
#define METHODNAME CRlePack_P::draw_rle_sprite8
#define METHODNAME_FLIP CRlePack_P::draw_rle_sprite_v_flip8
#define PIXEL_PTR unsigned char*
#define PUT_PIXEL(p,c) (*((unsigned char *)(p)) = (c))
#define PITCH (dst->pitch)
#include "DrawRle.h"
#undef METHODNAME
#undef METHODNAME_FLIP
#undef PIXEL_PTR
#undef PUT_PIXEL
#undef PITCH
#define METHODNAME CRlePack_P::draw_rle_sprite16
#define METHODNAME_FLIP CRlePack_P::draw_rle_sprite_v_flip16
#define PIXEL_PTR Uint16*
#define PUT_PIXEL(p,c) (*((PIXEL_PTR )(p)) = (m_aiRGBPalette[c]))
#define PITCH (dst->pitch / 2)
#include "DrawRle.h"
#undef METHODNAME
#undef METHODNAME_FLIP
#undef PIXEL_PTR
#undef PUT_PIXEL
#undef PITCH
#define METHODNAME CRlePack_P::draw_rle_sprite32
#define METHODNAME_FLIP CRlePack_P::draw_rle_sprite_v_flip32
#define PIXEL_PTR Uint32*
#define PUT_PIXEL(p,c) (*((PIXEL_PTR )(p)) = (m_aiRGBPalette[c]))
#define PITCH (dst->pitch / 4)
#include "DrawRle.h"
void CRlePack::Draw( int a_iIndex, int a_iX, int a_iY, bool a_bFlipped )
{
if ( (a_iIndex<0) || (a_iIndex>=p->m_iCount) )
return;
SRleSprite* poSprite = p->m_pSprites[a_iIndex];
if (!poSprite)
return;
CSurfaceLocker oLock;
if ( a_bFlipped )
{
switch (gamescreen->format->BitsPerPixel)
{
case 8:
p->draw_rle_sprite_v_flip8( poSprite, a_iX, a_iY ); break;
case 15:
case 16:
p->draw_rle_sprite_v_flip16( poSprite, a_iX, a_iY ); break;
case 32:
p->draw_rle_sprite_v_flip32( poSprite, a_iX, a_iY ); break;
}
}
else
{
switch (gamescreen->format->BitsPerPixel)
{
case 8:
p->draw_rle_sprite8( poSprite, a_iX, a_iY ); break;
case 15:
case 16:
p->draw_rle_sprite16( poSprite, a_iX, a_iY ); break;
case 32:
p->draw_rle_sprite32( poSprite, a_iX, a_iY ); break;
}
}
}
SDL_Surface* CRlePack::CreateSurface( int a_iIndex, bool a_bFlipped )
{
if ( (a_iIndex<0) || (a_iIndex>=p->m_iCount) )
return NULL;
SRleSprite* poSprite = p->m_pSprites[a_iIndex];
if (!poSprite)
return NULL;
SDL_Surface* poSurface = SDL_CreateRGBSurface( SDL_SWSURFACE, poSprite->w, poSprite->h, gamescreen->format->BitsPerPixel,
gamescreen->format->Rmask, gamescreen->format->Gmask, gamescreen->format->Bmask, gamescreen->format->Amask );
if ( NULL == poSurface )
{
return NULL;
}
if ( gamescreen->format->BitsPerPixel <= 8 )
{
SDL_SetColors( poSurface, gamescreen->format->palette->colors, 0, gamescreen->format->palette->ncolors );
}
SDL_FillRect( poSurface, NULL, 0 );// C_LIGHTGREEN );
SDL_SetColorKey( poSurface, SDL_SRCCOLORKEY, 0 ); //C_LIGHTGREEN );
SDL_Surface* poTemp = gamescreen;
gamescreen = poSurface;
Draw( a_iIndex, 0, 0, a_bFlipped );
gamescreen = poTemp;
return poSurface;
}
diff --git a/src/RlePack.h b/src/RlePack.h
index eddd3fe..0f6fba0 100644
--- a/src/RlePack.h
+++ b/src/RlePack.h
@@ -1,72 +1,72 @@
/***************************************************************************
RlePack.h - description
-------------------
begin : Mon Sep 24 2001
copyright : (C) 2001 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifndef __RLEPACK_H
#define __RLEPACK_H
#include "FighterEnum.h"
struct CRlePack_P;
struct SDL_Surface;
/**
\class CRlePack
-\brief CRlePack is an array of images, compressed with runlength encoding.
+\brief CRlePack is an array of images, compressed with runlength encoding.
\ingroup Media
-
-OpenMortal stores the character graphics in CRlePack objects. The reason is
-simple: CRlePacks give an acceptable tradeoff between memory usage and
-blitting speed. Also the CRlePack allows the sprites to be draw horizontally
-flipped, thus saving memory (the mirrored version of the same sprite doesn't
-need to be stored).
-
-The sprites in the RlePack are always paletted (8 bits per pixel). The size
-of the palette is between 1 and 256. The RlePack stores two copies of its
-palette: one is the "base" palette, as it was read from disk, the other is
-the "tinted" palette. The TintEnum contains values that can be passed to
-SetTint(). This is used for two things:
-
-\li In case both players choose the same fighter, player 2's fighter is
-tinted so they won't get confused.
-\li Some special effects (e.g. frozen) make the figther tinted as well.
+
+OpenMortal stores the character graphics in CRlePack objects. The reason is
+simple: CRlePacks give an acceptable tradeoff between memory usage and
+blitting speed. Also the CRlePack allows the sprites to be draw horizontally
+flipped, thus saving memory (the mirrored version of the same sprite doesn't
+need to be stored).
+
+The sprites in the RlePack are always paletted (8 bits per pixel). The size
+of the palette is between 1 and 256. The RlePack stores two copies of its
+palette: one is the "base" palette, as it was read from disk, the other is
+the "tinted" palette. The TintEnum contains values that can be passed to
+SetTint(). This is used for two things:
+
+\li In case both players choose the same fighter, player 2's fighter is
+tinted so they won't get confused.
+\li Some special effects (e.g. frozen) make the figther tinted as well.
CRlePack loads the sprites from a .DAT file in its constructor. If there is
an error (e.g. file doesn't exist), the number of sprites loaded will be 0.
-CRlePack is usually used to store the many frames of a fighter in OpenMortal.
-It is also used for the 'cast' in the CMainScreenDemo.
-
-CRlePack doesn't concern itself with concepts such as "player" or "doodad",
-it merely stores the palette and sprites. This part of OpenMortal can be
-reused in any project with little changes.
+CRlePack is usually used to store the many frames of a fighter in OpenMortal.
+It is also used for the 'cast' in the CMainScreenDemo.
+
+CRlePack doesn't concern itself with concepts such as "player" or "doodad",
+it merely stores the palette and sprites. This part of OpenMortal can be
+reused in any project with little changes.
\sa TintEnum
*/
class CRlePack
{
public:
CRlePack( const char* a_pcFilename, int a_iNumColors );
~CRlePack();
void Clear();
int LoadFile( const char* a_pcFilename, int a_iNumColors );
int Count();
void OffsetSprites( int a_iOffset );
void SetTint( TintEnum a_enTint );
void ApplyPalette();
int GetWidth( int a_iIndex );
int GetHeight( int a_iIndex );
void Draw( int a_iIndex, int a_iX, int a_iY, bool a_bFlipped=false );
SDL_Surface* CreateSurface( int a_iIndex, bool a_bFlipped=false );
private:
CRlePack_P* p;
};
#endif
diff --git a/src/State.h b/src/State.h
index 74032c9..4442a6c 100644
--- a/src/State.h
+++ b/src/State.h
@@ -1,102 +1,102 @@
/***************************************************************************
State.h - description
-------------------
begin : Mon Aug 12 2003
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifndef STATE_H
#define STATE_H
#define MAXPLAYERS 4
-
+
/**
-\ingroup GameLogic
-SState aggregates all the state variables of OpenMortal that do not belong
-to the backend. This includes transient variables such as the current
-game mode (e.g. SStade::IN_DEMO) and configuration variables (such as the
-keyboard layout).
-
-SState is a singlular object, and is accessed with a global pointer,
-g_oState. All other frontend modules access the state through this object.
-The state is made persistent through it's methods, Load() and Save().
-Load() is called on program start, Save() is called when the program exits.
-
-
-The State is the way the CMenu communicate with the rest of the system.
-For example, if the user chooses "Quit" from the menu, the m_bQuitFlag is
-set to true, and the program will react accordingly.
-
-
-The state's most important properties are:
-
-\li m_enGameMode: The mode changes when a game is started or the game ends
-(either in the GameOver screen, or via the "Surrender Game" menu option).
-\li m_bQuitFlag: This is set if the program receives a quit event from the operating system (e.g. KILL signal, window close event, etc), or the user chooses "Quit" from the menu. Once the quit flag is set, the program will abort. All main loops check the value of the quit flag, and will break as soon as it is true.
-\li m_bFullScreen: Quite simply, it is true in fullscreen mode, and false in windowed mode. The user can change this via the menu. The State's ToggleFullscreen() method will switch between fullscreen and windowed mode. Maybe this functionality doesn't belong to the State? ...
-\li Sound properties: Mixing rate, number of channels, volume, etc.
-\li m_aiPlayerKeys: A double array of each player's keys. This is used most often in processing SDL key events: if the event's keysym matches a value in m_aiPlayerKeys, that means that a meaningful key was pushed or released.
-*/
+\ingroup GameLogic
+SState aggregates all the state variables of OpenMortal that do not belong
+to the backend. This includes transient variables such as the current
+game mode (e.g. SStade::IN_DEMO) and configuration variables (such as the
+keyboard layout).
+
+SState is a singlular object, and is accessed with a global pointer,
+g_oState. All other frontend modules access the state through this object.
+The state is made persistent through it's methods, Load() and Save().
+Load() is called on program start, Save() is called when the program exits.
+
+
+The State is the way the CMenu communicate with the rest of the system.
+For example, if the user chooses "Quit" from the menu, the m_bQuitFlag is
+set to true, and the program will react accordingly.
+
+
+The state's most important properties are:
+
+\li m_enGameMode: The mode changes when a game is started or the game ends
+(either in the GameOver screen, or via the "Surrender Game" menu option).
+\li m_bQuitFlag: This is set if the program receives a quit event from the operating system (e.g. KILL signal, window close event, etc), or the user chooses "Quit" from the menu. Once the quit flag is set, the program will abort. All main loops check the value of the quit flag, and will break as soon as it is true.
+\li m_bFullScreen: Quite simply, it is true in fullscreen mode, and false in windowed mode. The user can change this via the menu. The State's ToggleFullscreen() method will switch between fullscreen and windowed mode. Maybe this functionality doesn't belong to the State? ...
+\li Sound properties: Mixing rate, number of channels, volume, etc.
+\li m_aiPlayerKeys: A double array of each player's keys. This is used most often in processing SDL key events: if the event's keysym matches a value in m_aiPlayerKeys, that means that a meaningful key was pushed or released.
+*/
struct SState
{
enum TGameMode {
IN_DEMO, ///< The game is currently in "demo" mode: displaying the intro screens, etc.
IN_SINGLE, ///< The game is in single-player mode.
IN_MULTI, ///< The game is in multi-player mode.
IN_NETWORK, ///< There is against a network opponent in progress
IN_CHAT, ///< The user is on MortalNet
} m_enGameMode;
bool m_bQuitFlag; // true if quit event came
const char* m_pcArgv0; // Set by main to argv[0]
// CONFIGURATION VARIABLES
int m_iNumPlayers; // The number of players =2
enum TTeamModeEnum {
Team_ONE_VS_ONE,
Team_GOOD_VS_EVIL,
Team_CUSTOM,
} m_enTeamMode; // Team mode
int m_iTeamSize; // The size of each team.
int m_bTeamMultiselect; // Can the same player be selected twice?
-
+
// TODO Rename this to m_iRoundLength
int m_iRoundLength; // Length of rounds in seconds.
int m_iHitPoints; // The initial number of hit points.
int m_iGameSpeed; // The speed of the game (fps = 1000/GameSpeed)
bool m_bFullscreen; // True in fullscreen mode.
int m_iChannels; // 1: mono, 2: stereo
int m_iMixingRate; // The mixing rate, in kHz
int m_iMixingBits; // 1: 8bit, 2: 16bit
int m_iMusicVolume; // Volume of music; 0: off, 100: max
int m_iSoundVolume; // Volume of sound effects; 0: off, 100: max
int m_aiPlayerKeys[MAXPLAYERS][9]; // Player keysyms
char m_acLanguage[10]; // Language ID (en,hu,fr,es,..)
int m_iLanguageCode; // Non-persistend language code (set by backend based on the language)
char m_acLatestServer[256]; // Last server
bool m_bServer; // We were server in the last network game
char m_acNick[128]; // The user name on the last server.
SState();
void Load();
void Save();
void ToggleFullscreen();
void SetLanguage( const char* a_pcLanguage );
void SetServer( const char* a_pcServer );
};
extern SState g_oState;
#endif
diff --git a/src/TextArea.h b/src/TextArea.h
index 3e41cc5..cc01aef 100644
--- a/src/TextArea.h
+++ b/src/TextArea.h
@@ -1,56 +1,56 @@
/***************************************************************************
TextArea.h - description
-------------------
begin : Wed Jan 28 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
#ifndef TEXTAREA_H
#define TEXTAREA_H
#include "SDL_video.h"
struct SDL_Surface;
struct _sge_TTFont;
#include <string>
#include <list>
typedef std::list<std::string> TStringList;
typedef std::list<int> TIntList;
-
-/**
-\brief CTextArea displays scrolling text.
-\ingroup Media
-*/
+
+/**
+\brief CTextArea displays scrolling text.
+\ingroup Media
+*/
class CTextArea
{
public:
CTextArea( SDL_Surface* a_poScreen, _sge_TTFont* a_poFont, int a_x, int a_y, int a_w, int a_h );
~CTextArea();
void TintBackground( int a_iColor, int a_iAlpha );
void AddString( const char* a_poText, int a_iColor );
void Redraw();
void Clear();
void ScrollUp();
void ScrollDown();
protected:
SDL_Surface* m_poScreen;
SDL_Surface* m_poBackground;
_sge_TTFont* m_poFont;
SDL_Rect m_oClipRect;
int x, y, w, h;
int m_iScrollOffset;
TStringList m_asRowTexts;
TIntList m_aiRowColors;
};
#endif // TEXTAREA_H
diff --git a/src/common.h b/src/common.h
index 2666da9..a0afc12 100644
--- a/src/common.h
+++ b/src/common.h
@@ -1,78 +1,78 @@
-/***************************************************************************
- common.h - description
- -------------------
- begin : Fri Aug 24 2001
- copyright : (C) 2001 by upi
- email : upi@apocalypse.rulez.org
- ***************************************************************************/
-
-#ifndef __COMMON_H
-#define __COMMON_H
-
-
+/***************************************************************************
+ common.h - description
+ -------------------
+ begin : Fri Aug 24 2001
+ copyright : (C) 2001 by upi
+ email : upi@apocalypse.rulez.org
+ ***************************************************************************/
+
+#ifndef __COMMON_H
+#define __COMMON_H
+
+
#ifndef _SDL_types_h
-#include "SDL_types.h"
-#endif
-
-#define MAXPLAYERS 4
-
-
-void debug( const char* format, ... );
-#ifndef ABS
-#define ABS(A) ( (A>=0) ? (A) : -(A) )
-#endif
-#ifndef MAX
-#define MAX(A,B) ( (A) > (B) ? (A) : (B) )
-#endif
-#ifndef MIN
-#define MIN(A,B) ( (A) < (B) ? (A) : (B) )
-#endif
-
-// -----------------------------------------------------------------------
-// Main program methods
-// -----------------------------------------------------------------------
-
-void DoMenu();
-void GameOver( int a_iPlayerWon );
-void DoDemos();
-int DoGame( char* replay, bool isReplay, bool bDebug );
-void DoOnlineChat();
-
-// -----------------------------------------------------------------------
-// Other subroutines
-// -----------------------------------------------------------------------
-
-bool Connect( const char* a_pcHostname );
-
-const char* Translate( const char* a_pcText );
-const char* TranslateUTF8( const char* a_pcText );
-
-// -----------------------------------------------------------------------
-// Global variables
-// -----------------------------------------------------------------------
-
-struct SDL_Surface;
-extern SDL_Surface* gamescreen;
-
-extern Uint32 C_BLACK;
-extern Uint32 C_BLUE;
-extern Uint32 C_GREEN;
-extern Uint32 C_CYAN;
-
-extern Uint32 C_RED;
-extern Uint32 C_MAGENTA;
-extern Uint32 C_ORANGE;
-extern Uint32 C_LIGHTGRAY;
-
-extern Uint32 C_DARKGRAY;
-extern Uint32 C_LIGHTBLUE;
-extern Uint32 C_LIGHTGREEN;
-extern Uint32 C_LIGHTCYAN;
-
-extern Uint32 C_LIGHTRED;
-extern Uint32 C_LIGHTMAGENTA;
-extern Uint32 C_YELLOW;
-extern Uint32 C_WHITE;
-
-
-#endif
+#include "SDL_types.h"
+#endif
+
+#define MAXPLAYERS 4
+
+
+void debug( const char* format, ... );
+#ifndef omABS
+#define omABS(A) ( (A>=0) ? (A) : -(A) )
+#endif
+#ifndef omMAX
+#define omMAX(A,B) ( (A) > (B) ? (A) : (B) )
+#endif
+#ifndef omMIN
+#define omMIN(A,B) ( (A) < (B) ? (A) : (B) )
+#endif
+
+// -----------------------------------------------------------------------
+// Main program methods
+// -----------------------------------------------------------------------
+
+void DoMenu();
+void GameOver( int a_iPlayerWon );
+void DoDemos();
+int DoGame( char* replay, bool isReplay, bool bDebug );
+void DoOnlineChat();
+
+// -----------------------------------------------------------------------
+// Other subroutines
+// -----------------------------------------------------------------------
+
+bool Connect( const char* a_pcHostname );
+
+const char* Translate( const char* a_pcText );
+const char* TranslateUTF8( const char* a_pcText );
+
+// -----------------------------------------------------------------------
+// Global variables
+// -----------------------------------------------------------------------
+
+struct SDL_Surface;
+extern SDL_Surface* gamescreen;
+
+extern Uint32 C_BLACK;
+extern Uint32 C_BLUE;
+extern Uint32 C_GREEN;
+extern Uint32 C_CYAN;
+
+extern Uint32 C_RED;
+extern Uint32 C_MAGENTA;
+extern Uint32 C_ORANGE;
+extern Uint32 C_LIGHTGRAY;
+
+extern Uint32 C_DARKGRAY;
+extern Uint32 C_LIGHTBLUE;
+extern Uint32 C_LIGHTGREEN;
+extern Uint32 C_LIGHTCYAN;
+
+extern Uint32 C_LIGHTRED;
+extern Uint32 C_LIGHTMAGENTA;
+extern Uint32 C_YELLOW;
+extern Uint32 C_WHITE;
+
+
+#endif
diff --git a/src/gfx.cpp b/src/gfx.cpp
index 2de9103..695db71 100644
--- a/src/gfx.cpp
+++ b/src/gfx.cpp
@@ -1,466 +1,466 @@
-/***************************************************************************
- gfx.cpp - description
- -------------------
- begin : Tue Apr 10 2001
- copyright : (C) 2001 by UPi
- email : upi@apocalypse.rulez.org
- ***************************************************************************/
-
-#include <string.h>
-
-#include "SDL.h"
-#include "SDL_video.h"
-#include "SDL_image.h"
-#include "sge_tt_text.h"
-#include "sge_surface.h"
-
-#ifndef __COMMON_H
-#include "common.h"
-#endif
-#ifndef _GFX_H
-#include "gfx.h"
-#endif
-#include "State.h"
-#include "Event.h"
-
-
-int CSurfaceLocker::m_giLockCount = 0;
-
-
-
-Uint16 *UTF8_to_UNICODE(Uint16 *unicode, const char *utf8, int len);
-
-
-void sge_TTF_SizeText( _sge_TTFont*font, const char* text, int* x, int* y )
-{
-#ifdef MSZ_USES_UTF8
- Uint16 *unicode_text;
- int unicode_len;
-
- /* Copy the UTF-8 text to a UNICODE text buffer */
- unicode_len = strlen(text);
- unicode_text = new Uint16[unicode_len+1]; // (Uint16 *)malloc( (unicode_len+1) * sizeof (Uint16) );
- if ( unicode_text == NULL )
- {
- SDL_SetError("SGE - Out of memory");
- *x = *y = 0;
- return;
- }
- UTF8_to_UNICODE(unicode_text, text, unicode_len);
-
- /* Render the new text */
- SDL_Rect r = sge_TTF_TextSizeUNI(font, unicode_text);
-
- /* Free the text buffer and return */
- delete[] unicode_text; //free(unicode_text);
-#else
- SDL_Rect r = sge_TTF_TextSize( font, text );
-#endif
- *x = r.w;
- *y = r.h;
-}
-
-int DrawTextMSZ( const char* string, _sge_TTFont* font, int x, int y, int flags,
- int fg, SDL_Surface* target, bool a_bTranslate )
-{
- int retval = 0;
-
- if (!string || !*string) return retval;
-
- if ( a_bTranslate )
- {
- string = Translate( string );
- }
-
- if (flags & UseTilde)
- {
- char *str2 = strdup( string );
- char onechar[2];
- char *c1, *c2;
- int w = 0;
- int i, j;
- bool notend;
-
- if (flags & AlignHCenter)
- {
- // Determine width of the string without the stupid tildes
- c1 = c2 = str2;
- notend = true;
-
-
- while (notend)
- {
- c2 = c1; // c1: start of this run
- while (*c2 && (*c2!='~')) c2++; // c2: end of this run
- notend = *c2 != 0;
- *c2 = 0;
-
- sge_TTF_SizeText( font, c1, &i, &j);
- w += i;
-
- if (notend) { *c2='~'; c1=c2+1; } // next run..
- }
-
- x -= w/2;
- }
-
- flags &= ~(UseTilde | AlignHCenter);
-
- c1 = str2;
- onechar[1]=0;
- notend = true;
-
- while (1)
- {
- c2 = c1;
- while (*c2 && (*c2!='~')) c2++; // c2: end of this run
- notend = *c2 != 0;
- *c2 = 0;
-
- sge_TTF_SizeText( font, c1, &i, &j);
- DrawTextMSZ( c1, font, x, y, flags, fg, target, false );
- x += i;
-
- // At this point, we're either at a ~ or end of the text (notend)
- if (!notend) break;
-
- onechar[0]= *++c2; // Could be 0, if ~ at end.
- if (!onechar[0]) break;
- sge_TTF_SizeText( font, onechar, &i, &j);
- DrawTextMSZ( onechar, font, x, y, flags, C_LIGHTCYAN, target, false );
- x += i;
- retval += i;
- c1 = c2+1;
-
-
- if (!*c1) break; // ~X was end of string
- }
-
- delete( str2 );
- return retval;
- }
-
- SDL_Rect dest;
- int w, h;
- sge_TTF_SizeText( font, string, &w, &h );
- dest.w = retval = w;
- dest.h = h;
- dest.x = flags & AlignHCenter ? x-dest.w/2 : x;
- dest.y = flags & AlignVCenter ? y-dest.h/2 : y;
-
- //debug( "X: %d, Y: %d, W: %d, H: %d\n", dest.x, dest.y, dest.w, dest.h );
-
- CSurfaceLocker oLock;
-
- if ( flags & UseShadow )
- {
-#ifdef MSZ_USES_UTF8
- sge_tt_textout_UTF8( target, font, string, dest.x+2, dest.y+2+sge_TTF_FontAscent(font), C_BLACK, C_BLACK, 255 );
-#else
- sge_tt_textout( target, font, string, dest.x+2, dest.y+2+sge_TTF_FontAscent(font), C_BLACK, C_BLACK, 255 );
-#endif
- }
-
- sge_TTF_AAOn();
-#ifdef MSZ_USES_UTF8
- dest = sge_tt_textout_UTF8( target, font, string, dest.x, dest.y+sge_TTF_FontAscent(font), fg, C_BLACK, 255 );
-#else
- dest = sge_tt_textout( target, font, string, dest.x, dest.y+sge_TTF_FontAscent(font), fg, C_BLACK, 255 );
-#endif
- sge_TTF_AAOff();
-
- return dest.w;
-}
-
-
-
-void DrawGradientText( const char* text, _sge_TTFont* font, int y, SDL_Surface* target, bool a_bTranslate )
-{
- int i;
-
- if ( a_bTranslate )
- {
- text = Translate( text );
- }
-
- // 1. CREATE OFFSCREEN SURFACE
-
- SDL_Rect size = sge_TTF_TextSize( font, (char*)text );
- size.w += 2;
- size.h += 2;
- size.x = 320 - size.w / 2;
- if ( size.x < 0 ) size.x = 0;
- size.y = y;
- SDL_Surface* surface = SDL_CreateRGBSurface( SDL_SRCCOLORKEY, size.w, size.h, 8, 0,0,0,0 );
-
-
- if ( NULL == surface )
- {
- debug( "DrawGradientText: Couldn't allocate %d by %d surface!\n", size.w, size.h );
- return;
- }
-
- // 2. SET OFFSCREEN SURFACE COLORS
-
- SDL_SetColorKey( surface, SDL_SRCCOLORKEY, 0 );
- SDL_Color colors[256];
- colors[0].r = colors[0].g = colors[0].b = 0;
- colors[1] = colors[0];
-
- // The rest is red->yellow gradient.
-
- for ( i=2; i<255; ++i )
- {
- int j = i > 25 ? i-25 : 0;
- colors[i].r = 255;
- colors[i].g = 255-j;
- colors[i].b = 0;
- }
-
- SDL_SetColors( surface, colors, 0, 256 );
-
- // 3. DRAW TEXT, APPLY BORDER, APPLY GRADIENT.
-
- int y1 = sge_TTF_FontAscent(font);
- sge_tt_textout( surface, font, text,
- 1, y1, 255, 0, 255);
-
-
- if ( SDL_MUSTLOCK(surface) ) SDL_LockSurface(surface);
- for ( y=1; y<size.h-1; ++y )
- {
- int color = 254 * y / (size.h-1) + 1;
- unsigned char *p0, *p1, *p2;
- p1 = (unsigned char*) surface->pixels;
- p1 += surface->pitch * y + 1;
- p0 = p1 - surface->pitch;
- p2 = p1 + surface->pitch;
-
- for ( int x=1; x<size.w-1; ++x, ++p0, ++p1, ++p2 )
- {
- if ( *p1 > 2 )
- {
- *p1 = color;
- }
- else
- {
- if ( (*(p1-1) > 2) || (*(p1+1) > 2) || *p0 > 2 || *p2 > 2 )
- {
- *p1 = 1;
- }
- }
- }
- }
- if ( SDL_MUSTLOCK(surface) ) SDL_UnlockSurface(surface);
-
- // 4. FINALLY
-
- SDL_BlitSurface( surface, NULL, target, &size );
- SDL_FreeSurface( surface );
- SDL_UpdateRect( target, size.x, size.y, size.w, size.h );
-}
-
-
-
-SDL_Color MakeColor( Uint8 r, Uint8 g, Uint8 b )
-{
- SDL_Color color;
- color.r = r; color.g = g; color.b = b; color.unused = 0;
- return color;
-}
-
-
-/**
-Waits for a key event and returns it.
-
-\param a_bTranslate If this is true, then keypad events will also be
-read and processed info keys (cursor, return and escape).
-*/
-
-SDLKey GetKey( bool a_bTranslate )
-{
- SDL_Event oSdlEvent;
- SMortalEvent oEvent;
-
- while (SDL_WaitEvent(&oSdlEvent))
- {
- if ( SDL_KEYDOWN == oSdlEvent.type )
- {
- return oSdlEvent.key.keysym.sym;
- }
- if ( SDL_QUIT == oSdlEvent.type )
-
- {
- g_oState.m_bQuitFlag = true;
- return SDLK_ESCAPE;
- }
-
- if ( ! a_bTranslate )
- {
- continue;
- }
-
- // Handle gamepad and others
- TranslateEvent( &oSdlEvent, &oEvent );
-
- switch (oEvent.m_enType)
- {
- case Me_QUIT:
- g_oState.m_bQuitFlag = true;
- return SDLK_ESCAPE;
-
- case Me_PLAYERKEYDOWN:
- switch ( oEvent.m_iKey ) {
- case Mk_UP: return SDLK_UP;
- case Mk_DOWN: return SDLK_DOWN;
- case Mk_LEFT: return SDLK_LEFT;
- case Mk_RIGHT: return SDLK_RIGHT;
- default: return SDLK_RETURN;
- }
- break;
-
- case Me_MENU:
- return SDLK_ESCAPE;
-
- default:
- break;
- } // switch statement
- } // Polling events
-
- // Code will never reach this point, unless there's an error.
- return SDLK_ESCAPE;
-}
-
-/**
-\TODO Remove a_iNumcolors, a_iPaletteOffset
-*/
-
-SDL_Surface* LoadBackground( const char* a_pcFilename, int a_iNumColors, int a_iPaletteOffset, bool a_bTransparent )
-{
- char acFilepath[FILENAME_MAX+1];
- strcpy( acFilepath, DATADIR );
- strcat( acFilepath, "/gfx/" );
- strcat( acFilepath, a_pcFilename );
-
- SDL_Surface* poBackground = IMG_Load( acFilepath );
- if (!poBackground)
- {
- debug( "Can't load file: %s\n", acFilepath );
- return NULL;
- }
-
- SDL_Palette* pal = poBackground->format->palette;
- if ( pal && gamescreen->format->palette )
- {
- int ncolors = pal->ncolors;
- if (ncolors>a_iNumColors) ncolors = a_iNumColors;
- if (ncolors+a_iPaletteOffset > 255) ncolors = 255 - a_iPaletteOffset;
- SDL_SetColors( gamescreen, pal->colors, a_iPaletteOffset, ncolors );
- }
-
- SDL_Surface* poRetval = SDL_DisplayFormat( poBackground );
- SDL_FreeSurface( poBackground );
-
- // 2. TRY TO LOAD AN IMAGE MASK
- // This means trying to load a .png file which acts as a mask for the
- // original [jpg] image.
- // If the original file is <Basename>.jpg, the mask is <Basename>.mask.png
-
- int iLength = strlen( acFilepath );
- char acMaskFilename[FILENAME_MAX+1];
- strncpy( acMaskFilename, acFilepath, iLength-4 );
- acMaskFilename[iLength-4] = 0;
- strcat( acMaskFilename, ".mask.png" );
-
- SDL_Surface* poMask = IMG_Load( acMaskFilename );
- if ( !poMask )
- {
- // No mask.
- return poRetval;
- }
-
- if ( poMask->w < poRetval->w
- || poMask->h < poRetval->h )
- {
- debug( "Error loading mask for %s: mask is too small.\n", acFilepath );
- SDL_FreeSurface( poMask );
- return poRetval;
- }
-
- debug( "Loading mask for %s.\n", acFilepath );
-
- Uint32 iTransparent = SDL_MapRGB( gamescreen->format, 255, 217, 0 ); // an unlikely color in openmortal..
- Uint32 iMask = sge_GetPixel( poMask, 0, 0 );
- Uint32 iPixel;
-
- for ( int y = 0; y < poRetval->h; ++y ) {
- for ( int x=0; x< poRetval->w; ++x ) {
- iPixel = sge_GetPixel( poMask, x, y );
-// debug( "%d ", iPixel );
- if ( iPixel == iMask ) {
- sge_PutPixel( poRetval, x, y, iTransparent );
- }
- }
-// debug( "\n" );
- }
-
- SDL_FreeSurface( poMask );
-
- SDL_SetColorKey( poRetval, SDL_SRCCOLORKEY, iTransparent );
-
- return poRetval;
-}
-
-
-SDL_Surface *LoadImage( const char* a_pcFilename )
-{
- return LoadBackground(a_pcFilename, 0, 0);
-}
-
-
-bool SetVideoMode( bool a_bLarge, bool a_bFullScreen, int a_iAdditionalFlags )
-{
- // SET THE PARAMETERS FOR THE VIDEO MODE
-
- int iBpp = 16; // Try the display's BPP first.
- if ( NULL != gamescreen )
- {
- iBpp = gamescreen->format->BitsPerPixel;
- }
-
- int iFlags = a_iAdditionalFlags;
- if ( a_bFullScreen )
- {
- iFlags |= SDL_FULLSCREEN;
- }
-
- // CALL SDL_SetVideoMode
-
- int iWidth = a_bLarge ? 800 : 640;
- int iHeight = a_bLarge ? 600 : 480;
-// if ( !a_bFullScreen ) iHeight = 480;
-
- gamescreen = SDL_SetVideoMode( iWidth, iHeight, iBpp, iFlags );
- if ( NULL == gamescreen )
- {
- debug( "SDL_SetVideoMode( %d, %d, %d, %d ) failed.\n", iWidth, iHeight, iBpp, iFlags );
- return false;
- }
-
- // IF THE DISPLAY IS 24BPP OR 8 BPP OR LESS, EMULATE 16 BPP INSTEAD
- // (because we are lazy and won't write 8bpp and 24bpp code anymore)
-
- if ( gamescreen->format->BytesPerPixel != 2
- && gamescreen->format->BytesPerPixel != 4 )
- {
- gamescreen = SDL_SetVideoMode( iWidth, iHeight, 16, iFlags );
- if ( NULL == gamescreen )
- {
- debug( "SDL_SetVideoMode( %d, %d, %d, %d ) failed.\n", iWidth, iHeight, 16, iFlags );
- return false;
- }
- }
-
- return true;
-}
-
+/***************************************************************************
+ gfx.cpp - description
+ -------------------
+ begin : Tue Apr 10 2001
+ copyright : (C) 2001 by UPi
+ email : upi@apocalypse.rulez.org
+ ***************************************************************************/
+
+#include <string.h>
+
+#include "SDL.h"
+#include "SDL_video.h"
+#include "SDL_image.h"
+#include "sge_tt_text.h"
+#include "sge_surface.h"
+
+#ifndef __COMMON_H
+#include "common.h"
+#endif
+#ifndef _GFX_H
+#include "gfx.h"
+#endif
+#include "State.h"
+#include "Event.h"
+
+
+int CSurfaceLocker::m_giLockCount = 0;
+
+
+
+Uint16 *UTF8_to_UNICODE(Uint16 *unicode, const char *utf8, int len);
+
+
+void sge_TTF_SizeText( _sge_TTFont*font, const char* text, int* x, int* y )
+{
+#ifdef MSZ_USES_UTF8
+ Uint16 *unicode_text;
+ int unicode_len;
+
+ /* Copy the UTF-8 text to a UNICODE text buffer */
+ unicode_len = strlen(text);
+ unicode_text = new Uint16[unicode_len+1]; // (Uint16 *)malloc( (unicode_len+1) * sizeof (Uint16) );
+ if ( unicode_text == NULL )
+ {
+ SDL_SetError("SGE - Out of memory");
+ *x = *y = 0;
+ return;
+ }
+ UTF8_to_UNICODE(unicode_text, text, unicode_len);
+
+ /* Render the new text */
+ SDL_Rect r = sge_TTF_TextSizeUNI(font, unicode_text);
+
+ /* Free the text buffer and return */
+ delete[] unicode_text; //free(unicode_text);
+#else
+ SDL_Rect r = sge_TTF_TextSize( font, text );
+#endif
+ *x = r.w;
+ *y = r.h;
+}
+
+int DrawTextMSZ( const char* string, _sge_TTFont* font, int x, int y, int flags,
+ int fg, SDL_Surface* target, bool a_bTranslate )
+{
+ int retval = 0;
+
+ if (!string || !*string) return retval;
+
+ if ( a_bTranslate )
+ {
+ string = Translate( string );
+ }
+
+ if (flags & UseTilde)
+ {
+ char *str2 = strdup( string );
+ char onechar[2];
+ char *c1, *c2;
+ int w = 0;
+ int i, j;
+ bool notend;
+
+ if (flags & AlignHCenter)
+ {
+ // Determine width of the string without the stupid tildes
+ c1 = c2 = str2;
+ notend = true;
+
+
+ while (notend)
+ {
+ c2 = c1; // c1: start of this run
+ while (*c2 && (*c2!='~')) c2++; // c2: end of this run
+ notend = *c2 != 0;
+ *c2 = 0;
+
+ sge_TTF_SizeText( font, c1, &i, &j);
+ w += i;
+
+ if (notend) { *c2='~'; c1=c2+1; } // next run..
+ }
+
+ x -= w/2;
+ }
+
+ flags &= ~(UseTilde | AlignHCenter);
+
+ c1 = str2;
+ onechar[1]=0;
+ notend = true;
+
+ while (1)
+ {
+ c2 = c1;
+ while (*c2 && (*c2!='~')) c2++; // c2: end of this run
+ notend = *c2 != 0;
+ *c2 = 0;
+
+ sge_TTF_SizeText( font, c1, &i, &j);
+ DrawTextMSZ( c1, font, x, y, flags, fg, target, false );
+ x += i;
+
+ // At this point, we're either at a ~ or end of the text (notend)
+ if (!notend) break;
+
+ onechar[0]= *++c2; // Could be 0, if ~ at end.
+ if (!onechar[0]) break;
+ sge_TTF_SizeText( font, onechar, &i, &j);
+ DrawTextMSZ( onechar, font, x, y, flags, C_LIGHTCYAN, target, false );
+ x += i;
+ retval += i;
+ c1 = c2+1;
+
+
+ if (!*c1) break; // ~X was end of string
+ }
+
+ delete( str2 );
+ return retval;
+ }
+
+ SDL_Rect dest;
+ int w, h;
+ sge_TTF_SizeText( font, string, &w, &h );
+ dest.w = retval = w;
+ dest.h = h;
+ dest.x = flags & AlignHCenter ? x-dest.w/2 : x;
+ dest.y = flags & AlignVCenter ? y-dest.h/2 : y;
+
+ //debug( "X: %d, Y: %d, W: %d, H: %d\n", dest.x, dest.y, dest.w, dest.h );
+
+ CSurfaceLocker oLock;
+
+ if ( flags & UseShadow )
+ {
+#ifdef MSZ_USES_UTF8
+ sge_tt_textout_UTF8( target, font, string, dest.x+2, dest.y+2+sge_TTF_FontAscent(font), C_BLACK, C_BLACK, 255 );
+#else
+ sge_tt_textout( target, font, string, dest.x+2, dest.y+2+sge_TTF_FontAscent(font), C_BLACK, C_BLACK, 255 );
+#endif
+ }
+
+ sge_TTF_AAOn();
+#ifdef MSZ_USES_UTF8
+ dest = sge_tt_textout_UTF8( target, font, string, dest.x, dest.y+sge_TTF_FontAscent(font), fg, C_BLACK, 255 );
+#else
+ dest = sge_tt_textout( target, font, string, dest.x, dest.y+sge_TTF_FontAscent(font), fg, C_BLACK, 255 );
+#endif
+ sge_TTF_AAOff();
+
+ return dest.w;
+}
+
+
+
+void DrawGradientText( const char* text, _sge_TTFont* font, int y, SDL_Surface* target, bool a_bTranslate )
+{
+ int i;
+
+ if ( a_bTranslate )
+ {
+ text = Translate( text );
+ }
+
+ // 1. CREATE OFFSCREEN SURFACE
+
+ SDL_Rect size = sge_TTF_TextSize( font, (char*)text );
+ size.w += 2;
+ size.h += 2;
+ size.x = 320 - size.w / 2;
+ if ( size.x < 0 ) size.x = 0;
+ size.y = y;
+ SDL_Surface* surface = SDL_CreateRGBSurface( SDL_SRCCOLORKEY, size.w, size.h, 8, 0,0,0,0 );
+
+
+ if ( NULL == surface )
+ {
+ debug( "DrawGradientText: Couldn't allocate %d by %d surface!\n", size.w, size.h );
+ return;
+ }
+
+ // 2. SET OFFSCREEN SURFACE COLORS
+
+ SDL_SetColorKey( surface, SDL_SRCCOLORKEY, 0 );
+ SDL_Color colors[256];
+ colors[0].r = colors[0].g = colors[0].b = 0;
+ colors[1] = colors[0];
+
+ // The rest is red->yellow gradient.
+
+ for ( i=2; i<255; ++i )
+ {
+ int j = i > 25 ? i-25 : 0;
+ colors[i].r = 255;
+ colors[i].g = 255-j;
+ colors[i].b = 0;
+ }
+
+ SDL_SetColors( surface, colors, 0, 256 );
+
+ // 3. DRAW TEXT, APPLY BORDER, APPLY GRADIENT.
+
+ int y1 = sge_TTF_FontAscent(font);
+ sge_tt_textout( surface, font, text,
+ 1, y1, 255, 0, 255);
+
+
+ if ( SDL_MUSTLOCK(surface) ) SDL_LockSurface(surface);
+ for ( y=1; y<size.h-1; ++y )
+ {
+ int color = 254 * y / (size.h-1) + 1;
+ unsigned char *p0, *p1, *p2;
+ p1 = (unsigned char*) surface->pixels;
+ p1 += surface->pitch * y + 1;
+ p0 = p1 - surface->pitch;
+ p2 = p1 + surface->pitch;
+
+ for ( int x=1; x<size.w-1; ++x, ++p0, ++p1, ++p2 )
+ {
+ if ( *p1 > 2 )
+ {
+ *p1 = color;
+ }
+ else
+ {
+ if ( (*(p1-1) > 2) || (*(p1+1) > 2) || *p0 > 2 || *p2 > 2 )
+ {
+ *p1 = 1;
+ }
+ }
+ }
+ }
+ if ( SDL_MUSTLOCK(surface) ) SDL_UnlockSurface(surface);
+
+ // 4. FINALLY
+
+ SDL_BlitSurface( surface, NULL, target, &size );
+ SDL_FreeSurface( surface );
+ SDL_UpdateRect( target, size.x, size.y, size.w, size.h );
+}
+
+
+
+SDL_Color MakeColor( Uint8 r, Uint8 g, Uint8 b )
+{
+ SDL_Color color;
+ color.r = r; color.g = g; color.b = b; color.unused = 0;
+ return color;
+}
+
+
+/**
+Waits for a key event and returns it.
+
+\param a_bTranslate If this is true, then keypad events will also be
+read and processed info keys (cursor, return and escape).
+*/
+
+SDLKey GetKey( bool a_bTranslate )
+{
+ SDL_Event oSdlEvent;
+ SMortalEvent oEvent;
+
+ while (SDL_WaitEvent(&oSdlEvent))
+ {
+ if ( SDL_KEYDOWN == oSdlEvent.type )
+ {
+ return oSdlEvent.key.keysym.sym;
+ }
+ if ( SDL_QUIT == oSdlEvent.type )
+
+ {
+ g_oState.m_bQuitFlag = true;
+ return SDLK_ESCAPE;
+ }
+
+ if ( ! a_bTranslate )
+ {
+ continue;
+ }
+
+ // Handle gamepad and others
+ TranslateEvent( &oSdlEvent, &oEvent );
+
+ switch (oEvent.m_enType)
+ {
+ case Me_QUIT:
+ g_oState.m_bQuitFlag = true;
+ return SDLK_ESCAPE;
+
+ case Me_PLAYERKEYDOWN:
+ switch ( oEvent.m_iKey ) {
+ case Mk_UP: return SDLK_UP;
+ case Mk_DOWN: return SDLK_DOWN;
+ case Mk_LEFT: return SDLK_LEFT;
+ case Mk_RIGHT: return SDLK_RIGHT;
+ default: return SDLK_RETURN;
+ }
+ break;
+
+ case Me_MENU:
+ return SDLK_ESCAPE;
+
+ default:
+ break;
+ } // switch statement
+ } // Polling events
+
+ // Code will never reach this point, unless there's an error.
+ return SDLK_ESCAPE;
+}
+
+/**
+\TODO Remove a_iNumcolors, a_iPaletteOffset
+*/
+
+SDL_Surface* LoadBackground( const char* a_pcFilename, int a_iNumColors, int a_iPaletteOffset, bool a_bTransparent )
+{
+ char acFilepath[FILENAME_MAX+1];
+ strcpy( acFilepath, DATADIR );
+ strcat( acFilepath, "/gfx/" );
+ strcat( acFilepath, a_pcFilename );
+
+ SDL_Surface* poBackground = IMG_Load( acFilepath );
+ if (!poBackground)
+ {
+ debug( "Can't load file: %s\n", acFilepath );
+ return NULL;
+ }
+
+ SDL_Palette* pal = poBackground->format->palette;
+ if ( pal && gamescreen->format->palette )
+ {
+ int ncolors = pal->ncolors;
+ if (ncolors>a_iNumColors) ncolors = a_iNumColors;
+ if (ncolors+a_iPaletteOffset > 255) ncolors = 255 - a_iPaletteOffset;
+ SDL_SetColors( gamescreen, pal->colors, a_iPaletteOffset, ncolors );
+ }
+
+ SDL_Surface* poRetval = SDL_DisplayFormat( poBackground );
+ SDL_FreeSurface( poBackground );
+
+ // 2. TRY TO LOAD AN IMAGE MASK
+ // This means trying to load a .png file which acts as a mask for the
+ // original [jpg] image.
+ // If the original file is <Basename>.jpg, the mask is <Basename>.mask.png
+
+ int iLength = strlen( acFilepath );
+ char acMaskFilename[FILENAME_MAX+1];
+ strncpy( acMaskFilename, acFilepath, iLength-4 );
+ acMaskFilename[iLength-4] = 0;
+ strcat( acMaskFilename, ".mask.png" );
+
+ SDL_Surface* poMask = IMG_Load( acMaskFilename );
+ if ( !poMask )
+ {
+ // No mask.
+ return poRetval;
+ }
+
+ if ( poMask->w < poRetval->w
+ || poMask->h < poRetval->h )
+ {
+ debug( "Error loading mask for %s: mask is too small.\n", acFilepath );
+ SDL_FreeSurface( poMask );
+ return poRetval;
+ }
+
+ debug( "Loading mask for %s.\n", acFilepath );
+
+ Uint32 iTransparent = SDL_MapRGB( gamescreen->format, 255, 217, 0 ); // an unlikely color in openmortal..
+ Uint32 iMask = sge_GetPixel( poMask, 0, 0 );
+ Uint32 iPixel;
+
+ for ( int y = 0; y < poRetval->h; ++y ) {
+ for ( int x=0; x< poRetval->w; ++x ) {
+ iPixel = sge_GetPixel( poMask, x, y );
+// debug( "%d ", iPixel );
+ if ( iPixel == iMask ) {
+ sge_PutPixel( poRetval, x, y, iTransparent );
+ }
+ }
+// debug( "\n" );
+ }
+
+ SDL_FreeSurface( poMask );
+
+ SDL_SetColorKey( poRetval, SDL_SRCCOLORKEY, iTransparent );
+
+ return poRetval;
+}
+
+
+SDL_Surface *LoadImage( const char* a_pcFilename )
+{
+ return LoadBackground(a_pcFilename, 0, 0);
+}
+
+
+bool SetVideoMode( bool a_bLarge, bool a_bFullScreen, int a_iAdditionalFlags )
+{
+ // SET THE PARAMETERS FOR THE VIDEO MODE
+
+ int iBpp = 16; // Try the display's BPP first.
+ if ( NULL != gamescreen )
+ {
+ iBpp = gamescreen->format->BitsPerPixel;
+ }
+
+ int iFlags = a_iAdditionalFlags;
+ if ( a_bFullScreen )
+ {
+ iFlags |= SDL_FULLSCREEN;
+ }
+
+ // CALL SDL_SetVideoMode
+
+ int iWidth = a_bLarge ? 800 : 640;
+ int iHeight = a_bLarge ? 600 : 480;
+// if ( !a_bFullScreen ) iHeight = 480;
+
+ gamescreen = SDL_SetVideoMode( iWidth, iHeight, iBpp, iFlags );
+ if ( NULL == gamescreen )
+ {
+ debug( "SDL_SetVideoMode( %d, %d, %d, %d ) failed.\n", iWidth, iHeight, iBpp, iFlags );
+ return false;
+ }
+
+ // IF THE DISPLAY IS 24BPP OR 8 BPP OR LESS, EMULATE 16 BPP INSTEAD
+ // (because we are lazy and won't write 8bpp and 24bpp code anymore)
+
+ if ( gamescreen->format->BytesPerPixel != 2
+ && gamescreen->format->BytesPerPixel != 4 )
+ {
+ gamescreen = SDL_SetVideoMode( iWidth, iHeight, 16, iFlags );
+ if ( NULL == gamescreen )
+ {
+ debug( "SDL_SetVideoMode( %d, %d, %d, %d ) failed.\n", iWidth, iHeight, 16, iFlags );
+ return false;
+ }
+ }
+
+ return true;
+}
+
diff --git a/src/gfx.h b/src/gfx.h
index 733fcab..d02d925 100644
--- a/src/gfx.h
+++ b/src/gfx.h
@@ -1,95 +1,95 @@
-/***************************************************************************
- gfx.h - description
- -------------------
- begin : Tue Apr 10 2001
- copyright : (C) 2001 by UPi
- email : upi@apocalypse.rulez.org
- ***************************************************************************/
-
-
-#ifndef _GFX_H
-#define _GFX_H
-
-/**
-\defgroup Media Sound and graphics
-Classes that deal with sound, graphics, input, etc.
-*/
-
-
-struct _sge_TTFont;
-
-#include "SDL.h"
-
-enum GFX_Constants {
- AlignHCenter = 1,
- AlignVCenter = 2,
- AlignCenter = 3,
- UseTilde = 4,
- UseShadow = 8,
-};
-
-int DrawTextMSZ( const char* text, _sge_TTFont* font, int x, int y,
- int flags, int fg, SDL_Surface* target, bool a_bTranslate = true );
-
-void DrawGradientText( const char* text, _sge_TTFont* font, int y,
- SDL_Surface* target, bool a_bTranslate = true );
-
-SDL_Color MakeColor( Uint8 r, Uint8 g, Uint8 b );
-
-SDLKey GetKey( bool a_bTranslate );
-
-SDL_Surface* LoadBackground( const char* a_pcFilename, int a_iNumColors, int a_iPaletteOffset=0, bool a_bTransparent = false );
-SDL_Surface* LoadImage( const char* a_pcFilename );
-
-bool SetVideoMode( bool a_bLarge, bool a_bFullscreen, int a_iAdditionalFlags=0 );
-
-extern SDL_Surface* gamescreen;
-
-/**
-\ingroup Media
-*/
-class CSurfaceLocker
-{
-public:
- inline CSurfaceLocker()
- {
- if ( 0 == m_giLockCount )
- {
- if (SDL_MUSTLOCK(gamescreen)) {
- SDL_LockSurface( gamescreen );
- }
- }
- ++m_giLockCount;
- }
- inline ~CSurfaceLocker()
- {
- --m_giLockCount;
- if ( 0 == m_giLockCount )
- {
- if (SDL_MUSTLOCK(gamescreen)) {
- SDL_UnlockSurface( gamescreen );
- }
- }
- }
-
-protected:
- static int m_giLockCount;
-};
-
-extern _sge_TTFont* titleFont; // Largest font, for titles
-extern _sge_TTFont* inkFont; // Medium-size front, headings
-extern _sge_TTFont* impactFont; // Smallest font, for long descriptions
-extern _sge_TTFont* chatFont; // small but legible.
-
-#ifdef sge_bm_text_H
-extern sge_bmpFont* fastFont; // In-game text, e.g. combo text
-extern sge_bmpFont* creditsFont;
-extern sge_bmpFont* storyFont;
-#endif
-
-
-
-
-
-
-#endif
+/***************************************************************************
+ gfx.h - description
+ -------------------
+ begin : Tue Apr 10 2001
+ copyright : (C) 2001 by UPi
+ email : upi@apocalypse.rulez.org
+ ***************************************************************************/
+
+
+#ifndef _GFX_H
+#define _GFX_H
+
+/**
+\defgroup Media Sound and graphics
+Classes that deal with sound, graphics, input, etc.
+*/
+
+
+struct _sge_TTFont;
+
+#include "SDL.h"
+
+enum GFX_Constants {
+ AlignHCenter = 1,
+ AlignVCenter = 2,
+ AlignCenter = 3,
+ UseTilde = 4,
+ UseShadow = 8,
+};
+
+int DrawTextMSZ( const char* text, _sge_TTFont* font, int x, int y,
+ int flags, int fg, SDL_Surface* target, bool a_bTranslate = true );
+
+void DrawGradientText( const char* text, _sge_TTFont* font, int y,
+ SDL_Surface* target, bool a_bTranslate = true );
+
+SDL_Color MakeColor( Uint8 r, Uint8 g, Uint8 b );
+
+SDLKey GetKey( bool a_bTranslate );
+
+SDL_Surface* LoadBackground( const char* a_pcFilename, int a_iNumColors, int a_iPaletteOffset=0, bool a_bTransparent = false );
+SDL_Surface* LoadImage( const char* a_pcFilename );
+
+bool SetVideoMode( bool a_bLarge, bool a_bFullscreen, int a_iAdditionalFlags=0 );
+
+extern SDL_Surface* gamescreen;
+
+/**
+\ingroup Media
+*/
+class CSurfaceLocker
+{
+public:
+ inline CSurfaceLocker()
+ {
+ if ( 0 == m_giLockCount )
+ {
+ if (SDL_MUSTLOCK(gamescreen)) {
+ SDL_LockSurface( gamescreen );
+ }
+ }
+ ++m_giLockCount;
+ }
+ inline ~CSurfaceLocker()
+ {
+ --m_giLockCount;
+ if ( 0 == m_giLockCount )
+ {
+ if (SDL_MUSTLOCK(gamescreen)) {
+ SDL_UnlockSurface( gamescreen );
+ }
+ }
+ }
+
+protected:
+ static int m_giLockCount;
+};
+
+extern _sge_TTFont* titleFont; // Largest font, for titles
+extern _sge_TTFont* inkFont; // Medium-size front, headings
+extern _sge_TTFont* impactFont; // Smallest font, for long descriptions
+extern _sge_TTFont* chatFont; // small but legible.
+
+#ifdef sge_bm_text_H
+extern sge_bmpFont* fastFont; // In-game text, e.g. combo text
+extern sge_bmpFont* creditsFont;
+extern sge_bmpFont* storyFont;
+#endif
+
+
+
+
+
+
+#endif
diff --git a/src/main.cpp b/src/main.cpp
index 38c0c24..d1946c8 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,759 +1,672 @@
-/***************************************************************************
- main.cpp - description
- -------------------
- begin : Wed Aug 22 10:18:47 CEST 2001
- copyright : (C) 2001 by upi
- email : upi@apocalypse.rulez.org
- ***************************************************************************/
-
-
-/**
-\mainpage
-
-The document you read now describes the design of OpenMortal. This page
-serves as a starting point. The documentation is generated with doxygen
-(http://doxygen.org).
-
-OpenMortal consists of two main parts: the \b frontend and the \b backend.
-
-\li The frontend is a C++ program, responsible for multimedia
-(sounds, music, graphics) and general interaction with the players
-(menus, keyboard input), and the demo and intro screens.
-
-\li The backend is written in Perl, and is incorporated into the C++
-program with Perl embedding.
-
-
-
-\section s1 1. Modules
-
-The classes of OpenMortal are organized into the following groups (see Modules above).
-
-\li \ref Media - OpenMortal uses \b SDL (http://libsdl.org) for hardware
-access such as screen drawing, music, sound effect and keyboard input. For
-information and documentation of SDL, SDL_image, SDL_ttf and SDL_mixer,
-please look at the SDL homepage.
-\li \ref PlayerSelect
-\li \ref Network
-\li \ref Demo
-\li \ref GameLogic
-
-
-
-\section s2 2. Main Functions
-These global functions implement important parts of the program. They serve
-as entry points into functional parts.
-
-\li DoMenu() - Displays and runs the menu over the current screen
-\li GameOver() - Displays the "Final Judgeent" screen
-\li DoDemos() - Runs the demos in an endless loop until a game is started or the program ends.
-\li DoGame() - Runs the game.
-\li DoOnlineChat() - Connects to and runs the MortalNet.
-\li CPlayerSelect::DoPlayerSelect() - Runs the player selection screen.
-
-
-\section s3 3. Definitions
-
-Here are the definitions of terms used in this documentation.
-
-<dl>
-
-<dt>\b Player <dd>
- Player refers to one of the two persons playing the game. A player chooses a fighter. The two players are referred to as "Player 1" and "Player 2", even though the C++ and perl code count arrays from 0.
-<dt>\b Fighter <dd>
- Fighter is one of the many available characters. Usually there are only two fighters loaded at any time. Fighters are static: their properties never change. Maybe Fighter should be renamed to Character?
-<dt>\b Game <dd>
- One game is the part of the program in which the players actually compete. The game consists of a number of rounds. The player selection, and gameover screen are not part of this definition.
-<dt>\b Round <dd>
- One round starts with both players at full health, and ends either with a timeout or with a ko.
-<dt>\b Doodad <dd>
- A graphical element on the game screen that is not the background or the characters. E.g. the "3x combo" text or a thrown projectile are doodads.
-<dt>\b Tint <dd>
- A tint is a methodical change in a palette. There are many ways to tint (e.g. grayscaling, darkening, green chroma, etc). Usually when two players choose the same fighter, the fighter of player 2 is tinted.
-<dt>\b Scene <dd>
- The description of a frozen moment in the course of a game. The Backend is responsible for calculating each consecutive scene. The number of scenes calculated per second is constant (except for the "hurry up mode", or if the computer is too slow).
-<dt>\b FPS <dd>
- Frames Per Second. The FPS indicator on the screen during a game indicates the number of scenes drawn, not the number of scenes calculated by the backend.
-</dl>
-
-
-\section s4 4. C++ Coding conventions
-
-Historically two different coding conventions were mixed in OpenMortal.
-Hopefully most of the old conventions are eliminated by now.
-Here I will describe the new conventions:
-
-\li <B> Class names: </B> CMixedCaps.
-\li <B> Struct names: </B> SMixedCaps.
-\li <B> Typedef names: </B> CSomeTypedef (There's some traces of the old TSomeTypedef
- left, these should be eliminated.
-\li <B> Enum names: </B> SomeThingEnum.
-\li <B> Enum values: </B> Prefix_ENUM_VALUE
-\li <B> Method names: </B> MixedCaps.
-\li <B> Variable names: </B> &lt;prefix&gt;VariableName.
-\li <B> Instance property names: </B> m_&lt;prefix&gt;VariableName,
-\li <B> Class property names </B>(a.k.a. static class variables): mg_&lt;prefix&gt;VariableName.
-\li <B> Method argument names: </B> a_&lt;prefix&gt;VariableName.
-If a reference or pointer argument is "output-only: a_&lt;prefix&gt;OutVariableName.
-\li <B> Global variable names: </B> g_&lt;prefix&gt;VariableName.
-
-The prefixes used are:
-
-\li <B> Array of something: </B> a&lt;something&gt;
-\li <B> Pointer to something: </B> p&lt;something&gt;
-\li <B> Reference of something: </B> r&lt;something&gt;
-\li <B> Basic types: </B> Integer: i; char: c; double: d; enum: en; object (class or struct): o; std::string: s;
-
-Example:
-\code
-CSomeExampleClass: public CSomeBaseClass
-{
-public:
- CSomeExampleClass();
- void SomeMethod( int& a_riOutSomething );
-protected:
- int m_iSomething;
- char* m_pcSomethingElse;
- static enum SomeThingEnum
- {
- Ste_VALUE,
- } mg_enWhatever;
-};
-\endcode
-*/
-
-
-#include "config.h"
-
-#include "PlayerSelect.h"
-
-#include "SDL_video.h"
-#include "sge_tt_text.h"
-#include "sge_bm_text.h"
-#include "sge_surface.h"
-#include "SDL.h"
-#include "SDL_image.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <string>
-
-#include "common.h"
-#include "gfx.h"
-#include "Audio.h"
-#include "RlePack.h"
-#include "Backend.h"
-#include "State.h"
-#include "FighterStats.h"
-#include "MortalNetwork.h"
-
-
-#ifdef _WINDOWS
-
-#undef DATADIR // GRRR.. windows keyword...
-#include <windows.h>
-#define DATADIR "../data"
-
-#endif
-
-_sge_TTFont* inkFont;
-_sge_TTFont* impactFont;
-_sge_TTFont* titleFont;
-_sge_TTFont* chatFont;
-sge_bmpFont* fastFont;
-sge_bmpFont* creditsFont;
-sge_bmpFont* storyFont;
-bool bDebug = false;
-
-Uint32 C_BLACK, C_BLUE, C_GREEN, C_CYAN, C_RED, C_MAGENTA, C_ORANGE, C_LIGHTGRAY,
- C_DARKGRAY, C_LIGHTBLUE, C_LIGHTGREEN, C_LIGHTCYAN, C_LIGHTRED, C_LIGHTMAGENTA, C_YELLOW, C_WHITE;
-
-SDL_Color Colors[] =
-{
- { 0, 0, 0, 0 }, { 0, 0, 42, 0 }, { 0, 42, 0, 0 }, { 0, 42, 42, 0 },
- { 42, 0, 0, 0 }, { 42, 0, 42, 0 }, { 63, 42, 0, 0 }, { 42, 42, 42, 0 },
- { 21, 21, 21, 0 }, { 21, 21, 63, 0 }, { 21, 63, 21, 0 }, { 21, 63, 63, 0 },
- { 63, 21, 21, 0 }, { 63, 21, 63, 0 }, { 63, 63, 21, 0 }, { 63, 63, 63, 0 }
-};
-
-
-void Complain( const char* a_pcError )
-{
-#ifdef _WINDOWS
- ::MessageBoxA( 0, a_pcError, "OpenMortal", MB_ICONEXCLAMATION );
-#else
- fprintf( stderr, "%s", a_pcError );
-#endif
-}
-
-
-_sge_TTFont* LoadTTF( const char* a_pcFilename, int a_iSize )
-{
- std::string sPath = std::string(DATADIR) + "/fonts/" + a_pcFilename;
- _sge_TTFont* poFont = sge_TTF_OpenFont( sPath.c_str(), a_iSize );
-
- if ( NULL == poFont )
- {
- Complain( ("Couldn't load font: " + sPath).c_str() );
- }
-
- return poFont;
-}
-
-
-sge_bmpFont* LoadBMPFont( const char* a_pcFilename )
-{
- std::string sPath = std::string(DATADIR) + "/fonts/" + a_pcFilename;
- sge_bmpFont* poFont = sge_BF_OpenFont( sPath.c_str(), SGE_BFSFONT | SGE_BFTRANSP );
- if ( NULL == poFont )
- {
- Complain( ("Couldn't load font: " + sPath).c_str() );
- }
- return poFont;
-}
-
-
-int init()
-{
- if (SDL_Init(SDL_INIT_VIDEO /*| SDL_INIT_AUDIO*/) < 0)
- {
- fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError());
- return -1;
- }
- atexit(SDL_Quit);
-
- SetVideoMode( false, g_oState.m_bFullscreen );
- if (gamescreen == NULL)
- {
- fprintf(stderr, "failed to set video mode: %s\n", SDL_GetError());
- return -1;
- }
-
- SDL_WM_SetCaption( "OpenMortal", "OpenMortal" );
- std::string sPath = std::string(DATADIR) + "/gfx/icon.png";
- SDL_WM_SetIcon(IMG_Load(sPath.c_str()), NULL);
- SDL_ShowCursor( SDL_DISABLE );
-
- int i;
- for ( i=0; i<16; ++i )
- {
- Colors[i].r *=4; Colors[i].g *=4; Colors[i].b *=4;
- }
- if ( gamescreen->format->BitsPerPixel > 8 )
- {
- i = 0;
- C_BLACK = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
- C_BLUE = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
- C_GREEN = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
- C_CYAN = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
-
- C_RED = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
- C_MAGENTA = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
- C_ORANGE = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
- C_LIGHTGRAY = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
-
- C_DARKGRAY = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
- C_LIGHTBLUE = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
- C_LIGHTGREEN = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
- C_LIGHTCYAN = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
-
- C_LIGHTRED = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
- C_LIGHTMAGENTA = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
- C_YELLOW = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
- C_WHITE = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
- }
- else
- {
- SDL_SetColors( gamescreen, Colors, 256-16, 16 );
- C_BLACK = 240;
- C_BLUE = 241;
- C_GREEN = 242;
- C_CYAN = 243;
-
- C_RED = 244;
- C_MAGENTA = 245;
- C_ORANGE = 246;
- C_LIGHTGRAY = 247;
-
- C_DARKGRAY = 248;
- C_LIGHTBLUE = 249;
- C_LIGHTGREEN = 250;
- C_LIGHTCYAN = 251;
-
- C_LIGHTRED = 252;
- C_LIGHTMAGENTA = 253;
- C_YELLOW = 254;
- C_WHITE = 255;
- }
-
- if ( sge_TTF_Init() )
- {
- fprintf(stderr, "couldn't start ttf engine: %s\n", SDL_GetError());
- return -1;
- }
-
- sge_TTF_AAOff();
-
- inkFont = LoadTTF( "aardvark.ttf", 20 );
- if ( !inkFont ) return -1;
- impactFont = LoadTTF( "bradybun.ttf", 20 ); // gooddogc.ttf, 20
- if ( !impactFont ) return -1;
- titleFont = LoadTTF( "deadgrit.ttf", 48 ); // deadgrit.ttf, 48
- if ( !titleFont ) return -1;
- chatFont = LoadTTF( "thin.ttf", 20 ); // deadgrit.ttf, 48
- if ( !chatFont ) return -1;
-
- fastFont = LoadBMPFont( "brandybun3.png" );
- if ( !fastFont ) return -1;
- creditsFont = LoadBMPFont( "CreditsFont2.png" );//"fangfont.png" );
- if ( !creditsFont ) return -1;
- storyFont = LoadBMPFont( "glossyfont.png" );
- if ( !storyFont ) return -1;
-
- return 0;
-}
-
-
-int init2()
-{
- if ( !g_oBackend.Construct() )
- {
-
- fprintf(stderr, "couldn't start backend.\n" );
- return -1;
- }
- return 0;
-}
-
-
-
-
-
-int DrawMainScreen()
-{
- SDL_Surface* background = LoadBackground( "Mortal.jpg", 240 );
-
- DrawTextMSZ( "Version " VERSION " - European Union Editition", inkFont, 320, 430, UseShadow | AlignHCenter, C_WHITE, background, false );
- SDL_Rect r;
- r.x = r.y = 0;
-
- std::string sStaffFilename = DATADIR;
- sStaffFilename += "/characters/STAFF.DAT";
- CRlePack pack( sStaffFilename.c_str(), 256 );
- pack.ApplyPalette();
- SDL_BlitSurface( background, NULL, gamescreen, &r );
- SDL_Flip( gamescreen );
-
-/* char* filename[15] = {
- "Jacint.pl", "Jozsi.pl", "Agent.pl", "Mrsmith.pl",
- "Sleepy.pl", "Tejszin.pl",
- "UPi.pl", "Zoli.pl", "Ulmar.pl", "Bence.pl",
- "Descant.pl", "Grizli.pl", "Sirpi.pl", "Macy.pl", "Cumi.pl" };*/
- int x[14] = {
- 0, 26, 67, 125, 159, 209,
- 249, 289, 358, 397, 451, 489, 532, 161 };
- int y[14] = {
- 5, 4, 5, 5, 5, 7,
- 4, 0, 7, 5, 5, 6, 5, 243 };
-
- /*
- int i;
-
- g_oBackend.PerlEvalF( "eval( \"require '%s/characters/Kinga.pl';\" )", DATADIR );
- g_oBackend.PerlEvalF( "eval( \"require '%s/characters/Ambrus.pl';\" )", DATADIR );
- g_oBackend.PerlEvalF( "eval( \"require '%s/characters/Dani.pl';\" )", DATADIR );
-
- for ( i=0; i<15; ++i )
- {
- pack.Draw( i, x[i], y[i], false );
- SDL_Flip( gamescreen );
- if ( filename[i] != NULL )
- {
- debug( "Loading fighter %s", filename[i] );
- g_oBackend.PerlEvalF( "eval( \"require '%s/characters/%s';\" )", DATADIR, filename[i] );
-
-
- }
- }
-
- int retval = 0;
- i = 0;
- */
-
- int iNumFighterFiles, i;
-
-#ifdef MACOSX
- //[segabor]
- char char_buf[256];
- sprintf(char_buf, "%s/characters", DATADIR);
- g_oBackend.PerlEvalF( "$CppRetval = GetNumberOfFighterFiles('%s')", char_buf );
-#else
- g_oBackend.PerlEvalF( "$CppRetval = GetNumberOfFighterFiles('%s')", DATADIR "/characters" );
-#endif
- iNumFighterFiles = g_oBackend.GetPerlInt( "CppRetval" );
-
- for ( i=0; i<iNumFighterFiles; ++i )
- {
- g_oBackend.PerlEvalF( "LoadFighterFile(%d);", i );
-
- if ( i < 15 ) {
- pack.Draw( i, x[i], y[i], false );
- SDL_Flip( gamescreen );
- }
- }
-
- SDL_FreeSurface( background );
- return 0;
-
-}
-
-
-
-
-
-int InitJoystick();
-
-
-
-
-/**
-The game loop consists of the following events:
-
-\li Player selection
-\li DoGame
-\li GameOver and FighterStatsDemo (not in network mode)
-
-The loop ends if the game mode changes to a non-game mode (e.g. IN_DEMO or IN_CHAT)
-*/
-
-void GameLoop()
-{
- class CVideoModeChange
- {
- public:
- CVideoModeChange( bool a_bWide )
- {
- m_bWide = a_bWide;
- if ( m_bWide ) SetVideoMode( true, g_oState.m_bFullscreen );
- }
- ~CVideoModeChange()
- {
- if ( m_bWide ) SetVideoMode( false, g_oState.m_bFullscreen );
- }
- bool m_bWide;
- } oVideoModeChanger( g_oState.m_iNumPlayers > 2 );
-
-#define IS_GAME_MODE (g_oState.m_enGameMode != SState::IN_DEMO \
- && g_oState.m_enGameMode != SState::IN_CHAT \
- && !g_oState.m_bQuitFlag)
-
- Audio->PlaySample( "GAME_NEW" );
- Audio->PlayMusic( "GameMusic" );
-
- bool bNetworkGame = SState::IN_NETWORK == g_oState.m_enGameMode;
-
- if ( bNetworkGame )
- {
- g_oState.m_enTeamMode = SState::Team_ONE_VS_ONE;
- }
-
- while ( IS_GAME_MODE )
- {
- if ( SState::Team_GOOD_VS_EVIL == g_oState.m_enTeamMode )
- {
- std::vector<FighterEnum>& roTeam0 = g_oPlayerSelect.EditPlayerInfo(0).m_aenTeam;
- std::vector<FighterEnum>& roTeam1 = g_oPlayerSelect.EditPlayerInfo(1).m_aenTeam;
- roTeam0.clear();
- roTeam1.clear();
-
- roTeam0.push_back( SIRPI );
- roTeam0.push_back( MACI );
- roTeam0.push_back( GRIZLI );
- roTeam0.push_back( DANI );
- roTeam0.push_back( KINGA );
- roTeam0.push_back( CUMI );
-
- roTeam1.push_back( ZOLI );
- roTeam1.push_back( ULMAR );
- roTeam1.push_back( BENCE );
- roTeam1.push_back( AMBRUS );
- roTeam1.push_back( DESCANT ); // Temporary assignment
- roTeam1.push_back( UPI );
-
- for ( int i=0; i<10; ++i )
- {
- int j = rand() % ( roTeam0.size() -1 );
- int k = rand() % ( roTeam0.size() -1 );
- FighterEnum enTemp;
- enTemp = roTeam0[j]; roTeam0[j] = roTeam0[k]; roTeam0[k] = enTemp;
-
- j = rand() % ( roTeam1.size() -1 );
- k = rand() % ( roTeam1.size() -1 );
- enTemp = roTeam1[j]; roTeam1[j] = roTeam1[k]; roTeam1[k] = enTemp;
- }
- }
- else
- {
- g_oPlayerSelect.DoPlayerSelect();
- }
-
- if ( !IS_GAME_MODE ) break;
-
- //sprintf( acReplayFile, "/tmp/msz%d.replay", ++iGameNumber );
-
- int iGameResult = DoGame( NULL, false, bDebug );
- //int iGameResult = DoGame( acReplayFile, false, bDebug );
- //DoGame( acReplayFile, true, bDebug );
- debug ( "iGameResult = %d\n", iGameResult );
-
- if ( !IS_GAME_MODE ) break;
-
- if ( iGameResult >= 0 && !bNetworkGame )
- {
- GameOver( iGameResult );
- CFighterStatsDemo oDemo( g_oPlayerSelect.GetPlayerInfo( iGameResult ).m_enFighter );
- oDemo.Run();
- }
-
- if ( !IS_GAME_MODE ) break;
- }
-
- if ( bNetworkGame && !g_oState.m_bQuitFlag )
- {
- DrawTextMSZ( "Connection closed.", inkFont, 320, 210, AlignHCenter | UseShadow, C_WHITE, gamescreen );
- DrawTextMSZ( g_poNetwork->GetLastError(), impactFont, 320, 250, AlignHCenter | UseShadow, C_WHITE, gamescreen );
- SDL_Delay( 1000 );
- GetKey( true );
- }
-
- if ( !g_oState.m_bQuitFlag )
- {
- Audio->PlayMusic( "DemoMusic" );
- }
-
-}
-
-
-
-/**
-The chat loop consists of:
-
-\li DoOnlineChat
-\li GameLoop (if a game was started
-
-The loop ends if DoOnlineChat returns with a quit or disconnect
-(not IN_NETWORK mode).
-*/
-
-void ChatLoop()
-{
- while (1)
- {
- DoOnlineChat();
-
- if ( g_oState.m_bQuitFlag ||
- SState::IN_CHAT != g_oState.m_enGameMode )
- {
- break;
- }
-
- if ( SState::IN_NETWORK == g_oState.m_enGameMode )
- {
- GameLoop();
- }
-
- if ( g_oState.m_bQuitFlag ) break;
-
- g_oState.m_enGameMode = SState::IN_CHAT;
- }
-}
-
-
-
-
-int main(int argc, char *argv[])
-{
- srand( (unsigned int)time(NULL) );
- if ( 0 != init2() )
- {
- fprintf( stderr, "init2() failed." );
- return -1;
- }
-
- g_oState.m_pcArgv0 = argv[0];
- g_oState.Load();
- CMortalNetwork::Create();
-
- bDebug = false;
-
- int i;
- for ( i=1; i<argc; ++i )
- {
- if ( !strcmp(argv[i], "-debug") )
- {
- bDebug = true;
- }
-/*
- else if ( !strcmp(argv[i], "-fullscreen") )
- {
- iFlags |= SDL_FULLSCREEN;
- }
- else if ( !strcmp(argv[i], "-hwsurface") )
- {
- iFlags |= SDL_HWSURFACE;
- }
- else if ( !strcmp(argv[i], "-doublebuf") )
- {
- iFlags |= SDL_DOUBLEBUF;
- }
- else if ( !strcmp(argv[i], "-anyformat") )
- {
- iFlags |= SDL_ANYFORMAT;
- }
-
-*/
- else
-
- {
-// printf( "Usage: %s [-debug] [-fullscreen] [-hwsurface] [-doublebuf] [-anyformat]\n", argv[0] );
- printf( "Usage: %s [-debug]\n", argv[0] );
- return 0;
- }
- }
-
- if (init()<0)
- {
- return -1;
- }
-
- InitJoystick();
-
- g_oState.SetLanguage( g_oState.m_acLanguage );
-
- new COpenMortalAudio;
-// Audio->LoadMusic( "Last_Ninja_-_The_Wilderness.mid", "DemoMusic" );
- Audio->LoadMusic( "ride.mod", "DemoMusic" );
- Audio->PlayMusic( "DemoMusic" );
- Audio->LoadMusic( "2nd_pm.s3m", "GameMusic" );
-
- DrawMainScreen();
-
- g_oPlayerSelect.SetPlayer( 0, UPI );
- g_oPlayerSelect.SetPlayer( 1, ULMAR );
-
- /*
- {
- int iGameNumber=0;
- char acReplayFile[1024];
-
- for ( i=0; i<15; ++i )
- {
- sprintf( acReplayFile, DATADIR "/msz%i.replay", i );
- DrawTextMSZ( acReplayFile, impactFont, 10, 10, 0, C_WHITE, gamescreen );
- SDL_Delay(5000 );
-
- DoGame( acReplayFile, true, bDebug );
- }
- }
-
- */
-
-/* while ( !g_oState.m_bQuitFlag )
- {
- g_oState.m_enGameMode = SState::IN_MULTI;
- g_oState.m_bTeamMultiselect = false;
- g_oState.m_iTeamSize = 3;
- g_oState.m_enTeamMode = SState::Team_CUSTOM;
-
- std::vector<FighterEnum>& roTeam0 = g_oPlayerSelect.EditPlayerInfo(0).m_aenTeam;
- std::vector<FighterEnum>& roTeam1 = g_oPlayerSelect.EditPlayerInfo(1).m_aenTeam;
-
- roTeam0.clear();
- roTeam0.push_back( ZOLI );
- roTeam0.push_back( SIRPI );
- roTeam0.push_back( MACI );
- roTeam1.clear();
- roTeam1.push_back( UPI );
- roTeam1.push_back( ZOLI );
- roTeam1.push_back( ULMAR );
-
- DoGame( NULL, false, false );
- }
-*/
- while ( 1 )
- {
- if ( g_oState.m_bQuitFlag ) break;
-
- switch ( g_oState.m_enGameMode )
- {
- case SState::IN_DEMO:
- DoDemos();
- continue;
-
- case SState::IN_CHAT:
- ChatLoop();
- continue;
-
- default:
- GameLoop();
- continue;
- }
-
-#if 0
- // Remaining are game modes: IN_SINGLE, IN_MULTI, IN_NETWORK
-
- Audio->PlaySample( "car_start.voc" );
- Audio->PlayMusic( "GameMusic" );
-
- bNetworkGame = false;
-
- while ( g_oState.m_enGameMode != SState::IN_DEMO
- && g_oState.m_enGameMode != SState::IN_CHAT
- && !g_oState.m_bQuitFlag )
- {
- bNetworkGame = SState::IN_NETWORK == g_oState.m_enGameMode;
-
- g_oPlayerSelect.DoPlayerSelect();
- if ( g_oState.m_bQuitFlag || g_oState.m_enGameMode == SState::IN_DEMO ) break;
-
- //sprintf( acReplayFile, "/tmp/msz%d.replay", ++iGameNumber );
-
- int iGameResult = DoGame( NULL, false, bDebug );
- //int iGameResult = DoGame( acReplayFile, false, bDebug );
- //DoGame( acReplayFile, true, bDebug );
- if ( g_oState.m_bQuitFlag || g_oState.m_enGameMode == SState::IN_DEMO ) break;
-
- debug ( "iGameResult = %d\n", iGameResult );
-
- if ( iGameResult >= 0 && !bNetworkGame )
- {
- GameOver( iGameResult );
-
-
- FighterStatsDemo oDemo( g_oPlayerSelect.GetPlayerInfo( iGameResult ).m_enFighter );
- oDemo.Run();
- }
- if ( g_oState.m_bQuitFlag || g_oState.m_enGameMode == SState::IN_DEMO ) break;
- }
-
- if ( bNetworkGame && !g_oState.m_bQuitFlag )
- {
- DrawTextMSZ( "Connection closed.", inkFont, 320, 210, AlignHCenter | UseShadow, C_WHITE, gamescreen );
- DrawTextMSZ( g_poNetwork->GetLastError(), impactFont, 320, 250, AlignHCenter | UseShadow, C_WHITE, gamescreen );
- SDL_Delay( 1000 );
- GetKey( true );
- }
-
- if ( g_oState.m_bQuitFlag ) break;
- Audio->PlayMusic( "DemoMusic" );
-#endif
- }
-
- g_oState.Save();
-
- SDL_Quit();
-
- return EXIT_SUCCESS;
-}
+/***************************************************************************
+ main.cpp - description
+ -------------------
+ begin : Wed Aug 22 10:18:47 CEST 2001
+ copyright : (C) 2001 by upi
+ email : upi@apocalypse.rulez.org
+ ***************************************************************************/
+
+
+/**
+\mainpage
+
+The document you read now describes the design of OpenMortal. This page
+serves as a starting point. The documentation is generated with doxygen
+(http://doxygen.org).
+
+OpenMortal consists of two main parts: the \b frontend and the \b backend.
+
+\li The frontend is a C++ program, responsible for multimedia
+(sounds, music, graphics) and general interaction with the players
+(menus, keyboard input), and the demo and intro screens.
+
+\li The backend is written in Perl, and is incorporated into the C++
+program with Perl embedding.
+
+
+
+\section s1 1. Modules
+
+The classes of OpenMortal are organized into the following groups (see Modules above).
+
+\li \ref Media - OpenMortal uses \b SDL (http://libsdl.org) for hardware
+access such as screen drawing, music, sound effect and keyboard input. For
+information and documentation of SDL, SDL_image, SDL_ttf and SDL_mixer,
+please look at the SDL homepage.
+\li \ref PlayerSelect
+\li \ref Network
+\li \ref Demo
+\li \ref GameLogic
+
+
+
+\section s2 2. Main Functions
+These global functions implement important parts of the program. They serve
+as entry points into functional parts.
+
+\li DoMenu() - Displays and runs the menu over the current screen
+\li GameOver() - Displays the "Final Judgeent" screen
+\li DoDemos() - Runs the demos in an endless loop until a game is started or the program ends.
+\li DoGame() - Runs the game.
+\li DoOnlineChat() - Connects to and runs the MortalNet.
+\li CPlayerSelect::DoPlayerSelect() - Runs the player selection screen.
+
+
+\section s3 3. Definitions
+
+Here are the definitions of terms used in this documentation.
+
+<dl>
+
+<dt>\b Player <dd>
+ Player refers to one of the two persons playing the game. A player chooses a fighter. The two players are referred to as "Player 1" and "Player 2", even though the C++ and perl code count arrays from 0.
+<dt>\b Fighter <dd>
+ Fighter is one of the many available characters. Usually there are only two fighters loaded at any time. Fighters are static: their properties never change. Maybe Fighter should be renamed to Character?
+<dt>\b Game <dd>
+ One game is the part of the program in which the players actually compete. The game consists of a number of rounds. The player selection, and gameover screen are not part of this definition.
+<dt>\b Round <dd>
+ One round starts with both players at full health, and ends either with a timeout or with a ko.
+<dt>\b Doodad <dd>
+ A graphical element on the game screen that is not the background or the characters. E.g. the "3x combo" text or a thrown projectile are doodads.
+<dt>\b Tint <dd>
+ A tint is a methodical change in a palette. There are many ways to tint (e.g. grayscaling, darkening, green chroma, etc). Usually when two players choose the same fighter, the fighter of player 2 is tinted.
+<dt>\b Scene <dd>
+ The description of a frozen moment in the course of a game. The Backend is responsible for calculating each consecutive scene. The number of scenes calculated per second is constant (except for the "hurry up mode", or if the computer is too slow).
+<dt>\b FPS <dd>
+ Frames Per Second. The FPS indicator on the screen during a game indicates the number of scenes drawn, not the number of scenes calculated by the backend.
+</dl>
+
+
+\section s4 4. C++ Coding conventions
+
+Historically two different coding conventions were mixed in OpenMortal.
+Hopefully most of the old conventions are eliminated by now.
+Here I will describe the new conventions:
+
+\li <B> Class names: </B> CMixedCaps.
+\li <B> Struct names: </B> SMixedCaps.
+\li <B> Typedef names: </B> CSomeTypedef (There's some traces of the old TSomeTypedef
+ left, these should be eliminated.
+\li <B> Enum names: </B> SomeThingEnum.
+\li <B> Enum values: </B> Prefix_ENUM_VALUE
+\li <B> Method names: </B> MixedCaps.
+\li <B> Variable names: </B> &lt;prefix&gt;VariableName.
+\li <B> Instance property names: </B> m_&lt;prefix&gt;VariableName,
+\li <B> Class property names </B>(a.k.a. static class variables): mg_&lt;prefix&gt;VariableName.
+\li <B> Method argument names: </B> a_&lt;prefix&gt;VariableName.
+If a reference or pointer argument is "output-only: a_&lt;prefix&gt;OutVariableName.
+\li <B> Global variable names: </B> g_&lt;prefix&gt;VariableName.
+
+The prefixes used are:
+
+\li <B> Array of something: </B> a&lt;something&gt;
+\li <B> Pointer to something: </B> p&lt;something&gt;
+\li <B> Reference of something: </B> r&lt;something&gt;
+\li <B> Basic types: </B> Integer: i; char: c; double: d; enum: en; object (class or struct): o; std::string: s;
+
+Example:
+\code
+CSomeExampleClass: public CSomeBaseClass
+{
+public:
+ CSomeExampleClass();
+ void SomeMethod( int& a_riOutSomething );
+protected:
+ int m_iSomething;
+ char* m_pcSomethingElse;
+ static enum SomeThingEnum
+ {
+ Ste_VALUE,
+ } mg_enWhatever;
+};
+\endcode
+*/
+
+
+#include "config.h"
+
+#include "PlayerSelect.h"
+
+#include "SDL_video.h"
+#include "sge_tt_text.h"
+#include "sge_bm_text.h"
+#include "sge_surface.h"
+#include "SDL.h"
+#include "SDL_image.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <string>
+
+#include "common.h"
+#include "gfx.h"
+#include "Audio.h"
+#include "RlePack.h"
+#include "Backend.h"
+#include "State.h"
+#include "FighterStats.h"
+#include "MortalNetwork.h"
+
+
+#ifdef _WINDOWS
+
+#undef DATADIR // GRRR.. windows keyword...
+#include <windows.h>
+#define DATADIR "../data"
+
+#endif
+
+_sge_TTFont* inkFont;
+_sge_TTFont* impactFont;
+_sge_TTFont* titleFont;
+_sge_TTFont* chatFont;
+sge_bmpFont* fastFont;
+sge_bmpFont* creditsFont;
+sge_bmpFont* storyFont;
+bool bDebug = false;
+
+Uint32 C_BLACK, C_BLUE, C_GREEN, C_CYAN, C_RED, C_MAGENTA, C_ORANGE, C_LIGHTGRAY,
+ C_DARKGRAY, C_LIGHTBLUE, C_LIGHTGREEN, C_LIGHTCYAN, C_LIGHTRED, C_LIGHTMAGENTA, C_YELLOW, C_WHITE;
+
+SDL_Color Colors[] =
+{
+ { 0, 0, 0, 0 }, { 0, 0, 42, 0 }, { 0, 42, 0, 0 }, { 0, 42, 42, 0 },
+ { 42, 0, 0, 0 }, { 42, 0, 42, 0 }, { 63, 42, 0, 0 }, { 42, 42, 42, 0 },
+ { 21, 21, 21, 0 }, { 21, 21, 63, 0 }, { 21, 63, 21, 0 }, { 21, 63, 63, 0 },
+ { 63, 21, 21, 0 }, { 63, 21, 63, 0 }, { 63, 63, 21, 0 }, { 63, 63, 63, 0 }
+};
+
+
+void Complain( const char* a_pcError )
+{
+#ifdef _WINDOWS
+ ::MessageBoxA( 0, a_pcError, "OpenMortal", MB_ICONEXCLAMATION );
+#else
+ fprintf( stderr, "%s", a_pcError );
+#endif
+}
+
+
+_sge_TTFont* LoadTTF( const char* a_pcFilename, int a_iSize )
+{
+ std::string sPath = std::string(DATADIR) + "/fonts/" + a_pcFilename;
+ _sge_TTFont* poFont = sge_TTF_OpenFont( sPath.c_str(), a_iSize );
+
+ if ( NULL == poFont )
+ {
+ Complain( ("Couldn't load font: " + sPath).c_str() );
+ }
+
+ return poFont;
+}
+
+
+sge_bmpFont* LoadBMPFont( const char* a_pcFilename )
+{
+ std::string sPath = std::string(DATADIR) + "/fonts/" + a_pcFilename;
+ sge_bmpFont* poFont = sge_BF_OpenFont( sPath.c_str(), SGE_BFSFONT | SGE_BFTRANSP );
+ if ( NULL == poFont )
+ {
+ Complain( ("Couldn't load font: " + sPath).c_str() );
+ }
+ return poFont;
+}
+
+
+int init()
+{
+ if (SDL_Init(SDL_INIT_VIDEO /*| SDL_INIT_AUDIO*/) < 0)
+ {
+ fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError());
+ return -1;
+ }
+ atexit(SDL_Quit);
+
+ SetVideoMode( false, g_oState.m_bFullscreen );
+ if (gamescreen == NULL)
+ {
+ fprintf(stderr, "failed to set video mode: %s\n", SDL_GetError());
+ return -1;
+ }
+
+ SDL_WM_SetCaption( "OpenMortal", "OpenMortal" );
+ std::string sPath = std::string(DATADIR) + "/gfx/icon.png";
+ SDL_WM_SetIcon(IMG_Load(sPath.c_str()), NULL);
+//@ SDL_ShowCursor( SDL_DISABLE );
+
+ int i;
+ for ( i=0; i<16; ++i )
+ {
+ Colors[i].r *=4; Colors[i].g *=4; Colors[i].b *=4;
+ }
+ if ( gamescreen->format->BitsPerPixel > 8 )
+ {
+ i = 0;
+ C_BLACK = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
+ C_BLUE = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
+ C_GREEN = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
+ C_CYAN = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
+
+ C_RED = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
+ C_MAGENTA = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
+ C_ORANGE = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
+ C_LIGHTGRAY = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
+
+ C_DARKGRAY = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
+ C_LIGHTBLUE = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
+ C_LIGHTGREEN = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
+ C_LIGHTCYAN = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
+
+ C_LIGHTRED = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
+ C_LIGHTMAGENTA = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
+ C_YELLOW = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
+ C_WHITE = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
+ }
+ else
+ {
+ SDL_SetColors( gamescreen, Colors, 256-16, 16 );
+ C_BLACK = 240;
+ C_BLUE = 241;
+ C_GREEN = 242;
+ C_CYAN = 243;
+
+ C_RED = 244;
+ C_MAGENTA = 245;
+ C_ORANGE = 246;
+ C_LIGHTGRAY = 247;
+
+ C_DARKGRAY = 248;
+ C_LIGHTBLUE = 249;
+ C_LIGHTGREEN = 250;
+ C_LIGHTCYAN = 251;
+
+ C_LIGHTRED = 252;
+ C_LIGHTMAGENTA = 253;
+ C_YELLOW = 254;
+ C_WHITE = 255;
+ }
+
+ if ( sge_TTF_Init() )
+ {
+ fprintf(stderr, "couldn't start ttf engine: %s\n", SDL_GetError());
+ return -1;
+ }
+
+ sge_TTF_AAOff();
+
+ inkFont = LoadTTF( "aardvark.ttf", 20 );
+ if ( !inkFont ) return -1;
+ impactFont = LoadTTF( "bradybun.ttf", 20 ); // gooddogc.ttf, 20
+ if ( !impactFont ) return -1;
+ titleFont = LoadTTF( "deadgrit.ttf", 48 ); // deadgrit.ttf, 48
+ if ( !titleFont ) return -1;
+ chatFont = LoadTTF( "thin.ttf", 20 ); // deadgrit.ttf, 48
+ if ( !chatFont ) return -1;
+
+ fastFont = LoadBMPFont( "brandybun3.png" );
+ if ( !fastFont ) return -1;
+ creditsFont = LoadBMPFont( "CreditsFont2.png" );//"fangfont.png" );
+ if ( !creditsFont ) return -1;
+ storyFont = LoadBMPFont( "glossyfont.png" );
+ if ( !storyFont ) return -1;
+
+ return 0;
+}
+
+
+int init2()
+{
+ if ( !g_oBackend.Construct() )
+ {
+
+ fprintf(stderr, "couldn't start backend.\n" );
+ return -1;
+ }
+ return 0;
+}
+
+
+
+
+
+int DrawMainScreen()
+{
+ SDL_Surface* background = LoadBackground( "Mortal.jpg", 240 );
+
+ DrawTextMSZ( "Version " VERSION " - European Union Editition", inkFont, 320, 430, UseShadow | AlignHCenter, C_WHITE, background, false );
+ SDL_Rect r;
+ r.x = r.y = 0;
+
+ std::string sStaffFilename = DATADIR;
+ sStaffFilename += "/characters/STAFF.DAT";
+ CRlePack pack( sStaffFilename.c_str(), 256 );
+ pack.ApplyPalette();
+ SDL_BlitSurface( background, NULL, gamescreen, &r );
+ SDL_Flip( gamescreen );
+
+/* char* filename[15] = {
+ "Jacint.pl", "Jozsi.pl", "Agent.pl", "Mrsmith.pl",
+ "Sleepy.pl", "Tejszin.pl",
+ "UPi.pl", "Zoli.pl", "Ulmar.pl", "Bence.pl",
+ "Descant.pl", "Grizli.pl", "Sirpi.pl", "Macy.pl", "Cumi.pl" };*/
+ int x[14] = {
+ 0, 26, 67, 125, 159, 209,
+ 249, 289, 358, 397, 451, 489, 532, 161 };
+ int y[14] = {
+ 5, 4, 5, 5, 5, 7,
+ 4, 0, 7, 5, 5, 6, 5, 243 };
+
+ /*
+ int i;
+
+ g_oBackend.PerlEvalF( "eval( \"require '%s/characters/Kinga.pl';\" )", DATADIR );
+ g_oBackend.PerlEvalF( "eval( \"require '%s/characters/Ambrus.pl';\" )", DATADIR );
+ g_oBackend.PerlEvalF( "eval( \"require '%s/characters/Dani.pl';\" )", DATADIR );
+
+ for ( i=0; i<15; ++i )
+ {
+ pack.Draw( i, x[i], y[i], false );
+ SDL_Flip( gamescreen );
+ if ( filename[i] != NULL )
+ {
+ debug( "Loading fighter %s", filename[i] );
+ g_oBackend.PerlEvalF( "eval( \"require '%s/characters/%s';\" )", DATADIR, filename[i] );
+
+
+ }
+ }
+
+ int retval = 0;
+ i = 0;
+ */
+
+ int iNumFighterFiles, i;
+
+#ifdef MACOSX
+ //[segabor]
+ char char_buf[256];
+ sprintf(char_buf, "%s/characters", DATADIR);
+ g_oBackend.PerlEvalF( "$CppRetval = GetNumberOfFighterFiles('%s')", char_buf );
+#else
+ g_oBackend.PerlEvalF( "$CppRetval = GetNumberOfFighterFiles('%s')", DATADIR "/characters" );
+#endif
+ iNumFighterFiles = g_oBackend.GetPerlInt( "CppRetval" );
+
+ for ( i=0; i<iNumFighterFiles; ++i )
+ {
+ g_oBackend.PerlEvalF( "LoadFighterFile(%d);", i );
+
+ if ( i < 15 ) {
+ pack.Draw( i, x[i], y[i], false );
+ SDL_Flip( gamescreen );
+ }
+ }
+
+ SDL_FreeSurface( background );
+ return 0;
+
+}
+
+
+
+
+
+int InitJoystick();
+
+
+
+
+/**
+The game loop consists of the following events:
+
+\li Player selection
+\li DoGame
+\li GameOver and FighterStatsDemo (not in network mode)
+
+The loop ends if the game mode changes to a non-game mode (e.g. IN_DEMO or IN_CHAT)
+*/
+
+void GameLoop()
+{
+ class CVideoModeChange
+ {
+ public:
+ CVideoModeChange( bool a_bWide )
+ {
+ m_bWide = a_bWide;
+ if ( m_bWide ) SetVideoMode( true, g_oState.m_bFullscreen );
+ }
+ ~CVideoModeChange()
+ {
+ if ( m_bWide ) SetVideoMode( false, g_oState.m_bFullscreen );
+ }
+ bool m_bWide;
+ } oVideoModeChanger( g_oState.m_iNumPlayers > 2 );
+
+#define IS_GAME_MODE (g_oState.m_enGameMode != SState::IN_DEMO \
+ && g_oState.m_enGameMode != SState::IN_CHAT \
+ && !g_oState.m_bQuitFlag)
+
+ Audio->PlaySample( "GAME_NEW" );
+ Audio->PlayMusic( "GameMusic" );
+
+ bool bNetworkGame = SState::IN_NETWORK == g_oState.m_enGameMode;
+
+ if ( bNetworkGame )
+ {
+ g_oState.m_enTeamMode = SState::Team_ONE_VS_ONE;
+ }
+
+ while ( IS_GAME_MODE )
+ {
+ if ( SState::Team_GOOD_VS_EVIL == g_oState.m_enTeamMode )
+ {
+ std::vector<FighterEnum>& roTeam0 = g_oPlayerSelect.EditPlayerInfo(0).m_aenTeam;
+ std::vector<FighterEnum>& roTeam1 = g_oPlayerSelect.EditPlayerInfo(1).m_aenTeam;
+ roTeam0.clear();
+ roTeam1.clear();
+
+ roTeam0.push_back( SIRPI );
+ roTeam0.push_back( MACI );
+ roTeam0.push_back( GRIZLI );
+ roTeam0.push_back( DANI );
+ roTeam0.push_back( KINGA );
+ roTeam0.push_back( CUMI );
+
+ roTeam1.push_back( ZOLI );
+ roTeam1.push_back( ULMAR );
+ roTeam1.push_back( BENCE );
+ roTeam1.push_back( AMBRUS );
+ roTeam1.push_back( DESCANT ); // Temporary assignment
+ roTeam1.push_back( UPI );
+
+ for ( int i=0; i<10; ++i )
+ {
+ int j = rand() % ( roTeam0.size() -1 );
+ int k = rand() % ( roTeam0.size() -1 );
+ FighterEnum enTemp;
+ enTemp = roTeam0[j]; roTeam0[j] = roTeam0[k]; roTeam0[k] = enTemp;
+
+ j = rand() % ( roTeam1.size() -1 );
+ k = rand() % ( roTeam1.size() -1 );
+ enTemp = roTeam1[j]; roTeam1[j] = roTeam1[k]; roTeam1[k] = enTemp;
+ }
+ }
+ else
+ {
+ g_oPlayerSelect.DoPlayerSelect();
+ }
+
+ if ( !IS_GAME_MODE ) break;
+
+ //sprintf( acReplayFile, "/tmp/msz%d.replay", ++iGameNumber );
+
+ int iGameResult = DoGame( NULL, false, bDebug );
+ //int iGameResult = DoGame( acReplayFile, false, bDebug );
+ //DoGame( acReplayFile, true, bDebug );
+ debug ( "iGameResult = %d\n", iGameResult );
+
+ if ( !IS_GAME_MODE ) break;
+
+ if ( iGameResult >= 0 && !bNetworkGame )
+ {
+ GameOver( iGameResult );
+ CFighterStatsDemo oDemo( g_oPlayerSelect.GetPlayerInfo( iGameResult ).m_enFighter );
+ oDemo.Run();
+ }
+
+ if ( !IS_GAME_MODE ) break;
+ }
+
+ if ( bNetworkGame && !g_oState.m_bQuitFlag )
+ {
+ DrawTextMSZ( "Connection closed.", inkFont, 320, 210, AlignHCenter | UseShadow, C_WHITE, gamescreen );
+ DrawTextMSZ( g_poNetwork->GetLastError(), impactFont, 320, 250, AlignHCenter | UseShadow, C_WHITE, gamescreen );
+ SDL_Delay( 1000 );
+ GetKey( true );
+ }
+
+ if ( !g_oState.m_bQuitFlag )
+ {
+ Audio->PlayMusic( "DemoMusic" );
+ }
+
+}
+
+
+
+/**
+The chat loop consists of:
+
+\li DoOnlineChat
+\li GameLoop (if a game was started
+
+The loop ends if DoOnlineChat returns with a quit or disconnect
+(not IN_NETWORK mode).
+*/
+
+void ChatLoop()
+{
+ while (1)
+ {
+ DoOnlineChat();
+
+ if ( g_oState.m_bQuitFlag ||
+ SState::IN_CHAT != g_oState.m_enGameMode )
+ {
+ break;
+ }
+
+ if ( SState::IN_NETWORK == g_oState.m_enGameMode )
+ {
+ GameLoop();
+ }
+
+ if ( g_oState.m_bQuitFlag ) break;
+
+ g_oState.m_enGameMode = SState::IN_CHAT;
+ }
+}
+
+
+void PgTest();
+
+
+int main(int argc, char *argv[])
+{
+ srand( (unsigned int)time(NULL) );
+ if ( 0 != init2() )
+ {
+ fprintf( stderr, "init2() failed." );
+ return -1;
+ }
+
+ g_oState.m_pcArgv0 = argv[0];
+ g_oState.Load();
+ CMortalNetwork::Create();
+
+ bDebug = false;
+
+ int i;
+ for ( i=1; i<argc; ++i )
+ {
+ if ( !strcmp(argv[i], "-debug") )
+ {
+ bDebug = true;
+ }
+ else
+ {
+ printf( "Usage: %s [-debug]\n", argv[0] );
+ return 0;
+ }
+ }
+
+ if (init()<0)
+ {
+ return -1;
+ }
+
+ PgTest();
+
+ InitJoystick();
+
+ g_oState.SetLanguage( g_oState.m_acLanguage );
+
+ new COpenMortalAudio;
+// Audio->LoadMusic( "Last_Ninja_-_The_Wilderness.mid", "DemoMusic" );
+ Audio->LoadMusic( "ride.mod", "DemoMusic" );
+ Audio->PlayMusic( "DemoMusic" );
+ Audio->LoadMusic( "2nd_pm.s3m", "GameMusic" );
+
+ DrawMainScreen();
+
+ g_oPlayerSelect.SetPlayer( 0, UPI );
+ g_oPlayerSelect.SetPlayer( 1, ULMAR );
+
+ /*
+ {
+ int iGameNumber=0;
+ char acReplayFile[1024];
+
+ for ( i=0; i<15; ++i )
+ {
+ sprintf( acReplayFile, DATADIR "/msz%i.replay", i );
+ DrawTextMSZ( acReplayFile, impactFont, 10, 10, 0, C_WHITE, gamescreen );
+ SDL_Delay(5000 );
+
+ DoGame( acReplayFile, true, bDebug );
+ }
+ }
+
+ */
+
+
+ while ( 1 )
+ {
+ if ( g_oState.m_bQuitFlag ) break;
+
+ switch ( g_oState.m_enGameMode )
+ {
+ case SState::IN_DEMO:
+ DoDemos();
+ continue;
+
+ case SState::IN_CHAT:
+ ChatLoop();
+ continue;
+
+ default:
+ GameLoop();
+ continue;
+ }
+
+ }
+
+ g_oState.Save();
+
+ SDL_Quit();
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/menu.h b/src/menu.h
index 7150ddf..2fa8d0d 100644
--- a/src/menu.h
+++ b/src/menu.h
@@ -1,259 +1,259 @@
-/***************************************************************************
- menu.h - description
- -------------------
- begin : Sun Aug 3 2003
- copyright : (C) 2003 by upi
- email : upi@apocalypse.rulez.org
- ***************************************************************************/
-
-
-#ifndef MENU_H
-#define MENU_H
-
-
-#include <string>
-#include <vector>
-
-class CMenuItem;
-class CEnumMenuItem;
-class CTextMenuItem;
-
-
-enum
-{
-/* Master menu structure:
-MAIN MENU
-*/
-MENU_UNKNOWN,
- MENU_SURRENDER,
- MENU_SINGLE_PLAYER,
- MENU_EASY,
- MENU_MEDIUM,
- MENU_HARD,
- MENU_MULTI_PLAYER,
- MENU_MULTI_PLAYER_START,
- MENU_NUM_PLAYERS, // 2-4
- MENU_TEAM_MODE, // 1 vs 1, good vs evil, evil vs good, custom
- MENU_TEAM_SIZE, // 2-10
- MENU_TEAM_MULTISELECT, // yes / no
- MENU_NETWORK_GAME,
- MENU_SERVER,
- MENU_HOSTNAME,
- MENU_NICK,
- MENU_CONNECT,
- MENU_MORTALNET,
- MENU_CANCEL,
- MENU_OPTIONS,
- MENU_GAME_SPEED,
- MENU_ROUND_LENGTH, // ( :30 - 5:00 )
- MENU_TOTAL_HIT_POINTS, // ( 25 - 1000 )
- MENU_SOUND,
- MENU_CHANNELS, // MONO / STEREO
-
- MENU_MIXING_RATE, // 11kHz / 22kHz / 44.1 kHz
- MENU_BITS, // 8 bit / 16 bit
- MENU_MUSIC_VOLUME, // (0% - 100%)
- MENU_SOUND_VOLUME, // (0% - 100%)
- MENU_SOUND_OK,
- MENU_FULLSCREEN,
- MENU_KEYS_RIGHT,
- MENU_KEYS_LEFT,
- MENU_OPTIONS_OK,
- MENU_LANGUAGE,
- MENU_INFO,
- MENU_QUIT, // (confirm)
-};
-
-
-
-/**
-\brief Base class for menu systems in OpenMortal.
-\ingroup GameLogic
-
-Menus are displayed over the current screen and allow for the editing
-of the game's state, SState. If you think in terms of model, view and
-controller, then SState is the model and CMenu is both the view and
-the controller.
-
-Menus have menu items. The items in turn can edit various state
-variables or invoke submenus. The menu ends then the user exits the
-toplevel menu or invokes a command which unrolls the entire menu
-stack.
-*/
-
-class CMenu
-{
-public:
- CMenu( const char* a_pcTitle );
- virtual ~CMenu();
-
- virtual CMenuItem* AddMenuItem( const char* a_pcUtf8Text, SDLKey a_tShortcut = SDLK_UNKNOWN, int a_iCode = 0 );
- virtual CEnumMenuItem* AddEnumMenuItem( const char* a_pcUtf8Text, int a_iInitialValue,
- const char** a_ppcNames, const int* a_piValues, int a_iCode = 0 );
- virtual CTextMenuItem* AddTextMenuItem( const char* a_pcTitle, const char* a_pcValue, int a_iCode = 0 );
- virtual CMenuItem* AddMenuItem( CMenuItem* a_poItem );
- virtual void AddOkCancel( int a_iOkCode = 0 );
- virtual CMenuItem* GetMenuItem( int a_iCode ) const;
-
- virtual void ItemActivated( int a_iItemCode, CMenuItem* a_poMenuItem );
- virtual void ItemChanged( int a_iItemCode, int a_iValue, CMenuItem* a_poMenuItem );
- virtual int Run();
-
- virtual void Draw();
- virtual void Clear();
- virtual void EnterName( const char* a_pcTitle, std::string& a_rsTarget, CTextMenuItem* a_poMenuItem, int a_iMaxlen );
-
-protected:
-
- virtual void FocusNext();
- virtual void FocusPrev();
- virtual void InvokeSubmenu( CMenu* a_poSubmenu );
-
- typedef std::vector<CMenuItem*> CItemList;
- typedef CItemList::iterator CItemIterator;
-
-
- std::string m_sTitle;
- CItemList m_oItems;
- int m_iCurrentItem;
- int m_iReturnCode;
- bool m_bDone;
-};
-
-
-/**
-\ingroup GameLogic
-
-Basic menu item. Menu items have a code which they pass to their parent
-menu when they are activated. Menu items can be enabled or disabled.
-*/
-class CMenuItem
-{
-public:
- CMenuItem( CMenu* a_poMenu, const char* a_pcUtf8Text, int a_iCode = -1 );
- virtual ~CMenuItem();
-
- virtual void Draw();
- virtual void Clear();
- virtual void Activate();
- virtual void Increment() {};
- virtual void Decrement() {};
-
- virtual void SetText( const char* a_pcUtf8Text, bool a_bCenter );
- virtual void SetPosition( const SDL_Rect& a_roPosition );
- virtual void SetActive( bool a_bActive );
- virtual void SetEnabled( bool a_bEnabled );
-
- virtual bool GetEnabled() const { return m_bEnabled; }
- virtual int GetCode() const { return m_iCode; }
-
-protected:
- CMenu* m_poMenu;
-
- // appearance
- std::string m_sUtf8Text;
- SDL_Rect m_oPosition;
- bool m_bCenter;
- Uint32 m_iHighColor;
- Uint32 m_iLowColor;
- Uint32 m_iInactiveColor;
- Uint32 m_iBackgroundColor;
-
- // data content
- int m_iCode;
- bool m_bActive;
- bool m_bEnabled;
-};
-
-
-/**
-\ingroup GameLogic
-
-Enumerated menu items have an integer value, and a set of values and texts
-which they can display for the user. The user can switch between these
-values by incrementing and decrementing the value with the left and right
-arrow keys.
-*/
-
-class CEnumMenuItem: public CMenuItem
-{
-public:
- CEnumMenuItem( CMenu* a_poMenu, int a_iInitialValue, const char* a_pcUtf8Text, int a_iCode = -1 );
- virtual ~CEnumMenuItem();
-
- int GetCurrentValue();
- const char* GetCurrentText();
- virtual void Draw();
- virtual void Increment();
- virtual void Decrement();
-
- virtual void SetEnumValues( const char ** a_ppcNames, const int * a_piValues );
- virtual void SetMaxValue( int a_iMaxValue );
-
-protected:
- int m_iValue;
- int m_iMax;
- std::string m_sUtf8Title;
- const char** m_ppcNames;
- const int* m_piValues;
-};
-
-
-/**
-\ingroup GameLogic
-
-Text menu items are like regular menu items, but they have a text value
-which can be set. This value is displayed next to the regular name of
-the menu item.
-*/
-
-class CTextMenuItem: public CMenuItem
-{
-public:
- CTextMenuItem( CMenu* a_poMenu, const char* a_pcInitialValue, const char* a_pcUtf8Title, int a_iCode );
- virtual ~CTextMenuItem();
-
- virtual void Draw();
- virtual void SetValue( const char* a_pcValue );
-
-protected:
- std::string m_sTitle;
- std::string m_sValue;
-};
-
-
-
-/**
-\ingroup GameLogic
-
-The Network displays and modifies the network connection parameters.
-*/
-
-class CNetworkMenu: public CMenu
-{
-public:
- CNetworkMenu();
- virtual ~CNetworkMenu();
-
- void Connect();
-
- void ItemActivated( int a_iItemCode, CMenuItem* a_poMenuItem );
- void ItemChanged( int a_iItemCode, int a_iValue, CMenuItem* a_poMenuItem );
-
-protected:
- bool m_bOK;
- bool m_bServer;
- std::string m_sHostname;
- std::string m_sNick;
-
- CTextMenuItem* m_poServerMenuItem;
- CTextMenuItem* m_poNickMenuItem;
-};
-
-
-
-
-void DoMenu();
-void DoMenu( CMenu& a_roMenu );
-
-#endif
+/***************************************************************************
+ menu.h - description
+ -------------------
+ begin : Sun Aug 3 2003
+ copyright : (C) 2003 by upi
+ email : upi@apocalypse.rulez.org
+ ***************************************************************************/
+
+
+#ifndef MENU_H
+#define MENU_H
+
+
+#include <string>
+#include <vector>
+
+class CMenuItem;
+class CEnumMenuItem;
+class CTextMenuItem;
+
+
+enum
+{
+/* Master menu structure:
+MAIN MENU
+*/
+MENU_UNKNOWN,
+ MENU_SURRENDER,
+ MENU_SINGLE_PLAYER,
+ MENU_EASY,
+ MENU_MEDIUM,
+ MENU_HARD,
+ MENU_MULTI_PLAYER,
+ MENU_MULTI_PLAYER_START,
+ MENU_NUM_PLAYERS, // 2-4
+ MENU_TEAM_MODE, // 1 vs 1, good vs evil, evil vs good, custom
+ MENU_TEAM_SIZE, // 2-10
+ MENU_TEAM_MULTISELECT, // yes / no
+ MENU_NETWORK_GAME,
+ MENU_SERVER,
+ MENU_HOSTNAME,
+ MENU_NICK,
+ MENU_CONNECT,
+ MENU_MORTALNET,
+ MENU_CANCEL,
+ MENU_OPTIONS,
+ MENU_GAME_SPEED,
+ MENU_ROUND_LENGTH, // ( :30 - 5:00 )
+ MENU_TOTAL_HIT_POINTS, // ( 25 - 1000 )
+ MENU_SOUND,
+ MENU_CHANNELS, // MONO / STEREO
+
+ MENU_MIXING_RATE, // 11kHz / 22kHz / 44.1 kHz
+ MENU_BITS, // 8 bit / 16 bit
+ MENU_MUSIC_VOLUME, // (0% - 100%)
+ MENU_SOUND_VOLUME, // (0% - 100%)
+ MENU_SOUND_OK,
+ MENU_FULLSCREEN,
+ MENU_KEYS_RIGHT,
+ MENU_KEYS_LEFT,
+ MENU_OPTIONS_OK,
+ MENU_LANGUAGE,
+ MENU_INFO,
+ MENU_QUIT, // (confirm)
+};
+
+
+
+/**
+\brief Base class for menu systems in OpenMortal.
+\ingroup GameLogic
+
+Menus are displayed over the current screen and allow for the editing
+of the game's state, SState. If you think in terms of model, view and
+controller, then SState is the model and CMenu is both the view and
+the controller.
+
+Menus have menu items. The items in turn can edit various state
+variables or invoke submenus. The menu ends then the user exits the
+toplevel menu or invokes a command which unrolls the entire menu
+stack.
+*/
+
+class CMenu
+{
+public:
+ CMenu( const char* a_pcTitle );
+ virtual ~CMenu();
+
+ virtual CMenuItem* AddMenuItem( const char* a_pcUtf8Text, SDLKey a_tShortcut = SDLK_UNKNOWN, int a_iCode = 0 );
+ virtual CEnumMenuItem* AddEnumMenuItem( const char* a_pcUtf8Text, int a_iInitialValue,
+ const char** a_ppcNames, const int* a_piValues, int a_iCode = 0 );
+ virtual CTextMenuItem* AddTextMenuItem( const char* a_pcTitle, const char* a_pcValue, int a_iCode = 0 );
+ virtual CMenuItem* AddMenuItem( CMenuItem* a_poItem );
+ virtual void AddOkCancel( int a_iOkCode = 0 );
+ virtual CMenuItem* GetMenuItem( int a_iCode ) const;
+
+ virtual void ItemActivated( int a_iItemCode, CMenuItem* a_poMenuItem );
+ virtual void ItemChanged( int a_iItemCode, int a_iValue, CMenuItem* a_poMenuItem );
+ virtual int Run();
+
+ virtual void Draw();
+ virtual void Clear();
+ virtual void EnterName( const char* a_pcTitle, std::string& a_rsTarget, CTextMenuItem* a_poMenuItem, int a_iMaxlen );
+
+protected:
+
+ virtual void FocusNext();
+ virtual void FocusPrev();
+ virtual void InvokeSubmenu( CMenu* a_poSubmenu );
+
+ typedef std::vector<CMenuItem*> CItemList;
+ typedef CItemList::iterator CItemIterator;
+
+
+ std::string m_sTitle;
+ CItemList m_oItems;
+ int m_iCurrentItem;
+ int m_iReturnCode;
+ bool m_bDone;
+};
+
+
+/**
+\ingroup GameLogic
+
+Basic menu item. Menu items have a code which they pass to their parent
+menu when they are activated. Menu items can be enabled or disabled.
+*/
+class CMenuItem
+{
+public:
+ CMenuItem( CMenu* a_poMenu, const char* a_pcUtf8Text, int a_iCode = -1 );
+ virtual ~CMenuItem();
+
+ virtual void Draw();
+ virtual void Clear();
+ virtual void Activate();
+ virtual void Increment() {};
+ virtual void Decrement() {};
+
+ virtual void SetText( const char* a_pcUtf8Text, bool a_bCenter );
+ virtual void SetPosition( const SDL_Rect& a_roPosition );
+ virtual void SetActive( bool a_bActive );
+ virtual void SetEnabled( bool a_bEnabled );
+
+ virtual bool GetEnabled() const { return m_bEnabled; }
+ virtual int GetCode() const { return m_iCode; }
+
+protected:
+ CMenu* m_poMenu;
+
+ // appearance
+ std::string m_sUtf8Text;
+ SDL_Rect m_oPosition;
+ bool m_bCenter;
+ Uint32 m_iHighColor;
+ Uint32 m_iLowColor;
+ Uint32 m_iInactiveColor;
+ Uint32 m_iBackgroundColor;
+
+ // data content
+ int m_iCode;
+ bool m_bActive;
+ bool m_bEnabled;
+};
+
+
+/**
+\ingroup GameLogic
+
+Enumerated menu items have an integer value, and a set of values and texts
+which they can display for the user. The user can switch between these
+values by incrementing and decrementing the value with the left and right
+arrow keys.
+*/
+
+class CEnumMenuItem: public CMenuItem
+{
+public:
+ CEnumMenuItem( CMenu* a_poMenu, int a_iInitialValue, const char* a_pcUtf8Text, int a_iCode = -1 );
+ virtual ~CEnumMenuItem();
+
+ int GetCurrentValue();
+ const char* GetCurrentText();
+ virtual void Draw();
+ virtual void Increment();
+ virtual void Decrement();
+
+ virtual void SetEnumValues( const char ** a_ppcNames, const int * a_piValues );
+ virtual void SetMaxValue( int a_iMaxValue );
+
+protected:
+ int m_iValue;
+ int m_iMax;
+ std::string m_sUtf8Title;
+ const char** m_ppcNames;
+ const int* m_piValues;
+};
+
+
+/**
+\ingroup GameLogic
+
+Text menu items are like regular menu items, but they have a text value
+which can be set. This value is displayed next to the regular name of
+the menu item.
+*/
+
+class CTextMenuItem: public CMenuItem
+{
+public:
+ CTextMenuItem( CMenu* a_poMenu, const char* a_pcInitialValue, const char* a_pcUtf8Title, int a_iCode );
+ virtual ~CTextMenuItem();
+
+ virtual void Draw();
+ virtual void SetValue( const char* a_pcValue );
+
+protected:
+ std::string m_sTitle;
+ std::string m_sValue;
+};
+
+
+
+/**
+\ingroup GameLogic
+
+The Network displays and modifies the network connection parameters.
+*/
+
+class CNetworkMenu: public CMenu
+{
+public:
+ CNetworkMenu();
+ virtual ~CNetworkMenu();
+
+ void Connect();
+
+ void ItemActivated( int a_iItemCode, CMenuItem* a_poMenuItem );
+ void ItemChanged( int a_iItemCode, int a_iValue, CMenuItem* a_poMenuItem );
+
+protected:
+ bool m_bOK;
+ bool m_bServer;
+ std::string m_sHostname;
+ std::string m_sNick;
+
+ CTextMenuItem* m_poServerMenuItem;
+ CTextMenuItem* m_poNickMenuItem;
+};
+
+
+
+
+void DoMenu();
+void DoMenu( CMenu& a_roMenu );
+
+#endif
diff --git a/src/paragui/pgbutton.cpp b/src/paragui/pgbutton.cpp
new file mode 100644
index 0000000..24fa23f
--- /dev/null
+++ b/src/paragui/pgbutton.cpp
@@ -0,0 +1,660 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgbutton.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#pragma warning( disable : 4786 )
+
+
+#include "pgbutton.h"
+//@ #include "pgapplication.h"
+//@ #include "pgthemewidget.h"
+#include "common.h"
+#include "pgdraw.h"
+#include "pgrectlist.h"
+//@ #include "pgtheme.h"
+#include "SDL_image.h"
+
+class PG_ButtonStateData {
+public:
+ PG_ButtonStateData() : srf(NULL), srf_icon(NULL), bordersize(1), transparency(0),
+ background(NULL), backMode(BKMODE_TILE), backBlend(0) {
+ };
+
+ SDL_Surface* srf;
+ SDL_Surface* srf_icon;
+ Uint8 bordersize;
+ Uint8 transparency;
+ PG_Gradient gradState;
+ SDL_Surface* background;
+ int backMode;
+ int backBlend;
+};
+
+class PG_ButtonDataInternal : public std::map<PG_Button::STATE, PG_ButtonStateData> {
+public:
+
+ PG_ButtonDataInternal() : free_icons(false), isPressed(false), togglemode(false), state(PG_Button::UNPRESSED), pressShift(1),
+ iconindent(3) {
+ };
+
+ bool free_icons;
+ bool isPressed;
+ bool togglemode;
+ PG_Button::STATE state;
+ int pressShift;
+ Uint16 iconindent;
+};
+
+PG_Button::PG_Button(PG_Widget* parent, const PG_Rect& r, const char* text, int id, const char* style) :
+ PG_Widget(parent, r)
+{
+ SetDirtyUpdate(false);
+
+ _mid = new PG_ButtonDataInternal;
+
+ SetText(text);
+ SetID(id);
+
+ //LoadThemeStyle(style);
+}
+
+PG_Button::~PG_Button() {
+ FreeSurfaces();
+ FreeIcons();
+
+ delete _mid;
+}
+/*
+void PG_Button::LoadThemeStyle(const char* widgettype) {
+ LoadThemeStyle("Button", "Button");
+ if(strcmp(widgettype, "Button") != 0) {
+ LoadThemeStyle(widgettype, "Button");
+ }
+}
+
+void PG_Button::LoadThemeStyle(const char* widgettype, const char* objectname) {
+ const char* s = NULL;
+ PG_Theme* t = PG_Application::GetTheme();
+
+ PG_Color fontcolor = GetFontColor();
+ t->GetColor(widgettype, objectname, "textcolor", fontcolor);
+ SetFontColor(fontcolor);
+
+ const char *iconup = 0, *icondown = 0, *iconover = 0;
+
+ switch (GetID()) {
+ case OK:
+ iconup = "ok_icon";
+ break;
+
+ case YES:
+ iconup = "yes_icon";
+ break;
+
+ case NO:
+ iconup = "no_icon";
+ break;
+
+ case APPLY:
+ iconup = "apply_icon";
+ break;
+
+ case CANCEL:
+ iconup = "cancel_icon";
+ break;
+
+ case CLOSE:
+ iconup = "close_icon";
+ break;
+
+ case HELP:
+ iconup = "help_icon";
+ break;
+
+ default:
+ iconup = "iconup";
+ icondown = "icondown";
+ iconover = "iconover";
+ break;
+ }
+
+ SetIcon(
+ t->FindSurface(widgettype, objectname, iconup),
+ t->FindSurface(widgettype, objectname, icondown),
+ t->FindSurface(widgettype, objectname, iconover)
+ );
+
+ PG_Gradient* g;
+ g = t->FindGradient(widgettype, objectname, "gradient0");
+ if(g) {
+ (*_mid)[UNPRESSED].gradState = *g;
+ }
+
+ g = t->FindGradient(widgettype, objectname, "gradient1");
+ if(g) {
+ (*_mid)[HIGHLITED].gradState = *g;
+ }
+
+ g = t->FindGradient(widgettype, objectname, "gradient2");
+ if(g) {
+ (*_mid)[PRESSED].gradState = *g;
+ }
+
+ SDL_Surface* background;
+ background = t->FindSurface(widgettype, objectname, "background0");
+ t->GetProperty(widgettype, objectname, "backmode0", (*_mid)[UNPRESSED].backMode);
+ SetBackground(UNPRESSED, background, (*_mid)[UNPRESSED].backMode);
+
+ background = t->FindSurface(widgettype, objectname, "background1");
+ t->GetProperty(widgettype, objectname, "backmode1", (*_mid)[PRESSED].backMode);
+ SetBackground(PRESSED, background, (*_mid)[PRESSED].backMode);
+
+ background = t->FindSurface(widgettype, objectname, "background2");
+ t->GetProperty(widgettype, objectname, "backmode2", (*_mid)[HIGHLITED].backMode);
+ SetBackground(HIGHLITED, background, (*_mid)[HIGHLITED].backMode);
+
+ t->GetProperty(widgettype, objectname, "blend0", (*_mid)[UNPRESSED].backBlend);
+ t->GetProperty(widgettype, objectname, "blend1", (*_mid)[PRESSED].backBlend);
+ t->GetProperty(widgettype, objectname, "blend2", (*_mid)[HIGHLITED].backBlend);
+
+ t->GetProperty(widgettype, objectname, "shift", _mid->pressShift);
+
+ t->GetProperty(widgettype, objectname, "bordersize", (*_mid)[UNPRESSED].bordersize);
+ t->GetProperty(widgettype, objectname, "bordersize", (*_mid)[PRESSED].bordersize);
+ t->GetProperty(widgettype, objectname, "bordersize", (*_mid)[HIGHLITED].bordersize);
+
+ t->GetProperty(widgettype, objectname, "bordersize0", (*_mid)[UNPRESSED].bordersize);
+ t->GetProperty(widgettype, objectname, "bordersize1", (*_mid)[PRESSED].bordersize);
+ t->GetProperty(widgettype, objectname, "bordersize2", (*_mid)[HIGHLITED].bordersize);
+
+ t->GetProperty(widgettype, objectname, "transparency0", (*_mid)[UNPRESSED].transparency);
+ t->GetProperty(widgettype, objectname, "transparency1", (*_mid)[PRESSED].transparency);
+ t->GetProperty(widgettype, objectname, "transparency2", (*_mid)[HIGHLITED].transparency);
+
+ t->GetProperty(widgettype, objectname, "iconindent", _mid->iconindent);
+
+ s = t->FindString(widgettype, objectname, "label");
+ if(s != NULL) {
+ SetText(s);
+ }
+
+ PG_Widget::LoadThemeStyle(widgettype, objectname);
+}
+*/
+void PG_Button::SetBorderColor(int b, const PG_Color& color) {
+ my_colorBorder[b][0] = color;
+}
+
+/** */
+void PG_Button::eventSizeWidget(Uint16 w, Uint16 h) {
+ FreeSurfaces();
+}
+
+/** */
+void PG_Button::FreeSurfaces() {
+/*@ PG_ThemeWidget::DeleteThemedSurface((*_mid)[UNPRESSED].srf);
+ (*_mid)[UNPRESSED].srf = NULL;
+
+ PG_ThemeWidget::DeleteThemedSurface((*_mid)[HIGHLITED].srf);
+ (*_mid)[HIGHLITED].srf = NULL;
+
+ PG_ThemeWidget::DeleteThemedSurface((*_mid)[PRESSED].srf);
+ (*_mid)[PRESSED].srf = NULL;
+*/
+}
+
+void PG_Button::FreeIcons() {
+
+ if(!_mid->free_icons) {
+ return;
+ }
+
+ if((*_mid)[UNPRESSED].srf_icon) {
+ SDL_FreeSurface((*_mid)[UNPRESSED].srf_icon); // false
+ (*_mid)[UNPRESSED].srf_icon = NULL;
+ }
+
+ if((*_mid)[HIGHLITED].srf_icon) {
+ SDL_FreeSurface((*_mid)[HIGHLITED].srf_icon); // false
+ (*_mid)[HIGHLITED].srf_icon = NULL;
+ }
+
+ if((*_mid)[PRESSED].srf_icon) {
+ SDL_FreeSurface((*_mid)[PRESSED].srf_icon); // false
+ (*_mid)[PRESSED].srf_icon = NULL;
+ }
+
+ _mid->free_icons = false;
+}
+
+/** */
+void PG_Button::eventMouseEnter() {
+ if (!(_mid->togglemode && _mid->isPressed)) {
+ _mid->state = HIGHLITED;
+ }
+
+ Update();
+ PG_Widget::eventMouseEnter();
+}
+
+/** */
+void PG_Button::eventMouseLeave() {
+
+ if(_mid->state == HIGHLITED) {
+ (_mid->togglemode && _mid->isPressed) ? _mid->state = PRESSED : _mid->state = UNPRESSED;
+ }
+
+ Update();
+ PG_Widget::eventMouseLeave();
+}
+
+/** */
+bool PG_Button::eventMouseButtonDown(const SDL_MouseButtonEvent* button) {
+ if (!button)
+ return false;
+
+ if(button->button == 1) {
+ _mid->state = PRESSED;
+ SetCapture();
+
+ Update();
+ return true;
+ }
+
+ return false;
+}
+
+/** */
+bool PG_Button::eventMouseButtonUp(const SDL_MouseButtonEvent* button) {
+ if (!button)
+ return false;
+
+ if(button->button != 1) {
+ return false;
+ }
+
+ //if the user moved the cursor out of the button, ignore the click
+ if (!IsMouseInside()) {
+ if (!_mid->togglemode || !_mid->isPressed) {
+ _mid->state = UNPRESSED;
+ }
+ ReleaseCapture();
+ Update();
+ return false;
+ }
+
+ if(_mid->togglemode) {
+ if(!_mid->isPressed) {
+ _mid->state = PRESSED;
+ _mid->isPressed = true;
+ } else {
+ _mid->state = HIGHLITED;
+ _mid->isPressed = false;
+ }
+ } else {
+ _mid->state = HIGHLITED;
+ _mid->isPressed = false;
+ }
+
+ ReleaseCapture();
+ Update();
+
+ sigClick(this);
+ return true;
+}
+
+/** */
+bool PG_Button::SetIcon(const char* filenameup, const char* filenamedown, const char* filenameover, const PG_Color& colorkey) {
+ if(!SetIcon(filenameup, filenamedown, filenameover)) {
+ return false;
+ }
+
+ if((*_mid)[UNPRESSED].srf_icon != NULL) {
+ SDL_SetColorKey((*_mid)[UNPRESSED].srf_icon, SDL_SRCCOLORKEY, colorkey);
+ }
+
+ if((*_mid)[HIGHLITED].srf_icon != NULL) {
+ SDL_SetColorKey((*_mid)[HIGHLITED].srf_icon, SDL_SRCCOLORKEY, colorkey);
+ }
+
+ if((*_mid)[PRESSED].srf_icon != NULL) {
+ SDL_SetColorKey((*_mid)[PRESSED].srf_icon, SDL_SRCCOLORKEY, colorkey);
+ }
+
+ return true;
+}
+
+bool PG_Button::SetIcon(const char* filenameup, const char* filenamedown, const char* filenameover) {
+ SDL_Surface* icon0 = IMG_Load(filenameup);
+ SDL_Surface* icon1 = IMG_Load(filenameover);
+ SDL_Surface* icon2 = IMG_Load(filenamedown);
+
+ if(icon0 == NULL) {
+ return false;
+ }
+
+ FreeIcons();
+
+ (*_mid)[UNPRESSED].srf_icon = icon0;
+ (*_mid)[HIGHLITED].srf_icon = icon1;
+ (*_mid)[PRESSED].srf_icon = icon2;
+ _mid->free_icons = true;
+
+ Update();
+ return true;
+}
+
+
+/** */
+bool PG_Button::SetIcon(SDL_Surface* icon_up, SDL_Surface* icon_down,SDL_Surface* icon_over) {
+
+ if(!icon_up && !icon_down && !icon_over) {
+ return false;
+ }
+
+ FreeIcons();
+
+ (*_mid)[UNPRESSED].srf_icon = icon_up;
+ (*_mid)[HIGHLITED].srf_icon = icon_over;
+ (*_mid)[PRESSED].srf_icon = icon_down;
+
+ _mid->free_icons = false;
+
+ return true;
+}
+
+SDL_Surface* PG_Button::GetIcon(STATE num) {
+ return (*_mid)[num].srf_icon;
+}
+
+/** */
+void PG_Button::SetBorderSize(int norm, int pressed, int high) {
+
+ if(norm >= 0) {
+ (*_mid)[UNPRESSED].bordersize = norm;
+ }
+
+ if(pressed >= 0) {
+ (*_mid)[PRESSED].bordersize = pressed;
+ }
+
+ if(high >= 0) {
+ (*_mid)[HIGHLITED].bordersize = high;
+ }
+}
+
+/** */
+void PG_Button::SetToggle(bool bToggle) {
+ _mid->togglemode = bToggle;
+}
+
+/** */
+void PG_Button::SetPressed(bool pressed) {
+ if(!_mid->togglemode)
+ return;
+
+ _mid->isPressed = pressed;
+ _mid->state = (_mid->isPressed ? PRESSED : UNPRESSED);
+
+ Update();
+}
+void PG_Button::SetTransparency(Uint8 t, bool bRecursive) {
+ (*_mid)[UNPRESSED].transparency = t;
+ (*_mid)[PRESSED].transparency = t;
+ (*_mid)[HIGHLITED].transparency = t;
+
+ if(!bRecursive || (GetChildList() == NULL)) {
+ return;
+ }
+
+ for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
+ i->SetTransparency(t, true);
+ }
+}
+
+/** */
+void PG_Button::SetTransparency(Uint8 norm, Uint8 pressed, Uint8 high) {
+ (*_mid)[UNPRESSED].transparency = norm;
+ (*_mid)[PRESSED].transparency = pressed;
+ (*_mid)[HIGHLITED].transparency = high;
+}
+
+/**
+ * Set the moving distance of the image when we press on it
+ */
+void PG_Button::SetShift(int pixelshift) {
+ _mid->pressShift = pixelshift;
+}
+
+
+/** */
+void PG_Button::eventButtonSurface(SDL_Surface** surface, STATE newstate, Uint16 w, Uint16 h) {
+ if (!surface)
+ return;
+
+ *surface = SDL_CreateRGBSurface( SDL_HWSURFACE, w, h, gamescreen->format->BitsPerPixel,
+ gamescreen->format->Rmask, gamescreen->format->Gmask, gamescreen->format->Bmask, gamescreen->format->Amask
+ );
+ SDL_FillRect(*surface, NULL, C_LIGHTGRAY);
+
+ //TODO Make something nice..
+ /*
+ PG_Rect r(0, 0, w, h);
+
+ // remove the old button surface (if there are no more references)
+ SDL_FreeSurface(*surface);
+
+ // create a new one
+ *surface = PG_ThemeWidget::CreateThemedSurface(
+ r,
+ &((*_mid)[newstate].gradState),
+ (*_mid)[newstate].background,
+ (*_mid)[newstate].backMode,
+ (*_mid)[newstate].backBlend);
+ */
+}
+
+/** */
+void PG_Button::SetGradient(STATE state, const PG_Gradient& gradient) {
+ (*_mid)[state].gradState = gradient;
+}
+
+void PG_Button::SetBackground(STATE state, SDL_Surface* background, int mode) {
+
+ if(!background) {
+ return;
+ }
+
+ (*_mid)[state].background = background;
+ (*_mid)[state].backMode = mode;
+}
+
+/** */
+bool PG_Button::GetPressed() {
+ if(_mid->togglemode) {
+ return _mid->isPressed;
+ } else {
+ return (_mid->state == PRESSED);
+ }
+}
+
+void PG_Button::eventBlit(SDL_Surface* srf, const PG_Rect& src, const PG_Rect& dst) {
+ PG_Rect rect = *this;
+ PG_Rect r;
+ PG_Rect my_src, my_dst;
+ SDL_Surface** surface;
+
+ Uint8 t = 0;
+
+ // check for surfaces
+ surface = &((*_mid)[UNPRESSED].srf);
+ if(*surface == NULL) {
+ FreeSurfaces();
+
+ eventButtonSurface(surface, UNPRESSED, w, h);
+ if(*surface) {
+ SDL_SetAlpha(*surface, SDL_SRCALPHA, 255-(*_mid)[UNPRESSED].transparency);
+ }
+
+ surface = &((*_mid)[PRESSED].srf);
+ eventButtonSurface(surface, PRESSED, w, h);
+ if(*surface) {
+ SDL_SetAlpha(*surface, SDL_SRCALPHA, 255-(*_mid)[PRESSED].transparency);
+ }
+
+ surface = &((*_mid)[HIGHLITED].srf);
+ eventButtonSurface(surface, HIGHLITED, w, h);
+ if(*surface) {
+ SDL_SetAlpha(*surface, SDL_SRCALPHA, 255-(*_mid)[HIGHLITED].transparency);
+ }
+ }
+
+ // get the right surface for the current state
+ t = (*_mid)[_mid->state].transparency;
+ srf = (*_mid)[_mid->state].srf;
+
+ // blit it
+ //@ SDL_LockSurface(gamescreen);
+
+ if(t != 255) {
+ SDL_SetAlpha(srf, SDL_SRCALPHA, 255-t);
+ PG_Draw::BlitSurface(srf, src, gamescreen, dst);
+ }
+
+ // check for icon srf
+ SDL_Surface* iconsrf;
+ if(_mid->state == PRESSED) {
+ if((*_mid)[PRESSED].srf_icon == 0) {
+ iconsrf = (*_mid)[UNPRESSED].srf_icon;
+ } else {
+ iconsrf = (*_mid)[PRESSED].srf_icon;
+ }
+ } else if(_mid->state == HIGHLITED) {
+ if((*_mid)[HIGHLITED].srf_icon == 0) {
+ iconsrf = (*_mid)[UNPRESSED].srf_icon;
+ } else {
+ iconsrf = (*_mid)[HIGHLITED].srf_icon;
+ }
+ } else {
+ iconsrf = (*_mid)[UNPRESSED].srf_icon;
+ }
+
+ int tw = my_width;
+ int shift = (((_mid->state == PRESSED) || (_mid->togglemode && _mid->isPressed)) ? 1 : 0) * _mid->pressShift;
+
+ if(iconsrf) {
+
+ int dx = my_text.empty() ? (rect.my_width - iconsrf->w) / 2 : _mid->iconindent;
+ int dy = (rect.my_height - iconsrf->h) >> 1;
+
+ r.my_xpos = rect.my_xpos + dx + shift;
+ r.my_ypos = rect.my_ypos + dy + shift;
+ r.my_width = iconsrf->w;
+ r.my_height = iconsrf->h;
+
+ // calc new cliprect for icon
+ GetClipRects(my_src, my_dst, r);
+
+ // blit the icon
+ PG_Draw::BlitSurface(iconsrf, my_src, gamescreen, my_dst);
+
+ tw -= (iconsrf->w + _mid->iconindent);
+ }
+
+ // draw the text
+ if(!my_text.empty()) {
+ Uint16 w, h;
+ GetTextSize(w, h);
+
+ int tx = (tw - w)/2 + shift;
+ int ty = ((my_height - h)/2) + shift;
+
+ if (iconsrf) {
+ tx += (iconsrf->w + _mid->iconindent);
+ }
+
+ DrawText(tx, ty, my_text.c_str());
+ }
+
+ int i0, i1;
+
+ if(!_mid->togglemode) {
+ i0 = (_mid->state == PRESSED) ? 1 : 0;
+ i1 = (_mid->state == PRESSED) ? 0 : 1;
+ } else {
+ i0 = (_mid->isPressed) ? 1 : 0;
+ i1 = (_mid->isPressed) ? 0 : 1;
+ }
+
+ SDL_LockSurface(gamescreen); //!
+ DrawBorder(PG_Rect(0, 0, Width(), Height()), (*_mid)[_mid->state].bordersize, i1 != 0);
+ SDL_UnlockSurface(gamescreen); //!
+
+ //@ SDL_UnlockSurface(gamescreen);
+}
+
+void PG_Button::SetBlendLevel(STATE mode, Uint8 blend) {
+ (*_mid)[mode].backBlend = blend;
+}
+
+Uint8 PG_Button::GetBlendLevel(STATE mode) {
+ return (*_mid)[mode].backBlend;
+}
+
+void PG_Button::SetSizeByText(int Width, int Height, const char *Text) {
+ Width += 2 * (*_mid)[UNPRESSED].bordersize + _mid->pressShift;
+
+ SDL_Surface* srf = (*_mid)[UNPRESSED].srf_icon;
+
+ if (srf == NULL) {
+ PG_Widget::SetSizeByText(Width, Height, Text);
+ eventSizeWidget(my_width, my_height);
+ return;
+ }
+
+ Uint16 w,h;
+ int baselineY;
+
+ if (Text == NULL) {
+ Text = my_text.c_str();
+ }
+
+ if (!PG_FontEngine::GetTextSize(Text, GetFont(), &w, &h, &baselineY)) {
+ return;
+ }
+
+ Uint16 dx = srf->w + Width;
+
+ my_width = (srf->w > w) ? dx : w + dx;
+ my_height = omMAX(srf->h, h + baselineY) + Height;
+
+ eventSizeWidget(my_width, my_height);
+}
+
+void PG_Button::SetIconIndent(Uint16 indent) {
+ _mid->iconindent = indent;
+}
diff --git a/src/paragui/pgbutton.h b/src/paragui/pgbutton.h
new file mode 100644
index 0000000..2f494a2
--- /dev/null
+++ b/src/paragui/pgbutton.h
@@ -0,0 +1,363 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgbutton.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+/** \file pgbutton.h
+ Header file for the PG_Button class.
+ This include file defines the standard button ID's and the PG_Button class.
+*/
+
+#ifndef PG_BUTTON_H
+#define PG_BUTTON_H
+
+#include "pgwidget.h"
+#include "pgsignals.h"
+#include "pgdraw.h"
+#include <string>
+
+
+class PG_ButtonDataInternal;
+
+
+/**
+ @author Alexander Pipelka
+
+ @short Button that uses themes.
+
+ @image html pgbutton.png "button screenshot"
+
+
+ Several predefined button IDs exist. All of them are associated with
+ default icons used automatically when the given ID is assigned to a
+ button:
+
+ @image html button_ok_icon.png "PG_Button::OK"
+
+ @image html button_yes_icon.png "PG_Button::YES"
+ @image html button_no_icon.png "PG_Button::NO"
+ @image html button_apply_icon.png "PG_Button::APPLY"
+ @image html button_cancel_icon.png "PG_Button::CANCEL"
+ @image html button_close_icon.png "PG_Button::CLOSE"
+ @image html button_help_icon.png "PG_Button::HELP"
+
+ \anchor theme_PG_Button
+
+ <h2>Theme support</h2><p>
+
+ <b>widget type:</b> Button (default)<br>
+ <b>object name:</b> Button<br>
+
+ <h3>Parent theme:</h3>
+
+ \ref theme_PG_Widget "PG_Widget" theme<br>
+
+ <h3>Theme sample:</h3>
+
+ \verbatim
+ <widget>
+ <type value="Button"/>
+ <object>
+ <name value="Button"/>
+ <filename name="background0" value="default/button_unpressed.png"/>
+ <filename name="background1" value="default/button_pressed.png"/>
+ <filename name="background2" value="default/button_highlighted.png"/>
+ <color name="textcolor" value="0x00ff9807"/>
+ <property name="backmode0" value="TILE"/>
+ <property name="backmode1" value="TILE"/>
+ <property name="backmode2" value="TILE"/>
+ <gradient name="gradient0"
+ color0="0x000000FF"
+ color1="0x000000FF"
+ color2="0x000000FF"
+ color3="0x000000FF"/>
+ <gradient name="gradient1"
+ color0="0x000000FF"
+ color1="0x000000FF"
+ color2="0x000000FF"
+ color3="0x000000FF"/>
+ <gradient name="gradient2"
+ color0="0x000000FF"
+ color1="0x000000FF"
+ color2="0x000000FF"
+ color3="0x000000FF"/>
+ <property name="blend0" value="0"/>
+ <property name="blend1" value="0"/>
+ <property name="blend2" value="0"/>
+ <property name="bordersize0" value="0"/>
+ <property name="bordersize1" value="0"/>
+ <property name="bordersize2" value="0"/>
+ <property name="transparency0" value="0"/>
+ <property name="transparency1" value="0"/>
+ <property name="transparency2" value="0"/>
+ <filename name="iconup" value="none"/>
+ <filename name="icondown" value="none"/>
+ </object>
+ </widget>
+ \endverbatim
+ <p>
+ <h2>Code:</h2><p>
+*/
+
+class PG_Button : public PG_Widget {
+public:
+
+ /**
+ Standard button IDs
+ */
+ enum {
+ OK = 0x80000001,
+ YES = 0x80000002,
+ NO = 0x80000003,
+ APPLY = 0x80000004,
+ CANCEL = 0x80000005,
+ CLOSE = 0x80000006,
+ HELP = 0x80000007
+ };
+
+ /**
+ Button states
+ **/
+ typedef enum {
+ PRESSED,
+ UNPRESSED,
+ HIGHLITED
+ } STATE;
+
+ /**
+ Signal type declaration
+ **/
+ template<class datatype = PG_Pointer> class SignalButtonClick : public PG_Signal1<PG_Button*, datatype> {};
+
+ /**
+ Constructor for the PG_Button class
+ @param parent pointer to the parent widget or NULL
+ @param r screen position of the button
+ @param id id of the button (can be used in callbacks)
+ @param text button label
+ @param style themestyle of the button
+ */
+ PG_Button(PG_Widget* parent, const PG_Rect& r = PG_Rect::null, const char* text = NULL, int id = -1, const char* style="Button");
+
+ /** */
+ virtual ~PG_Button();
+
+ /** */
+ //void LoadThemeStyle(const char* widgettype);
+
+ /** */
+ //void LoadThemeStyle(const char* widgettype, const char* objectname);
+
+ /**
+ Set the gradient.
+ @param state buttonstate to set
+ @param gradient gradient to set
+
+ This member function set's the buttons gradient for a specific state.
+ */
+ void SetGradient(STATE state, const PG_Gradient& gradient);
+
+ /**
+ Set the background.
+ @param state buttonstate to set
+ @param background pointer to background surface
+ @param mode background tiling mode
+
+ This member function set's the buttons background and tiling mode for a specific state.
+ */
+ void SetBackground(STATE state, SDL_Surface* background, int mode = BKMODE_TILE);
+
+ /**
+ Set the color of the border
+ @param b borderindex 0 = upper-left / 1 = lower-right
+ @param color border color (e.g. 0xRRGGBB)
+ */
+ void SetBorderColor(int b, const PG_Color& color);
+
+ /**
+ Set icons for the button
+ @param filenameup icon for unpressed state
+ @param filenamedown icon for pressed state
+ @param filenameover icon for highlited state
+ @return true on success
+ */
+ bool SetIcon(const char* filenameup=NULL, const char* filenamedown=NULL, const char* filenameover = NULL);
+
+ /**
+ Set icons for the button
+ @param filenameup icon for unpressed state
+ @param filenamedown icon for pressed state
+ @param filenameover icon for highlited state
+ @param colorkey the colorkey assigned to the icons
+ @return true on success
+ */
+ bool SetIcon(const char* filenameup, const char* filenamedown, const char* filenameover, const PG_Color& colorkey);
+
+ /**
+ Set icons for the buttons
+ @param icon_up the icon surface for the unpressed state
+ @param icon_down the icon for the pressed state
+ @param icon_over the icon for the highlited state
+ @return true on success
+
+ @note The user has to care for freeing the surfaces after the button is deleted!
+ */
+ bool SetIcon(SDL_Surface* icon_up, SDL_Surface* icon_down = NULL, SDL_Surface* icon_over = NULL);
+
+ /**
+ Returns an image for a given button state
+ @param num (NORM = icon for unpressed state | PRESSED = icon for pressed state | HIGH = icon for highlighted state)
+ @return a pointer to an SDL_Surface for the given icon
+ */
+ SDL_Surface* GetIcon(STATE num);
+
+ /**
+ Set the distance between the left border of the button and the icon
+ @param indent spacing between widget border and icon
+ */
+ void SetIconIndent(Uint16 indent);
+
+ /**
+ Set the bordersize of the button
+ @param norm bordersize for unpressed state
+ @param pressed bordersize for pressed state
+ @param high bordersize for highlighted state
+ @return a pointer to an SDL_Surface for the given icon
+
+ If you don't want to set the bordersize for one of the states, set it to -1.
+ */
+ void SetBorderSize(int norm, int pressed, int high);
+
+ /**
+ Make the button a toggle button.
+ A normal (push) button will return to an unpressed state when the user
+ stops clicking it (releases the mouse button).
+ A toggle button will stay pressed once it is pressed. The user
+ must click the button a second time in order to unpress it.
+ */
+ void SetToggle(bool bToggle);
+
+ /**
+ If the button is a toggle button you can modify the status of the button
+ with this function
+ */
+ void SetPressed(bool pressed);
+
+ /**
+ Set the transparency of the button
+ @param t the transparency you want to assign
+ @param bRecursive if set to true, apply the transparency to all child widgets
+ */
+ void SetTransparency(Uint8 t, bool bRecursive = false);
+
+ /**
+ Set the transparency for the single button states
+ @param norm the transparency of the normal (unpressed) state
+ @param pressed the transparency of the pressed state
+ @param high the transparency of the highlited state
+ */
+ void SetTransparency(Uint8 norm, Uint8 pressed, Uint8 high);
+
+ /**
+ Set the moving distance of the image when we press on it
+ @param pixelshift int number of pixels to shift
+ */
+ void SetShift(int pixelshift);
+
+ /**
+ Determine whether a given button is pressed. This can either mean
+ that the user is clicking the button in the case of a push button,
+ or that the button is toggled in the case of a toggle button.
+ @return bool is the button pressed
+ */
+ bool GetPressed();
+
+ /**
+ Set the blend-level of gradient and background image
+ @param blend blend-level
+ @param mode one of BTN_STATE_NORMAL, BTN_STATE_PRESSED, BTN_STATE_HIGH
+ This function sets the blend level of gradient and background image.
+
+ If the blend-level is 0 only the background image is visible.
+ At a level of 255 only the gradient is visible.
+ */
+ void SetBlendLevel(STATE mode, Uint8 blend);
+
+ /**
+ Get the current blend level.
+ @param mode button mode
+ @return the current blend level
+ */
+ Uint8 GetBlendLevel(STATE mode);
+
+ /**
+ Resizes the button so that a specified text fits on it
+ @param Width additional width apart from the width required by the text
+ @param Height additional height apart from the one required by the text
+ @param text the text which is to fit on the button
+ */
+ void SetSizeByText(int Width = 0, int Height = 0, const char *Text = NULL);
+
+ SignalButtonClick<> sigClick;
+
+protected:
+
+ /** */
+ virtual void eventButtonSurface(SDL_Surface** surface, STATE newstate, Uint16 w, Uint16 h);
+
+ /** */
+ void eventBlit(SDL_Surface* surface, const PG_Rect& src, const PG_Rect& dst);
+
+ /** */
+ void eventSizeWidget(Uint16 w, Uint16 h);
+
+ /** */
+ void eventMouseLeave();
+
+ /** */
+ void eventMouseEnter();
+
+ /** */
+ bool eventMouseButtonUp(const SDL_MouseButtonEvent* button);
+
+ /** */
+ bool eventMouseButtonDown(const SDL_MouseButtonEvent* button);
+
+private:
+
+ PG_Button(const PG_Button&);
+ PG_Button& operator=(const PG_Button&);
+
+ /** */
+ void FreeSurfaces();
+
+ /** */
+ void FreeIcons();
+
+ PG_ButtonDataInternal* _mid;
+};
+
+#endif // PG_BUTTON_H
diff --git a/src/paragui/pgcolor.cpp b/src/paragui/pgcolor.cpp
new file mode 100644
index 0000000..00a4fcb
--- /dev/null
+++ b/src/paragui/pgcolor.cpp
@@ -0,0 +1,51 @@
+//
+// C++ Implementation: pgcolor
+//
+// Description:
+//
+//
+// Author: Alexander Pipelka <pipelka@pipelka.net>, (C) 2003
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#include "pgcolor.h"
+
+PG_Color::PG_Color() {
+ r = 0;
+ g = 0;
+ b = 0;
+}
+
+PG_Color::PG_Color(const SDL_Color& c) {
+ *this = c;
+}
+
+PG_Color::PG_Color(Uint32 c) {
+ *this = c;
+}
+
+PG_Color::PG_Color(Uint8 r, Uint8 g, Uint8 b) {
+ *this = (Uint32)((r << 16) | (g << 8) | b);
+}
+
+PG_Color& PG_Color::operator=(const SDL_Color& c) {
+ r = c.r;
+ g = c.g;
+ b = c.b;
+
+ return *this;
+}
+
+PG_Color& PG_Color::operator=(Uint32 c) {
+ r = (c >> 16) & 0xFF;
+ g = (c >> 8) & 0xFF;
+ b = c & 0xFF;
+
+ return *this;
+}
+
+PG_Color::operator Uint32() const {
+ return (r << 16) | (g << 8) | b;
+}
diff --git a/src/paragui/pgcolor.h b/src/paragui/pgcolor.h
new file mode 100644
index 0000000..c1fe340
--- /dev/null
+++ b/src/paragui/pgcolor.h
@@ -0,0 +1,60 @@
+//
+// C++ Interface: pgcolor
+//
+// Description:
+//
+//
+// Author: Alexander Pipelka <pipelka@pipelka.net>, (C) 2003
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#ifndef PG_COLOR_H
+#define PG_COLOR_H
+
+#include "SDL.h"
+
+/** @class PG_Color
+
+ @short Allows for an abstraction of a particular color.
+
+ The purpose of this is to allow one to create new colors. If one is interested
+ in using predefined color constants, see pgcolors.h (note the letter "s" at the end.)
+ A PG_Color can be created from an SDL_Color, a Uint32, or RGB based system.
+
+ @author Alexander Pipelka
+*/
+
+class PG_Color : public SDL_Color {
+public:
+ PG_Color();
+ PG_Color(const SDL_Color& c);
+ PG_Color(Uint32 c);
+ PG_Color(Uint8 r, Uint8 g, Uint8 b);
+
+ PG_Color& operator=(const SDL_Color& c);
+
+ PG_Color& operator=(Uint32 c);
+
+ operator Uint32() const;
+
+ inline Uint32 MapRGB(SDL_PixelFormat* format) const {
+ return SDL_MapRGB(format, r, g, b);
+ }
+
+ inline Uint32 MapRGBA(SDL_PixelFormat* format, Uint8 a) const {
+ return SDL_MapRGBA(format, r, g, b, a);
+ }
+
+ inline bool operator!=(const PG_Color& c) const {
+ return ((r != c.r) || (g != c.g) || (b != c.b));
+ }
+};
+
+//! Structure for widget gradients
+typedef struct {
+ PG_Color colors[4]; //!< array of gradient colors
+} PG_Gradient;
+
+#endif // PG_COLOR_H
diff --git a/src/paragui/pgdatacontainer.cpp b/src/paragui/pgdatacontainer.cpp
new file mode 100644
index 0000000..5f52abc
--- /dev/null
+++ b/src/paragui/pgdatacontainer.cpp
@@ -0,0 +1,85 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgdatacontainer.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pgdatacontainer.h"
+
+PG_DataContainer::PG_DataContainer(Uint32 size) {
+ if(size == 0) {
+ my_data = NULL;
+ my_size = 0;
+ }
+
+ my_data = new char[size];
+ my_size = size;
+}
+
+PG_DataContainer::~PG_DataContainer() {
+ if(my_data != NULL) {
+ delete[] my_data;
+ }
+}
+
+
+Uint32 PG_DataContainer::size() {
+ return my_size;
+}
+
+char* PG_DataContainer::data() {
+ return my_data;
+}
+
+PG_DataContainer *PG_DataContainer::ReadFromFile(const char *filename)
+{
+ FILE *File= fopen(filename, "rb");
+ if (NULL == File)
+ {
+ return NULL;
+ }
+ if (fseek(File, 0, SEEK_END)) {
+ fclose(File);
+ return NULL;
+ }
+
+ fpos_t Filesize;
+ if (fgetpos(File, &Filesize)) {
+ fclose(File);
+ return NULL;
+ }
+ fseek(File, 0, SEEK_SET);
+
+ PG_DataContainer *Container= new PG_DataContainer((Uint32)Filesize);
+ size_t BytesRead= fread(Container->data(), 1, (Uint32)Filesize, File);
+ if ( BytesRead < Filesize)
+ {
+ fclose(File);
+ delete Container;
+ return NULL;
+ }
+ fclose(File);
+ return Container;
+}
diff --git a/src/paragui/pgdatacontainer.h b/src/paragui/pgdatacontainer.h
new file mode 100644
index 0000000..f3f2930
--- /dev/null
+++ b/src/paragui/pgdatacontainer.h
@@ -0,0 +1,84 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgdatacontainer.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+/** \file pgdatacontainer.h
+ Header file of the PG_DataContainer class.
+*/
+
+#ifndef PG_DATACONTAINER
+#define PG_DATACONTAINER
+
+#include "SDL.h"
+
+/**
+ @short A container for binary data
+ @author Alexander Pipelka
+
+ This class is a container to hold binary data (imagedata, fonts,...).
+*/
+
+class PG_DataContainer {
+public:
+
+ /**
+ Constructor
+ @param size number of bytes to allocate
+
+ Creates a container which can hold "size" number of bytes.
+ */
+ PG_DataContainer(Uint32 size);
+
+ /**
+ Destructor
+
+ Deletes the object and frees to allocated memory.
+ */
+ virtual ~PG_DataContainer();
+
+ /**
+ return the number of bytes allocated by the container
+ @return number of bytes allocated
+ */
+ Uint32 size();
+
+ /**
+ access to the internal data
+ @return pointer to allocated memory
+ */
+ char* data();
+
+
+ static PG_DataContainer *ReadFromFile(const char *filename);
+
+
+private:
+ char* my_data;
+ Uint32 my_size;
+};
+
+#endif // PG_DATACONTAINER
diff --git a/src/paragui/pgdraw.h b/src/paragui/pgdraw.h
new file mode 100644
index 0000000..56a48c8
--- /dev/null
+++ b/src/paragui/pgdraw.h
@@ -0,0 +1,308 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgdraw.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+/** \file pgdraw.h
+ Header file for the PG_Draw namespace.
+ @author Alexander Pipelka
+*/
+
+#ifndef PG_DRAW_H
+#define PG_DRAW_H
+
+#include "pgrect.h"
+#include "pgcolor.h"
+
+#ifndef M_PI
+/**
+ The definition of the number PI.
+ Some platforms dont define M_PI. So we have to define it.
+*/
+#define M_PI 3.14159265359
+#endif // M_PI
+
+
+// Background modes
+
+/**
+ Backgroundmode TILE.
+ Macro defining the background mode for tiling
+*/
+#define BKMODE_TILE 1
+/**
+ Backgroundmode STRETCH.
+ Macro defining the background mode for stretching
+*/
+#define BKMODE_STRETCH 2
+/**
+ Backgroundmode 3TILEH.
+ Macro defining the background mode for horizontal 3 part tiling
+ (the left part of the tile to the left, the right part to the right,
+ the middle part repeatedly within the rest)
+*/
+#define BKMODE_3TILEH 3
+/**
+ Backgroundmode 3TILEV.
+ Macro defining the background mode for vertical 3 part tiling
+*/
+#define BKMODE_3TILEV 4
+/**
+ Backgroundmode 9TILE.
+ Macro defining the background mode for 9 part tiling
+*/
+#define BKMODE_9TILE 5
+
+/**
+ @short ParaGUI drawing functions
+
+ These functions can be used for native drawing on surfaces.
+*/
+
+namespace PG_Draw {
+
+//! Rotate and scale an SDL_Surface
+/*!
+ Rotates and scales a 32bit or 8bit SDL_Surface to newly created
+ destination surface. If smooth is 1 the destination 32bit surface is
+ anti-aliased. If the surface is not 8bit or 32bit RGBA/ABGR it will
+ be converted into a 32bit RGBA format on the fly.
+
+ \param src source surface
+ \param angle the rotation in degrees
+ \param zoom the scaling factor
+ \param smooth whether or not to use anti-aliasing
+
+ \return A new surface with the scaled, rotated original surface.
+*/
+
+SDL_Surface* RotoScaleSurface(SDL_Surface *src, double angle,
+ double zoom, bool smooth = true);
+
+//! Scale an SDL_Surface
+/*!
+ Scales a 32bit or 8bit SDL_Surface to newly created destination
+ surface. If the surface is not 8bit or 32bit RGBA/ABGR it will be
+ converted into a 32bit RGBA format on the fly.
+
+ \param src source surface
+ \param zoomx, zoomy width and height scaling factors
+ \param smooth whether or not to enable anti-aliasing
+
+ \return A newly created surface with the scaled surface
+*/
+SDL_Surface* ScaleSurface(SDL_Surface *src, double zoomx, double zoomy,
+ bool smooth = true);
+
+//! Scale an SDL_Surface
+/*!
+ Scales a 32bit or 8bit SDL_Surface to newly created destination
+ surface. If the surface is not 8bit or 32bit RGBA/ABGR it will be
+ converted into a 32bit RGBA format on the fly.
+
+ \param src source surface
+ \param rect PG_Rect specifying the width and height of the new surface
+ \param smooth whether or not to enable anti-aliasing
+
+ \return A newly created surface with the scaled surface
+*/
+static inline SDL_Surface *ScaleSurface(SDL_Surface *src, const PG_Rect &rect,
+ bool smooth = true) {
+ return ScaleSurface(src, static_cast<double>(rect.w) / src->w,
+ static_cast<double>(rect.h) / src->h, smooth);
+}
+
+//! Scale an SDL_Surface
+/*!
+ Scales a 32bit or 8bit SDL_Surface to newly created destination
+ surface. If the surface is not 8bit or 32bit RGBA/ABGR it will be
+ converted into a 32bit RGBA format on the fly.
+
+ \param src source surface
+ \param newx, newy the width and height of the new surface
+ \param smooth whether or not to enable anti-aliasing
+
+ \return A newly created surface with the scaled surface
+*/
+static inline SDL_Surface *ScaleSurface(SDL_Surface *src, Uint16 newx, Uint16 newy,
+ bool smooth = true) {
+ return ScaleSurface(src, static_cast<double>(newx) / src->w,
+ static_cast<double>(newy) / src->h, smooth);
+}
+
+//! Scale and blit surface
+/*!
+ Scales a 32 bit or 8 bit SDL_Surface to the size of the destination
+ surface dst and blits the result to the destination surface. If the
+ surface is not 8bit or 32bit RGBA/ABGR it will be converted into a
+ 32bit RGBA format on the fly.
+
+ \param src Source surface
+ \param dst destination surface
+ \param smooth whether or not to use anti-aliasing */
+void BlitScale(SDL_Surface *src, SDL_Surface *dst, bool smooth = true);
+
+/**
+ Creates a surface filled with a gradient
+
+ @param r the dimensions of the surface to be created
+ @param gradient the gradient colors to use (order: ul(upper left), ur, dl, dr)
+ @return a SDL_Surface pointer to the new surface
+
+ This function creates a new surface filled with a given gradient defined by a set of colors
+*/
+SDL_Surface* CreateGradient(const PG_Rect& r, PG_Gradient& gradient);
+
+/**
+ Creates a surface filled with a gradient
+
+ @param r the dimensions of the surface to be created
+ @param ul upper/left gradient color
+ @param ur upper/right gradient color
+ @param dl lower/left gradient color
+ @param dr lower/right gradient color
+ @return a SDL_Surface pointer to the new surface
+
+ This function creates a new surface filled with a given gradient defined by a set of colors
+*/
+SDL_Surface* CreateGradient(const PG_Rect& r, const PG_Color& ul, const PG_Color& ur, const PG_Color& dl, const PG_Color& dr);
+
+/**
+ Draw a gradient on a surface
+
+ @param surface the surface to draw the gradient to
+ @param r the rectangle where the gradient should be drawn
+ @param gradient the gradient colors (order: ul(upper left), ur, dl, dr)
+
+ \note If the surface is clipped, the gradient is only drawn within
+ the intersection of the clipping rect and r.
+*/
+void DrawGradient(SDL_Surface* surface, const PG_Rect& r, PG_Gradient& gradient);
+
+/**
+ Draw a gradient on a surface
+
+ @param surface the surface to draw the gradient to
+ @param rect the rectangle where the gradient should be drawn
+ @param ul upper/left gradient color
+ @param ur upper/right gradient color
+ @param dl lower/left gradient color
+ @param dr lower/right gradient color
+
+ This function is the same as the other one above except that the gradient
+ colors are the arguments instead of a gradient.
+*/
+void DrawGradient(SDL_Surface * surface, const PG_Rect& rect, const PG_Color& ul, const PG_Color& ur, const PG_Color& dl, const PG_Color& dr);
+
+/**
+ Create a new SDL surface
+ @param w width of the new surface
+ @param h height of the new surface
+ @param flags surface-flags (default = SDL_SWSURFACE)
+ @return pointer to the new surface
+ This function creates a new SDL surface
+*/
+SDL_Surface* CreateRGBSurface(Uint16 w, Uint16 h, int flags = SDL_SWSURFACE);
+
+/**
+ Draw a 'themed' surface
+
+ @param surface the surface to draw on
+ @param r the rectangle of the surface to draw in
+ @param gradient pointer to a gradient structure (may be NULL)
+ @param background pointer to a background surface (may be NULL)
+ @param bkmode the mode how to fill in the background surface (BKMODE_TILE | BKMODE_STRETCH | BKMODE_3TILEH | BKMODE_3TILEV | BKMODE_9TILE)
+ @param blend the blend-level between gradient an background; the
+ higher the blend level the more transparent the background is.
+
+ \note This function first draws the gradient, then the (partly transparent) background.
+*/
+void DrawThemedSurface(SDL_Surface* surface, const PG_Rect& r, PG_Gradient* gradient, SDL_Surface* background, int bkmode, Uint8 blend);
+
+/**
+ Draw a line.
+ @param surface destination surface
+ @param x0 x startposition
+ @param y0 y startposition
+ @param x1 x endposition
+ @param y1 y endposition
+ @param color color of the line
+ @param width width of the line
+
+ Draws a line with given color and width onto a surface.
+*/
+void DrawLine(SDL_Surface* surface, Uint32 x0, Uint32 y0, Uint32 x1, Uint32 y1, const PG_Color& color, Uint8 width = 1);
+
+/**
+ Set a pixel.
+ @param x x position
+ @param y y position
+ @param c color
+ @param surface destination surface
+
+ \note This function assumes that the surface has already been locked if
+ neccessary.
+*/
+void SetPixel(int x, int y, const PG_Color& c, SDL_Surface * surface);
+
+/**
+ replacement for SDL_BlitSurface
+ @param srf_src source surface
+ @param rect_src PG_Rect of the source rectangle
+ @param srf_dst destination surface
+ @param rect_dst PG_Rect of the destination rectangle
+
+ This function simply replaces SDL_BlitSurface and uses PG_Rect instead of SDL_Rect.
+*/
+inline void BlitSurface(SDL_Surface* srf_src, const PG_Rect& rect_src, SDL_Surface* srf_dst, const PG_Rect& rect_dst) {
+ SDL_BlitSurface(srf_src, (PG_Rect*)&rect_src, srf_dst, (PG_Rect*)&rect_dst);
+}
+
+/**
+ Tiles a surface with a given image
+
+ @param surface the surface to draw to
+ @param ref unused, to be removed
+ @param drawrect the area on the surface you want to draw to
+ @param tilemap the image you want to tile the surface with
+
+ This function takes the tilemap and repeatedly blits it on the surface.
+ If drawrect->w is not a multiple of tilemap->w (the same with the height),
+ the tiles on the right or lower border are cut off appropriately.
+ */
+void DrawTile(SDL_Surface* surface, const PG_Rect& ref, const PG_Rect& drawrect, SDL_Surface* tilemap);
+
+#ifndef DOXYGEN_SKIP
+// These will disappear (moved to another lib)
+void RectStretch(SDL_Surface* src_surface, int xs1, int ys1, int xs2, int ys2, SDL_Surface* dst_surface, int xd1, int yd1, int xd2, int yd2, Uint32* voiLUT);
+void CreateFilterLUT();
+void PG_SmoothFast(SDL_Surface* src, SDL_Surface* dst);
+void InterpolatePixel(SDL_Surface* src, SDL_Surface* dest);
+#endif // DOXYGEN_SKIP
+
+} // namespace PG_Draw
+
+#endif // PG_DRAW_H
diff --git a/src/paragui/pgdrawline.cpp b/src/paragui/pgdrawline.cpp
new file mode 100644
index 0000000..61bd14e
--- /dev/null
+++ b/src/paragui/pgdrawline.cpp
@@ -0,0 +1,205 @@
+/*
+ ParaGUI - crossplatform widgetset
+ drawline - line drawing algo
+
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgdrawline.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pgdraw.h"
+
+void plotpixel(SDL_Surface* surface, Uint32 x, Uint32 y, const PG_Color& c, Uint8 width, int *pixelflag) {
+ Uint32 xp, yp, xf, yf;
+ static Uint32 oldx, oldy;
+
+ // width=1? Only need to draw 1 pixel
+ if(width==1) {
+ PG_Draw::SetPixel(x, y, c, surface);
+ } else {
+
+ // calculate new pixel position (shifts are faster)
+ xp=x-((width-1) >> 1);
+ yp=y-((width-1) >> 1);
+
+ // beginning of line?
+ if (*pixelflag==0) {
+
+ *pixelflag=1;
+
+ // draw all pixels needed
+ for (xf=0; xf<width; xf++) {
+ for (yf=0; yf<width; yf++) {
+ PG_Draw::SetPixel(xf+xp, yf+yp, c, surface);
+ }
+ }
+ }
+ // not the offspring of line
+
+ else {
+
+ // moved down a pixel?
+ if (yp>oldy) {
+
+ // only need to draw the bottom pixels
+ for (xf=0; xf<width; xf++) {
+ PG_Draw::SetPixel(xf+xp, yp-1+(width-1), c, surface);
+ }
+ }
+
+ // moved right a pixel
+ if (xp>oldx) {
+ // only need to draw the most right pixels
+ for (yf=0; yf<width; yf++) {
+ PG_Draw::SetPixel(xp-1+(width-1), yp+yf, c, surface);
+ }
+ }
+
+ // moved left a pixel
+ if (xp<oldx) {
+
+ // only need to draw the most left pixels
+ for (yf=0; yf<width; yf++) {
+ PG_Draw::SetPixel(xp+1, yp+yf, c, surface);
+ }
+ }
+
+ // store actual pixel positions
+ oldx=xp;
+ oldy=yp;
+ }
+ }
+}
+
+void octant0(SDL_Surface* surface, Uint32 x0, Uint32 y0, Uint32 deltax, Uint32 deltay,
+ int xdirection, const PG_Color& color, Uint8 width, int pixelflag)
+{
+ int deltay2;
+ int error;
+ int deltay2deltax2; /* delta y2 - deltax2 */
+
+ /* setup intial error used in drawing loop */
+ deltay2 = deltay << 1;
+ deltay2deltax2 = deltay2 - (int)(deltax << 1);
+ error = deltay2 - (int)deltax;
+
+ /* draw the line */
+ plotpixel(surface, x0, y0, color, width, &pixelflag); /* draw first pixel */
+ while(deltax--) {
+ /* test to advance the y coordinate */
+ if (error >= 0) {
+ /* advance y coordinate and adjust the error term */
+ y0++;
+ error += deltay2deltax2;
+ } /* end of the if */
+ else {
+ /* add to the error term */
+ error += deltay2;
+ } /* end of if else */
+
+ x0 += xdirection; /* advance the x coordinate */
+ plotpixel(surface, x0, y0, color, width, &pixelflag);
+ } /* end of the while */
+
+} /* end of the function */
+
+void octant1(SDL_Surface* surface, Uint32 x0, Uint32 y0, Uint32 deltax, Uint32 deltay,
+ int xdirection, const PG_Color& color, Uint8 width, int pixelflag)
+{
+ int deltax2;
+ int error;
+ int deltax2deltay2; /* delta x2 - deltay2 */
+
+ /* setup intial error used in drawing loop */
+ deltax2 = deltax << 1;
+ deltax2deltay2 = deltax2 - (int)(deltay << 1);
+ error = deltax2 - (int)deltay;
+
+ /* draw the line */
+ plotpixel(surface, x0, y0, color, width, &pixelflag); /* draw first pixel */
+ while(deltay--) {
+ /* test to advance the y coordinate */
+ if (error >= 0) {
+ /* advance y coordinate and adjust the error term */
+ x0 += xdirection;
+ error += deltax2deltay2;
+ } /* end of the if */
+ else {
+ /* add to the error term */
+ error += deltax2;
+ } /* end of if else */
+
+ y0++; /* advance the x coordinate */
+ plotpixel(surface, x0, y0, color, width, &pixelflag);
+
+ } /* end of the while */
+
+} /* end of the function */
+
+void PG_Draw::DrawLine(SDL_Surface* surface, Uint32 x0, Uint32 y0, Uint32 x1, Uint32 y1, const PG_Color& color, Uint8 width) {
+ int deltax;
+ int deltay;
+ int temp;
+ int pixelflag;
+
+ if (!width || !surface)
+ return;
+
+ pixelflag=0;
+
+ /* swap y0 with y1 if y0 is greater than y1 */
+ if (y0 > y1) {
+ temp = y0;
+ y0 = y1;
+ y1 = temp;
+ temp = x0; /* switch the xs */
+ x0 = x1;
+ x1 = temp;
+
+ } /* end of the if */
+
+ /* handle four separate cases */
+ deltax = x1 - x0;
+ deltay = y1 - y0;
+ if (deltax > 0) {
+ if (deltax > deltay) {
+ octant0(surface, x0, y0, deltax, deltay, 1, color, width, pixelflag);
+ } /* end of if */
+ else {
+ octant1(surface, x0, y0, deltax, deltay, 1, color, width, pixelflag);
+ } /* end if else */
+
+ } /* end of the if */
+ else {
+ deltax = -deltax; /* abs value of delta x */
+ if (deltax > deltay) {
+ octant0(surface, x0, y0, deltax, deltay, -1, color, width, pixelflag);
+ } /* end of the if */
+ else {
+ /* not correct yet */
+ octant1(surface, x0, y0, deltax, deltay, -1, color, width, pixelflag);
+ } /* end of if-else */
+ } /* end of if - else */
+
+} /* end of the function */
diff --git a/src/paragui/pgfacecache.h b/src/paragui/pgfacecache.h
new file mode 100644
index 0000000..a0b8e5f
--- /dev/null
+++ b/src/paragui/pgfacecache.h
@@ -0,0 +1,63 @@
+#include "SDL.h"
+#include "pgdatacontainer.h"
+
+#define FT_FLOOR(X) ((X & -64) / 64)
+#define FT_CEIL(X) (((X + 63) & -64) / 64)
+#define PG_FITALIC_ANGLE 0.26f
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_ERRORS_H
+#include FT_CACHE_H
+#include FT_CACHE_IMAGE_H
+#include FT_CACHE_SMALL_BITMAPS_H
+
+#ifdef HASH_MAP_INC
+#include HASH_MAP_INC
+#endif
+#include <map>
+
+class PG_GlyphCacheItem : public PG_DataContainer {
+public:
+ PG_GlyphCacheItem(Uint32 size) : PG_DataContainer(size) {
+ };
+
+ int Glyph_Index;
+ FT_Bitmap Bitmap;
+
+ int Bitmap_left;
+ int Bitmap_top;
+ int Advance_x;
+};
+
+typedef std::map<int, PG_GlyphCacheItem*> PG_GlyphCache;
+
+class PG_FontFaceCacheItem {
+public:
+
+ PG_FontFaceCacheItem() {
+ Face = NULL;
+ };
+
+ virtual ~PG_FontFaceCacheItem() {
+ for(PG_GlyphCache::iterator i = GlyphCache.begin(); i != GlyphCache.end(); i++) {
+ delete (*i).second;
+ }
+ FT_Done_Face(Face);
+ };
+
+ FT_Face Face;
+ PG_GlyphCache GlyphCache;
+
+ //Additional font paramters - usable for style
+ int Bold_Offset;
+ int Underline_Height;
+
+ int Ascent;
+ int Descent;
+ int Height;
+ int LineSkip;
+
+ int Use_Kerning;
+ FT_F26Dot6 fontsize;
+};
diff --git a/src/paragui/pgfont.cpp b/src/paragui/pgfont.cpp
new file mode 100644
index 0000000..46b34c7
--- /dev/null
+++ b/src/paragui/pgfont.cpp
@@ -0,0 +1,788 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgfont.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "common.h"
+#include "pgfont.h"
+#include "pgfacecache.h"
+
+//#define OLD_TEXTRENDERING
+
+//SDL_Surface* PG_FontEngine::my_charSurface = NULL;
+PG_FontEngine::MAP_FONTS PG_FontEngine::my_fontcache;
+FT_Library PG_FontEngine::my_library;
+
+PG_FontEngine::PG_FontEngine() {
+ FT_Init_FreeType(&my_library);
+}
+
+PG_FontEngine::~PG_FontEngine() {
+
+ // clean fontcache
+ for(MAP_FONTS::iterator i = my_fontcache.begin(); i != my_fontcache.end(); i++) {
+ delete (*i).second;
+ }
+ my_fontcache.clear();
+
+ FT_Done_FreeType(my_library);
+}
+
+void PG_FontEngine::FontEngineError(FT_Error error) {
+#undef __FTERRORS_H__
+#define FT_ERRORDEF( e, v, s ) { e, s },
+#define FT_ERROR_START_LIST {
+#define FT_ERROR_END_LIST { -1, NULL } };
+ const struct {
+ int err_code;
+ const char *err_msg;
+ }
+ ft_errors[] =
+#include FT_ERRORS_H
+
+ int i = 0;
+ while (ft_errors[i].err_code != -1) {
+ if (ft_errors[i].err_code == error) {
+ debug("FreeType error %d : %s",error,ft_errors[i].err_msg);
+ return;
+ }
+ i++;
+ }
+
+ debug("FreeType : Unknown error : %d", error);
+ return;
+}
+
+/*bool PG_FontEngine::PG_GetFontFace(PG_Font* Param) {
+ PG_FontFaceCacheItem* CacheItem = LoadFontFace(
+ Param->GetName(),
+ Param->GetSize());
+
+ Param->SetFaceCache(CacheItem);
+
+ return (Param->GetFaceCache() != NULL);
+}*/
+
+PG_GlyphCacheItem* PG_FontEngine::GetGlyph(PG_Font *Param, int glyph_index) {
+
+ PG_FontFaceCacheItem* facecache = Param->GetFaceCache();
+ PG_GlyphCacheItem *GlyphCacheItem = facecache->GlyphCache[glyph_index];
+
+ if(GlyphCacheItem != NULL) {
+ return GlyphCacheItem;
+ }
+
+ FT_Face face = facecache->Face;
+
+ if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER ))
+ return NULL;
+
+ Uint32 bitmapsize = face->glyph->bitmap.pitch * face->glyph->bitmap.rows;
+ GlyphCacheItem = new PG_GlyphCacheItem(bitmapsize);
+
+ GlyphCacheItem->Glyph_Index = glyph_index;
+ GlyphCacheItem->Bitmap = face->glyph->bitmap;
+ GlyphCacheItem->Bitmap_left = face->glyph->bitmap_left;
+ GlyphCacheItem->Bitmap_top = face->glyph->bitmap_top;
+ GlyphCacheItem->Advance_x = FT_CEIL(face->glyph->metrics.horiAdvance);
+ memcpy(GlyphCacheItem->data(), face->glyph->bitmap.buffer, bitmapsize);
+ GlyphCacheItem->Bitmap.buffer = (unsigned char*)GlyphCacheItem->data();
+
+ facecache->GlyphCache[glyph_index] = GlyphCacheItem;
+ return GlyphCacheItem;
+}
+
+#ifndef OLD_TEXTRENDERING
+
+template < class DT >
+inline void BlitTemplate(DT pixels, SDL_Surface* Surface, FT_Bitmap *Bitmap, int PosX, int PosY, int x0, int x1, int y0, int y1, PG_Font *Param) {
+ int xw = x1-x0;
+
+ SDL_PixelFormat* format = Surface->format;
+ Uint8 Rloss = format->Rloss;
+ Uint8 Gloss = format->Gloss;
+ Uint8 Bloss = format->Bloss;
+ Uint8 Aloss = format->Aloss;
+ Uint8 Rloss8 = 8-Rloss;
+ Uint8 Gloss8 = 8-Gloss;
+ Uint8 Bloss8 = 8-Bloss;
+ Uint8 Aloss8 = 8-Aloss;
+ Uint8 Rshift = format->Rshift;
+ Uint8 Gshift = format->Gshift;
+ Uint8 Bshift = format->Bshift;
+ Uint8 Ashift = format->Ashift;
+ Uint32 Rmask = format->Rmask;
+ Uint32 Gmask = format->Gmask;
+ Uint32 Bmask = format->Bmask;
+ Uint32 Amask = format->Amask;
+
+ Uint8 bpp = format->BytesPerPixel;
+ Uint32 pitch = Surface->pitch;
+ Uint32 src_pitch = Bitmap->pitch;
+ register Uint8* src_pixels = Bitmap->buffer + x0 + y0*Bitmap->pitch;
+ register Uint8* dst_pixels = (Uint8*)pixels + (PosX+x0)*bpp + (PosY+y0)*pitch /*+ Surface->offset*/;
+ Uint8* line;
+
+ Uint8 r,g,b,a;
+ unsigned rv,gv,bv,av;
+ Sint32 cr,cg,cb;
+ Uint32 color = 0;
+ Sint32 v;
+
+ PG_Color fc = Param->GetColor();
+ cr = fc.r;
+ cg = fc.g;
+ cb = fc.b;
+
+ int alpha = Param->GetAlpha();
+
+ line = dst_pixels;
+ for (register int y = y0; y <y1; y++, src_pixels += src_pitch) {
+
+ dst_pixels = line;
+
+ for (register int x = x0; x < x1; x++, dst_pixels += bpp) {
+
+ // get source pixel value
+ v = *(Uint8 *)(src_pixels++);
+
+ // don't do anything if the pixel is fully transparent
+ if(v == 0) {
+ continue;
+ }
+
+ if(alpha != 255) {
+ v = (v * alpha) >> 8;
+ }
+
+ // Get the pixel
+ color = *((DT) (dst_pixels));
+ switch(Surface->format->BytesPerPixel) {
+ default:
+ // get the RGBA values
+ rv = (color & Rmask) >> Rshift;
+ r = (rv << Rloss) + (rv >> Rloss8);
+ gv = (color & Gmask) >> Gshift;
+ g = (gv << Gloss) + (gv >> Gloss8);
+ bv = (color & Bmask) >> Bshift;
+ b = (bv << Bloss) + (bv >> Bloss8);
+ if(Amask) {
+ av = (color & Amask) >> Ashift;
+ a = (av << Aloss) + (av >> Aloss8);
+ } else
+ a = SDL_ALPHA_OPAQUE;
+
+ //SDL_GetRGBA(color, format, &r, &g, &b, &a);
+
+ // calculate new RGBA values
+ if(v == 255) {
+ r = cr;
+ g = cg;
+ b = cb;
+ }
+ else {
+ //r += ((cr - r) * v) / 255;
+ //g += ((cg - g) * v) / 255;
+ //b += ((cb - b) * v) / 255;
+ r += ((cr - r) * v) >> 8;
+ g += ((cg - g) * v) >> 8;
+ b += ((cb - b) * v) >> 8;
+ }
+
+ // if the destination pixel is full transparent
+ // use the pixel shading as alpha
+ if(a == 0) {
+ a = v;
+ }
+
+ // get the destination color
+ color = (r >> Rloss) << Rshift
+ | (g >> Gloss) << Gshift
+ | (b >> Bloss) << Bshift
+ | ((a >> Aloss) << Ashift & Amask);
+ // Set the pixel
+ *((DT) (dst_pixels)) = color;
+ break;
+
+ case 3:
+ cr = (fc.r << format->Rshift) >> 16 & 0xff;
+ cg = (fc.g << format->Gshift) >> 8 & 0xff;
+ cb = fc.b << format->Bshift & 0xff;
+
+ if (v == 255) {
+ r = cr;
+ g = cg;
+ b = cb;
+ }
+ // calculate new RGB values
+ else {
+ b = *(dst_pixels);
+ g = *(dst_pixels+1);
+ r = *(dst_pixels+2);
+ r += ((cr - r) * v) >> 8;
+ g += ((cg - g) * v) >> 8;
+ b += ((cb - b) * v) >> 8;
+ }
+
+ *dst_pixels = b;
+ *(dst_pixels + 1) = g;
+ *(dst_pixels + 2) = r;
+ break;
+
+ case 1:
+ SDL_GetRGBA(color, format, &r, &g, &b, &a);
+
+ // calculate new RGBA values
+ if(v == 255) {
+ r = cr;
+ g = cg;
+ b = cb;
+ }
+ else {
+ //r += ((cr - r) * v) / 255;
+ //g += ((cg - g) * v) / 255;
+ //b += ((cb - b) * v) / 255;
+ r += ((cr - r) * v) >> 8;
+ g += ((cg - g) * v) >> 8;
+ b += ((cb - b) * v) >> 8;
+ }
+
+ // if the destination pixel is full transparent
+ // use the pixel shading as alpha
+ if(a == 0) {
+ a = v;
+ }
+ color = SDL_MapRGBA(format, r,g,b, a);
+ *((DT) (dst_pixels)) = color;
+ break;
+ }
+
+ }
+ src_pixels -= xw;
+ line += pitch;
+ }
+}
+
+bool PG_FontEngine::BlitFTBitmap(SDL_Surface *Surface, FT_Bitmap *Bitmap, int PosX, int PosY, PG_Font *Param, PG_Rect* ClipRect) {
+ int BitmapRealWidth;
+
+ // i think we can skip that test
+ /*if(Bitmap->pixel_mode != ft_pixel_mode_grays) {
+ return false;
+ }*/
+
+ // do nothing if we're fully transparent
+ if (Param->GetAlpha() == 0)
+ return true;
+
+ BitmapRealWidth = Bitmap->width;
+
+ // get the cliprectangle of the surface
+ static PG_Rect srfclip;
+ SDL_GetClipRect(Surface, &srfclip);
+
+ // the real clipping rectangle = surfaceclip / ClipRect
+ static PG_Rect clip;
+ clip = *ClipRect / srfclip;
+
+ //Italic font is widther than normal
+ //if (Param->Style & PG_FSTYLE_ITALIC) {
+ // BitmapRealWidth += (int)(Bitmap->rows * PG_FITALIC_ANGLE);
+ //}
+
+ int x0 = 0;
+ int x1 = BitmapRealWidth;
+ int y0 = 0;
+ int y1 = Bitmap->rows;
+
+ if(PosX < clip.x) {
+ x0 = clip.x - PosX;
+ }
+
+ if(PosX+BitmapRealWidth > clip.x + clip.w) {
+ x1 = (clip.x + clip.w) - PosX;
+ }
+
+ if(PosY < clip.y) {
+ y0 = clip.y - PosY;
+ }
+
+ if(PosY+Bitmap->rows > clip.y + clip.h) {
+ y1 = (clip.y + clip.h) - PosY;
+ }
+
+ if((x1 <= x0) || (y1 <= y0)) {
+ return false;
+ }
+
+ switch(Surface->format->BytesPerPixel) {
+ case 1:
+ case 3:
+ BlitTemplate((Uint8*)Surface->pixels, Surface, Bitmap, PosX, PosY, x0, x1, y0, y1, Param);
+ break;
+ case 2:
+ BlitTemplate((Uint16*)Surface->pixels, Surface, Bitmap, PosX, PosY, x0, x1, y0, y1, Param);
+ break;
+ case 4:
+ BlitTemplate((Uint32*)Surface->pixels, Surface, Bitmap, PosX, PosY, x0, x1, y0, y1, Param);
+ break;
+ default:
+ debug("Unable to draw font: unsupported bit depth!");
+ break;
+ }
+
+ return true;
+}
+
+#else
+
+bool PG_FontEngine::BlitFTBitmap(SDL_Surface *Surface, FT_Bitmap *Bitmap, int PosX, int PosY, PG_Font *Param, PG_Rect *ClipRect) {
+ int x,y;
+ Uint32 *raw_pixels;
+ SDL_Rect TargetPos;
+ SDL_Rect SourcePos;
+ int BitmapRealWidth;
+
+ if (Param->Alpha == 0)
+ return true;
+
+ TargetPos.x = PosX;
+ TargetPos.y = PosY;
+
+ //Italic font is widther than normal
+ BitmapRealWidth = Bitmap->width;
+ if (Param->Style & PG_FSTYLE_ITALIC) {
+ BitmapRealWidth += (int)(Bitmap->rows * PG_FITALIC_ANGLE);
+ }
+
+ //There is no need to draw
+ if ((TargetPos.x > (ClipRect->x + ClipRect->w)) || (TargetPos.y > (ClipRect->y +ClipRect->h )) || ((TargetPos.y+Bitmap->rows) < ClipRect->y) || ((TargetPos.x+BitmapRealWidth) < ClipRect->x))
+ return true;
+
+ //Is my_charSurface big enough ??
+ if (my_charSurface != NULL) {
+ if ((my_charSurface->w < BitmapRealWidth)||(my_charSurface->h < Bitmap->rows)) {
+ SDL_FreeSurface(my_charSurface);
+ my_charSurface = NULL;
+ }
+ }
+
+ if (my_charSurface == NULL) {
+ my_charSurface = SDL_CreateRGBSurface(SDL_SRCALPHA , BitmapRealWidth, Bitmap->rows, 32, 0xff0000, 0xff00, 0xff, 0xff000000);
+ if (my_charSurface == NULL) {
+ debug("Can`t get char surface : %s",SDL_GetError());
+ return false;
+ }
+ }
+
+ if (Param->Style & PG_FSTYLE_ITALIC) {
+ SDL_FillRect(my_charSurface, NULL, 0);
+ }
+
+ SourcePos.x = 0; // = my_charSurface->clip_rect;
+ SourcePos.y = 0;
+ SourcePos.w = BitmapRealWidth;
+ SourcePos.h = Bitmap->rows;
+
+ //Clipping
+ if ((TargetPos.x + SourcePos.w) > (ClipRect->x + ClipRect->w))
+ SourcePos.w = ClipRect->w - (TargetPos.x - ClipRect->x);
+ if ((TargetPos.y + SourcePos.h) > (ClipRect->y + ClipRect->h))
+ SourcePos.h = ClipRect->h - (TargetPos.y - ClipRect->y);
+ if (TargetPos.x < ClipRect->x) {
+ int delta;
+
+ delta = ClipRect->x - TargetPos.x;
+ SourcePos.w -= delta;
+ TargetPos.x += delta;
+ SourcePos.x += delta;
+ }
+
+ if (TargetPos.y < ClipRect->y) {
+ int delta;
+
+ delta = ClipRect->y - TargetPos.y;
+ SourcePos.h -= delta;
+ TargetPos.y += delta;
+ SourcePos.y += delta;
+ }
+
+ raw_pixels = (Uint32 *) my_charSurface->pixels;
+ Uint32 pitch_diff = 0;
+
+ switch (Bitmap->pixel_mode) {
+ case ft_pixel_mode_grays: {
+ Uint8 *SrcPix = Bitmap->buffer;
+ int a;
+
+
+ if (Param->Style & PG_FSTYLE_ITALIC) {
+ double ioffset = Bitmap->rows * PG_FITALIC_ANGLE;
+
+ for (y = 0; y < Bitmap->rows; y++, SrcPix += Bitmap->pitch, ioffset -= PG_FITALIC_ANGLE) {
+ for (x = 0; x < Bitmap->width; x++) {
+ a = *(Uint8 *)(SrcPix++);
+
+ // What the hell should do this ?
+ //if (Param->Alpha != 255)
+ // a = (a * Param->Alpha) / 255;
+
+ raw_pixels[int(ioffset) + x + (my_charSurface->pitch/4)*(y)] = Param->Color.MapRGBA(my_charSurface->format, a);
+ }
+ SrcPix -= x;
+ }
+ } else
+ pitch_diff = (my_charSurface->pitch/4);
+
+ for (y = 0; y < Bitmap->rows; y++, SrcPix += Bitmap->pitch) {
+ for (x = 0; x < Bitmap->width; x++) {
+ a = *(Uint8 *)(SrcPix++);
+
+ // Q: What the hell should do this ?
+ // A: This allows for alpha
+ // rendering of text. // Neo
+
+ if (Param->Alpha != 255)
+ a = (a * Param->Alpha) / 255;
+
+ *raw_pixels = Param->Color.MapRGBA(my_charSurface->format, a);
+ raw_pixels++;
+ }
+ SrcPix -= x;
+ raw_pixels -= x;
+ raw_pixels += pitch_diff;
+ }
+ break;
+ }
+
+ default:
+ debug("Unknown pixel type in font !");
+ return false;
+ }
+
+ // Final blit
+ SDL_Rect BoldTarget = TargetPos;
+ SDL_BlitSurface(my_charSurface, &SourcePos, Surface, &TargetPos);
+
+ //BOLD
+ if (Param->Style & PG_FSTYLE_BOLD) {
+ BoldTarget.x += Param->FaceCache->Bold_Offset;
+ SDL_BlitSurface(my_charSurface, &SourcePos, Surface, &BoldTarget);
+ }
+
+ return true;
+}
+
+#endif
+
+
+bool PG_FontEngine::RenderText(SDL_Surface *Surface, const PG_Rect& ClipRect, int BaseLineX, int BaseLineY, const char *Text, PG_Font *ParamIn) {
+ return RenderText(Surface, (PG_Rect*)&ClipRect, BaseLineX, BaseLineY, Text, ParamIn);
+}
+
+bool PG_FontEngine::RenderText(SDL_Surface *Surface, PG_Rect *ClipRect, int BaseLineX, int BaseLineY, const char *Text, PG_Font* font) {
+ static bool bRecursion = false;
+ int OriBaseX = BaseLineX;
+ FT_UInt previous = 0;
+
+ PG_FontFaceCacheItem* FaceCache = font->GetFaceCache();
+
+ // invalid font ?
+ if (FaceCache == NULL) {
+ return false;
+ }
+
+ FT_Face Face = FaceCache->Face;
+ FT_Vector delta;
+
+ if(SDL_MUSTLOCK(Surface)) {
+ SDL_LockSurface(Surface); //!
+ }
+
+ PG_String sText(Text);
+
+#ifndef ENABLE_UNICODE
+ unsigned char c;
+#else
+ YChar c;
+#endif
+
+ //Go thu text and draw characters
+ for (PG_String::iterator c0 = sText.begin(); c0 != sText.end(); c0++) {
+ int glyph_index;
+ PG_GlyphCacheItem* Glyph;
+ int OldBaseLineX = BaseLineX;
+
+#ifndef ENABLE_UNICODE
+ c = (unsigned char)(*c0);
+#else
+ c = (*c0);
+#endif
+
+ //Skip drawing we go non-printable char
+ if (c<32)
+ continue;
+
+ //Get glyph index
+ glyph_index = FT_Get_Char_Index(Face, c);
+
+ //Make space between characters == kerneling
+ if ( FaceCache->Use_Kerning && previous && glyph_index ) {
+ FT_Get_Kerning(Face, previous, glyph_index, ft_kerning_default, &delta );
+ BaseLineX += delta.x >> 6;
+ }
+ previous = glyph_index;
+
+ //Get glyph bitmap
+ Glyph = GetGlyph(font, glyph_index);
+
+ //Blit glyph bitmap into the surface
+ if (c != ' ') {
+ BlitFTBitmap(Surface, &Glyph->Bitmap, BaseLineX + Glyph->Bitmap_left, BaseLineY - Glyph->Bitmap_top, font, ClipRect);
+ }
+
+ BaseLineX += Glyph->Advance_x;
+ if (font->GetStyle() & PG_Font::BOLD) {
+ BaseLineX += FaceCache->Bold_Offset;
+ }
+
+ //UNDERLINE
+ //TO-DO : Underline is not transparent !!!! (Fill must be replaced by Blit)
+ if (font->GetStyle() & PG_Font::UNDERLINE) {
+ SDL_Rect und_rect;
+
+ und_rect.x = OldBaseLineX;
+ und_rect.y = BaseLineY;
+ und_rect.h = FaceCache->Underline_Height;
+ und_rect.w = BaseLineX - OldBaseLineX;
+
+ SDL_FillRect(
+ Surface,
+ &und_rect,
+ font->GetColor().MapRGB(Surface->format)
+ );
+ }
+ }
+
+ //BOLD
+ if (font->GetStyle() & PG_Font::BOLD && !bRecursion) {
+ bRecursion = true;
+ RenderText(Surface, ClipRect, OriBaseX+1, BaseLineY, Text, font);
+ bRecursion = false;
+ }
+
+ if(SDL_MUSTLOCK(Surface)) {
+ SDL_UnlockSurface(Surface); //!
+ }
+
+ return true;
+}
+
+bool PG_FontEngine::GetTextSize(const char *Text, PG_Font* font, Uint16 *Width, Uint16 *Height, int *BaselineY, int *FontLineSkip, Uint16 *FontHeight, int *Ascent, int *Descent) {
+ FT_UInt previous = 0;
+ int BaseLineX = 0;
+ int preBaseLineY = 0;
+ int MaxY = 0;
+
+ Uint16 preFontHeight = 0;
+ int preLineSkip = 0;
+ int preAscent = 0;
+ int preDescent = 0;
+
+ PG_FontFaceCacheItem* FaceCache = font->GetFaceCache();
+
+ // invalid font ?
+ if (FaceCache == NULL) {
+ return false;
+ }
+
+ FT_Face Face = FaceCache->Face;
+
+ //Initial parametrs check
+ if (FaceCache != NULL) {
+ if (preFontHeight < FaceCache->Height)
+ preFontHeight = FaceCache->Height;
+ if (preLineSkip < FaceCache->LineSkip)
+ preLineSkip = FaceCache->LineSkip;
+ if (preAscent < FaceCache->Ascent)
+ preAscent = FaceCache->Ascent;
+ if (preDescent > FaceCache->Descent)
+ preDescent = FaceCache->Descent;
+ }
+
+ PG_String sText(Text);
+
+ //Go thu text and get sizes of the characters
+
+#ifndef ENABLE_UNICODE
+ unsigned char c;
+#else
+ YChar c;
+#endif
+
+ for (PG_String::iterator c0 = sText.begin(); c0 !=sText.end(); c0++) {
+ int glyph_index;
+ PG_GlyphCacheItem *Glyph;
+
+#ifndef ENABLE_UNICODE
+ c = (unsigned char)(*c0);
+#else
+ c = (*c0);
+#endif
+
+ //Skip non-printable char
+ if (c<32)
+ continue;
+
+ //Get glyph index
+ glyph_index = FT_Get_Char_Index(Face, c);
+
+ //Make space between characters == kerneling
+ if ( FaceCache->Use_Kerning && previous && glyph_index ) {
+ FT_Vector delta;
+
+ FT_Get_Kerning(Face, previous, glyph_index, ft_kerning_default, &delta );
+ BaseLineX += delta.x >> 6;
+ }
+ previous = glyph_index;
+
+ //Get glyph bitmap
+ Glyph = GetGlyph(font, glyph_index);
+
+ if (preBaseLineY < Glyph->Bitmap_top) {
+ preBaseLineY = Glyph->Bitmap_top;
+ }
+
+ if (MaxY < Glyph->Bitmap.rows) {
+ MaxY = Glyph->Bitmap.rows;
+ }
+
+ BaseLineX += Glyph->Advance_x;
+ if (font->GetStyle() & PG_Font::BOLD) {
+ BaseLineX += FaceCache->Bold_Offset;
+ }
+
+ }
+
+ if (Height != NULL)
+ *Height = MaxY;
+ if (Width != NULL)
+ *Width = BaseLineX;
+ if (BaselineY!= NULL)
+ *BaselineY = preBaseLineY;
+ if (FontLineSkip!= NULL)
+ *FontLineSkip = preLineSkip;
+ if (FontHeight != NULL)
+ *FontHeight = preFontHeight;
+ if (Ascent != NULL)
+ *Ascent = preAscent;
+ if (Descent != NULL)
+ *Descent = preDescent;
+
+ return true;
+}
+
+PG_FontFaceCacheItem* PG_FontEngine::LoadFontFace(const char* filename, FT_F26Dot6 fontsize, int index) {
+
+ // lets see if the file is already in the cache
+ FONT_ITEM* item = my_fontcache[(std::string)filename];
+
+ // NO -> Load the face from the file
+ if(item == NULL) {
+
+ // open the fontfile
+ PG_DataContainer* data = PG_DataContainer::ReadFromFile(filename);
+ if(!data) {
+ return NULL;
+ }
+
+ // create new font item
+ item = new FONT_ITEM;
+ item->name = filename;
+ item->memdata = data;
+
+ // add the face to the cache
+ my_fontcache[(std::string)filename] = item;
+ }
+
+ // let's see if we already have a face for the given size
+ PG_FontFaceCacheItem* subitem = item->subitems[fontsize];
+
+ // NO -> create new face for the size
+ if(subitem == NULL) {
+ subitem = new PG_FontFaceCacheItem;
+ subitem->fontsize = fontsize;
+
+ // create the freetype face
+ FT_New_Memory_Face(my_library, (FT_Byte*)item->memdata->data(),
+ item->memdata->size(), 0,
+ &(subitem->Face));
+
+ // check if the font is scaleable
+ if (!FT_IS_SCALABLE(subitem->Face) ) {
+ debug("Font %s is not scalable !", filename);
+ delete subitem;
+ return NULL;
+ }
+
+ // set font size
+ FT_Set_Char_Size(subitem->Face, 0, fontsize*64, 0, 0);
+
+ // set subitem params
+ subitem->Bold_Offset = 1 + fontsize / 20;
+ subitem->Underline_Height = FT_FLOOR(FT_MulFix(subitem->Face->underline_thickness, subitem->Face->size->metrics.y_scale));
+ if ( subitem->Underline_Height < 1 ) {
+ subitem->Underline_Height = 1;
+ }
+
+ subitem->Ascent = FT_CEIL(FT_MulFix(subitem->Face->bbox.yMax, subitem->Face->size->metrics.y_scale));
+ subitem->Descent = FT_CEIL(FT_MulFix(subitem->Face->bbox.yMin, subitem->Face->size->metrics.y_scale));
+ subitem->Height = subitem->Ascent - subitem->Descent + 1;
+ subitem->LineSkip = FT_CEIL(FT_MulFix(subitem->Face->height, subitem->Face->size->metrics.y_scale));
+ subitem->Use_Kerning = FT_HAS_KERNING(subitem->Face);
+
+ // add to subitem list
+ item->subitems[fontsize] = subitem;
+ }
+
+ return subitem;
+}
+
+PG_FontEngine::FONT_ITEM::~FONT_ITEM() {
+ for(MAP_SUBITEMS::iterator i = subitems.begin(); i != subitems.end(); i++) {
+ delete (*i).second;
+ }
+ delete memdata;
+}
+
+
+/*
+ * Local Variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
+
diff --git a/src/paragui/pgfont.h b/src/paragui/pgfont.h
new file mode 100644
index 0000000..271ac0a
--- /dev/null
+++ b/src/paragui/pgfont.h
@@ -0,0 +1,251 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgfont.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+/** \file pgfont.h
+ Header file of the PG_Font and PG_FontEngine classes.
+*/
+
+#ifndef PG_FONT_H
+#define PG_FONT_H
+
+#include "pgdatacontainer.h"
+#include "pgcolor.h"
+#include "pgrect.h"
+#include <string>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_ERRORS_H
+#include FT_CACHE_H
+#include FT_CACHE_IMAGE_H
+#include FT_CACHE_SMALL_BITMAPS_H
+
+#ifdef HASH_MAP_INC
+#include HASH_MAP_INC
+#endif
+#include <map>
+
+class PG_FontFaceCacheItem;
+class PG_GlyphCacheItem;
+struct PG_FontDataInternal;
+
+/**
+ @short font description class
+
+ This class defines the parameters of a font (size, style, ...)
+*/
+class PG_Font {
+public:
+
+ //! Font styles
+ typedef enum {
+ NORMAL = 0x00,
+ BOLD = 0x01,
+ ITALIC = 0x02,
+ UNDERLINE = 0x04
+ } Style;
+
+ static PG_Font *GetDefaultFont();
+
+ /**
+ Construct a PG_Font object
+ @param fontfile name of the fontfile to load
+ @param size size of the new font
+ @param index font index of the loaded file
+ */
+ PG_Font(const char* fontfile, int size=14, int index=0);
+
+ /**
+ */
+ virtual ~PG_Font();
+
+ /**
+ */
+ int GetFontAscender();
+
+ /**
+ */
+ int GetFontDescender();
+
+ /**
+ Get the absolute height of the font (in pixels)
+ @return height of the font
+ */
+ int GetFontHeight();
+
+ /**
+ Set the color of the font
+ @param c PG_Color class of the new color
+ */
+ void SetColor(const PG_Color& c);
+
+ /**
+ Get the current color of the font
+ @return PG_Color class containing the current color
+ */
+ PG_Color GetColor();
+
+ /**
+ Set the transparency of the font
+ @param a font alpha value
+ */
+ void SetAlpha(int a);
+
+ /**
+ Get the transparency of the font
+ @return font alpha value
+ */
+ int GetAlpha();
+
+ /**
+ Set the size of the font
+ @param s new font size
+ */
+ void SetSize(int s);
+
+ /**
+ Get the size of the font
+ @return current size of the font
+ */
+ int GetSize();
+
+ /**
+ */
+ void SetStyle(Style s);
+
+ /**
+ */
+ Style GetStyle();
+
+ /**
+ Set the name (filename) of the font
+ @param fontfile name of the new fontfile.
+ @return true - on success
+ This function loads a new font from a file
+ */
+ bool SetName(const char* fontfile);
+
+ /**
+ Get the current name of the font (filename)
+ @return the filename of the font
+ */
+ const char* GetName();
+
+ void SetIndex(int index);
+
+ int GetIndex();
+
+private:
+
+ PG_FontFaceCacheItem* GetFaceCache(int index=0);
+ PG_FontDataInternal* my_internaldata;
+ static PG_Font *gDefaultFont;
+
+ friend class PG_FontEngine;
+};
+
+
+/**
+ @author Alexander Pipelka / Ales Teska
+ @short C++ Encapsulation of the FreeType engine
+*/
+
+class PG_FontEngine {
+public:
+
+ /** */
+ PG_FontEngine();
+
+ /** */
+ ~PG_FontEngine();
+
+ /**
+ render text onto a surface
+ @param Surface destination for rendered text
+ @param ClipRect clipping rectangle
+ @param BaseLineX x-startposition of the rendered text (inside the surface)
+ @param BaseLineY baseline of the rendered text (inside the surface)
+ @param Text text to render
+ @param ParamIn pointer to font
+ @return true on success
+ */
+ static bool RenderText(SDL_Surface *Surface, const PG_Rect& ClipRect, int BaseLineX, int BaseLineY, const char *Text, PG_Font* ParamIn);
+
+ static bool RenderText(SDL_Surface *Surface, PG_Rect *ClipRect, int BaseLineX, int BaseLineY, const char *Text, PG_Font* ParamIn);
+
+ /**
+ */
+ static bool GetTextSize(const char *Text, PG_Font* ParamIn, Uint16 *Width = NULL, Uint16 *Height = NULL, int *BaselineY = NULL, int *FontLineSkip = NULL, Uint16 *FontHeight = NULL, int *Ascent = NULL, int *Descent = NULL);
+
+protected:
+
+ /**
+ */
+ static bool BlitFTBitmap(SDL_Surface *Surface, FT_Bitmap *Bitmap, int PosX, int PosY, PG_Font* Param, PG_Rect *ClipRect);
+
+ /**
+ */
+ static void FontEngineError(FT_Error error);
+
+private:
+
+ /**
+ Load a font face from the archive
+ @param filename fontfile to load (truetype)
+ @param fontsize size of the face in pixels
+ @return pointer to the loaded PG_FontFaceCacheItem
+ */
+ static PG_FontFaceCacheItem* LoadFontFace(const char* filename, FT_F26Dot6 fontsize, int index = 0);
+
+ /**
+ */
+ static PG_GlyphCacheItem* GetGlyph(PG_Font *Param, int glyph_index);
+
+ typedef std::map<FT_F26Dot6, PG_FontFaceCacheItem*> MAP_SUBITEMS;
+
+ class FONT_ITEM {
+ public:
+ FONT_ITEM() : memdata(NULL) {
+ };
+
+ virtual ~FONT_ITEM();
+
+ std::string name;
+ PG_DataContainer* memdata;
+ MAP_SUBITEMS subitems;
+ };
+
+ typedef std::map<std::string, FONT_ITEM*> MAP_FONTS;
+
+ static MAP_FONTS my_fontcache;
+ static FT_Library my_library;
+
+ friend class PG_Font;
+};
+
+#endif
diff --git a/src/paragui/pgfont_impl.cpp b/src/paragui/pgfont_impl.cpp
new file mode 100644
index 0000000..a03cf5f
--- /dev/null
+++ b/src/paragui/pgfont_impl.cpp
@@ -0,0 +1,151 @@
+#include "common.h"
+#include "pgfacecache.h"
+#include "pgfont.h"
+
+PG_Font *PG_Font::gDefaultFont= NULL;
+PG_Font *PG_Font::GetDefaultFont()
+{
+ return gDefaultFont;
+}
+
+
+struct PG_FontDataInternal {
+ PG_Color color;
+ int alpha;
+ PG_Font::Style style;
+
+ int size;
+ int index;
+ std::string name;
+
+ Uint32 dummy1;
+ Uint32 dummy2;
+
+ PG_FontFaceCacheItem* FaceCache;
+
+};
+
+PG_Font::PG_Font(const char* fontfile, int size, int index) {
+ if (NULL == gDefaultFont)
+ {
+ gDefaultFont= this;
+ }
+ my_internaldata = new PG_FontDataInternal;
+ my_internaldata->FaceCache = NULL;
+
+ my_internaldata->name = fontfile;
+ my_internaldata->size = size;
+ my_internaldata->index = index;
+ my_internaldata->color.r = 255;
+ my_internaldata->color.g = 255;
+ my_internaldata->color.b = 255;
+ my_internaldata->alpha = 255;
+ my_internaldata->style = NORMAL;
+
+ my_internaldata->FaceCache = PG_FontEngine::LoadFontFace(fontfile, size, index);
+
+ if(my_internaldata->FaceCache == NULL) {
+ debug("Unable to create font (name=\"%s\", size=\"%i\", index=\"%i\"", fontfile, size, index);
+ }
+}
+
+PG_Font::~PG_Font() {
+ delete my_internaldata;
+}
+
+int PG_Font::GetFontAscender() {
+ return my_internaldata->FaceCache ?
+ FT_CEIL(FT_MulFix(my_internaldata->FaceCache->Face->ascender, my_internaldata->FaceCache->Face->size->metrics.y_scale)) : 0;
+}
+
+int PG_Font::GetFontDescender() {
+ return my_internaldata->FaceCache ?
+ FT_CEIL(FT_MulFix(my_internaldata->FaceCache->Face->descender, my_internaldata->FaceCache->Face->size->metrics.y_scale)) : 0;
+}
+
+int PG_Font::GetFontHeight() {
+ return my_internaldata->FaceCache ?
+ FT_CEIL(FT_MulFix(my_internaldata->FaceCache->Face->height, my_internaldata->FaceCache->Face->size->metrics.y_scale)) : 0;
+}
+
+void PG_Font::SetColor(const PG_Color& c) {
+ my_internaldata->color = c;
+}
+
+PG_Color PG_Font::GetColor() {
+ return my_internaldata->color;
+}
+
+void PG_Font::SetAlpha(int a) {
+ my_internaldata->alpha = a;
+}
+
+int PG_Font::GetAlpha() {
+ return my_internaldata->alpha;
+}
+
+void PG_Font::SetStyle(Style s) {
+ my_internaldata->style = s;
+}
+
+PG_Font::Style PG_Font::GetStyle() {
+ return my_internaldata->style;
+}
+
+bool PG_Font::SetName(const char* fontfile) {
+ my_internaldata->name = fontfile;
+ my_internaldata->FaceCache = PG_FontEngine::LoadFontFace(
+ fontfile,
+ GetSize(),
+ GetIndex());
+
+ if(my_internaldata->FaceCache == NULL) {
+ debug("Unable to create font (name=\"%s\", size=\"%i\", index=\"%i\"",
+ GetName(),
+ GetSize(),
+ GetIndex());
+ }
+
+ return (my_internaldata->FaceCache != NULL);
+}
+
+const char* PG_Font::GetName() {
+ return my_internaldata->name.c_str();
+}
+
+void PG_Font::SetSize(int s) {
+ my_internaldata->size = s;
+ my_internaldata->FaceCache = PG_FontEngine::LoadFontFace(
+ GetName(),
+ GetSize(),
+ GetIndex());
+
+
+ if(my_internaldata->FaceCache == NULL) {
+ debug("Unable to create font (name=\"%s\", size=\"%i\", index=\"%i\"",
+ GetName(),
+ GetSize(),
+ GetIndex());
+ }
+
+}
+
+int PG_Font::GetSize() {
+ return my_internaldata->size;
+}
+
+PG_FontFaceCacheItem* PG_Font::GetFaceCache(int index) {
+ return my_internaldata->FaceCache;
+}
+
+void PG_Font::SetIndex(int index) {
+ my_internaldata->index = index;
+}
+
+int PG_Font::GetIndex() {
+ return my_internaldata->index;
+}
+
+/*void PG_Font::SetFaceCache(PG_FontFaceCacheItem* cache, int index) {
+ my_internaldata->FaceCache = cache;
+}*/
diff --git a/src/paragui/pggradient.cpp b/src/paragui/pggradient.cpp
new file mode 100644
index 0000000..a09bc97
--- /dev/null
+++ b/src/paragui/pggradient.cpp
@@ -0,0 +1,226 @@
+/*
+ ParaGUI - crossplatform widgetset
+ gradient - gradient drawing functions
+
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pggradient.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pgdraw.h"
+
+#include <cmath>
+#include <cassert>
+
+SDL_Surface* PG_Draw::CreateGradient(const PG_Rect& r, PG_Gradient& gradient) {
+ return CreateGradient(
+ r,
+ gradient.colors[0],
+ gradient.colors[1],
+ gradient.colors[2],
+ gradient.colors[3]);
+}
+
+SDL_Surface* PG_Draw::CreateGradient(const PG_Rect& r, const PG_Color& ul, const PG_Color& ur, const PG_Color& dl, const PG_Color& dr) {
+ SDL_Surface *grd = PG_Draw::CreateRGBSurface(r.w, r.h);
+
+ r.my_xpos = 0;
+ r.my_ypos = 0;
+ PG_Draw::DrawGradient(grd, r, ul, ur, dl, dr);
+
+ return grd;
+}
+
+void PG_Draw::DrawGradient(SDL_Surface* surface, const PG_Rect& r, PG_Gradient& gradient) {
+ PG_Draw::DrawGradient(
+ surface,
+ r,
+ gradient.colors[0],
+ gradient.colors[1],
+ gradient.colors[2],
+ gradient.colors[3]);
+}
+
+void PG_Draw::DrawGradient(SDL_Surface * surface, const PG_Rect& rect, const PG_Color& ul, const PG_Color& ur, const PG_Color& dl, const PG_Color& dr) {
+ Sint32 v00,v01,v02;
+ Sint32 v10,v11,v12;
+
+ Sint32 w = rect.my_width;
+ Sint32 h = rect.my_height;
+
+ if (!surface)
+ return;
+
+ if(w == 0 || h == 0)
+ return;
+
+ if (w > surface->w || h > surface->h)
+ return;
+
+ Uint32 c1 = ul.MapRGB(surface->format);
+ Uint32 c2 = ur.MapRGB(surface->format);
+ Uint32 c3 = dl.MapRGB(surface->format);
+ Uint32 c4 = dr.MapRGB(surface->format);
+
+ // solid color gradient ?
+ if((c1 == c2) && (c2 == c3) && (c3 == c4)) {
+ SDL_FillRect(surface, (PG_Rect*)&rect, c1);
+ return;
+ }
+
+ PG_Rect clip;
+ SDL_GetClipRect(surface, &clip);
+ PG_Rect drawrect = rect.IntersectRect(clip);
+
+ if(drawrect.IsNull()) {
+ return;
+ }
+
+ int ox = drawrect.x - rect.x;
+ int oy = drawrect.y - rect.y;
+
+ if(SDL_MUSTLOCK(surface)) {
+ SDL_LockSurface(surface);
+ }
+
+ // color space vectors
+ v00 = ((ur.r - ul.r) * 256) / w;
+ v01 = ((ur.g - ul.g) * 256) / w;
+ v02 = ((ur.b - ul.b) * 256) / w;
+
+ v10 = ((dr.r - dl.r) * 256) / w;
+ v11 = ((dr.g - dl.g) * 256) / w;
+ v12 = ((dr.b - dl.b) * 256) / w;
+
+ Sint32 r1, g1, b1;
+ Sint32 r2, g2, b2;
+ Sint32 yr, yg, yb;
+ Sint32 r,g,b;
+
+ r1 = ul.r * 256;
+ g1 = ul.g * 256;
+ b1 = ul.b * 256;
+
+ r2 = dl.r * 256;
+ g2 = dl.g * 256;
+ b2 = dl.b * 256;
+
+ // set colors with offset (ox)
+ r1 += v00 * ox;
+ g1 += v01 * ox;
+ b1 += v02 * ox;
+ r2 += v10 * ox;
+ g2 += v11 * ox;
+ b2 += v12 * ox;
+
+ SDL_PixelFormat* format = surface->format;
+ Uint8 Rloss = 8+format->Rloss;
+ Uint8 Gloss = 8+format->Gloss;
+ Uint8 Bloss = 8+format->Bloss;
+ Uint8 Rshift = format->Rshift;
+ Uint8 Gshift = format->Gshift;
+ Uint8 Bshift = format->Bshift;
+ //Uint8 Amask = format->Amask;
+
+ Uint8 bpp = format->BytesPerPixel;
+ Uint32 pitch = surface->pitch;
+ Uint8* bits = ((Uint8 *) surface->pixels) + (rect.y + oy)* pitch + (rect.x + ox)* bpp;
+ Uint32 y_pitch = pitch*drawrect.h - bpp;
+ register Uint32 pixel = 0;
+
+ for (register Sint32 x = 0; x < drawrect.w; x++) {
+
+ yr = (r2 - r1) / h;
+ yg = (g2 - g1) / h;
+ yb = (b2 - b1) / h;
+
+ r = r1;
+ g = g1;
+ b = b1;
+ r += yr * oy;
+ g += yg * oy;
+ b += yb * oy;
+
+ for (register Sint32 y = 0; y < drawrect.h; y++) {
+
+ /* Set the pixel */
+ switch (bpp) {
+ case 1:
+ pixel = SDL_MapRGB ( surface->format, r>>8, g>>8, b>>8 );
+ *((Uint8 *) (bits)) = (Uint8) pixel;
+ break;
+
+ case 2:
+ pixel = (r>>Rloss) << Rshift
+ | (g>>Gloss) << Gshift
+ | (b>>Bloss) << Bshift;
+
+ *((Uint16 *) (bits)) = (Uint16) pixel;
+ break;
+
+ case 3: {
+ pixel = (r>>Rloss) << Rshift
+ | (g>>Gloss) << Gshift
+ | (b>>Bloss) << Bshift;
+
+ Uint8 ri = (pixel >> surface->format->Rshift) & 0xFF;
+ Uint8 gi = (pixel >> surface->format->Gshift) & 0xFF;
+ Uint8 bi = (pixel >> surface->format->Bshift) & 0xFF;
+ *((bits) + surface->format->Rshift / 8) = ri;
+ *((bits) + surface->format->Gshift / 8) = gi;
+ *((bits) + surface->format->Bshift / 8) = bi;
+ }
+ break;
+
+ case 4:
+ pixel = (r>>Rloss) << Rshift
+ | (g>>Gloss) << Gshift
+ | (b>>Bloss) << Bshift;
+
+ *((Uint32 *) (bits)) = (Uint32) pixel;
+ break;
+ }
+
+ r += yr;
+ g += yg;
+ b += yb;
+
+ // next pixel
+ bits += pitch;
+ }
+
+ r1 += v00;
+ g1 += v01;
+ b1 += v02;
+ r2 += v10;
+ g2 += v11;
+ b2 += v12;
+
+ bits -= y_pitch;
+ }
+
+ if(SDL_MUSTLOCK(surface)) {
+ SDL_UnlockSurface(surface);
+ }
+}
diff --git a/src/paragui/pglabel.cpp b/src/paragui/pglabel.cpp
new file mode 100644
index 0000000..5c0896b
--- /dev/null
+++ b/src/paragui/pglabel.cpp
@@ -0,0 +1,188 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pglabel.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pglabel.h"
+#include "gfx.h"
+#include "common.h"
+
+PG_Label::PG_Label(PG_Widget* parent, const PG_Rect& r, const char* text, const char* style) :
+PG_Widget(parent, r),
+my_indent(0) {
+
+ my_alignment = LEFT;
+ my_srfIcon = NULL;
+ my_freeicon = false;
+
+ SetText(text);
+// LoadThemeStyle(style);
+}
+
+PG_Label::~PG_Label() {
+ if(my_freeicon) {
+ SDL_FreeSurface(my_srfIcon); // false
+ }
+}
+/*
+void PG_Label::LoadThemeStyle(const char* style) {
+ if(strcmp(style, "Label") != 0) {
+ PG_Label::LoadThemeStyle("Label", "Label");
+ }
+ PG_Label::LoadThemeStyle(style, "Label");
+}
+
+void PG_Label::LoadThemeStyle(const char* widgettype, const char* object) {
+ PG_Theme* t = PG_Application::GetTheme();
+
+ const char* s = t->FindString(widgettype, object, "label");
+
+ if(s != NULL) {
+ SetText(s);
+ }
+
+ t->GetAlignment(widgettype, object, "alignment", my_alignment);
+
+ PG_Widget::LoadThemeStyle(widgettype, object);
+}
+*/
+void PG_Label::eventBlit(SDL_Surface* srf, const PG_Rect& src, const PG_Rect& dst) {
+ PG_Rect my_rectLabel;
+ int xshift = my_indent;
+
+ // should we blit an icon ?
+ if(my_srfIcon != NULL) {
+ xshift = my_srfIcon->w + my_indent;
+
+ PG_Rect icon_rect(
+ my_xpos + my_indent,
+ my_ypos + (my_height - my_srfIcon->h)/2,
+ my_srfIcon->w,
+ my_srfIcon->h);
+
+ PG_Rect icon_src;
+ PG_Rect icon_dst;
+
+ GetClipRects(icon_src, icon_dst, icon_rect);
+
+ PG_Widget::eventBlit(my_srfIcon, icon_src, icon_dst);
+ }
+
+ Uint16 wl;
+ Uint16 hl;
+
+ GetTextSize(wl, hl);
+
+ switch (my_alignment) {
+ case LEFT:
+ my_rectLabel.my_xpos = xshift;
+ my_rectLabel.my_ypos = (my_height - hl) >> 1;
+ break;
+
+ case RIGHT:
+ my_rectLabel.my_xpos = (my_width - wl);
+ my_rectLabel.my_ypos = (my_height - hl) >> 1;
+ break;
+
+ case CENTER:
+ my_rectLabel.my_xpos = (my_width - wl) >> 1;
+ my_rectLabel.my_ypos = (my_height - hl) >> 1;
+ break;
+ }
+
+ DrawText(my_rectLabel, my_text.c_str());
+}
+
+/** */
+void PG_Label::eventDraw(SDL_Surface* surface, const PG_Rect& rect) {}
+
+void PG_Label::SetAlignment(TextAlign a) {
+ my_alignment = a;
+ Update();
+}
+
+SDL_Surface* PG_Label::SetIcon(SDL_Surface* icon) {
+
+ if((icon != my_srfIcon) && my_freeicon){
+ SDL_FreeSurface(my_srfIcon);
+ }
+
+ my_srfIcon = icon;
+ my_freeicon = false;
+ Update();
+
+ return my_srfIcon;
+}
+
+SDL_Surface* PG_Label::SetIcon(const char* filename) {
+ if(my_freeicon){
+ SDL_FreeSurface(my_srfIcon);
+ }
+
+ my_srfIcon = LoadImage(filename);
+ my_freeicon = true;
+ Update();
+
+ return my_srfIcon;
+}
+
+SDL_Surface* PG_Label::GetIcon() {
+ return my_srfIcon;
+}
+
+void PG_Label::SetIndent(Uint16 indent) {
+ my_indent = indent;
+}
+
+Uint16 PG_Label::GetIndent() {
+ return my_indent;
+}
+
+void PG_Label::SetSizeByText(int Width, int Height, const char *Text) {
+ if (GetIcon() == NULL) {
+ PG_Widget::SetSizeByText(Width, Height, Text);
+ return;
+ }
+
+ Uint16 w,h;
+ int baselineY;
+
+ if (Text == NULL) {
+ Text = my_text.c_str();
+ }
+
+ if (!PG_FontEngine::GetTextSize(Text, GetFont(), &w, &h, &baselineY)) {
+ return;
+ }
+
+ if (GetIcon()->w > w) {
+ my_width = GetIcon()->w + my_indent + Width;
+ }
+ else {
+ my_width = w + GetIcon()->w + my_indent + Width;
+ }
+ my_height = omMAX(GetIcon()->h, h + baselineY) + Height + baselineY;
+}
diff --git a/src/paragui/pglabel.h b/src/paragui/pglabel.h
new file mode 100644
index 0000000..9fb1c46
--- /dev/null
+++ b/src/paragui/pglabel.h
@@ -0,0 +1,115 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pglabel.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#ifndef PG_LABEL_H
+#define PG_LABEL_H
+
+#include "pgwidget.h"
+
+/**
+ @author Alexander Pipelka
+
+ @short Text label.
+
+ A text label (unmodifiable by end user). Has attributes for font style,
+ alignment, etc.
+*/
+
+class PG_Label : public PG_Widget {
+public:
+
+ // Text alignment
+ typedef enum {
+ LEFT,
+ CENTER,
+ RIGHT
+ } TextAlign;
+
+ /** Only constructor
+ @param parent Parent widget.
+ @param r Rectangle to draw in, relative to parent.
+ @param text Text displayed by label.
+ @param style initial widget style (from xml theme)
+ */
+ PG_Label(PG_Widget* parent, const PG_Rect& r = PG_Rect::null, const char* text = NULL, const char* style="Label");
+
+ /** Only destructor */
+ ~PG_Label();
+
+ /** */
+// void LoadThemeStyle(const char* widgettype);
+
+ /** */
+// void LoadThemeStyle(const char* widgettype, const char* objectname);
+
+ /** Sets text alignment */
+ void SetAlignment(TextAlign a);
+
+ /** */
+ SDL_Surface* SetIcon(const char* filename);
+
+ /** */
+ SDL_Surface* SetIcon(SDL_Surface* icon);
+
+ SDL_Surface* GetIcon();
+
+ /**
+ Set the text indentation
+ @param indent number of pixels for text indentation
+ */
+ void SetIndent(Uint16 indent);
+
+ /** Returns the text indentation */
+ Uint16 GetIndent();
+
+ void SetSizeByText(int Width = 0, int Height = 0, const char *Text = NULL);
+
+protected:
+
+ /** Draw event handler
+ @param surface Surface to draw to.
+ @param rect Rectangle to draw in, relative to surface.
+ */
+ void eventDraw(SDL_Surface* surface, const PG_Rect& rect);
+
+ /** */
+ void eventBlit(SDL_Surface* surface, const PG_Rect& src, const PG_Rect& dst);
+
+ SDL_Surface* my_srfIcon;
+
+private:
+
+ PG_Label(const PG_Label&);
+ PG_Label& operator=(const PG_Label&);
+
+ TextAlign my_alignment;
+ Uint16 my_indent;
+ bool my_freeicon;
+};
+
+#endif // PG_LABEL_H
diff --git a/src/paragui/pglineedit.cpp b/src/paragui/pglineedit.cpp
new file mode 100644
index 0000000..62d6c88
--- /dev/null
+++ b/src/paragui/pglineedit.cpp
@@ -0,0 +1,590 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pglineedit.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pglineedit.h"
+//#include "pgapplication.h"
+//#include "pgtheme.h"
+
+PG_LineEdit::PG_LineEdit(PG_Widget* parent, const PG_Rect& r, const char* style, int _my_maximumLength)
+:
+//PG_ThemeWidget(parent, r, style) {
+PG_Widget(parent, r)
+{
+
+ my_buffer = "";
+ my_cursorPosition = 0;
+ my_maximumLength = _my_maximumLength;
+ my_isCursorVisible = false;
+ my_isEditable = true;
+ my_offsetX = 0;
+ my_srfTextCursor = NULL;
+ my_startMark = -1;
+ my_endMark = -1;
+ my_passchar = 0;
+
+ //LoadThemeStyle(style);
+}
+
+PG_LineEdit::~PG_LineEdit() {
+}
+
+void PG_LineEdit::eventBlit(SDL_Surface* surface, const PG_Rect& src, const PG_Rect& dst) {
+ PG_Widget::eventBlit(surface, src, dst);
+ DrawBorder(PG_Rect(0, 0, Width(), Height()), 1, false);
+ DrawText(dst);
+}
+
+void PG_LineEdit::DrawText(const PG_Rect& dst) {
+ int x, y;
+
+ x = 3;
+ y = (my_height - GetFontHeight()) >> 1;
+
+ // should we draw the cursor ?
+ if(my_isCursorVisible) {
+
+ if(my_cursorPosition < my_offsetX) {
+ my_offsetX = my_cursorPosition;
+ }
+
+ // check if my_cursorPosition is visible
+ if(x + GetCursorXPos() > (my_width - 2)) {
+ my_offsetX++;
+ DrawText(dst);
+ return;
+ }
+
+ DrawTextCursor();
+ }
+
+ // draw text
+ PG_Widget::DrawText(x, y, GetDrawText().c_str());
+}
+
+void PG_LineEdit::DrawTextCursor() {
+ int x = my_xpos + 1;
+ int y = my_ypos + 1;
+ int h = my_height - 2;
+
+ // draw simple cursor
+ if(my_srfTextCursor == NULL) {
+ DrawVLine(GetCursorXPos() + 2, 2, h-4, PG_Color(255,255,255));
+ }
+
+ // draw a nice cursor bitmap
+ else {
+ PG_Rect src, dst;
+ PG_Rect rect(x + GetCursorXPos(), y + (Height() - my_srfTextCursor->h)/2, my_srfTextCursor->w, my_srfTextCursor->h);
+ GetClipRects(src, dst, rect);
+ PG_Widget::eventBlit(my_srfTextCursor, src, dst);
+ }
+
+}
+
+Uint16 PG_LineEdit::GetCursorXPos() {
+ Uint16 w;
+ PG_String drawtext(GetDrawText());
+
+ int newpos = my_cursorPosition - my_offsetX;
+
+ if(newpos == 0)
+ return 0;
+
+ if(drawtext[0] == 0)
+ return 0;
+
+ PG_FontEngine::GetTextSize(PG_String(drawtext, 0, newpos).c_str(), GetFont(), &w);
+
+ return w;
+}
+
+int PG_LineEdit::GetCursorPosFromScreen(int x, int y) {
+ int min_dist = 1000000;
+ int min_pos = 0;
+ int dist = 0;
+ int old = my_cursorPosition;
+
+ // loop all cursor positions
+ for(Uint16 c=my_offsetX; c<=my_text.size(); c++) {
+
+ my_cursorPosition = c;
+
+ // get distance between screen point and cursor position
+ dist = abs(x - (my_xpos + 3 + GetCursorXPos()));
+
+ // store the minimum distance
+ if(dist < min_dist) {
+ min_dist = dist;
+ min_pos = c;
+ }
+ }
+
+ my_cursorPosition = old;
+
+ // result should be stored in min_pos
+ return min_pos;
+}
+
+PG_String PG_LineEdit::GetDrawText() {
+ if (my_passchar == '\0')
+ return my_text.substr(my_offsetX).c_str();
+
+ return PG_String(my_text.length(), my_passchar).substr(my_offsetX).c_str();
+}
+
+void PG_LineEdit::EditBegin() {
+ SetInputFocus();
+ my_isCursorVisible = true;
+
+ Update();
+
+ if (my_isEditable)
+ {
+ sigEditBegin(this);
+ eventEditBegin(GetID(), this, 0,0);
+ }
+}
+
+void PG_LineEdit::EditEnd() {
+ my_offsetX = 0;
+// my_cursorPosition = 0;
+ my_isCursorVisible = false;
+ Update();
+ ReleaseInputFocus();
+
+ sigEditEnd(this);
+ eventEditEnd(GetID(), this, 0,0);
+}
+
+bool PG_LineEdit::eventKeyDown(const SDL_KeyboardEvent* key) {
+ PG_Char c;
+
+ if(!my_isCursorVisible) {
+ return false;
+ }
+
+ SDL_KeyboardEvent key_copy = *key; // copy key structure
+ //@ PG_Application::TranslateNumpadKeys(&key_copy);
+ // from now, we use key_copy which was copied or translated from key
+
+ //
+ // Maybe it would be a good idea to support the windoze CUI keyboard
+ // bindings as well?
+ // /grendel, Nov 06
+ //
+ if(key_copy.keysym.mod & KMOD_CTRL) {
+ // Handle std emacs bindings
+ switch(key_copy.keysym.sym) {
+ case SDLK_a: // Beginning of Line
+ SetCursorPos(0);
+ return true;
+
+ case SDLK_e: // End of Line
+ SetCursorPos(my_text.length());
+ return true;
+
+ case SDLK_SPACE: // Set mark start
+ StartMark(my_cursorPosition);
+ return true;
+
+ case SDLK_w: // Cut from start mark
+ if(!my_isEditable) {
+ return false;
+ }
+ EndMark(my_cursorPosition);
+ CopyText(true);
+ return true;
+
+ case SDLK_k: // Delete all after point
+ if(!my_isEditable) {
+ return false;
+ }
+ StartMark(my_cursorPosition);
+ EndMark(my_text.length());
+ CopyText(true);
+ return true;
+
+ case SDLK_y: // Paste buffer at point
+ if(!my_isEditable) {
+ return false;
+ }
+ PasteText(my_cursorPosition);
+ return true;
+
+ case SDLK_f: // Forward char
+ SetCursorPos(++my_cursorPosition);
+ return true;
+
+ case SDLK_b: // Backward char
+ SetCursorPos(--my_cursorPosition);
+ return true;
+
+ case SDLK_d:
+ if(!my_isEditable) {
+ return false;
+ }
+ if(eventFilterKey(key)) {
+ return false;
+ }
+ SendDel();
+ return true;
+
+ default:
+ return false;
+ }
+ } else if(key_copy.keysym.mod & (KMOD_ALT | KMOD_META)) {
+
+ // Handle std emacs bindings
+ switch(key_copy.keysym.sym) {
+
+ case SDLK_w: // Copy from start mark
+ EndMark(my_cursorPosition);
+ CopyText();
+ return true;
+
+ default:
+ goto handleModKeys;
+ }
+ }
+
+ switch(key_copy.keysym.sym) {
+
+ case SDLK_TAB:
+ return false;
+
+ case SDLK_LEFT:
+
+ SetCursorPos(my_cursorPosition-1);
+ return true;
+
+ case SDLK_RIGHT:
+
+ SetCursorPos(my_cursorPosition+1);
+ return true;
+
+ case SDLK_RETURN:
+ if(!my_isEditable) {
+ return false;
+ }
+ EditEnd();
+ sigEditReturn(this);
+ return true;
+
+ case SDLK_HOME:
+ SetCursorPos(0);
+ return true;
+
+ case SDLK_END:
+ SetCursorPos(my_text.length());
+ return true;
+
+ case SDLK_BACKSPACE:
+ if(!my_isEditable) {
+ return false;
+ }
+ if(eventFilterKey(key)) {
+ return false;
+ }
+ SendBackspace();
+ return true;
+
+ case SDLK_DELETE:
+ if(!my_isEditable) {
+ return false;
+ }
+ if(eventFilterKey(key)) {
+ return false;
+ }
+ SendDel();
+ return true;
+
+ default:
+handleModKeys:
+ if(!my_isEditable) {
+ return false;
+ }
+
+ if(key_copy.keysym.unicode == 0) {
+ return false;
+ }
+
+ if(eventFilterKey(key)) {
+ return false;
+ }
+
+ if ((key_copy.keysym.unicode & 0xFF80) == 0) {
+ c = key_copy.keysym.unicode & 0x7F;
+
+ if(!IsValidKey(c)) {
+ return false;
+ }
+
+ InsertChar(&c);
+ return true;
+ } else {
+ c = (PG_Char)key_copy.keysym.unicode;
+
+ if(!IsValidKey(c)) {
+ return false;
+ }
+
+ InsertChar(&c);
+ return true;
+ }
+
+ return false;
+ }
+
+ return false;
+}
+
+void PG_LineEdit::eventInputFocusLost(PG_MessageObject* newfocus) {
+ EditEnd();
+}
+
+void PG_LineEdit::SetCursorPos(int p) {
+
+ if(p < 0) {
+ p = 0;
+ }
+
+ if(p > (int)my_text.size()) {
+ p = (int)my_text.size();
+ }
+
+ if (p > my_maximumLength) {
+ p = my_maximumLength;
+ }
+
+ my_cursorPosition = p;
+
+ if(my_offsetX > my_cursorPosition) {
+ my_offsetX = my_cursorPosition;
+ }
+
+ Update();
+}
+
+int PG_LineEdit::GetCursorPos() {
+ return my_cursorPosition;
+}
+
+bool PG_LineEdit::eventMouseButtonUp(const SDL_MouseButtonEvent* button) {
+ if(!my_isEditable) {
+ return false;
+ }
+
+ if(!my_isCursorVisible) {
+ EditBegin();
+ }
+
+ int p = GetCursorPosFromScreen(button->x, button->y);
+ SetCursorPos(p);
+ return true;
+}
+
+void PG_LineEdit::InsertChar(const PG_Char* c) {
+ if (my_cursorPosition < my_maximumLength) {
+#ifdef ENABLE_UNICODE
+ my_text.insert(my_cursorPosition, *c);
+#else
+ char buffer[2];
+ buffer[0] = *c;
+ buffer[1] = '\0';
+ my_text.insert(my_cursorPosition, buffer);
+#endif
+ SetCursorPos(++my_cursorPosition);
+ }
+}
+
+/** */
+void PG_LineEdit::DeleteChar(Uint16 pos) {
+ my_text.erase(pos, 1);
+}
+
+/** */
+void PG_LineEdit::StartMark(Uint16 pos) {
+ my_startMark = pos;
+ my_endMark = -1;
+}
+
+/** */
+void PG_LineEdit::EndMark(Uint16 pos) {
+ my_endMark = pos;
+}
+
+/** */
+void PG_LineEdit::CopyText(bool del) {
+ int start, len;
+ if(my_endMark == -1) {
+ my_endMark = my_cursorPosition;
+ }
+ if(my_startMark == my_endMark ||
+ my_startMark == -1) {
+ // No text is marked
+ return;
+ }
+ if(my_startMark > my_endMark) {
+ start = my_endMark;
+ len = my_startMark - start;
+ } else {
+ start = my_startMark;
+ len = my_endMark - start;
+ }
+ my_buffer = my_text.substr(start, len);
+ if(del) {
+ my_text.erase(start, len);
+ SetCursorPos(my_cursorPosition); // If end was > start
+ Update();
+ }
+ my_startMark = my_endMark = -1; // Reset mark
+}
+
+/** */
+void PG_LineEdit::PasteText(Uint16 pos) {
+ if(!my_buffer.length()) {
+ return;
+ }
+ my_text.insert(pos, my_buffer);
+ my_cursorPosition += my_buffer.length();
+ my_startMark = my_endMark = -1;
+ Update();
+}
+
+void PG_LineEdit::SetText(const char* new_text) {
+ my_cursorPosition = 0;
+ my_offsetX = 0;
+ PG_Widget::SetText(new_text);
+}
+
+void PG_LineEdit::eventEditBegin(int id, PG_Widget* widget, unsigned long data, void *clientdata) {}
+
+void PG_LineEdit::eventEditEnd(int id, PG_Widget* widget, unsigned long data, void *clientdata) {}
+
+bool PG_LineEdit::IsCursorVisible() {
+ return my_isCursorVisible;
+}
+
+bool PG_LineEdit::eventFilterKey(const SDL_KeyboardEvent* key) {
+ return false;
+}
+/*
+void PG_LineEdit::LoadThemeStyle(const char* widgettype) {
+ // load defaults first
+ if(strcmp(widgettype, "LineEdit") != 0) {
+ LoadThemeStyle("LineEdit");
+ }
+
+ // load custom values
+ PG_ThemeWidget::LoadThemeStyle(widgettype, "LineEdit");
+ LoadThemeStyle(widgettype, "LineEdit");
+}
+
+void PG_LineEdit::LoadThemeStyle(const char* widgettype, const char* objectname) {
+ PG_Theme* t = PG_Application::GetTheme();
+
+ my_srfTextCursor = t->FindSurface(widgettype, objectname, "textcursor");
+
+ const char* keys = t->FindString(widgettype, objectname, "validkeys");
+
+ if(keys != NULL) {
+ SetValidKeys(keys);
+ }
+}
+*/
+void PG_LineEdit::SendChar(PG_Char c) {
+ if(!IsValidKey(c)) {
+ return;
+ }
+
+ InsertChar(&c);
+}
+
+void PG_LineEdit::SendDel() {
+ DeleteChar(my_cursorPosition);
+ SetCursorPos(my_cursorPosition);
+}
+
+void PG_LineEdit::SendBackspace() {
+ if(my_cursorPosition > 0) {
+ DeleteChar(my_cursorPosition-1);
+ SetCursorPos(--my_cursorPosition);
+ }
+}
+
+void PG_LineEdit::SetValidKeys(const char* keys) {
+ my_validkeys = keys;
+}
+
+bool PG_LineEdit::IsValidKey(PG_Char c) {
+ if(my_validkeys.size() == 0) {
+ return true;
+ }
+
+ return (my_validkeys.find(c) != PG_String::npos);
+}
+
+void PG_LineEdit::eventHide() {
+ if(my_isCursorVisible) {
+ EditEnd();
+ }
+}
+
+void PG_LineEdit::SetEditable(bool edit) {
+ my_isEditable = edit;
+ if (!edit && my_isCursorVisible)
+ EditEnd();
+}
+
+bool PG_LineEdit::GetEditable() {
+ return my_isEditable;
+}
+
+bool PG_LineEdit::Action(KeyAction action) {
+
+ switch(action) {
+ case ACT_OK:
+ EditBegin();
+ return true;
+ case ACT_CANCEL:
+ EditEnd();
+ return true;
+ default:
+ break;
+ }
+
+ return PG_Widget::Action(action);
+}
+
+void PG_LineEdit::SetPassHidden(char passchar) {
+ my_passchar = passchar;
+}
+
+char PG_LineEdit::GetPassHidden() {
+ return my_passchar;
+}
diff --git a/src/paragui/pglineedit.h b/src/paragui/pglineedit.h
new file mode 100644
index 0000000..d7b80f3
--- /dev/null
+++ b/src/paragui/pglineedit.h
@@ -0,0 +1,219 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pglineedit.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#ifndef PG_LINEEDIT
+#define PG_LINEEDIT
+
+#include "pgwidget.h"
+#include "pgsignals.h"
+// #include "pgstring.h"
+
+/**
+ @author Alexander Pipelka
+
+ @short An editable text box.
+
+ This really should be renamed to PG_TextBox or something similar, because
+ PG_LineEdit really makes no sense :). Also the 'Edit' part implies that
+ it will always be modifiable, but having a modifyable attribute would
+ probably be better than creating a whole new widget for an unmodifiable
+ text box.
+*/
+
+class PG_LineEdit : public PG_Widget {
+//class PG_LineEdit : public PG_ThemeWidget {
+public:
+
+ /**
+ Signal type declaration
+ **/
+ template<class datatype = PG_Pointer> class SignalEditBegin : public PG_Signal1<PG_LineEdit*, datatype> {};
+ template<class datatype = PG_Pointer> class SignalEditEnd : public PG_Signal1<PG_LineEdit*, datatype> {};
+ template<class datatype = PG_Pointer> class SignalEditReturn : public PG_Signal1<PG_LineEdit*, datatype> {};
+
+ /** */
+ PG_LineEdit(PG_Widget* parent, const PG_Rect& r = PG_Rect::null, const char* style="LineEdit", int maximumLength = 1000000);
+
+ /** */
+ ~PG_LineEdit();
+
+ // void LoadThemeStyle(const char* widgettype);
+
+ /** */
+ // void LoadThemeStyle(const char* widgettype, const char* objectname);
+
+ /** start edit */
+ void EditBegin();
+
+ /** */
+ void EditEnd();
+
+ /** */
+ virtual void SetCursorPos(int p);
+
+ /** */
+ int GetCursorPos();
+
+ /**
+ Set the current text string
+ @param new_text pointer to text string
+ */
+ virtual void SetText(const char* new_text);
+
+ /** */
+ bool IsCursorVisible();
+
+ /**
+ Send a char into the LineEdit widget
+
+ @param c the character to insert
+ */
+ void SendChar(PG_Char c);
+
+ /**
+ Send a 'del' keystroke into the LineEdit widget
+ */
+ void SendDel();
+
+ /**
+ Send a 'BKSPC' keystroke into the LineEdit widget
+ */
+ void SendBackspace();
+
+ /**
+ Define a set of valid keys
+
+ @param keys a string which contains all valid chars
+ */
+ void SetValidKeys(const char* keys);
+
+ /**
+ Set if the widget is editable by the user
+ @param edit true - widget is editable / false - widget is read only
+ */
+ void SetEditable(bool edit);
+
+ /**
+ Check if the widget is editable by the user
+ @return true - widget is editable / false - widget is read only
+ */
+ bool GetEditable();
+
+ /**
+ Set password character (witch will be displayed in place of letter)
+ @param passchar character (if = 0 do not any replacement)
+ */
+ void SetPassHidden(char passchar);
+
+ /**
+ Return setted passchar
+ @return Returns character, witch is displayed in place on letters
+ */
+ char GetPassHidden();
+
+ bool Action(KeyAction action);
+
+ SignalEditBegin<> sigEditBegin;
+ SignalEditEnd<> sigEditEnd;
+ SignalEditReturn<> sigEditReturn;
+
+protected:
+
+ /** */
+ virtual void InsertChar(const PG_Char* c);
+
+ /** */
+ virtual void DeleteChar(Uint16 pos);
+
+ /** */
+ void CopyText(bool del = false);
+
+ /** */
+ void PasteText(Uint16 pos);
+
+ /** */
+ void StartMark(Uint16 pos);
+
+ /** */
+ void EndMark(Uint16 pos);
+
+ /** */
+ virtual bool eventFilterKey(const SDL_KeyboardEvent* key);
+
+ /** */
+ virtual void eventEditBegin(int id, PG_Widget* widget, unsigned long data, void *clientdata);
+
+ /** */
+ virtual void eventEditEnd(int id, PG_Widget* widget, unsigned long data, void *clientdata);
+
+ /** */
+ void eventBlit(SDL_Surface* surface, const PG_Rect& src, const PG_Rect& dst);
+ //void eventDraw(SDL_Surface* surface, const PG_Rect& rect);
+
+ /** */
+ bool eventKeyDown(const SDL_KeyboardEvent* key);
+
+ /** */
+ bool eventMouseButtonUp(const SDL_MouseButtonEvent* button);
+
+ /** */
+ void eventInputFocusLost(PG_MessageObject* newfocus);
+
+ void eventHide();
+
+ int my_cursorPosition;
+
+ SDL_Surface* my_srfTextCursor;
+
+private:
+
+ PG_LineEdit(const PG_LineEdit&);
+ PG_LineEdit& operator=(PG_LineEdit&);
+
+ void DrawText(const PG_Rect& dst);
+ void DrawTextCursor();
+ Uint16 GetCursorXPos();
+ PG_String GetDrawText();
+ int GetCursorPosFromScreen(int x, int y);
+
+ bool IsValidKey(PG_Char c);
+
+ std::string my_buffer;
+ int my_startMark;
+ int my_endMark;
+
+ bool my_isCursorVisible;
+ int my_offsetX;
+ PG_String my_validkeys;
+ bool my_isEditable;
+ int my_maximumLength;
+
+ PG_Char my_passchar;
+};
+
+#endif // PG_LINEEDIT
diff --git a/src/paragui/pglistbox.cpp b/src/paragui/pglistbox.cpp
new file mode 100644
index 0000000..7dc6a95
--- /dev/null
+++ b/src/paragui/pglistbox.cpp
@@ -0,0 +1,281 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pglistbox.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pglistbox.h"
+#include "pglistboxbaseitem.h"
+#include "pgscrollarea.h"
+#include "common.h"
+
+PG_ListBox::PG_ListBox(PG_Widget* parent, const PG_Rect& r, const char* style) :
+ PG_WidgetList(parent, r, style),
+ m_poCurrentItem(NULL), my_alignment(PG_Label::LEFT)
+{
+ my_multiselect = false;
+ my_indent = 0;
+}
+
+PG_ListBox::~PG_ListBox()
+{
+}
+
+void PG_ListBox::AddChild(PG_Widget* item)
+{
+ if(item == NULL)
+ {
+ return;
+ }
+
+ item->SizeWidget(Width(), item->Height());
+
+ PG_WidgetList::AddChild(item);
+}
+
+void PG_ListBox::SetMultiSelect(bool multi)
+{
+ my_multiselect = multi;
+}
+
+bool PG_ListBox::GetMultiSelect()
+{
+ return my_multiselect;
+}
+
+// =======================================================================
+// Interface for PG_ListBoxBaseItems
+// =======================================================================
+
+void PG_ListBox::OnItemSelected(PG_ListBoxBaseItem* item, bool select)
+{
+ if(item == NULL)
+ {
+ return;
+ }
+
+ if(!my_multiselect)
+ {
+ if((m_poCurrentItem != NULL) && (m_poCurrentItem != item))
+ {
+ m_poCurrentItem->Select(false);
+ m_poCurrentItem->Update();
+ }
+
+ m_poCurrentItem = item;
+ m_poCurrentItem->Update();
+ }
+
+ if (select)
+ {
+ sigSelectItem(item);
+ eventSelectItem(item);
+ EnsureVisible(item);
+ }
+}
+
+void PG_ListBox::OnItemDeleted(PG_ListBoxBaseItem *a_poItem)
+{
+ if (m_poCurrentItem == a_poItem)
+ {
+ m_poCurrentItem = NULL;
+ }
+}
+
+void PG_ListBox::EnsureVisible(PG_ListBoxBaseItem *a_poItem)
+{
+ my_scrollarea->EnsureVisible(a_poItem);
+ CheckScrollBars();
+}
+
+bool PG_ListBox::eventSelectItem(PG_ListBoxBaseItem* item)
+{
+ return false;
+}
+
+bool PG_ListBox::eventKeyDown(const SDL_KeyboardEvent* key)
+{
+ switch(key->keysym.sym)
+ {
+ case SDLK_UP:
+ SelectPrevItem();
+ return true;
+ case SDLK_DOWN:
+ SelectNextItem();
+ return true;
+ case SDLK_HOME:
+ SelectFirstItem();
+ return true;
+ }
+
+ return false;
+}
+
+bool PG_ListBox::eventMouseButtonUp(const SDL_MouseButtonEvent* button)
+{
+ SetInputFocus();
+ return true;
+}
+
+bool PG_ListBox::eventMouseButtonDown(const SDL_MouseButtonEvent* button)
+{
+ return true;
+}
+
+bool PG_ListBox::eventMouseMotion(const SDL_MouseMotionEvent* motion)
+{
+ return true;
+}
+
+void PG_ListBox::RemoveAll()
+{
+ m_poCurrentItem = NULL;
+ my_scrollarea->RemoveAll();
+}
+
+void PG_ListBox::DeleteAll()
+{
+ m_poCurrentItem = NULL;
+ my_scrollarea->DeleteAll();
+ my_scrollarea->ScrollTo(0,0);
+ Update();
+}
+
+PG_ListBoxBaseItem* PG_ListBox::GetCurrentItem()
+{
+ return m_poCurrentItem;
+}
+
+void PG_ListBox::SetIndent(Uint16 indent) {
+ my_indent = indent;
+ PG_RectList* list = my_scrollarea->GetChildList();
+ if(list == NULL) {
+ return;
+ }
+
+ for(PG_Widget* w = list->first(); w != NULL; w = w->next()) {
+ PG_ListBoxBaseItem* item = static_cast<PG_ListBoxBaseItem*>(w);
+ item->SetIndent(my_indent);
+ }
+ Update();
+}
+
+void PG_ListBox::SelectFirstItem()
+{
+ PG_ListBoxBaseItem* item = (PG_ListBoxBaseItem*)FindWidget(0);
+
+ if(item == NULL)
+ {
+ return;
+ }
+
+ item->Select();
+}
+
+void PG_ListBox::SelectNextItem()
+{
+ if (m_poCurrentItem)
+ {
+ int index = FindIndex(m_poCurrentItem);
+ index = omMAX(0, index+1);
+ PG_ListBoxBaseItem *item = (PG_ListBoxBaseItem *)FindWidget(index);
+ if (item)
+ {
+ item->Select();
+ }
+ }
+}
+
+void PG_ListBox::SelectPrevItem()
+{
+ if (m_poCurrentItem)
+ {
+ int index = FindIndex(m_poCurrentItem);
+ if (index > 0)
+ {
+ PG_ListBoxBaseItem *item = (PG_ListBoxBaseItem *)FindWidget(index - 1);
+ if (item)
+ {
+ item->Select();
+ }
+ }
+ }
+}
+
+void PG_ListBox::SelectLastItem()
+{
+ PG_ListBoxBaseItem* item = (PG_ListBoxBaseItem*)my_scrollarea->GetChildList()->last();
+ if(item == NULL)
+ {
+ return;
+ }
+
+ item->Select();
+}
+
+int PG_ListBox::GetSelectedIndex()
+{
+ if (m_poCurrentItem)
+ {
+ return FindIndex(m_poCurrentItem);
+ }
+ return -1;
+}
+
+void PG_ListBox::GetSelectedItems(std::vector<PG_ListBoxBaseItem*>& items) {
+ PG_RectList* list = my_scrollarea->GetChildList();
+ if(list == NULL) {
+ return;
+ }
+
+ for(PG_Widget* i = list->first(); i != NULL; i = i->next()) {
+ PG_ListBoxBaseItem* item = static_cast<PG_ListBoxBaseItem*>(i);
+ if (item->IsSelected()) {
+ items.push_back(item);
+ }
+ }
+}
+
+Uint16 PG_ListBox::GetIndent() {
+ return my_indent;
+}
+
+void PG_ListBox::SetAlignment(PG_Label::TextAlign style) {
+ my_alignment = style;
+
+ PG_RectList* list = my_scrollarea->GetChildList();
+ if(list == NULL) {
+ return;
+ }
+
+ for(PG_Widget* i = list->first(); i != NULL; i = i->next()) {
+ static_cast<PG_ListBoxBaseItem*>(i)->SetAlignment(style);
+ }
+ Update();
+}
+
+PG_Label::TextAlign PG_ListBox::GetAlignment() {
+ return my_alignment;
+}
diff --git a/src/paragui/pglistbox.h b/src/paragui/pglistbox.h
new file mode 100644
index 0000000..a9e8e13
--- /dev/null
+++ b/src/paragui/pglistbox.h
@@ -0,0 +1,143 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pglistbox.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#ifndef PG_LISTBOX_H
+#define PG_LISTBOX_H
+
+#include "pgwidgetlist.h"
+#include "pglabel.h"
+
+class PG_ListBoxBaseItem;
+
+/**
+ @author Alexander Pipelka
+
+ @short A scrollable box that can hold any number of text items
+
+ @image html listbox.png "listbox screenshot"
+*/
+
+class PG_ListBox : public PG_WidgetList {
+public:
+
+ /**
+ Signal type declaration
+ **/
+ template<class datatype = PG_Pointer> class SignalSelectItem : public PG_Signal1<PG_ListBoxBaseItem*, datatype> {};
+
+ /** */
+ PG_ListBox(PG_Widget* parent, const PG_Rect& r = PG_Rect::null, const char* style="ListBox");
+ ~PG_ListBox();
+
+ void SetMultiSelect(bool multi = true);
+ bool GetMultiSelect();
+
+ PG_ListBoxBaseItem* GetCurrentItem();
+
+ /** Called by PG_ListBoxBaseItem when it is selected by an event, */
+ void OnItemSelected(PG_ListBoxBaseItem* item, bool select = true);
+ void OnItemDeleted(PG_ListBoxBaseItem* item);
+ void EnsureVisible(PG_ListBoxBaseItem *a_poItem);
+
+ void SelectFirstItem();
+ void SelectNextItem();
+ void SelectPrevItem();
+ void SelectLastItem();
+
+ /**
+ Remove all widgets from the list (without deletion)
+ */
+ void RemoveAll();
+
+ /**
+ Delete (destroy) all widgets in the list
+ */
+ void DeleteAll();
+
+ /**
+ Set the item indentation
+ @param indent number of pixels for item indentation (must be set before adding items)
+ */
+ void SetIndent(Uint16 indent);
+
+ /**
+ Returns the item indentation
+ */
+ Uint16 GetIndent();
+
+ /**
+ Set the alignment for all items
+ @param style alignment to be used for all items
+ */
+ void SetAlignment(PG_Label::TextAlign style);
+
+ /**
+ Returns the set alignment rule of this list
+ */
+ PG_Label::TextAlign GetAlignment();
+
+ /**
+ Returns the index of the last selected item
+ */
+ int GetSelectedIndex();
+
+ void GetSelectedItems(std::vector<PG_ListBoxBaseItem*>& items);
+
+ void AddChild(PG_Widget* child);
+
+ SignalSelectItem<> sigSelectItem;
+
+protected:
+
+ bool eventKeyDown(const SDL_KeyboardEvent* key);
+
+ /** */
+ virtual bool eventSelectItem(PG_ListBoxBaseItem* item);
+
+ /** */
+ bool eventMouseButtonUp(const SDL_MouseButtonEvent* button);
+
+ /** */
+ bool eventMouseButtonDown(const SDL_MouseButtonEvent* button);
+
+ /** */
+ bool eventMouseMotion(const SDL_MouseMotionEvent* motion);
+
+ friend class PG_ListBoxBaseItem;
+
+private:
+
+ bool my_multiselect;
+ Uint16 my_indent;
+
+ PG_ListBoxBaseItem* m_poCurrentItem;
+ PG_Label::TextAlign my_alignment;
+
+};
+
+#endif // PG_LISTBOX_H
diff --git a/src/paragui/pglistboxbaseitem.cpp b/src/paragui/pglistboxbaseitem.cpp
new file mode 100644
index 0000000..ba21fd4
--- /dev/null
+++ b/src/paragui/pglistboxbaseitem.cpp
@@ -0,0 +1,134 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pglistboxbaseitem.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pglistboxbaseitem.h"
+#include "pglistbox.h"
+
+PG_ListBoxBaseItem::PG_ListBoxBaseItem(PG_Widget* parent, Uint16 height, void* userdata) : PG_Label(parent, PG_Rect(0,0,0,height), NULL) {
+ my_userdata = userdata;
+ my_selected = false;
+ my_hover = false;
+ //my_itemheight = height;
+
+ if (parent != NULL) {
+ SetIndent(GetParent()->GetIndent());
+ SetAlignment(GetParent()->GetAlignment());
+ }
+}
+
+PG_ListBoxBaseItem::~PG_ListBoxBaseItem()
+{
+ if(GetParent()->GetCurrentItem() == this)
+ {
+ GetParent()->OnItemDeleted(this);
+ }
+}
+
+void PG_ListBoxBaseItem::SetUserData(void* userdata)
+{
+ my_userdata = userdata;
+}
+
+void* PG_ListBoxBaseItem::GetUserData()
+{
+ return my_userdata;
+}
+
+bool PG_ListBoxBaseItem::IsSelected()
+{
+ return my_selected;
+}
+
+void PG_ListBoxBaseItem::Select(bool select)
+{
+ my_selected = select;
+
+ if(GetParent() != NULL)
+ {
+ if(select)
+ {
+ GetParent()->OnItemSelected(this);
+ }
+ }
+}
+
+void PG_ListBoxBaseItem::eventSizeWidget(Uint16 w, Uint16 h) {
+ //my_itemheight = h;
+}
+
+void PG_ListBoxBaseItem::eventMouseEnter() {
+ my_hover = true;
+ Update();
+}
+
+void PG_ListBoxBaseItem::eventMouseLeave() {
+ my_hover = false;
+ PG_Label::eventMouseLeave();
+ Update();
+}
+
+void PG_ListBoxBaseItem::eventHide() {
+ my_hover = false;
+}
+
+bool PG_ListBoxBaseItem::eventMouseButtonUp(const SDL_MouseButtonEvent* button) {
+
+ if(button->button == 4 && this != PG_Label::GetParent()->GetChildList()->first()) {
+ SDL_WarpMouse(button->x, button->y - my_height);
+ return true;
+ }
+
+ if(button->button == 5 && this != PG_Label::GetParent()->GetChildList()->last()) {
+ SDL_WarpMouse(button->x, button->y + my_height);
+ return true;
+ }
+
+ if(button->button != 1) {
+ return false;
+ }
+
+ if(GetParent() == NULL || !GetParent()->IsVisible()) {
+ return true;
+ }
+
+ GetParent()->SetInputFocus();
+
+ if(GetParent()->GetMultiSelect()) {
+ Select(!IsSelected());
+ } else {
+ Select(true);
+ }
+
+ return true;
+}
+
+PG_ListBox* PG_ListBoxBaseItem::GetParent() {
+ // oh, oh,... close your eyes
+ // hack hack
+ return (PG_ListBox*)(PG_Label::GetParent()->GetParent());
+}
diff --git a/src/paragui/pglistboxbaseitem.h b/src/paragui/pglistboxbaseitem.h
new file mode 100644
index 0000000..b1be35a
--- /dev/null
+++ b/src/paragui/pglistboxbaseitem.h
@@ -0,0 +1,88 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pglistboxbaseitem.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#ifndef PG_LISTBOXBASEITEM_H
+#define PG_LISTBOXBASEITEM_H
+
+#include "pglabel.h"
+
+/**
+ @author Alexander Pipelka
+
+ @short Base class for all items that can be inserted into a PG_ListBox
+*/
+
+class PG_ListBox;
+
+class PG_ListBoxBaseItem : public PG_Label {
+public:
+
+ /** */
+ PG_ListBoxBaseItem(PG_Widget* parent, Uint16 height, void* userdata = NULL);
+
+ /** */
+ ~PG_ListBoxBaseItem();
+
+ /** */
+ void SetUserData(void* userdata);
+
+ /** */
+ void* GetUserData();
+
+ /** */
+ bool IsSelected();
+
+ /** */
+ void Select(bool select = true);
+
+ /** */
+ PG_ListBox* GetParent();
+
+protected:
+
+ void eventSizeWidget(Uint16 w, Uint16 h);
+
+ /** */
+ void eventMouseEnter();
+
+ /** */
+ void eventMouseLeave();
+
+ /** */
+ bool eventMouseButtonUp (const SDL_MouseButtonEvent* button);
+
+ /** */
+ void eventHide();
+
+ void* my_userdata;
+ bool my_selected;
+ bool my_hover;
+ //Uint16 my_itemheight;
+};
+
+#endif // PG_LISTBOXBASEITEM_H
diff --git a/src/paragui/pglistboxitem.cpp b/src/paragui/pglistboxitem.cpp
new file mode 100644
index 0000000..872f703
--- /dev/null
+++ b/src/paragui/pglistboxitem.cpp
@@ -0,0 +1,157 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pglistboxitem.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "gfx.h"
+#include "common.h"
+#include "pglistboxitem.h"
+#include "pglistbox.h"
+
+PG_ListBoxItem::PG_ListBoxItem(PG_Widget* parent, int height, const char* text, SDL_Surface* icon, void* userdata, const char* style) : PG_ListBoxBaseItem(parent, height, userdata) {
+
+ for(int i=0; i<3; i++) {
+ my_background[i] = NULL;
+ my_bkmode[i] = BKMODE_TILE;
+ my_blend[i] = 0;
+ my_gradient[i] = NULL;
+ }
+
+ SetFontColor( PG_Color(0xc0, 0xc0, 0xc0) );
+ SetText(text);
+// LoadThemeStyle(style, "ListBoxItem");
+
+ my_srfHover = NULL;
+ my_srfSelected = NULL;
+
+ my_srfIcon = icon;
+}
+
+PG_ListBoxItem::~PG_ListBoxItem() {
+ SDL_FreeSurface(my_srfHover);
+ SDL_FreeSurface(my_srfSelected);
+}
+
+void PG_ListBoxItem::eventSizeWidget(Uint16 w, Uint16 h) {
+ SDL_FreeSurface(my_srfHover);
+ SDL_FreeSurface(my_srfSelected);
+
+ // reset surface pointers, will be regenerated on next blit
+ my_srfHover = NULL;
+ my_srfSelected = NULL;
+}
+
+void PG_ListBoxItem::eventBlit(SDL_Surface* srf, const PG_Rect& src, const PG_Rect& dst) {
+
+ if((dst.my_width == 0) || (dst.my_height == 0)) {
+ return;
+ }
+
+ if (NULL == my_srfHover)
+ {
+ my_srfHover= SDL_CreateRGBSurface( SDL_HWSURFACE, my_width, my_height,
+ gamescreen->format->BitsPerPixel,
+ gamescreen->format->Rmask, gamescreen->format->Gmask, gamescreen->format->Bmask, gamescreen->format->Amask
+ );
+ SDL_FillRect(my_srfHover, NULL, SDL_MapRGB(my_srfHover->format, 60, 60, 60));
+ SDL_SetAlpha(my_srfHover, SDL_SRCALPHA, 128);
+ }
+
+ if (NULL == my_srfSelected)
+ {
+ my_srfSelected= SDL_CreateRGBSurface( SDL_HWSURFACE, my_width, my_height,
+ gamescreen->format->BitsPerPixel,
+ gamescreen->format->Rmask, gamescreen->format->Gmask, gamescreen->format->Bmask, gamescreen->format->Amask
+ );
+ SDL_FillRect(my_srfSelected, NULL, C_BLUE);
+ SDL_SetAlpha(my_srfSelected, SDL_SRCALPHA, 128);
+ }
+ /*
+ if(my_srfHover == NULL) {
+ my_srfHover = PG_ThemeWidget::CreateThemedSurface(
+ PG_Rect(0, 0, my_width, my_height),
+ my_gradient[2],
+ my_background[2],
+ my_bkmode[2],
+ my_blend[2]);
+ }
+
+ if(my_srfSelected == NULL) {
+ my_srfSelected = PG_ThemeWidget::CreateThemedSurface(
+ PG_Rect(0, 0, my_width, my_height),
+ my_gradient[1],
+ my_background[1],
+ my_bkmode[1],
+ my_blend[1]);
+ }
+ */
+
+ if(my_selected) {
+ RedrawBackground(&dst);
+ SetFontColor( PG_Color(0xf0, 0xf0, 0xf0) );
+ PG_Widget::eventBlit(my_srfSelected, src, dst);
+ }
+ else if(my_hover) {
+ RedrawBackground(&dst);
+ SetFontColor( PG_Color(0xf0, 0xf0, 0x30) );
+ PG_Widget::eventBlit(my_srfHover, src, dst);
+ }
+ else
+ {
+ SetFontColor( PG_Color(0xc0, 0xc0, 0xc0) );
+ }
+
+ PG_Label::eventBlit(NULL, src, dst);
+}
+/*
+void PG_ListBoxItem::LoadThemeStyle(const char* widgettype, const char* objectname) {
+ static char prop[80];
+ PG_Theme* t = PG_Application::GetTheme();
+
+ for(int i=0; i<3; i++) {
+ sprintf(prop, "background%i", i);
+ my_background[i] = t->FindSurface(widgettype, objectname, prop);
+
+ sprintf(prop, "blend%i", i);
+ t->GetProperty(widgettype, objectname, prop, my_blend[i]);
+
+ sprintf(prop, "backmode%i", i);
+ t->GetProperty(widgettype, objectname, prop, my_bkmode[i]);
+
+ sprintf(prop, "gradient%i", i);
+ PG_Gradient* g = t->FindGradient(widgettype, objectname, prop);
+
+ if(g) {
+ my_gradient[i] = g;
+ }
+
+ }
+
+ PG_Color fontcolor(0xFFFFFF);
+ t->GetColor(widgettype, objectname, "textcolor", fontcolor);
+ SetFontColor(fontcolor);
+}
+*/
\ No newline at end of file
diff --git a/src/paragui/pglistboxitem.h b/src/paragui/pglistboxitem.h
new file mode 100644
index 0000000..bee66e6
--- /dev/null
+++ b/src/paragui/pglistboxitem.h
@@ -0,0 +1,67 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pglistboxitem.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#ifndef PG_LISTBOXITEM_H
+#define PG_LISTBOXITEM_H
+
+#include "pglistboxbaseitem.h"
+
+class PG_ListBox;
+
+class PG_ListBoxItem : public PG_ListBoxBaseItem {
+public:
+
+ /** */
+ PG_ListBoxItem(PG_Widget* parent, int height, const char* text = NULL, SDL_Surface* icon = NULL, void* userdata = NULL, const char* style="ListBox");
+
+ /** */
+ ~PG_ListBoxItem();
+
+ /** */
+// void LoadThemeStyle(const char* widgettype, const char* objectname);
+
+protected:
+
+ /** */
+ void eventBlit(SDL_Surface* surface, const PG_Rect& src, const PG_Rect& dst);
+
+ /** */
+ void eventSizeWidget(Uint16 w, Uint16 h);
+
+private:
+
+ PG_Gradient* my_gradient[3];
+ SDL_Surface* my_background[3];
+ SDL_Surface* my_srfHover;
+ SDL_Surface* my_srfSelected;
+
+ int my_bkmode[3];
+ Uint8 my_blend[3];
+};
+
+#endif // PG_LISTBOXITEM_H
diff --git a/src/paragui/pgmessageobject.cpp b/src/paragui/pgmessageobject.cpp
new file mode 100644
index 0000000..f0b03c0
--- /dev/null
+++ b/src/paragui/pgmessageobject.cpp
@@ -0,0 +1,351 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgmessageobject.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pgmessageobject.h"
+//#include "pgapplication.h"
+#include "pgwidget.h"
+//#include "pglog.h"
+
+#include <iostream>
+#include <algorithm>
+
+// static variables for message processing
+//vector<PG_MessageObject*> PG_MessageObject::objectList;
+PG_MessageObject* PG_MessageObject::captureObject = NULL;
+PG_MessageObject* PG_MessageObject::inputFocusObject = NULL;
+PG_Widget* PG_MessageObject::lastwidget = NULL;
+
+/** constructor */
+
+PG_MessageObject::PG_MessageObject() {
+
+ // init vars
+ my_canReceiveMessages = true;
+ my_oldCapture = NULL;
+ my_oldFocus = NULL;
+
+ //objectList.push_back(this);
+}
+
+
+/** destructor */
+
+PG_MessageObject::~PG_MessageObject() {
+
+ //RemoveObject(this);
+
+ //PG_UnregisterEventObject(this);
+
+ if (inputFocusObject == this) {
+ inputFocusObject = NULL;
+ }
+
+ if (lastwidget == this) {
+ lastwidget = NULL;
+ }
+
+ if (captureObject == this) {
+ captureObject = NULL;
+ }
+}
+
+
+bool PG_MessageObject::HandleEvent(SDL_Event *pEvent) // static
+{
+ if((pEvent->type != SDL_USEREVENT) && (pEvent->type != SDL_VIDEORESIZE)) {
+ if(captureObject) {
+ return captureObject->ProcessEvent(pEvent);
+ }
+ }
+
+ PG_Widget* widget = NULL;
+
+ switch(pEvent->type)
+ {
+
+ case SDL_KEYDOWN:
+ case SDL_KEYUP:
+ if(inputFocusObject) {
+ // first send it to the focus object
+ if(inputFocusObject->ProcessEvent(pEvent)) {
+ return true;
+ }
+ // if the focus object doesn't respond -> pump it into the queue
+ }
+ break;
+
+ case SDL_MOUSEMOTION:
+ widget = PG_Widget::FindWidgetFromPos(pEvent->motion.x, pEvent->motion.y);
+
+ if(lastwidget && (lastwidget != widget)) {
+ lastwidget->eventMouseLeave();
+ lastwidget = NULL;
+ }
+
+ if(widget) {
+ lastwidget = widget;
+ widget->ProcessEvent(pEvent);
+ return true;
+ }
+ return true;
+
+ case SDL_MOUSEBUTTONUP:
+ case SDL_MOUSEBUTTONDOWN:
+ widget = PG_Widget::FindWidgetFromPos(pEvent->button.x, pEvent->button.y);
+ if(widget) {
+ widget->ProcessEvent(pEvent);
+ return true;
+ }
+ break;
+ }
+
+ return false;
+}
+
+
+/** enable / disable if object can receive messages */
+
+void PG_MessageObject::EnableReceiver(bool enable) {
+ my_canReceiveMessages = enable;
+}
+
+
+/** message dispatcher */
+
+bool PG_MessageObject::ProcessEvent(const SDL_Event* event) {
+ SDL_Event e;
+
+ // check if we are able to process messages
+ if(!my_canReceiveMessages) {
+ return false;
+ }
+
+ if(event->type != SDL_USEREVENT) {
+ if(captureObject != this)
+ if(!AcceptEvent(event)) {
+ return false;
+ }
+ }
+
+ if((captureObject != NULL) && (captureObject != this)) {
+ return false;
+ }
+
+ while(SDL_PeepEvents(&e, 1, SDL_GETEVENT, SDL_MOUSEMOTIONMASK) > 0);
+
+ bool rc = false;
+
+ // dispatch message
+ switch(event->type) {
+ case SDL_ACTIVEEVENT:
+ rc = eventActive(&event->active) || sigActive(this, &event->active);
+ break;
+
+ case SDL_KEYDOWN:
+ rc = eventKeyDown(&event->key) || sigKeyDown(this, &event->key);
+ break;
+
+ case SDL_KEYUP:
+ rc = eventKeyUp(&event->key) || sigKeyUp(this, &event->key);;
+ break;
+
+ case SDL_MOUSEMOTION:
+ rc = eventMouseMotion(&event->motion) || sigMouseMotion(this, &event->motion);
+ break;
+
+ case SDL_MOUSEBUTTONDOWN:
+ rc = eventMouseButtonDown(&event->button) || sigMouseButtonDown(this, &event->button);
+ break;
+
+ case SDL_MOUSEBUTTONUP:
+ rc = eventMouseButtonUp(&event->button) || sigMouseButtonUp(this, &event->button);
+ break;
+
+ case SDL_QUIT:
+ rc = eventQuit(0, NULL, (unsigned long)&event->quit) || sigQuit(this);
+ break;
+
+ case SDL_SYSWMEVENT:
+ rc = eventSysWM(&event->syswm) || sigSysWM(this, &event->syswm);
+ break;
+
+ case SDL_VIDEORESIZE:
+ rc = eventResize(&event->resize) || sigVideoResize(this, &event->resize);
+ break;
+
+ default:
+ rc = false;
+ break;
+ }
+
+ return rc;
+}
+
+
+/** virtual message handlers */
+
+bool PG_MessageObject::eventActive(const SDL_ActiveEvent* active) {
+ return false;
+}
+
+
+bool PG_MessageObject::eventKeyDown(const SDL_KeyboardEvent* key) {
+ return false;
+}
+
+
+bool PG_MessageObject::eventKeyUp(const SDL_KeyboardEvent* key) {
+ return false;
+}
+
+
+bool PG_MessageObject::eventMouseMotion(const SDL_MouseMotionEvent* motion) {
+ return false;
+}
+
+
+bool PG_MessageObject::eventMouseButtonDown(const SDL_MouseButtonEvent* button) {
+ return false;
+}
+
+
+bool PG_MessageObject::eventMouseButtonUp(const SDL_MouseButtonEvent* button) {
+ return false;
+}
+
+
+bool PG_MessageObject::eventQuit(int id, PG_MessageObject* widget, unsigned long data) {
+ return false;
+}
+
+bool PG_MessageObject::eventQuitModal(int id, PG_MessageObject* widget, unsigned long data) {
+ return false;
+}
+
+
+bool PG_MessageObject::eventSysWM(const SDL_SysWMEvent* syswm) {
+ return false;
+}
+
+
+bool PG_MessageObject::eventResize(const SDL_ResizeEvent* event) {
+ return false;
+}
+
+bool PG_MessageObject::AcceptEvent(const SDL_Event* event) {
+ return true; // PG_MessageObject accepts all events
+}
+
+/** capture handling (an object can capture all messages) */
+
+PG_MessageObject* PG_MessageObject::SetCapture() {
+ if(captureObject == this)
+ return my_oldCapture;
+
+ my_oldCapture = captureObject;
+ captureObject = this;
+ return my_oldCapture;
+}
+
+
+void PG_MessageObject::ReleaseCapture() {
+ if(captureObject != this) {
+ return;
+ }
+
+ captureObject = my_oldCapture;
+}
+
+PG_MessageObject* PG_MessageObject::SetInputFocus() {
+ if(inputFocusObject == this)
+ return my_oldFocus;
+
+ my_oldFocus = inputFocusObject;
+
+ if(my_oldFocus != NULL) {
+ my_oldFocus->eventInputFocusLost(inputFocusObject);
+ }
+
+ inputFocusObject = this;
+ return my_oldFocus;
+}
+
+
+/** */
+void PG_MessageObject::eventInputFocusLost(PG_MessageObject* newfocus) {}
+
+
+/** */
+void PG_MessageObject::ReleaseInputFocus() {
+ if(inputFocusObject != this) {
+ return;
+ }
+
+ inputFocusObject = NULL;
+}
+
+/*SDL_Event PG_MessageObject::WaitEvent(Uint32 delay) {
+ static SDL_Event event;
+
+ while(SDL_PollEvent(&event) == 0) {
+ // eventIdle();
+ if(delay > 0) {
+ SDL_Delay(delay);
+ }
+ }
+
+ return event;
+}*/
+
+
+/** Remove an object from the message queue */
+
+/*bool PG_MessageObject::RemoveObject(PG_MessageObject* obj) {
+ vector<PG_MessageObject*>::iterator list = objectList.begin();
+
+ // search the object
+ list = find(objectList.begin(), objectList.end(), obj);
+
+ // check if object was found
+ if(list == objectList.end()) {
+ return false;
+ }
+
+ // mark object for removal
+ *list = NULL;
+
+ return true;
+}*/
+
+PG_MessageObject* PG_MessageObject::GetCapture() {
+ return captureObject;
+}
+
+bool PG_MessageObject::IsEnabled() {
+ return my_canReceiveMessages;
+}
diff --git a/src/paragui/pgmessageobject.h b/src/paragui/pgmessageobject.h
new file mode 100644
index 0000000..2dbb58f
--- /dev/null
+++ b/src/paragui/pgmessageobject.h
@@ -0,0 +1,295 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgmessageobject.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#ifndef PG_MESSAGEOBJECT_H
+#define PG_MESSAGEOBJECT_H
+
+#include "SDL.h"
+#include "pgsignals.h"
+#include <vector>
+
+class PG_Widget;
+
+/**
+ @author Alexander Pipelka
+
+ @short Base class of all objects (provides message handling).
+
+ Provides a message pump and global handlers for all other PG_MessageObject instances.
+*/
+
+class PG_MessageObject : public virtual SigC::Object {
+
+public:
+
+ /**
+ Signal type declaration
+ **/
+ template<class datatype = PG_Pointer> class SignalActive : public PG_Signal2<PG_MessageObject*, const SDL_ActiveEvent*, datatype> {};
+ template<class datatype = PG_Pointer> class SignalKeyDown : public PG_Signal2<PG_MessageObject*, const SDL_KeyboardEvent*, datatype> {};
+ template<class datatype = PG_Pointer> class SignalKeyUp : public PG_Signal2<PG_MessageObject*, const SDL_KeyboardEvent*, datatype> {};
+ template<class datatype = PG_Pointer> class SignalMouseMotion : public PG_Signal2<PG_MessageObject*, const SDL_MouseMotionEvent*, datatype> {};
+ template<class datatype = PG_Pointer> class SignalMouseButtonDown : public PG_Signal2<PG_MessageObject*, const SDL_MouseButtonEvent*, datatype> {};
+ template<class datatype = PG_Pointer> class SignalMouseButtonUp : public PG_Signal2<PG_MessageObject*, const SDL_MouseButtonEvent*, datatype> {};
+ template<class datatype = PG_Pointer> class SignalQuit : public PG_Signal1<PG_MessageObject*, datatype> {};
+ template<class datatype = PG_Pointer> class SignalSysWM : public PG_Signal2<PG_MessageObject*, const SDL_SysWMEvent*, datatype> {};
+ template<class datatype = PG_Pointer> class SignalVideoResize : public PG_Signal2<PG_MessageObject*, const SDL_ResizeEvent*, datatype> {};
+
+ /**
+ Creates a PG_MessageObject
+ */
+ PG_MessageObject();
+
+ /**
+ Destroys a PG_MessageObject and removes it from the global object list.
+ */
+ virtual ~PG_MessageObject();
+
+ static bool HandleEvent(SDL_Event *pEvent);
+
+ /**
+ This function enables or disables receiving of SDL_Event messages.
+
+ @param enable Enable or disable the ability of receiving messages. When set to false
+ no event handlers will be called for this object
+
+ */
+ void EnableReceiver(bool enable);
+
+ /**
+ Set a message capture for this object. This object will receive all SDL_Event messages regardless
+ if it is able to process them or not.
+ */
+ PG_MessageObject* SetCapture();
+
+ /**
+ Releases a previous capture.
+ */
+ void ReleaseCapture();
+
+ /**
+ Return the current capture object.
+ */
+ PG_MessageObject* GetCapture();
+
+ /**
+ Set an inputfocus for this object
+ @return pointer to the object that had the inputfocus till now
+ If the inputfocus is set all key events will be sent to this object
+ */
+ PG_MessageObject* SetInputFocus();
+
+ /**
+ Release the inputfocus
+ */
+ void ReleaseInputFocus();
+
+ /**
+ Check if the object can receive messages
+ @return true/false
+ returns true when the object can receive messages or false if not.
+ */
+ bool IsEnabled();
+
+ /** */
+ //static SDL_Event WaitEvent(Uint32 delay=0);
+
+ /**
+ Sends an event directly to an object.
+
+ @param event SDL_Event message
+
+ @return Notifies the message pump if this message is processed by this object or it should be routed to the next message receiver.
+ */
+ virtual bool ProcessEvent(const SDL_Event* event);
+
+ SignalActive<> sigActive;
+ SignalKeyDown<> sigKeyDown;
+ SignalKeyUp<> sigKeyUp;
+ SignalMouseMotion<> sigMouseMotion;
+ SignalMouseButtonDown<> sigMouseButtonDown;
+ SignalMouseButtonUp<> sigMouseButtonUp;
+ SignalSysWM<> sigSysWM;
+ SignalVideoResize<> sigVideoResize;
+ SignalQuit<> sigQuit;
+
+protected:
+
+ /**
+ Overridable Eventhandler for the SDL_ActiveEvent message.
+ The default implementation returns 'false' which indicates that this message is not processed by this object.
+
+ @param active SDL_ActiveEvent message
+
+ @return Notifies the message pump if this message is processed by this object or it should be routed to the next message receiver.
+ */
+ virtual bool eventActive(const SDL_ActiveEvent* active);
+
+ /**
+ Overridable Eventhandler for a SDL_KeyboardEvent message.
+ This handler is called when a key changed it's state from unpressed to pressed.
+ The default implementation returns 'false' which indicates that this message is not processed by this object.
+
+ @param key SDL_KeyboardEvent message
+
+ @return Notifies the message pump if this message is processed by this object or it should be routed to the next message receiver.
+ */
+ virtual bool eventKeyDown(const SDL_KeyboardEvent* key);
+
+ /**
+ Overridable Eventhandler for a SDL_KeyboardEvent message.
+ This handler is called when a key changed it's state from pressed to unpressed.
+ The default implementation returns 'false' which indicates that this message is not processed by this object.
+
+ @param key SDL_KeyboardEvent message
+
+ @return Notifies the message pump if this message is processed by this object or it should be routed to the next message receiver.
+ */
+ virtual bool eventKeyUp(const SDL_KeyboardEvent* key);
+
+ /**
+ Overridable Eventhandler for a SDL_MouseMotionEvent message.
+ This handler is called when mouse movement is detected.
+ The default implementation returns 'false' which indicates that this message is not processed by this object.
+
+ @param motion SDL_MouseMotionEvent message
+
+ @return Notifies the message pump if this message is processed by this object or it should be routed to the next message receiver.
+ */
+ virtual bool eventMouseMotion(const SDL_MouseMotionEvent* motion);
+
+ /**
+ Overridable Eventhandler for a SDL_MouseButtonEvent message.
+ This handler is called when a mouse button is pressed.
+ The default implementation returns 'false' which indicates that this message is not processed by this object.
+
+ @param button SDL_MouseButtonEvent message
+
+ @return Notifies the message pump if this message is processed by this object or it should be routed to the next message receiver.
+ */
+ virtual bool eventMouseButtonDown(const SDL_MouseButtonEvent* button);
+
+ /**
+ Overridable Eventhandler for a SDL_MouseButtonEvent message.
+ This handler is called when a mouse button is released.
+ The default implementation returns 'false' which indicates that this message is not processed by this object.
+
+ @param button SDL_MouseButtonEvent message
+
+ @return Notifies the message pump if this message is processed by this object or it should be routed to the next message receiver.
+ */
+ virtual bool eventMouseButtonUp(const SDL_MouseButtonEvent* button);
+
+ /**
+ Overridable Eventhandler for a SDL_QuitEvent message.
+ The default implementation returns 'false' which indicates that this message is not processed by this object.
+
+ @param id id of the sending widget
+ @param widget pointer to the widget
+ @param data event specific data
+
+ @return Notifies the message pump if this message is processed by this object or it should be routed to the next message receiver.
+ */
+ virtual bool eventQuit(int id, PG_MessageObject* widget, unsigned long data);
+
+ /**
+ Overridable Eventhandler for a MSG_QUITMODAL message.
+ The default implementation returns 'false' which indicates that this message is not processed by this object.
+
+ @param id id of the sending widget
+ @param widget pointer to the widget
+ @param data event specific data
+
+ @return Notifies the message pump if this message is processed by this object or it should be routed to the next message receiver.
+ */
+ virtual bool eventQuitModal(int id, PG_MessageObject* widget, unsigned long data);
+
+ /**
+ Overridable Eventhandler for a SDL_SysWMEvent message.
+ The default implementation returns 'false' which indicates that this message is not processed by this object.
+
+ @param syswm SDL_SysWMEvent message
+
+ @return Notifies the message pump if this message is processed by this object or it should be routed to the next message receiver.
+ */
+ virtual bool eventSysWM(const SDL_SysWMEvent* syswm);
+
+ /**
+ Overridable Eventhandler for a SDL_ResizeEvent message.
+ The default implementation returns 'false' which indicates that this message is not processed by this object.
+
+ @param event SDL_ResizeEvent message
+
+ @return Notifies the message pump if this message is processed by this object or it should be routed to the next message receiver.
+ */
+ virtual bool eventResize(const SDL_ResizeEvent* event);
+
+ /**
+ Overridable Eventhandler for a SDL_SysUserEvent message.
+ The default implementation returns 'false' which indicates that this message is not processed by this object.
+
+ @param event SDL_SysUserEvent message
+
+ @return Notifies the message pump if this message is processed by this object or it should be routed to the next message receiver.
+ */
+ //virtual bool eventMessage(MSG_MESSAGE* msg);
+
+ /** */
+ virtual void eventInputFocusLost(PG_MessageObject* newfocus);
+
+ /**
+ Overridable message filter function. Derivated classes can filter special events.
+ The default implementation returns 'false' which indicates that this message is not processed by this object.
+
+ @param event SDL_Event message
+
+ @return Notifies the message pump if this message is processed by this object or it should be routed to the next message receiver.
+ */
+ virtual bool AcceptEvent(const SDL_Event* event);
+
+ //static vector<PG_MessageObject*> objectList;
+
+ static PG_MessageObject* captureObject;
+
+private:
+
+ PG_MessageObject(const PG_MessageObject&);
+ PG_MessageObject& operator=(const PG_MessageObject&);
+
+ //bool RemoveObject(PG_MessageObject* obj);
+
+ static PG_MessageObject* inputFocusObject;
+ static PG_Widget* lastwidget;
+
+ PG_MessageObject* my_oldCapture;
+ PG_MessageObject* my_oldFocus;
+
+ bool my_canReceiveMessages;
+};
+
+#endif // PG_MESSAGEOBJECT_H
diff --git a/src/paragui/pgmultilineedit.cpp b/src/paragui/pgmultilineedit.cpp
new file mode 100644
index 0000000..0c0d18f
--- /dev/null
+++ b/src/paragui/pgmultilineedit.cpp
@@ -0,0 +1,702 @@
+#include "common.h"
+#include "pgmultilineedit.h"
+
+using namespace std;
+
+/*
+Selection is between: my_mark and my_cursorPosition.
+If my_mark is negative, there is no selection.
+*/
+
+PG_MultiLineEdit::PG_MultiLineEdit(PG_Widget* parent, const PG_Rect& r, const char* style, int maximumLength)
+: PG_LineEdit(parent, r, style, maximumLength)
+{
+ my_vscroll = new PG_ScrollBar(this, PG_Rect(r.w-16,0,16,r.h));
+ my_isCursorAtEOL = false;
+ my_allowHiddenCursor = true;
+ my_firstLine = 0;
+ my_vscroll->sigScrollPos.connect(slot(*this, &PG_MultiLineEdit::handleScroll));
+ my_vscroll->sigScrollTrack.connect(slot(*this, &PG_MultiLineEdit::handleScroll));
+ my_vscroll->Hide();
+ my_mark = -1;
+}
+
+bool PG_MultiLineEdit::handleScroll(PG_ScrollBar* widget, long data)
+{
+ SetVPosition(my_vscroll->GetPosition());
+ my_allowHiddenCursor = true;
+ return true;
+}
+
+void PG_MultiLineEdit::AddText(const char* text, PG_Color color, bool update)
+{
+ SetFontColor(color);
+ AddText(text, update);
+}
+
+void PG_MultiLineEdit::AddText(const char* text, bool update)
+{
+ size_t PreviousLength = my_text.size();
+ my_text += "\n";
+ my_text += text;
+ AppendTextVector(PreviousLength+1);
+
+ SetupVScroll();
+ my_isCursorAtEOL = false;
+ my_allowHiddenCursor = false;
+ if (!SetVPosition(my_vscroll->GetMaxRange()))
+ {
+ Update();
+ }
+}
+
+bool PG_MultiLineEdit::SetVPosition(int line)
+{
+ line = omMAX(line, 0);
+ line = omMIN(line, my_vscroll->GetMaxRange());
+
+ if (line == my_firstLine)
+ {
+ return false;
+ }
+
+ my_firstLine = line;
+
+ if (my_vscroll->GetPosition() != my_firstLine)
+ {
+ my_vscroll->SetPosition(my_firstLine);
+ }
+
+ Update();
+ return true;
+}
+
+void PG_MultiLineEdit::eventBlit(SDL_Surface* surface, const PG_Rect& src, const PG_Rect& dst)
+{
+ PG_Widget::eventBlit(surface, src, dst);
+ DrawText(dst);
+}
+
+void PG_MultiLineEdit::DrawText(const PG_Rect& dst)
+{
+ int _x = 3;
+ int _y = 3;
+ unsigned int i;
+
+ // should we draw the cursor ?
+ if(IsCursorVisible()) {
+ DrawTextCursor();
+ }
+
+ // figure out the cursor position that we start at
+ int pos = 0;
+ for (i = 0; i < (unsigned int)my_firstLine; ++i) {
+ pos += my_textdata[i].first.size();
+ }
+
+ // draw text
+ int maxLines = my_height/GetFontSize() + 1;
+ int endpos, start, end;
+
+ int x1 = 0;
+ Uint16 w = 0;
+ int offset = 0;
+
+ for (i = my_firstLine;
+ i < (unsigned int)my_firstLine + maxLines && i < my_textdata.size();
+ ++i)
+ {
+ PG_Color linecolor= my_textdata[i].second;
+ endpos = pos + my_textdata[i].first.size();
+ start = (my_cursorPosition < my_mark ? my_cursorPosition : my_mark);
+ end = (my_cursorPosition >= my_mark ? my_cursorPosition : my_mark);
+
+ // check if we are in the highlighted section
+ if (my_mark != -1
+ && my_mark != my_cursorPosition
+ && pos <= end
+ && endpos >= start)
+ {
+ x1 = _x;
+ offset = 0;
+
+ // draw the initial unhighlighted part
+ if (pos < start) {
+ string s = my_textdata[i].first.substr(0, start-pos);
+ PG_Widget::DrawText(x1, _y, s.c_str(), linecolor );
+ PG_FontEngine::GetTextSize(s.c_str(), GetFont(), &w);
+ x1 += w;
+ offset = start-pos;
+ }
+
+ string middlepart = my_textdata[i].first.c_str() + offset;
+ // check if the end part is unhighlighted
+ if (endpos > end) {
+ middlepart = middlepart.substr(0, middlepart.size() - (endpos-end));
+ string s = my_textdata[i].first.substr(end - pos, my_textdata[i].first.size() - (end - pos));
+ PG_FontEngine::GetTextSize(middlepart.c_str(), GetFont(), &w);
+ PG_Widget::DrawText(x1+w, _y, s.c_str(), linecolor);
+ }
+
+ PG_Color color(linecolor);
+ PG_Color inv_color(255 - color.r, 255 - color.g, 255 - color.b);
+ SetFontColor(inv_color);
+ PG_FontEngine::GetTextSize(middlepart.c_str(), GetFont(), &w);
+ SDL_Rect rect = {x + x1, y + _y, w, GetFontHeight()};
+ SDL_Surface* screen = gamescreen;
+ SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, color.r, color.g, color.b));
+ PG_Widget::DrawText(x1, _y, middlepart.c_str());
+ SetFontColor(color);
+ }
+ else {
+ PG_Widget::DrawText(_x, _y, my_textdata[i].first.c_str(), linecolor);
+ }
+ _y += GetFontHeight();
+ pos += my_textdata[i].first.size();
+ }
+}
+
+void PG_MultiLineEdit::DrawTextCursor()
+{
+ int x = my_xpos + 1;
+ int y = my_ypos + 1;
+ int xpos, ypos;
+ GetCursorPos(xpos, ypos);
+
+ /*
+ // check for a hidden cursor
+ if(!my_allowHiddenCursor) {
+ // scroll up for cursor
+ while (ypos < 0 && my_firstLine > 0) {
+ SetVPosition(--my_firstLine);
+ GetCursorPos(xpos, ypos);
+ }
+
+ // scroll down for cursor
+ while (ypos + GetFontHeight() > my_height && my_firstLine < my_vscroll->GetMaxRange()) {
+ SetVPosition(++my_firstLine);
+ GetCursorPos(xpos, ypos);
+ }
+ }
+ */
+
+ // draw simple cursor
+ if(my_srfTextCursor == NULL)
+ {
+ DrawVLine(xpos + 2, ypos + 2, GetFontHeight()-4, PG_Color(255, 255, 255));
+ }
+ // draw a nice cursor bitmap
+ else
+ {
+ PG_Rect src, dst;
+ PG_Rect rect(x + xpos, y + ypos + GetFontHeight()/2 - my_srfTextCursor->h/2,
+ my_srfTextCursor->w, my_srfTextCursor->h);
+ GetClipRects(src, dst, rect);
+ PG_Widget::eventBlit(my_srfTextCursor, src, dst);
+ }
+}
+
+void PG_MultiLineEdit::FindWordRight() {
+ unsigned int currentPos = my_cursorPosition;
+
+ // step off the initial space
+ ++currentPos;
+
+ // find the next space
+ while (currentPos-1 <= my_text.size() && my_text[currentPos-1] != ' ' && my_text[currentPos-1] != '\n') {
+ ++currentPos;
+ }
+
+ // go to the end of multiple spaces
+ while (currentPos <= my_text.size() && (my_text[currentPos] == ' ' || my_text[currentPos] == '\n')) {
+ ++currentPos;
+ }
+
+ SetCursorPos(currentPos);
+}
+
+void PG_MultiLineEdit::FindWordLeft() {
+ unsigned int currentPos = my_cursorPosition;
+
+ // step off the initial space(s)
+ while (currentPos-1 >= 0 && (my_text[currentPos-1] == ' ' || my_text[currentPos-1] == '\n')) {
+ --currentPos;
+ }
+
+ // find the next space
+ while (currentPos-1 >= 0 && my_text[currentPos-1] != ' ' && my_text[currentPos-1] != '\n') {
+ --currentPos;
+ }
+
+ SetCursorPos(currentPos);
+}
+
+void PG_MultiLineEdit::GetCursorTextPosFromScreen(int x, int y, unsigned int& horzOffset, unsigned int& lineOffset)
+{
+ // check for an empty text box
+ if (my_textdata.size() == 0) {
+ horzOffset = 0;
+ lineOffset = 0;
+ return;
+ }
+
+ // get the line number
+ int ypos = (y - my_ypos - 3) / GetFontHeight() + my_firstLine;
+
+ // stay within limits
+ if (ypos < 0)
+ {
+ ypos = 0;
+ }
+
+ if ((unsigned int)ypos >= my_textdata.size())
+ {
+ ypos = my_textdata.size()-1;
+ }
+
+ unsigned int min = (unsigned int)-1;
+ unsigned int min_xpos = 0;
+
+ // loop through to find the closest x position
+ string temp;
+ for (Uint16 i = 0; i <= my_textdata[ypos].first.size(); ++i)
+ {
+ // get the string up to that point
+ temp = my_textdata[ypos].first.substr(0, i);
+
+ // get the distance for that section
+ Uint16 w;
+ PG_FontEngine::GetTextSize(temp.c_str(), GetFont(), &w);
+ unsigned int dist = abs(x - (my_xpos + 3 + w));
+
+ // update minimum
+ if (dist < min) {
+ min = dist;
+ min_xpos = i;
+ }
+ }
+
+ // set return data
+ horzOffset = min_xpos;
+ lineOffset = (unsigned int)ypos;
+}
+
+void PG_MultiLineEdit::GetCursorTextPos(unsigned int& horzOffset, unsigned int& lineOffset) {
+ // check for an empty text box
+ if (my_textdata.size() == 0) {
+ horzOffset = 0;
+ lineOffset = 0;
+ return;
+ }
+
+ unsigned int currentPos = my_cursorPosition;
+ unsigned int line = 0;
+
+ // cycle through the lines, finding where our cursor lands
+ for (cTextData::iterator i = my_textdata.begin(); i != my_textdata.end(); ++i) {
+ if(currentPos < i->first.size() || (currentPos <= i->first.size() && my_isCursorAtEOL)) {
+ break;
+ }
+ currentPos -= i->first.size();
+ line++;
+ }
+
+ // if we're too far, assume we're at the end of the string
+ if (line >= my_textdata.size()) {
+ line = my_textdata.size()-1;
+ currentPos = my_textdata[line].first.size();
+ }
+
+ // if we're too far on this line, assum we're at the end of line
+ if (currentPos > my_textdata[line].first.size()) {
+ currentPos = my_textdata[line].first.size();
+ }
+
+ horzOffset = currentPos;
+ lineOffset = line;
+}
+
+void PG_MultiLineEdit::GetCursorPos(int& x, int& y) {
+ // check for an empty text box
+ if (my_textdata.size() == 0) {
+ x = 0;
+ y = 0;
+ return;
+ }
+
+ // get the cursor text position
+ unsigned int currentPos, line;
+ GetCursorTextPos(currentPos, line);
+
+ // now get the x,y position
+ string temp = my_textdata[line].first.substr(0, currentPos);
+
+ Uint16 w;
+ PG_FontEngine::GetTextSize(temp.c_str(), GetFont(), &w);
+
+ x = w;
+ y = (line - my_firstLine)*GetFontHeight();
+}
+
+void PG_MultiLineEdit::CreateTextVector(bool bSetupVScroll)
+{
+ my_textdata.clear();
+ AppendTextVector(0);
+ // setup the scrollbar
+ if(bSetupVScroll) {
+ SetupVScroll();
+ }
+}
+
+
+void PG_MultiLineEdit::AppendTextVector(unsigned int start)
+{
+// int w = my_width - 6 - ((my_vscroll->IsVisible() || !my_vscroll->IsHidden()) ? my_vscroll->w : 0);
+ int w = my_width - 6 - my_vscroll->w;
+ unsigned int end = start, last = start;
+
+ do {
+ Uint16 lineWidth = 0;
+ PG_String temp = my_text.substr(start, end-start);
+ PG_FontEngine::GetTextSize(temp.c_str(), GetFont(), &lineWidth);
+
+ if (lineWidth > w) {
+ if (last == start) {
+ PG_String s = my_text.substr(start, end-start-1);
+ my_textdata.push_back( cColoredText(s, GetFontColor()) );
+ start = --end;
+ }
+ else {
+ PG_String s = my_text.substr(start, last-start);
+ my_textdata.push_back( cColoredText(s, GetFontColor()) );
+ start = last;
+ end = last-1;
+ }
+ last = start;
+ }
+
+ else if (my_text[end] == ' ') {
+ last = end+1;
+ }
+
+ else if (my_text[end] == '\n' || my_text[end] == '\0') {
+ PG_String s = my_text.substr(start, end-start+1);
+ my_textdata.push_back( cColoredText(s, GetFontColor()) );
+ start = end+1;
+ last = start;
+ }
+ } while (end++ < my_text.size());
+}
+
+void PG_MultiLineEdit::SetupVScroll()
+{
+ if (my_textdata.size()*GetFontHeight() < my_height)
+ {
+ my_vscroll->SetRange(0, 0);
+ my_vscroll->Hide();
+ SetVPosition(0);
+ Update();
+ }
+ else
+ {
+
+ my_vscroll->SetRange(0, my_textdata.size() - my_height/GetFontHeight());
+ if (my_firstLine > my_vscroll->GetMaxRange()) {
+ SetVPosition(my_vscroll->GetMaxRange());
+ }
+
+ if (!my_vscroll->IsVisible() || my_vscroll->IsHidden()) {
+ // scrollbar makes the window less wide, so we have to redo the text
+ // (note: don't switch these next two lines, unless you like infinite loops)
+ my_vscroll->Show();
+ }
+ }
+}
+
+bool PG_MultiLineEdit::eventKeyDown(const SDL_KeyboardEvent* key) {
+ PG_Char c;
+
+// if(!IsCursorVisible()) {
+// return false;
+// }
+
+ SDL_KeyboardEvent key_copy = *key; // copy key structure
+
+ if ((key_copy.keysym.mod & KMOD_SHIFT) && my_mark == -1) {
+ my_mark = my_cursorPosition;
+ }
+
+ if(key_copy.keysym.mod & KMOD_CTRL) {
+ switch(key_copy.keysym.sym) {
+ case SDLK_HOME:
+ if (!(key_copy.keysym.mod & KMOD_SHIFT)) {
+ my_mark = -1;
+ }
+ SetCursorPos(0);
+ return true;
+
+ case SDLK_END:
+ if (!(key_copy.keysym.mod & KMOD_SHIFT)) {
+ my_mark = -1;
+ }
+ SetCursorPos(my_text.length());
+ return true;
+
+ case SDLK_RIGHT:
+ if (!(key_copy.keysym.mod & KMOD_SHIFT)) {
+ my_mark = -1;
+ }
+ FindWordRight();
+ return true;
+
+ case SDLK_LEFT:
+ if (!(key_copy.keysym.mod & KMOD_SHIFT)) {
+ my_mark = -1;
+ }
+ FindWordLeft();
+ return true;
+
+ case SDLK_UP:
+ my_allowHiddenCursor = true;
+ SetVPosition(--my_firstLine);
+ return true;
+
+ case SDLK_DOWN:
+ my_allowHiddenCursor = true;
+ SetVPosition(++my_firstLine);
+ return true;
+
+ default:
+ break;
+ }
+ }
+ else if(key_copy.keysym.mod & (KMOD_ALT | KMOD_META)) {
+ }
+ else {
+ unsigned int currentPos, line;
+ int x, y;
+
+ switch(key_copy.keysym.sym) {
+ case SDLK_RIGHT:
+ case SDLK_LEFT:
+ if (!(key_copy.keysym.mod & KMOD_SHIFT)) {
+ my_mark = -1;
+ }
+ // break here, we still want PG_LineEdit to handle these
+ break;
+
+ case SDLK_UP:
+ if (!(key_copy.keysym.mod & KMOD_SHIFT)) {
+ my_mark = -1;
+ }
+ GetCursorPos(x, y);
+ GetCursorTextPosFromScreen(my_xpos + x + 3, my_ypos + y + 3 - GetFontHeight(), currentPos, line);
+ SetCursorTextPos(currentPos, line);
+ return true;
+
+ case SDLK_DOWN:
+ if (!(key_copy.keysym.mod & KMOD_SHIFT)) {
+ my_mark = -1;
+ }
+ GetCursorPos(x, y);
+ GetCursorTextPosFromScreen(my_xpos + x + 3, my_ypos + y + 3 + GetFontHeight(), currentPos, line);
+ SetCursorTextPos(currentPos, line);
+ return true;
+
+ case SDLK_PAGEUP:
+ if (!(key_copy.keysym.mod & KMOD_SHIFT)) {
+ my_mark = -1;
+ }
+ GetCursorPos(x, y);
+ GetCursorTextPosFromScreen(my_xpos + x + 3, my_ypos + y + 3 - (my_height - GetFontHeight()), currentPos, line);
+ SetCursorTextPos(currentPos, line);
+ return true;
+
+ case SDLK_PAGEDOWN:
+ if (!(key_copy.keysym.mod & KMOD_SHIFT)) {
+ my_mark = -1;
+ }
+
+ GetCursorPos(x, y);
+ GetCursorTextPosFromScreen(my_xpos + x + 3, my_ypos + y + 3 + (my_height - GetFontHeight()), currentPos, line);
+ SetCursorTextPos(currentPos, line);
+ return true;
+
+ case SDLK_HOME:
+ if (!(key_copy.keysym.mod & KMOD_SHIFT)) {
+ my_mark = -1;
+ }
+ GetCursorTextPos(currentPos, line);
+ SetCursorTextPos(0, line);
+ return true;
+
+ case SDLK_END: {
+ if (!(key_copy.keysym.mod & KMOD_SHIFT)) {
+ my_mark = -1;
+ }
+ GetCursorTextPos(currentPos, line);
+ PG_String &roThisLine= my_textdata[line].first;
+ int cursorPos = roThisLine.size() -
+ (roThisLine[roThisLine.size()-1] == '\n' ? 1 : 0);
+ SetCursorTextPos(cursorPos, line);
+ }
+ return true;
+
+ case SDLK_RETURN:
+ // c = '\n';
+ //InsertChar(&c);
+ //SetCursorPos(my_cursorPosition);
+ return true;
+
+ default:
+ break;
+ }
+ }
+
+ SetCursorPos(my_cursorPosition);
+
+ return PG_LineEdit::eventKeyDown(key);
+}
+
+bool PG_MultiLineEdit::eventMouseButtonDown(const SDL_MouseButtonEvent* button) {
+ // check for mousewheel
+ if ((button->button == 4 || button->button == 5) && my_vscroll->IsVisible()) {
+ if (button->button == 4) {
+ SetVPosition(my_firstLine - 1);
+ }
+ else {
+ SetVPosition(my_firstLine + 1);
+ }
+ return true;
+ }
+
+// if (!GetEditable()) {
+// return false;
+// }
+
+ if (!IsCursorVisible()) {
+ EditBegin();
+ }
+
+ // if we're clicking the scrollbar....
+ if (my_vscroll->IsVisible() && button->x > my_xpos + my_width - my_vscroll->w) {
+ return false;
+ }
+
+ if (button->button == 1) {
+ Uint8* keys = SDL_GetKeyState(NULL);
+
+ if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT])) {
+ my_mark = -1;
+ }
+
+ unsigned int currentPos, line;
+ GetCursorTextPosFromScreen(button->x, button->y, currentPos, line);
+ SetCursorTextPos(currentPos, line);
+ if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT])) {
+ my_mark = my_cursorPosition;
+ }
+ }
+
+ return true;
+}
+
+bool PG_MultiLineEdit::eventMouseMotion(const SDL_MouseMotionEvent* motion) {
+ if (motion->state & SDL_BUTTON(1)) {
+ unsigned int currentPos, line;
+ GetCursorTextPosFromScreen(motion->x, motion->y, currentPos, line);
+ SetCursorTextPos(currentPos, line);
+ }
+
+ return PG_LineEdit::eventMouseMotion(motion);
+}
+
+bool PG_MultiLineEdit::eventMouseButtonUp(const SDL_MouseButtonEvent* button) {
+ if(!GetEditable()) {
+ return false;
+ }
+
+ if(!IsCursorVisible()) {
+ EditBegin();
+ }
+
+ return true;
+}
+
+void PG_MultiLineEdit::SetCursorTextPos(unsigned int offset, unsigned int line) {
+ if (line < 0) {
+ SetCursorPos(0);
+ }
+ else if (line >= my_textdata.size()) {
+ SetCursorPos(my_text.size());
+ my_isCursorAtEOL = false;
+ }
+ else {
+ PG_LineEdit::SetCursorPos(ConvertCursorPos(offset, line));
+ my_isCursorAtEOL = (offset == my_textdata[line].first.size() && my_textdata[line].first.size() != 0);
+ Update();
+ }
+}
+
+int PG_MultiLineEdit::ConvertCursorPos(unsigned int offset, unsigned int line) {
+ unsigned int charCount = 0;
+ for (unsigned int i = 0; i < line; ++i) {
+ charCount += my_textdata[i].first.size();
+ }
+
+ return charCount+offset;
+}
+
+void PG_MultiLineEdit::SetCursorPos(int p) {
+ my_isCursorAtEOL = false;
+ PG_LineEdit::SetCursorPos(p);
+}
+
+void PG_MultiLineEdit::InsertChar(const PG_Char* c) {
+ if (my_mark != -1 && my_mark != my_cursorPosition) {
+ DeleteSelection();
+ }
+
+ PG_LineEdit::InsertChar(c);
+ my_mark = -1;
+ CreateTextVector();
+ Update();
+}
+
+void PG_MultiLineEdit::DeleteChar(Uint16 pos) {
+ if (my_mark != -1 && my_mark != my_cursorPosition) {
+ Uint16 oldpos = my_cursorPosition;
+ DeleteSelection();
+ // check if backspace was pressed
+ if (pos == oldpos-1) {
+ my_cursorPosition++;
+ }
+ }
+ else {
+ PG_LineEdit::DeleteChar(pos);
+ }
+
+ my_mark = -1;
+ CreateTextVector();
+ Update();
+}
+
+void PG_MultiLineEdit::DeleteSelection() {
+ if (my_mark != -1 && my_mark != my_cursorPosition) {
+ int start = (my_cursorPosition < my_mark ? my_cursorPosition : my_mark);
+ int end = (my_cursorPosition >= my_mark ? my_cursorPosition : my_mark);
+ my_text.erase(start, end-start);
+ if (my_mark < my_cursorPosition) {
+ SetCursorPos(my_mark);
+ }
+ my_mark = -1;
+ }
+}
+
+void PG_MultiLineEdit::SetText(const char* new_text) {
+ PG_LineEdit::SetText(new_text);
+ CreateTextVector();
+ my_isCursorAtEOL = false;
+ my_mark = -1;
+ SetVPosition(0);
+}
diff --git a/src/paragui/pgmultilineedit.h b/src/paragui/pgmultilineedit.h
new file mode 100644
index 0000000..dac3708
--- /dev/null
+++ b/src/paragui/pgmultilineedit.h
@@ -0,0 +1,58 @@
+#ifndef PG_MULTI_LINE_EDIT
+#define PG_MULTI_LINE_EDIT
+
+#include "pglineedit.h"
+#include "pgscrollbar.h"
+// #include "pgtheme.h"
+// #include "pgstring.h"
+#include <vector>
+
+class PG_MultiLineEdit : public PG_LineEdit {
+public:
+
+ PG_MultiLineEdit(PG_Widget* parent, const PG_Rect& r, const char* style="LineEdit", int maximumLength = 1000000);
+ virtual void SetText(const char* new_text);
+ PG_ScrollBar *GetScrollBar() { return my_vscroll; }
+ void AddText(const char* text, bool update = false);
+ void AddText(const char* text, PG_Color color, bool update = false );
+
+protected:
+
+ void eventBlit(SDL_Surface* surface, const PG_Rect& src, const PG_Rect& dst);
+ bool eventKeyDown(const SDL_KeyboardEvent* key);
+ bool eventMouseButtonDown(const SDL_MouseButtonEvent* button);
+ bool eventMouseMotion(const SDL_MouseMotionEvent* motion);
+ bool eventMouseButtonUp(const SDL_MouseButtonEvent* button);
+ virtual void InsertChar(const PG_Char* c);
+ virtual void DeleteChar(Uint16 pos);
+ bool handleScroll(PG_ScrollBar* widget, long data);
+
+private:
+
+ void FindWordRight();
+ void FindWordLeft();
+ void DeleteSelection();
+ void GetCursorTextPosFromScreen(int x, int y, unsigned int& horzOffset, unsigned int& lineOffset);
+ void GetCursorTextPos(unsigned int& horzOffset, unsigned int& lineOffset);
+ void SetCursorTextPos(unsigned int offset, unsigned int line);
+ int ConvertCursorPos(unsigned int offset, unsigned int line);
+ void GetCursorPos(int& x, int& y);
+ void SetCursorPos(int p);
+ void DrawText(const PG_Rect& dst);
+ void DrawTextCursor();
+ void CreateTextVector(bool bSetupVScroll = true);
+ void AppendTextVector(unsigned int start);
+ void SetupVScroll();
+ bool SetVPosition(int line);
+
+ typedef std::pair<PG_String,PG_Color> cColoredText;
+ typedef std::vector<cColoredText> cTextData;
+ cTextData my_textdata;
+ PG_ScrollBar* my_vscroll;
+ int my_firstLine;
+ int my_mark;
+ bool my_isCursorAtEOL;
+ bool my_allowHiddenCursor;
+};
+
+#endif
diff --git a/src/paragui/pgpoint.cpp b/src/paragui/pgpoint.cpp
new file mode 100644
index 0000000..9faedb8
--- /dev/null
+++ b/src/paragui/pgpoint.cpp
@@ -0,0 +1,37 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000-2004 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgpoint.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pgpoint.h"
+
+PG_Point PG_Point::null;
+
+PG_Point::PG_Point() : x(0), y(0) {
+}
+
+PG_Point::PG_Point(Sint16 _x, Sint16 _y) : x(_x), y(_y) {
+}
diff --git a/src/paragui/pgpoint.h b/src/paragui/pgpoint.h
new file mode 100644
index 0000000..d428bce
--- /dev/null
+++ b/src/paragui/pgpoint.h
@@ -0,0 +1,60 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000-2004 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgpoint.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#ifndef PG_POINT_H
+#define PG_POINT_H
+
+#include "SDL.h"
+
+
+#include <string>
+#define PG_String std::string
+#define PG_Char char
+
+/**
+ @author Alexander Pipelka
+
+ @short A wrapper for a point on the screen.
+
+ Useful when its necessary to specify a 2D using Cartesian coordinates (x, y).
+
+*/
+
+
+class PG_Point {
+public:
+ PG_Point();
+ PG_Point(Sint16 _x, Sint16 _y);
+
+ Sint16 x;
+ Sint16 y;
+
+ static PG_Point null;
+};
+
+#endif // PG_POINT_H
diff --git a/src/paragui/pgrect.cpp b/src/paragui/pgrect.cpp
new file mode 100644
index 0000000..6907db0
--- /dev/null
+++ b/src/paragui/pgrect.cpp
@@ -0,0 +1,145 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgrect.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pgrect.h"
+
+PG_Rect PG_Rect::null;
+
+PG_Rect::PG_Rect(Sint16 xv, Sint16 yv, Uint16 wv, Uint16 hv) :
+my_xpos(x),
+my_ypos(y),
+my_width(w),
+my_height(h),
+index(0),
+my_next(NULL),
+my_prev(NULL)
+{
+ SetRect(xv, yv, wv, hv);
+}
+
+PG_Rect::PG_Rect(const PG_Rect& src) :
+my_xpos(x),
+my_ypos(y),
+my_width(w),
+my_height(h)
+{
+ *this = src;
+ my_next = NULL;
+ my_prev = NULL;
+}
+
+PG_Rect::PG_Rect(const SDL_Rect& src) :
+my_xpos(x),
+my_ypos(y),
+my_width(w),
+my_height(h)
+{
+ *this = src;
+ my_next = NULL;
+ my_prev = NULL;
+}
+
+PG_Rect::~PG_Rect() {}
+
+PG_Rect PG_Rect::IntersectRect(const PG_Rect& p, const PG_Rect& c) {
+ static int px0,py0,px1,py1;
+ static int cx0,cy0,cx1,cy1;
+ static int rx0,ry0,rx1,ry1;
+
+ // fill in default (NULL) result rectangle
+ PG_Rect result;
+
+ // get coordinates of the rectangles
+ px0 = p.my_xpos;
+ py0 = p.my_ypos;
+ px1 = p.my_xpos + p.my_width - 1;
+ py1 = p.my_ypos + p.my_height - 1;
+
+ cx0 = c.my_xpos;
+ cy0 = c.my_ypos;
+ cx1 = c.my_xpos + c.my_width - 1;
+ cy1 = c.my_ypos + c.my_height - 1;
+
+ // check if the rectangles intersect
+ if((cx1 < px0) || (cx0 > px1) || (cy1 < py0) || (cy0 > py1))
+ return result;
+
+ // intersect x
+ if(cx0 <= px0)
+ rx0 = px0;
+ else
+ rx0 = cx0;
+
+ if(cx1 >= px1)
+ rx1 = px1;
+ else
+ rx1 = cx1;
+
+ // intersect y
+ if(cy0 <= py0)
+ ry0 = py0;
+ else
+ ry0 = cy0;
+
+ if(cy1 >= py1)
+ ry1 = py1;
+ else
+ ry1 = cy1;
+
+ // fill in result rect
+ result.SetRect(
+ rx0,
+ ry0,
+ (rx1-rx0)+1,
+ (ry1-ry0)+1);
+
+ return result;
+}
+
+PG_Rect PG_Rect::IntersectRect(const PG_Rect& p) const {
+ return IntersectRect(p, *this);
+}
+
+PG_Rect& PG_Rect::operator =(const PG_Rect& src) {
+ SetRect(src.x, src.y, src.w, src.h);
+ my_next = NULL;
+ my_prev = NULL;
+ return *this;
+}
+
+PG_Rect PG_Rect::operator / (PG_Rect& b) {
+ return IntersectRect(b);
+}
+
+PG_Rect& PG_Rect::operator =(const SDL_Rect& src) {
+ x = src.x;
+ y = src.y;
+ w = src.w;
+ h = src.h;
+ return *this;
+}
diff --git a/src/paragui/pgrect.h b/src/paragui/pgrect.h
new file mode 100644
index 0000000..cb2ca6f
--- /dev/null
+++ b/src/paragui/pgrect.h
@@ -0,0 +1,229 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgrect.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#ifndef PG_RECT_H
+#define PG_RECT_H
+
+#include "pgpoint.h"
+
+class PG_Widget;
+
+/**
+ @author Alexander Pipelka
+ @short Encapsulation of the SDL_Rect structure
+*/
+
+class PG_Rect : public SDL_Rect {
+public:
+
+ /**
+ Create a new PG_Rect object with give values
+ @param x x-startposition
+ @param y y-startposition
+ @param w width
+ @param h height
+
+ Initializes the created PG_Rect object with x/y postions and width/height
+ */
+ PG_Rect(Sint16 x = 0, Sint16 y = 0, Uint16 w = 0, Uint16 h = 0);
+
+ /**
+ Create a new PG_Rect from a reference
+ @param src reference rectangle
+
+ Initializes the created PG_Rect object with the position of the reference rectangle
+ */
+ PG_Rect(const PG_Rect& src);
+
+ /**
+ Create a new PG_Rect from a SDL_Rect structure
+ @param src source SDL_Rect structure
+
+ Initializes the created PG_Rect object with the position of the SDL_Rect structure
+ */
+ PG_Rect(const SDL_Rect& src);
+
+ virtual ~PG_Rect();
+
+ /**
+ Set the position of the rectangle
+ @param nx x-startposition
+ @param ny y-startposition
+ @param nw width
+ @param nh height
+ Moves the rectangle to the given values
+ */
+ inline void SetRect(Sint16 nx, Sint16 ny, Uint16 nw, Uint16 nh) {
+ x = nx;
+ y = ny;
+ w = nw;
+ h = nh;
+ }
+
+ /**
+ */
+ PG_Rect& operator =(const SDL_Rect& src);
+
+ PG_Rect& operator =(const PG_Rect& src);
+
+ /**
+ */
+ PG_Rect operator / (PG_Rect& b);
+
+ inline bool operator ==(const PG_Rect& r) const {
+ return (x == r.x) && (y == r.y) && (r.w == w) && (r.h == h);
+ }
+
+ inline bool operator !=(const PG_Rect& r) const {
+ return !((x == r.x) && (y == r.y) && (r.w == w) && (r.h == h));
+ }
+ /**
+ Check if a given point is inside a rectangle (boxtest)
+
+ @param p the point to test
+ @param r the rectangle the point should be inside
+ @return true if the point is inside the rectangle
+ */
+ inline static bool IsInside(const PG_Point& p, PG_Rect& r) {
+ return r.IsInside(p);
+ }
+
+ /**
+ Check if a given point is inside a rectangle (boxtest)
+
+ @param p the point to test
+ @return true if the point is inside the rectangle
+ */
+ inline bool IsInside(const PG_Point& p) {
+ return ( (x <= p.x) && (p.x <= x + w) && (y <= p.y) && (p.y <= y + h) );
+ }
+
+ /**
+ Intersect two rectangles
+ @param p reference rectangle
+ @param c rectangle to intersect with reference
+ @return resulting intersection rectangle
+ */
+ static PG_Rect IntersectRect(const PG_Rect& p, const PG_Rect& c);
+
+ /**
+ Intersect two rectangles
+ @param p rectangle to intersect with
+ @return resulting intersection rectangle
+ */
+ PG_Rect IntersectRect(const PG_Rect& p) const;
+
+ /**
+ Return the width of the rectangle
+ @return width
+ */
+ inline Uint16 Width() {
+ return w;
+ }
+
+ inline Uint16 Width() const {
+ return w;
+ }
+
+ /**
+ Return the height of the rectangle
+ @return height
+ */
+ inline Uint16 Height() {
+ return h;
+ }
+
+ inline Uint16 Height() const {
+ return h;
+ }
+
+ inline bool IsNull() {
+ return (!Width() && !Height());
+ }
+
+ //! Check if two rectangles overlap
+ /*!
+ \param p, c rectangles to check for overlap
+ \return true if the rectangles overlap, false otherwise
+ */
+ inline bool OverlapRect(const PG_Rect& p, const PG_Rect& c) const {
+ return !( (p.x + p.w < c.x) || (p.x > c.x + c.w) || (p.y + p.h < c.y) || (p.y > c.y + c.h) || (p.IntersectRect(c).IsNull()) );
+ }
+
+ //! Check if this rectangle overlap another one
+ /*!
+ \param p rectangle to check for overlap
+ \return true if this rectangle an p overlap, false otherwise
+ */
+ inline bool OverlapRect(const PG_Rect& p) const {
+ return OverlapRect(p, *this);
+ }
+
+ //! Check if this rectangle overlap another one
+ /*!
+ \param p pointer to rectangle to check for overlap
+ \return true if this rectangle an p overlap, false otherwise
+ */
+ inline bool OverlapRect(PG_Rect* p) {
+ return OverlapRect(*p, *this);
+ }
+
+ /**
+ Get the next Rectangle from the list
+ Moves to the next rectangle in the list
+ */
+ inline PG_Widget* next() {
+ return my_next;
+ }
+
+ /**
+ Get the previous Rectangle from the list
+ Moves to the previous rectangle in the list
+ */
+ inline PG_Widget* prev() {
+ return my_prev;
+ }
+
+ Sint16& my_xpos;
+ Sint16& my_ypos;
+ Uint16& my_width;
+ Uint16& my_height;
+
+ Uint32 index;
+
+ static PG_Rect null;
+
+protected:
+
+ PG_Widget* my_next;
+ PG_Widget* my_prev;
+
+ friend class PG_RectList;
+};
+
+#endif // PG_RECT_H
diff --git a/src/paragui/pgrectlist.cpp b/src/paragui/pgrectlist.cpp
new file mode 100644
index 0000000..0f3f5fd
--- /dev/null
+++ b/src/paragui/pgrectlist.cpp
@@ -0,0 +1,278 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgrectlist.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pgrectlist.h"
+#include "pgwidget.h"
+// #include "pgapplication.h"
+// #include "pglog.h"
+#include "common.h"
+
+#include <algorithm>
+
+PG_RectList::PG_RectList() :
+my_first(NULL),
+my_last(NULL) {
+ my_count = 0;
+}
+
+PG_RectList::~PG_RectList() {}
+
+/*PG_RectList PG_RectList::Intersect(PG_Rect* rect, PG_Rect* first, PG_Rect* last) {
+ PG_RectList result;
+
+ if(first == NULL) {
+ return result;
+ }
+
+ //PG_Widget* testwidget;
+ PG_Rect* testrect;
+
+ // loop through all rects
+ for(PG_Widget* i = static_cast<PG_Widget*>(first); i != last; i = static_cast<PG_Widget*>(i->next)) {
+
+ // get the next rectangle to test
+ //testwidget = (*i).second;
+
+ if(!i->IsVisible() || i->IsHidden()) {
+ continue;
+ }
+
+ testrect = i->GetClipRect();
+ if(rect->OverlapRect(*testrect)) {
+ // append the matching rectangle
+ result.Add(new PG_Rect(*i));
+ }
+ }
+
+ return result;
+}*/
+
+PG_Widget* PG_RectList::IsInside(const PG_Point& p) {
+ // loop down all rects till we find a match
+ for(PG_Widget* i = last(); i != NULL; i = i->prev()) {
+
+ // check if the tested rect is visible
+ if(!i->IsVisible() || i->IsHidden()) {
+ continue;
+ }
+
+ // check for a match
+ if(i->GetClipRect()->IsInside(p)) {
+ return i;
+ }
+ }
+
+ return NULL;
+}
+
+void PG_RectList::Add(PG_Widget* rect, bool front) {
+ if(rect->next() != NULL || rect->prev() != NULL) {
+ debug("PG_RectList::Add(...) Trying to add a linked PG_Rect object");
+ return;
+ }
+
+ Uint32 index = 2^31;
+ my_count++;
+
+ // get highest index
+ if(my_last != NULL) {
+ index = my_last->index;
+ }
+ index++;
+
+ if(front) {
+ if(my_first != NULL) {
+ my_first->my_prev = rect;
+ rect->index = my_first->index-1;
+ }
+ else {
+ rect->index = index;
+ }
+ rect->my_next = my_first;
+ rect->my_prev = NULL;
+ my_first = rect;
+ return;
+ }
+
+ if(my_first == NULL) {
+ my_first = rect;
+ rect->my_prev = NULL;
+ rect->my_next = NULL;
+ }
+ else {
+ my_last->my_next = rect;
+ rect->my_next = NULL;
+ rect->my_prev = my_last;
+ }
+ my_last = rect;
+ rect->index = index;
+}
+
+bool PG_RectList::Remove(PG_Rect* rect) {
+ if(rect == NULL) {
+ return false;
+ }
+
+ if((rect->next() == NULL) && (rect->prev() == NULL) && (my_first != rect)) {
+ //debug("PG_RectList::Remove(...) Trying to remove an unlinked PG_Rect object");
+ return false;
+ }
+
+ if(my_count > 0) {
+ my_count--;
+ }
+
+ // first in list
+ if(rect->my_prev == NULL) {
+ my_first = rect->next();
+ if(my_first != NULL) {
+ my_first->my_prev = NULL;
+ }
+ // first and last
+ else {
+ my_last = NULL;
+ }
+ }
+ // last
+ else if(rect->my_next == NULL) {
+ my_last = rect->my_prev;
+ if(my_last != NULL) {
+ my_last->my_next = NULL;
+ }
+ }
+ // in between
+ else {
+ rect->my_prev->my_next = rect->my_next;
+ rect->my_next->my_prev = rect->my_prev;
+ }
+
+ rect->my_next = NULL;
+ rect->my_prev = NULL;
+
+ return true;
+}
+
+void PG_RectList::Blit(const PG_Rect& rect) {
+ Blit(rect, first());
+}
+
+void PG_RectList::Blit(const PG_Rect& rect, PG_Widget* start, PG_Widget* end) {
+ if(start == NULL) {
+ return;
+ }
+
+ PG_RectList* childs;
+ SDL_Surface* screen = gamescreen;
+
+ // store old clipping rectangle
+ PG_Rect o;
+ SDL_GetClipRect(screen, &o);
+
+ // blit all objects in the list
+ for(PG_Widget* i = start; i != end; i = i->next()) {
+
+ if(!i->IsVisible() || i->IsHidden()) {
+ continue;
+ }
+
+ // calculate the clipping rectangle
+ // cliprect = blittingregion / widgetcliprect
+ PG_Rect* cr = i->GetClipRect();
+ if(!rect.OverlapRect(*cr)) {
+ continue;
+ }
+
+ PG_Rect c = cr->IntersectRect(rect);
+ SDL_SetClipRect(screen, &c);
+
+ // blit it
+ i->Blit(false, false);
+
+ // blit all children of the widget
+ childs = i->GetChildList();
+ if(childs) {
+ childs->Blit(rect);
+ }
+ }
+
+ // reset clipping rectangle
+ SDL_SetClipRect(gamescreen, &o);
+}
+
+void PG_RectList::Blit() {
+ // blit all objects in the list
+ for(PG_Widget* i = first(); i != NULL; i = i->next()) {
+ if(!i->IsVisible() || i->IsHidden()) {
+ continue;
+ }
+
+ i->Blit(true, false);
+ }
+}
+
+bool PG_RectList::BringToFront(PG_Widget* rect) {
+ if(!Remove(rect)) {
+ return false;
+ }
+ Add(rect);
+
+ return true;
+}
+
+bool PG_RectList::SendToBack(PG_Widget* rect) {
+ if(!Remove(rect)) {
+ return false;
+ }
+ Add(rect, true);
+
+ return true;
+}
+
+PG_Widget* PG_RectList::Find(int id) {
+ for(PG_Widget* i = first(); i != NULL; i = i->next()) {
+ if(i->GetID() == id) {
+ return i;
+ }
+ }
+ return NULL;
+}
+
+PG_Widget* PG_RectList::Find(const char* name) {
+ for(PG_Widget* i = first(); i != NULL; i = i->next()) {
+ if(strcmp(i->GetName(), name) == 0) {
+ return i;
+ }
+ }
+ return NULL;
+}
+
+void PG_RectList::clear() {
+ my_first = NULL;
+ my_last = NULL;
+ my_count = 0;
+}
diff --git a/src/paragui/pgrectlist.h b/src/paragui/pgrectlist.h
new file mode 100644
index 0000000..e32cc80
--- /dev/null
+++ b/src/paragui/pgrectlist.h
@@ -0,0 +1,143 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgrectlist.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#ifndef PG_RECTLIST_H
+#define PG_RECTLIST_H
+
+//#include "paragui.h"
+#include "pgrect.h"
+
+class PG_Widget;
+
+/**
+ @author Alexander Pipelka
+ @short A list derived from vector to handle overlapping and child-widgets
+*/
+
+class PG_RectList {
+
+public:
+
+ /**
+ constructor of the list
+ */
+ PG_RectList();
+
+ /**
+ destructor
+ */
+ virtual ~PG_RectList();
+
+ /**
+ add a widget to the list
+ @param rect pointer to the widget (rect)
+ @param front insert the rectangle at the head of the list if true
+ This functions adds the widget to the back of the list.
+ */
+ void Add(PG_Widget* rect, bool front = false);
+
+ /**
+ remove a widget from the list
+ @param rect pointer to the widget (rect)
+ @return true - if the widget was remove successfully
+
+ This functions removes the given widget from the list
+ */
+ bool Remove(PG_Rect* rect);
+
+ /**
+ check if a given point is inside any rectangle in the list
+ @param p point to check
+ @return pointer to the first widget that contains the point / NULL if there is no match
+
+ Returns the first visible widget which contains the given point.
+ */
+ PG_Widget* IsInside(const PG_Point& p);
+
+ PG_Widget* Find(int id);
+
+ PG_Widget* Find(const char* name);
+
+ /**
+ blit all rectangles in the list to the screen
+
+ This function blits all visible rectangles from the first to the last position to the screen.
+ */
+ void Blit();
+
+ /**
+ blit all rectangles from the list intersecting a reference rectangle to the screen
+ @param rect reference rectangle
+
+ Performs an intersection of all visible rectangles in the list with the reference rectangle.
+ The resulting list is clipped to the reference and blitted to the screen.
+ */
+ void Blit(const PG_Rect& rect);
+
+ void Blit(const PG_Rect& rect, PG_Widget* first, PG_Widget* last = NULL);
+
+ /**
+ reorder a widget (rectangle) - front
+ @param rect widget to reorder
+ @return true - the rectangle was found and reordered / false - the rectangle isn't in the list.
+
+ Bring the given widget (rectangle) to the front (will overlap all other widgets in the list).
+ */
+ bool BringToFront(PG_Widget* rect);
+
+ /**
+ reorder a widget (rectangle) - back
+ @param rect widget to reorder
+ @return true - the rectangle was found and reordered / false - the rectangle isn't in the list.
+
+ Send the given widget (rectangle) to the back (will be overlapped by all other widgets in the list).
+ */
+ bool SendToBack(PG_Widget* rect);
+
+ inline PG_Widget* first() {
+ return my_first;
+ }
+
+ inline PG_Widget* last() {
+ return my_last;
+ }
+
+ void clear();
+
+ inline Uint32 size() {
+ return my_count;
+ }
+
+protected:
+
+ PG_Widget* my_first;
+ PG_Widget* my_last;
+ Uint32 my_count;
+};
+
+#endif // PG_RECTLIST_H
diff --git a/src/paragui/pgrotozoom.cpp b/src/paragui/pgrotozoom.cpp
new file mode 100644
index 0000000..5d01b3c
--- /dev/null
+++ b/src/paragui/pgrotozoom.cpp
@@ -0,0 +1,750 @@
+/*
+ pgrotozoom.cpp
+
+ Copyright (C) A. Schiffler, July 2001
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ The code here within is based on the LGPL SDL_Rotozoom package by
+ A. Schiffler <aschiffler@home.com>. The only changes made are
+ cosmetical (interface and naming) to fit the ParaGUI library.
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgrotozoom.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pgdraw.h"
+
+#include <cstdlib>
+#include <cstring>
+#include <cmath>
+
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+
+/* ---- Structures */
+
+typedef struct tColorRGBA {
+ Uint8 r;
+ Uint8 g;
+ Uint8 b;
+ Uint8 a;
+}
+tColorRGBA;
+
+typedef struct tColorY {
+ Uint8 y;
+}
+tColorY;
+
+// 32bit Zoomer with optional anti-aliasing by bilinear interpolation.
+// Zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
+static int zoomSurfaceRGBA (SDL_Surface * src, SDL_Surface * dst, bool smooth) {
+ int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep;
+ tColorRGBA *c00, *c01, *c10, *c11;
+ tColorRGBA *sp, *csp, *dp;
+ int sgap, dgap, orderRGBA;
+
+ /* Variable setup */
+ if (smooth) {
+ /* For interpolation: assume source dimension is one pixel */
+ /* smaller to avoid overflow on right and bottom edge. */
+ sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
+ sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
+ } else {
+ sx = (int) (65536.0 * (float) src->w / (float) dst->w);
+ sy = (int) (65536.0 * (float) src->h / (float) dst->h);
+ }
+
+ /* Allocate memory for row increments */
+ if ((sax = (int *) malloc ((dst->w + 1) * sizeof (Uint32))) == NULL) {
+ return (-1);
+ }
+ if ((say = (int *) malloc ((dst->h + 1) * sizeof (Uint32))) == NULL) {
+ free (sax);
+ return (-1);
+ }
+
+ /* Precalculate row increments */
+ csx = 0;
+ csax = sax;
+ for (x = 0; x <= dst->w; x++) {
+ *csax = csx;
+ csax++;
+ csx &= 0xffff;
+ csx += sx;
+ }
+ csy = 0;
+ csay = say;
+ for (y = 0; y <= dst->h; y++) {
+ *csay = csy;
+ csay++;
+ csy &= 0xffff;
+ csy += sy;
+ }
+
+ /* Pointer setup */
+ sp = csp = (tColorRGBA *) src->pixels;
+ dp = (tColorRGBA *) dst->pixels;
+ sgap = src->pitch - src->w * 4;
+ dgap = dst->pitch - dst->w * 4;
+ orderRGBA = (src->format->Rmask == 0x000000ff);
+
+ /* Switch between interpolating and non-interpolating code */
+ if (smooth) {
+
+ /* Interpolating Zoom */
+
+ /* Scan destination */
+ csay = say;
+ for (y = 0; y < dst->h; y++) {
+ /* Setup color source pointers */
+ c00 = csp;
+ c01 = csp;
+ c01++;
+ c10 = (tColorRGBA *) ((Uint8 *) csp + src->pitch);
+ c11 = c10;
+ c11++;
+ csax = sax;
+ for (x = 0; x < dst->w; x++) {
+ /* ABGR ordering */
+ /* Interpolate colors */
+ ex = (*csax & 0xffff);
+ ey = (*csay & 0xffff);
+ t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
+ t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
+ dp->r = (((t2 - t1) * ey) >> 16) + t1;
+ t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
+ t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
+ dp->g = (((t2 - t1) * ey) >> 16) + t1;
+ t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
+ t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
+ dp->b = (((t2 - t1) * ey) >> 16) + t1;
+ t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
+ t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
+ dp->a = (((t2 - t1) * ey) >> 16) + t1;
+ /* Advance source pointers */
+ csax++;
+ sstep = (*csax >> 16);
+ c00 += sstep;
+ c01 += sstep;
+ c10 += sstep;
+ c11 += sstep;
+ /* Advance destination pointer */
+ dp++;
+ }
+ /* Advance source pointer */
+ csay++;
+ csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
+ /* Advance destination pointers */
+ dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
+ }
+
+ } else {
+
+ /* Non-Interpolating Zoom */
+
+ csay = say;
+ for (y = 0; y < dst->h; y++) {
+ sp = csp;
+ csax = sax;
+ for (x = 0; x < dst->w; x++) {
+ /* Draw */
+ *dp = *sp;
+ /* Advance source pointers */
+ csax++;
+ sp += (*csax >> 16);
+ /* Advance destination pointer */
+ dp++;
+ }
+ /* Advance source pointer */
+ csay++;
+ csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
+ /* Advance destination pointers */
+ dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
+ }
+
+ }
+
+ /* Remove temp arrays */
+ free (sax);
+ free (say);
+
+ return (0);
+}
+
+// 8bit Zoomer without smoothing.
+// Zoomes 8bit palette/Y 'src' surface to 'dst' surface.
+
+static int zoomSurfaceY (SDL_Surface * src, SDL_Surface * dst) {
+ Uint32 sx, sy, *sax, *say, *csax, *csay, csx, csy;
+ Sint32 x, y;
+ Uint8 *sp, *dp, *csp;
+ int dgap;
+
+ /* Variable setup */
+ sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
+ sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
+
+ /* Allocate memory for row increments */
+ if ((sax = (Uint32 *) malloc (dst->w * sizeof (Uint32))) == NULL) {
+ return (-1);
+ }
+ if ((say = (Uint32 *) malloc (dst->h * sizeof (Uint32))) == NULL) {
+ if (sax != NULL) {
+ free (sax);
+ }
+ return (-1);
+ }
+
+ /* Precalculate row increments */
+ csx = 0;
+ csax = sax;
+ for (x = 0; x < dst->w; x++) {
+ csx += sx;
+ *csax = (csx >> 16);
+ csx &= 0xffff;
+ csax++;
+ }
+ csy = 0;
+ csay = say;
+ for (y = 0; y < dst->h; y++) {
+ csy += sy;
+ *csay = (csy >> 16);
+ csy &= 0xffff;
+ csay++;
+ }
+
+ csx = 0;
+ csax = sax;
+ for (x = 0; x < dst->w; x++) {
+ csx += (*csax);
+ csax++;
+ }
+ csy = 0;
+ csay = say;
+ for (y = 0; y < dst->h; y++) {
+ csy += (*csay);
+ csay++;
+ }
+
+ /* Pointer setup */
+ sp = csp = (Uint8 *) src->pixels;
+ dp = (Uint8 *) dst->pixels;
+ dgap = dst->pitch - dst->w;
+
+ /* Draw */
+ csay = say;
+ for (y = 0; y < dst->h; y++) {
+ csax = sax;
+ sp = csp;
+ for (x = 0; x < dst->w; x++) {
+ /* Draw */
+ *dp = *sp;
+ /* Advance source pointers */
+ sp += (*csax);
+ csax++;
+ /* Advance destination pointer */
+ dp++;
+ }
+ /* Advance source pointer (for row) */
+ csp += ((*csay) * src->pitch);
+ csay++;
+ /* Advance destination pointers */
+ dp += dgap;
+ }
+
+ /* Remove temp arrays */
+ free (sax);
+ free (say);
+
+ return (0);
+}
+
+// 32bit Rotozoomer with optional anti-aliasing by bilinear interpolation.
+// Rotates and zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
+
+static void transformSurfaceRGBA (SDL_Surface * src, SDL_Surface * dst, int cx,
+ int cy, int isin, int icos, bool smooth) {
+ int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
+ tColorRGBA c00, c01, c10, c11;
+ tColorRGBA *pc, *sp;
+ int gap, orderRGBA;
+
+ /* Variable setup */
+ xd = ((src->w - dst->w) << 15);
+ yd = ((src->h - dst->h) << 15);
+ ax = (cx << 16) - (icos * cx);
+ ay = (cy << 16) - (isin * cx);
+ sw = src->w - 1;
+ sh = src->h - 1;
+ pc = reinterpret_cast<tColorRGBA*>(dst->pixels);
+ gap = dst->pitch - dst->w * 4;
+ orderRGBA = (src->format->Rmask == 0x000000ff);
+
+ /* Switch between interpolating and non-interpolating code */
+ if (smooth) {
+ for (y = 0; y < dst->h; y++) {
+ dy = cy - y;
+ sdx = (ax + (isin * dy)) + xd;
+ sdy = (ay - (icos * dy)) + yd;
+ for (x = 0; x < dst->w; x++) {
+ dx = (sdx >> 16);
+ dy = (sdy >> 16);
+ if ((dx >= -1) && (dy >= -1) && (dx < src->w) && (dy < src->h)) {
+ if ((dx >= 0) && (dy >= 0) && (dx < sw) && (dy < sh)) {
+ sp =
+ (tColorRGBA *) ((Uint8 *) src->pixels +
+ src->pitch * dy);
+ sp += dx;
+ c00 = *sp;
+ sp += 1;
+ c01 = *sp;
+ sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
+ sp -= 1;
+ c10 = *sp;
+ sp += 1;
+ c11 = *sp;
+ } else if ((dx == sw) && (dy == sh)) {
+ sp =
+ (tColorRGBA *) ((Uint8 *) src->pixels +
+ src->pitch * dy);
+ sp += dx;
+ c00 = *sp;
+ c01 = *pc;
+ c10 = *pc;
+ c11 = *pc;
+ } else if ((dx == -1) && (dy == -1)) {
+ sp = (tColorRGBA *) (src->pixels);
+ c00 = *pc;
+ c01 = *pc;
+ c10 = *pc;
+ c11 = *sp;
+ } else if ((dx == -1) && (dy == sh)) {
+ sp = (tColorRGBA *) (src->pixels);
+ sp =
+ (tColorRGBA *) ((Uint8 *) src->pixels +
+ src->pitch * dy);
+ c00 = *pc;
+ c01 = *sp;
+ c10 = *pc;
+ c11 = *pc;
+ } else if ((dx == sw) && (dy == -1)) {
+ sp = (tColorRGBA *) (src->pixels);
+ sp += dx;
+ c00 = *pc;
+ c01 = *pc;
+ c10 = *sp;
+ c11 = *pc;
+ } else if (dx == -1) {
+ sp =
+ (tColorRGBA *) ((Uint8 *) src->pixels +
+ src->pitch * dy);
+ c00 = *pc;
+ c01 = *sp;
+ c10 = *pc;
+ sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
+ c11 = *sp;
+ } else if (dy == -1) {
+ sp = (tColorRGBA *) (src->pixels);
+ sp += dx;
+ c00 = *pc;
+ c01 = *pc;
+ c10 = *sp;
+ sp += 1;
+ c11 = *sp;
+ } else if (dx == sw) {
+ sp =
+ (tColorRGBA *) ((Uint8 *) src->pixels +
+ src->pitch * dy);
+ sp += dx;
+ c00 = *sp;
+ c01 = *pc;
+ sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
+ c10 = *sp;
+ c11 = *pc;
+ } else if (dy == sh) {
+ sp =
+ (tColorRGBA *) ((Uint8 *) src->pixels +
+ src->pitch * dy);
+ sp += dx;
+ c00 = *sp;
+ sp += 1;
+ c01 = *sp;
+ c10 = *pc;
+ c11 = *pc;
+ }
+ /* Interpolate colors */
+ ex = (sdx & 0xffff);
+ ey = (sdy & 0xffff);
+ t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
+ t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
+ pc->r = (((t2 - t1) * ey) >> 16) + t1;
+ t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
+ t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
+ pc->g = (((t2 - t1) * ey) >> 16) + t1;
+ t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
+ t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
+ pc->b = (((t2 - t1) * ey) >> 16) + t1;
+ t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
+ t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
+ pc->a = (((t2 - t1) * ey) >> 16) + t1;
+
+ }
+ sdx += icos;
+ sdy += isin;
+ pc++;
+ }
+ pc = (tColorRGBA *) ((Uint8 *) pc + gap);
+ }
+ } else {
+ for (y = 0; y < dst->h; y++) {
+ dy = cy - y;
+ sdx = (ax + (isin * dy)) + xd;
+ sdy = (ay - (icos * dy)) + yd;
+ for (x = 0; x < dst->w; x++) {
+ dx = (short) (sdx >> 16);
+ dy = (short) (sdy >> 16);
+ if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
+ sp =
+ (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
+ sp += dx;
+ *pc = *sp;
+ }
+ sdx += icos;
+ sdy += isin;
+ pc++;
+ }
+ pc = (tColorRGBA *) ((Uint8 *) pc + gap);
+ }
+ }
+}
+
+// 8bit Rotozoomer without smoothing
+// Rotates and zoomes 8bit palette/Y 'src' surface to 'dst' surface.
+
+static void transformSurfaceY (SDL_Surface * src, SDL_Surface * dst,
+ int cx, int cy, int isin, int icos) {
+ int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
+ tColorY *pc, *sp;
+ int gap;
+
+ /* Variable setup */
+ xd = ((src->w - dst->w) << 15);
+ yd = ((src->h - dst->h) << 15);
+ ax = (cx << 16) - (icos * cx);
+ ay = (cy << 16) - (isin * cx);
+ sw = src->w - 1;
+ sh = src->h - 1;
+ pc = reinterpret_cast<tColorY*>(dst->pixels);
+ gap = dst->pitch - dst->w;
+ /* Clear surface to colorkey */
+ memset (pc, (unsigned char) (src->format->colorkey & 0xff),
+ dst->pitch * dst->h);
+ /* Iterate through destination surface */
+ for (y = 0; y < dst->h; y++) {
+ dy = cy - y;
+ sdx = (ax + (isin * dy)) + xd;
+ sdy = (ay - (icos * dy)) + yd;
+ for (x = 0; x < dst->w; x++) {
+ dx = (short) (sdx >> 16);
+ dy = (short) (sdy >> 16);
+ if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
+ sp = (tColorY *) (src->pixels);
+ sp += (src->pitch * dy + dx);
+ *pc = *sp;
+ }
+ sdx += icos;
+ sdy += isin;
+ pc++;
+ }
+ pc += gap;
+ }
+}
+
+
+
+// Rotates and zoomes a 32bit or 8bit 'src' surface to newly created
+// 'dst' surface. 'angle' is the rotation in degrees. 'zoom' a
+// scaling factor. If 'smooth' is 1 then the destination 32bit surface
+// is anti-aliased. If the surface is not 8bit or 32bit RGBA/ABGR it
+// will be converted into a 32bit RGBA format on the fly.
+
+#define VALUE_LIMIT 0.001
+
+SDL_Surface* PG_Draw::RotoScaleSurface(SDL_Surface *src, double angle,
+ double zoom, bool smooth) {
+ SDL_Surface *rz_src;
+ SDL_Surface *rz_dst;
+ double zoominv;
+ double radangle, sanglezoom, canglezoom, sanglezoominv, canglezoominv;
+ int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
+ double x,y,cx,cy,sx,sy;
+ int is32bit;
+ int i,src_converted;
+
+ /* Sanity check */
+ if (src==NULL)
+ return(NULL);
+
+ /* Determine if source surface is 32bit or 8bit */
+ is32bit=(src->format->BitsPerPixel==32);
+ if ( (is32bit) || (src->format->BitsPerPixel==8)) {
+ /* Use source surface 'as is' */
+ rz_src=src;
+ src_converted=0;
+ } else {
+ /* New source surface is 32bit with a defined RGBA ordering */
+ rz_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
+ SDL_BlitSurface(src,NULL,rz_src,NULL);
+ src_converted=1;
+ is32bit=1;
+ }
+
+ /* Sanity check zoom factor */
+ if (zoom<VALUE_LIMIT) {
+ zoom=VALUE_LIMIT;
+ }
+ zoominv=65536.0/zoom;
+
+ /* Check if we have a rotozoom or just a zoom */
+ if (fabs(angle)>VALUE_LIMIT) {
+
+ /* Angle!=0: full rotozoom */
+ /* ----------------------- */
+
+ /* Calculate target factors from sin/cos and zoom */
+ radangle=angle*(M_PI/180.0);
+ sanglezoom=sanglezoominv=sin(radangle);
+ canglezoom=canglezoominv=cos(radangle);
+ sanglezoom *= zoom;
+ canglezoom *= zoom;
+ sanglezoominv *= zoominv;
+ canglezoominv *= zoominv;
+
+ /* Determine destination width and height by rotating a centered source box */
+ x=rz_src->w/2;
+ y=rz_src->h/2;
+ cx=canglezoom*x;
+ cy=canglezoom*y;
+ sx=sanglezoom*x;
+ sy=sanglezoom*y;
+ dstwidthhalf =MAX((int)ceil(MAX(MAX(MAX(fabs(cx+sy),fabs(cx-sy)),fabs(-cx+sy)),fabs(-cx-sy))),1);
+ dstheighthalf=MAX((int)ceil(MAX(MAX(MAX(fabs(sx+cy),fabs(sx-cy)),fabs(-sx+cy)),fabs(-sx-cy))),1);
+ dstwidth=2*dstwidthhalf;
+ dstheight=2*dstheighthalf;
+
+ /* Alloc space to completely contain the rotated surface */
+ rz_dst=NULL;
+ if (is32bit) {
+ /* Target surface is 32bit with source RGBA/ABGR ordering */
+ rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32, rz_src->format->Rmask, rz_src->format->Gmask, rz_src->format->Bmask, rz_src->format->Amask);
+ } else {
+ /* Target surface is 8bit */
+ rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
+ }
+
+ /* Lock source surface */
+ SDL_LockSurface(rz_src);
+ /* Check which kind of surface we have */
+ if (is32bit) {
+ /* Call the 32bit transformation routine to do the rotation (using alpha) */
+ transformSurfaceRGBA(rz_src,rz_dst,dstwidthhalf,dstheighthalf,
+ (int)(sanglezoominv),
+ (int)(canglezoominv),
+ smooth);
+ /* Turn on source-alpha support */
+ SDL_SetAlpha(rz_dst, SDL_SRCALPHA , 255);
+ } else {
+ /* Copy palette and colorkey info */
+ for (i=0; i<rz_src->format->palette->ncolors; i++) {
+ rz_dst->format->palette->colors[i]=rz_src->format->palette->colors[i];
+ }
+ rz_dst->format->palette->ncolors=rz_src->format->palette->ncolors;
+ /* Call the 8bit transformation routine to do the rotation */
+ transformSurfaceY(rz_src,rz_dst,dstwidthhalf,dstheighthalf,
+ (int)(sanglezoominv),
+ (int)(canglezoominv));
+ SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
+ }
+ /* Unlock source surface */
+ SDL_UnlockSurface(rz_src);
+
+ } else {
+
+ /* Angle=0: Just a zoom */
+ /* -------------------- */
+
+ /* Calculate target size and set rect */
+ dstwidth=(int)((double)rz_src->w*zoom);
+ dstheight=(int)((double)rz_src->h*zoom);
+ if (dstwidth<1) {
+ dstwidth=1;
+ }
+ if (dstheight<1) {
+ dstheight=1;
+ }
+
+ /* Alloc space to completely contain the zoomed surface */
+ rz_dst=NULL;
+ if (is32bit) {
+ /* Target surface is 32bit with source RGBA/ABGR ordering */
+ rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32, rz_src->format->Rmask, rz_src->format->Gmask, rz_src->format->Bmask, rz_src->format->Amask);
+ } else {
+ /* Target surface is 8bit */
+ rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
+ }
+
+ /* Lock source surface */
+ SDL_LockSurface(rz_src);
+ /* Check which kind of surface we have */
+ if (is32bit) {
+ /* Call the 32bit transformation routine to do the zooming (using alpha) */
+ zoomSurfaceRGBA(rz_src,rz_dst,smooth);
+ /* Turn on source-alpha support */
+ SDL_SetAlpha(rz_dst, SDL_SRCALPHA , 255);
+ } else {
+ /* Copy palette and colorkey info */
+ for (i=0; i<rz_src->format->palette->ncolors; i++) {
+ rz_dst->format->palette->colors[i]=rz_src->format->palette->colors[i];
+ }
+ rz_dst->format->palette->ncolors=rz_src->format->palette->ncolors;
+ /* Call the 8bit transformation routine to do the zooming */
+ zoomSurfaceY(rz_src,rz_dst);
+ SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
+ }
+ /* Unlock source surface */
+ SDL_UnlockSurface(rz_src);
+ }
+
+ /* Cleanup temp surface */
+ if (src_converted) {
+ SDL_FreeSurface(rz_src);
+ }
+
+ /* Return destination surface */
+ return(rz_dst);
+}
+
+// Zoomes a 32bit or 8bit 'src' surface to newly created 'dst'
+// surface. 'zoomx' and 'zoomy' are scaling factors for width and
+// height. If 'smooth' is 1 then the destination 32bit surface is
+// anti-aliased. If the surface is not 8bit or 32bit RGBA/ABGR it will
+// be converted into a 32bit RGBA format on the fly.
+
+#define VALUE_LIMIT 0.001
+
+SDL_Surface* PG_Draw::ScaleSurface(SDL_Surface *src,
+ double zoomx, double zoomy, bool smooth) {
+ SDL_Surface *rz_src;
+ SDL_Surface *rz_dst;
+ int dstwidth, dstheight;
+ int is32bit;
+ int i,src_converted;
+
+ /* Sanity check */
+ if (src==NULL)
+ return(NULL);
+
+ /* Determine if source surface is 32bit or 8bit */
+ is32bit=(src->format->BitsPerPixel==32);
+ if ( (is32bit) || (src->format->BitsPerPixel==8)) {
+ /* Use source surface 'as is' */
+ rz_src=src;
+ src_converted=0;
+ } else {
+ /* New source surface is 32bit with a defined RGBA ordering */
+ rz_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
+ SDL_BlitSurface(src,NULL,rz_src,NULL);
+ src_converted=1;
+ is32bit=1;
+ }
+
+ /* Sanity check zoom factors */
+ if (zoomx<VALUE_LIMIT) {
+ zoomx=VALUE_LIMIT;
+ }
+ if (zoomy<VALUE_LIMIT) {
+ zoomy=VALUE_LIMIT;
+ }
+
+ /* Calculate target size and set rect */
+ dstwidth=(int)((double)rz_src->w*zoomx);
+ dstheight=(int)((double)rz_src->h*zoomy);
+ if (dstwidth<1) {
+ dstwidth=1;
+ }
+ if (dstheight<1) {
+ dstheight=1;
+ }
+
+ /* Alloc space to completely contain the zoomed surface */
+ rz_dst=NULL;
+ if (is32bit) {
+ /* Target surface is 32bit with source RGBA/ABGR ordering */
+ rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32, rz_src->format->Rmask, rz_src->format->Gmask, rz_src->format->Bmask, rz_src->format->Amask);
+ } else {
+ /* Target surface is 8bit */
+ rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
+ }
+
+ /* Lock source surface */
+ SDL_LockSurface(rz_src);
+ /* Check which kind of surface we have */
+ if (is32bit) {
+ /* Call the 32bit transformation routine to do the zooming (using alpha) */
+ zoomSurfaceRGBA(rz_src,rz_dst,smooth);
+ /* Turn on source-alpha support */
+ SDL_SetAlpha(rz_dst, SDL_SRCALPHA , 255);
+ } else {
+ /* Copy palette and colorkey info */
+ for (i=0; i<rz_src->format->palette->ncolors; i++) {
+ rz_dst->format->palette->colors[i]=rz_src->format->palette->colors[i];
+ }
+ rz_dst->format->palette->ncolors=rz_src->format->palette->ncolors;
+ /* Call the 8bit transformation routine to do the zooming */
+ zoomSurfaceY(rz_src,rz_dst);
+ SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
+ }
+ /* Unlock source surface */
+ SDL_UnlockSurface(rz_src);
+
+ /* Cleanup temp surface */
+ if (src_converted) {
+ SDL_FreeSurface(rz_src);
+ }
+
+ /* Return destination surface */
+ return(rz_dst);
+}
+
+void PG_Draw::BlitScale(SDL_Surface *src, SDL_Surface *dst, bool smooth) {
+ SDL_Surface *tmp = ScaleSurface(src,
+ static_cast<double>(dst->w) / src->w,
+ static_cast<double>(dst->h) / src->h,
+ smooth);
+ SDL_BlitSurface(tmp, 0, dst, 0);
+ SDL_FreeSurface(tmp);
+}
+
+
+/*
+ * Local Variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/src/paragui/pgscrollarea.cpp b/src/paragui/pgscrollarea.cpp
new file mode 100644
index 0000000..c15094f
--- /dev/null
+++ b/src/paragui/pgscrollarea.cpp
@@ -0,0 +1,278 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000-2004 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgscrollarea.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pgscrollarea.h"
+#include "common.h"
+
+PG_ScrollArea::PG_ScrollArea(PG_Widget* parent, const PG_Rect& r) : PG_Widget(parent, r),
+my_shiftx(false), my_shifty(false), my_AddResizeParent(false), my_RemoveResizeParent(false) {
+}
+
+PG_ScrollArea::~PG_ScrollArea() {
+}
+
+void PG_ScrollArea::ScrollTo(Uint16 x, Uint16 y) {
+ if (my_area.x == x && my_area.y == y)
+ return;
+
+ if(y > my_area.h - my_height && my_area.h > my_height) {
+ y = my_area.h - my_height;
+ }
+
+ if(x > my_area.w - my_width && my_area.w > my_width) {
+ x = my_area.w - my_width;
+ }
+
+ Sint32 dx = my_area.x - x;
+ Sint32 dy = my_area.y - y;
+
+ my_area.x = x;
+ my_area.y = y;
+
+ if(GetChildList() == NULL) {
+ Update();
+ return;
+ }
+
+ for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
+ i->MoveRect(i->x + dx, i->y + dy);
+ }
+
+ Update();
+}
+
+void PG_ScrollArea::AddChild(PG_Widget* child) {
+ PG_Widget::AddChild(child);
+ child->MoveRect(child->x - my_area.x, child->y - my_area.y);
+
+ if(child->x+child->w+my_area.x-my_xpos > my_area.w) {
+ my_area.w = child->x+child->w+my_area.x-my_xpos;
+ sigAreaChangedWidth(this, my_area.w);
+
+ if(my_AddResizeParent) {
+ GetParent()->SizeWidget(my_area.w, GetParent()->my_height);
+ }
+ }
+ if(child->y+child->h+my_area.y-my_ypos > my_area.h) {
+ my_area.h = child->y+child->h+my_area.y-my_ypos;
+ sigAreaChangedHeight(this, my_area.h);
+
+ if(my_AddResizeParent) {
+ GetParent()->SizeWidget(GetParent()->my_width, my_area.h);
+ }
+ }
+
+ if(IsVisible()) {
+ child->Show();
+ }
+}
+
+void PG_ScrollArea::ScrollToWidget(PG_Widget* widget, bool bVertical) {
+ if(GetWidgetCount() == 0) {
+ return;
+ }
+
+ Uint16 ypos = 0;
+ Uint16 xpos = 0;
+
+ if(bVertical) {
+ ypos = widget->y - my_ypos + my_area.y;
+ xpos = my_area.x;
+ }
+ else {
+ xpos = widget->x - my_xpos + my_area.x;
+ ypos = my_area.y;
+ }
+
+ ScrollTo(xpos, ypos);
+}
+
+void PG_ScrollArea::EnsureVisible(PG_Widget *widget, bool bVertical)
+{
+ debug("Widget: %3d : %3d - %3d x %3d\n", widget->my_xpos, widget->my_ypos, widget->my_width, widget->my_height);
+ debug("Widget: %3d : %3d - %3d x %3d\n", widget->x, widget->y, widget->w, widget->h);
+ debug("Scroll: %3d : %3d - %3d x %3d\n", my_xpos, my_ypos, my_width, my_height);
+ debug("Scroll: %3d : %3d - %3d x %3d\n", x, y, w, h);
+
+ int dy = 0;
+
+ if (widget->my_ypos < my_ypos)
+ {
+ dy = widget->my_ypos - my_ypos;
+ }
+ else if (widget->my_ypos + widget->my_height > my_ypos + my_height)
+ {
+ dy = (widget->my_ypos + widget->my_height) - (my_ypos + my_height);
+ }
+
+ ScrollTo(my_area.x, my_area.y + dy);
+}
+
+
+bool PG_ScrollArea::RemoveChild(PG_Widget* child) {
+
+ // recalc scrollarea
+ Uint16 w = 0;
+ Uint16 h = 0;
+
+ if(GetChildList() == NULL) {
+ return false;
+ }
+
+ // remove widget
+ PG_Rect r = *child;
+ if(!PG_Widget::RemoveChild(child)) {
+ return false;
+ }
+
+ for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
+
+ // check if i should move the widget (x)
+ if(my_shiftx && (i->x >= r.x+r.w)) {
+ i->MoveRect(i->x - r.w, i->y);
+ }
+
+ // check if i should move the widget (y)
+ if(my_shifty && (i->y >= r.y+r.h)) {
+ i->MoveRect(i->x, i->y - r.h);
+ }
+
+ // recalc new scrollarea
+ if(i->x+i->w+my_area.x-my_xpos > w) {
+ w = i->x+i->w+my_area.x-my_xpos;
+ }
+ if(i->y+i->h+my_area.y-my_ypos > h) {
+ h = i->y+i->h+my_area.y-my_ypos;
+ }
+ }
+
+ // signal changes
+ if(w != my_area.w) {
+ my_area.w = w;
+ sigAreaChangedWidth(this, my_area.w);
+
+ if(my_RemoveResizeParent) {
+ GetParent()->SizeWidget(my_area.w, GetParent()->my_height);
+ }
+ }
+
+ if(h != my_area.h) {
+ my_area.h = h;
+ sigAreaChangedHeight(this, my_area.h);
+
+ if(my_RemoveResizeParent) {
+ GetParent()->SizeWidget(GetParent()->my_width, my_area.h);
+ }
+ }
+
+ Update();
+ return true;
+}
+
+void PG_ScrollArea::RemoveAll() {
+ if(GetChildList() == NULL) {
+ return;
+ }
+ GetChildList()->clear();
+ Update();
+}
+
+void PG_ScrollArea::DeleteAll() {
+ if(GetChildList() == NULL) {
+ return;
+ }
+
+ PG_Widget* list = GetChildList()->first();
+
+ GetChildList()->clear();
+ Update();
+
+ for(; list != NULL; ) {
+ PG_Widget* w = list;
+ list = list->next();
+ delete w;
+ }
+ my_area.w = 0;
+ my_area.h = 0;
+ sigAreaChangedWidth(this, my_area.w);
+ sigAreaChangedHeight(this, my_area.h);
+}
+
+Uint16 PG_ScrollArea::GetWidgetCount() {
+ if(GetChildList() == NULL) {
+ return 0;
+ }
+
+ return GetChildList()->size();
+}
+
+Uint16 PG_ScrollArea::GetScrollPosX() {
+ return my_area.x;
+}
+
+Uint16 PG_ScrollArea::GetScrollPosY() {
+ return my_area.y;
+}
+
+void PG_ScrollArea::SetShiftOnRemove(bool shiftx, bool shifty) {
+ my_shiftx = shiftx;
+ my_shifty = shifty;
+}
+
+void PG_ScrollArea::SetAreaWidth(Uint16 w) {
+ if(my_area.w == w) {
+ return;
+ }
+ my_area.w = w;
+ sigAreaChangedWidth(this, my_area.w);
+}
+
+void PG_ScrollArea::SetAreaHeight(Uint16 h) {
+ if(my_area.h == h) {
+ return;
+ }
+ my_area.h = h;
+ sigAreaChangedHeight(this, my_area.h);
+}
+
+PG_Widget* PG_ScrollArea::GetFirstInList() {
+ PG_RectList* list = GetChildList();
+ if(list == NULL) {
+ return NULL;
+ }
+ return list->first();
+}
+
+void PG_ScrollArea::SetResizeParent(bool bRemove, bool bAdd) {
+ if(GetParent() == NULL) {
+ return;
+ }
+
+ my_RemoveResizeParent = bRemove;
+ my_AddResizeParent = bAdd;
+}
diff --git a/src/paragui/pgscrollarea.h b/src/paragui/pgscrollarea.h
new file mode 100644
index 0000000..bbd4088
--- /dev/null
+++ b/src/paragui/pgscrollarea.h
@@ -0,0 +1,160 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000-2004 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgscrollarea.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#ifndef PG_SCROLLAREA_H
+#define PG_SCROLLAREA_H
+
+#include "pgwidget.h"
+#include "pgpoint.h"
+
+/**
+ @author Alexander Pipelka
+ @short A widget containing other widgets which can be paned.
+ With this widget you can create larger scrollable areas. This could be one larger
+ client-widget or any number of widgets "spanning" the scrollable area. This
+ widget doesn't provide scrollbars you can only move to a position by using the
+ PG_ScrollArea::ScrollTo method.
+*/
+
+class PG_ScrollArea : public PG_Widget {
+public:
+
+ class SignalAreaChangedHeight : public PG_Signal2<PG_ScrollArea*, Uint16> {};
+ class SignalAreaChangedWidth : public PG_Signal2<PG_ScrollArea*, Uint16> {};
+
+ /**
+ Create a scrollarea widget.
+ @param parent parent widget if the scrollarea should be within the client
+ context of an other widget, or NULL if this widget has no parent.
+ @param r position and dimensions of the widget
+ */
+ PG_ScrollArea(PG_Widget* parent, const PG_Rect& r = PG_Rect::null);
+
+ ~PG_ScrollArea();
+
+ /**
+ Shift widgets on removal.
+ @param shiftx shift all widgets to the right of the removed widgets.
+ @param shifty shift all widgets beneath the removed one.
+ This method controls the behaviour if a widget will be removed from the client
+ context.
+ */
+ void SetShiftOnRemove(bool shiftx, bool shifty);
+
+ /**
+ scroll to a give X/Y-Coordinate within the client area.
+ @param x X-Position
+ @param y Y-Position
+ */
+ void ScrollTo(Uint16 x, Uint16 y);
+
+ /**
+ Scroll to a widget
+ @param widget the target widget
+ @param bVertical scroll direction
+ */
+ void ScrollToWidget(PG_Widget* widget, bool bVertical = true);
+ void EnsureVisible(PG_Widget *widget, bool bVertical = true);
+
+ /**
+ Set the width of the scrollable area manually.
+ @param w new width of the scrollable area.
+ This method overrides the automatically computed width of the scrollable area.
+ */
+ void SetAreaWidth(Uint16 w);
+
+ /**
+ Set the height of the scrollable area manually.
+ @param h new height of the scrollable area.
+ This method overrides the automatically computed height of the scrollable area.
+ */
+ void SetAreaHeight(Uint16 h);
+
+ /**
+ Get the width of the scrollable area.
+ @return width (in pixels) of the scrollable area
+ */
+ inline Uint16 GetAreaWidth() {
+ return my_area.w;
+ };
+
+ /**
+ Get the height of the scrollable area.
+ @return width (in pixels) of the scrollable area
+ */
+ inline Uint16 GetAreaHeight() {
+ return my_area.h;
+ };
+
+ /**
+ Remove all widgets from the list (without deletion)
+ */
+ void RemoveAll();
+
+ /**
+ Delete (destroy) all widgets in the list
+ */
+ void DeleteAll();
+
+ /**
+ Get the number of widgets in the list
+ */
+ Uint16 GetWidgetCount();
+
+ Uint16 GetScrollPosX();
+
+ Uint16 GetScrollPosY();
+
+ SignalAreaChangedHeight sigAreaChangedHeight;
+
+ SignalAreaChangedWidth sigAreaChangedWidth;
+
+ void AddChild(PG_Widget* child);
+
+ bool RemoveChild(PG_Widget* child);
+
+ PG_Widget* GetFirstInList();
+
+ /**
+ Automatically adjusts the parent's size to the actual scroll area size;
+ @param bRemove adjusts size when removing a child
+ @param bAdd adjusts size when adding a child
+ */
+ void SetResizeParent(bool bRemove, bool bAdd);
+
+protected:
+
+ PG_Rect my_area;
+ bool my_shiftx;
+ bool my_shifty;
+
+ bool my_AddResizeParent;
+ bool my_RemoveResizeParent;
+};
+
+#endif // PG_SCROLLAREA_H
diff --git a/src/paragui/pgscrollbar.cpp b/src/paragui/pgscrollbar.cpp
new file mode 100644
index 0000000..6286438
--- /dev/null
+++ b/src/paragui/pgscrollbar.cpp
@@ -0,0 +1,482 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgscrollbar.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pgscrollbar.h"
+//#include "pgapplication.h"
+
+PG_ScrollBar::PG_ScrollBar(PG_Widget* parent, const PG_Rect& r, ScrollDirection direction, int id, const char* style) :
+ PG_Widget(parent, r)
+{
+ sb_direction = direction;
+
+ SetID(id);
+
+ scroll_min = 0;
+ scroll_max = 4;
+ scroll_current = 0;
+
+ my_linesize = 1;
+ my_pagesize = 5;
+
+ scrollbutton[0] = new PG_Button(this);
+ scrollbutton[0]->SetID((direction == VERTICAL) ? IDSCROLLBAR_UP : IDSCROLLBAR_LEFT);
+ scrollbutton[0]->sigClick.connect(slot(*this, &PG_ScrollBar::handleButtonClick));
+
+ scrollbutton[1] = new PG_Button(this);
+ scrollbutton[1]->SetID((direction == VERTICAL) ? IDSCROLLBAR_DOWN : IDSCROLLBAR_RIGHT);
+ scrollbutton[1]->sigClick.connect(slot(*this, &PG_ScrollBar::handleButtonClick));
+
+ dragbutton = new ScrollButton(this);
+ dragbutton->SetID(IDSCROLLBAR_DRAG);
+ dragbutton->sigClick.connect(slot(*this, &PG_ScrollBar::handleButtonClick));
+
+/* if(strcmp(style, "Scrollbar") != 0) {
+ LoadThemeStyle("Scrollbar");
+ }
+ LoadThemeStyle(style);
+*/ SetPosition(0);
+}
+
+PG_ScrollBar::~PG_ScrollBar() {}
+
+/*
+void PG_ScrollBar::LoadThemeStyle(const char* widgettype) {
+
+ PG_ThemeWidget::LoadThemeStyle(widgettype, "Scrollbar");
+
+ if(sb_direction == VERTICAL) {
+ scrollbutton[0]->LoadThemeStyle(widgettype, "ScrollbarUp");
+ scrollbutton[1]->LoadThemeStyle(widgettype, "ScrollbarDown");
+ } else {
+ scrollbutton[0]->LoadThemeStyle(widgettype, "ScrollbarLeft");
+ scrollbutton[1]->LoadThemeStyle(widgettype, "ScrollbarRight");
+ }
+
+ dragbutton->LoadThemeStyle(widgettype, "ScrollbarDrag");
+
+ if(sb_direction == VERTICAL) {
+ dragbutton->LoadThemeStyle(widgettype, "ScrollbarDragV");
+ PG_ThemeWidget::LoadThemeStyle(widgettype, "ScrollbarV");
+ } else {
+ dragbutton->LoadThemeStyle(widgettype, "ScrollbarDragH");
+ PG_ThemeWidget::LoadThemeStyle(widgettype, "ScrollbarH");
+ }
+ RecalcPositions();
+}
+*/
+void PG_ScrollBar::RecalcPositions() {
+
+ if(sb_direction == VERTICAL) {
+ position[0].x = 0;
+ position[0].y = 0;
+ position[0].w = w;
+ position[0].h = w;
+
+ position[1].x = 0;
+ position[1].y = abs(h-w);
+ position[1].w = w;
+ position[1].h = w;
+
+ position[2].x = 0;
+ position[2].y = w;
+ position[2].w = w;
+ position[2].h = abs(h-(w*2));
+
+ position[3].x = 0;
+ position[3].w = w;
+ position[3].h = (position[2].h / 2); //(scroll_max - scroll_min)) * scroll_windowsize;
+
+ if((scroll_max - scroll_min) == 0) {
+ position[3].y = position[2].y;
+ } else {
+ position[3].y = ((position[2].h - position[3].h) / (scroll_max - scroll_min)) * scroll_current;
+ }
+ } else {
+ position[0].x = 0;
+ position[0].y = 0;
+ position[0].w = h;
+ position[0].h = h;
+
+ position[1].x = abs(w - h);
+ position[1].y = 0;
+ position[1].w = h;
+ position[1].h = h;
+
+ position[2].x = h;
+ position[2].y = 0;
+ position[2].w = abs(w-(h*2));
+ position[2].h = h;
+
+ position[3].y = 0;
+ position[3].w = (Uint16)((double)position[2].w / 2.0);
+ position[3].h = h;
+
+ if((scroll_max - scroll_min) == 0) {
+ position[3].x = position[2].x;
+ } else {
+ position[3].x = ((position[2].w - position[3].w) / (scroll_max - scroll_min)) * scroll_current;
+ }
+ }
+
+ int pos = scroll_current - scroll_min;
+
+ if(sb_direction == VERTICAL) {
+ position[3].x = 0;
+ position[3].h = (Uint16)((double)position[2].h / ((double)position[2].h / (double)position[3].h));
+ position[3].y = (Uint16)(position[0].h + (((double)position[2].h - (double)position[3].h) / (double)(scroll_max - scroll_min)) * (double)pos);
+ } else {
+ position[3].y = 0;
+ position[3].w = (Uint16)((double)position[2].w / ((double)position[2].w / (double)position[3].w) );
+ position[3].x = (Uint16)(position[0].w + (((double)position[2].w - (double)position[3].w) / (double)(scroll_max - scroll_min)) * (double)pos);
+ }
+
+ // bordersize
+
+ for(int i=0; i<4; i++) {
+ if(i == 3 || i == 2) {
+ if(sb_direction == VERTICAL) {
+ position[i].x += my_bordersize;
+ if(position[i].w > 2*my_bordersize) {
+ position[i].w -= 2*my_bordersize;
+ }
+ }
+ else {
+ position[i].y += my_bordersize;
+ if(position[i].h > 2*my_bordersize) {
+ position[i].h -= 2*my_bordersize;
+ }
+ }
+ continue;
+ }
+ position[i].x += my_bordersize;
+ position[i].y += my_bordersize;
+ if(position[i].w > 2*my_bordersize) {
+ position[i].w -= 2*my_bordersize;
+ }
+ if(position[i].h > 2*my_bordersize) {
+ position[i].h -= 2*my_bordersize;
+ }
+ }
+ if(scrollbutton[0] != NULL) {
+ scrollbutton[0]->MoveWidget(position[0]);
+ }
+ if(scrollbutton[1] != NULL) {
+ scrollbutton[1]->MoveWidget(position[1]);
+ }
+ dragbutton->MoveWidget(position[3]);
+}
+
+void PG_ScrollBar::eventSizeWidget(Uint16 w, Uint16 h) {
+
+ PG_Widget::eventSizeWidget(w, h);
+
+ RecalcPositions();
+ SetPosition(scroll_current);
+ return;
+}
+
+/** */
+bool PG_ScrollBar::eventMouseMotion(const SDL_MouseMotionEvent* motion) {
+ return PG_Widget::eventMouseMotion(motion);
+}
+
+/** */
+bool PG_ScrollBar::eventMouseButtonUp(const SDL_MouseButtonEvent* button) {
+ int x;
+ int y;
+ int mx = dragbutton->my_xpos + dragbutton->my_width / 2;
+ int my = dragbutton->my_ypos + dragbutton->my_height / 2;
+
+ SDL_GetMouseState(&x, &y);
+
+ switch (button->button) {
+ case 1:
+ if(sb_direction == VERTICAL) {
+ if(y < my) {
+ SetPosition(scroll_current - my_pagesize);
+ } else {
+ SetPosition(scroll_current + my_pagesize);
+ }
+ } else {
+ if(x < mx) {
+ SetPosition(scroll_current - my_pagesize);
+ } else {
+ SetPosition(scroll_current + my_pagesize);
+ }
+ }
+
+ sigScrollPos(this, scroll_current);
+ return true;
+
+ case 4:
+ if(scroll_current <= scroll_min + my_linesize) {
+ SetPosition(scroll_min);
+ } else {
+ SetPosition(scroll_current - my_linesize);
+ }
+ sigScrollPos(this, scroll_current);
+ return true;
+
+ case 5:
+ SetPosition(scroll_current + my_linesize);
+ sigScrollPos(this, scroll_current);
+ return true;
+ }
+
+ return PG_Widget::eventMouseButtonUp(button);
+}
+
+
+PG_ScrollBar::ScrollButton::ScrollButton(PG_ScrollBar* parent, const PG_Rect& r) : PG_Button(parent, r) {
+ SetID(IDSCROLLBAR_DRAG);
+ my_tickMode = false;
+}
+
+PG_ScrollBar::ScrollButton::~ScrollButton() {}
+
+/** */
+bool PG_ScrollBar::ScrollButton::eventMouseMotion(const SDL_MouseMotionEvent* motion) {
+ PG_Point p;
+
+ if(GetPressed()) {
+
+ //SDL_GetMouseState(&x, &y);
+ p = GetParent()->ScreenToClient(motion->x, motion->y);
+
+ if(GetParent()->sb_direction == VERTICAL) {
+ p.y -= offset.y;
+
+ if(p.y < GetParent()->position[2].y) {
+ p.y = GetParent()->position[2].y;
+ }
+
+ int maxy;
+ if(!my_tickMode) {
+ maxy = GetParent()->position[2].y + (GetParent()->position[2].h) - my_height;
+ } else {
+ maxy = GetParent()->my_height - my_height;
+ }
+
+ if(p.y > maxy) {
+ p.y = maxy;
+ }
+
+ MoveWidget(GetParent()->position[2].x, p.y);
+ } else {
+ p.x -= offset.x;
+
+ if(p.x < GetParent()->position[2].x) {
+ p.x = GetParent()->position[2].x;
+ }
+
+ int maxx;
+ if(!my_tickMode) {
+ maxx = GetParent()->position[2].x + (GetParent()->position[2].w) - (my_width);
+ } else {
+ maxx = GetParent()->my_width - my_width;
+ }
+
+ if(p.x > maxx) {
+ p.x = maxx;
+ }
+
+ MoveWidget(p.x, GetParent()->position[2].y);
+ }
+
+ int pos = GetPosFromPoint(p);
+ if(GetParent()->scroll_current != pos || my_tickMode) {
+ GetParent()->scroll_current = pos;
+ GetParent()->sigScrollTrack(GetParent(), pos);
+ }
+
+ }
+
+ return true;
+}
+
+/** */
+bool PG_ScrollBar::ScrollButton::eventMouseButtonDown(const SDL_MouseButtonEvent* button) {
+ int x,y;
+
+ if(button->button == 1) {
+ SDL_GetMouseState(&x, &y);
+ offset = ScreenToClient(x, y);
+ }
+
+ return PG_Button::eventMouseButtonDown(button);
+}
+
+/** */
+PG_ScrollBar* PG_ScrollBar::ScrollButton::GetParent() {
+ return (PG_ScrollBar*)PG_Button::GetParent();
+}
+
+/** */
+void PG_ScrollBar::SetPosition(int pos) {
+
+ if(pos < scroll_min) {
+ pos = scroll_min;
+ }
+
+ if(pos > scroll_max) {
+ pos = scroll_max;
+ }
+
+ scroll_current = pos;
+ pos -= scroll_min;
+
+ // check if we are currently in a drag operation
+ if(dragbutton->GetPressed()) {
+ return;
+ }
+
+ RecalcPositions();
+}
+
+int PG_ScrollBar::GetPosition() {
+ return scroll_current;
+}
+
+/** */
+bool PG_ScrollBar::handleButtonClick(PG_Button* button) {
+
+ if(button == scrollbutton[0]) { // UP | LEFT
+ if(scroll_current == scroll_min) {
+ return false;
+ }
+ SetPosition(scroll_current - my_linesize);
+ sigScrollPos(this, scroll_current);
+ return true;
+ }
+
+ if(button == scrollbutton[1]) { // DOWN | RIGHT
+ if(scroll_current == scroll_max) {
+ return false;
+ }
+ SetPosition(scroll_current + my_linesize);
+ sigScrollPos(this, scroll_current);
+ return true;
+
+ }
+
+ return false;
+}
+
+/** */
+bool PG_ScrollBar::eventMouseButtonDown(const SDL_MouseButtonEvent* button) {
+ return false;
+}
+
+/** */
+bool PG_ScrollBar::ScrollButton::eventMouseButtonUp(const SDL_MouseButtonEvent* button) {
+ int pos = GetParent()->scroll_current; //my_tempPos;
+
+ if(button->button != 1) {
+ return false;
+ }
+
+ PG_Button::eventMouseButtonUp(button);
+
+ //GetParent()->SetPosition(pos);
+ GetParent()->sigScrollPos(GetParent(), pos);
+
+ return true;
+}
+
+void PG_ScrollBar::ScrollButton::SetTickMode(bool on) {
+ my_tickMode = on;
+}
+
+/** */
+void PG_ScrollBar::SetRange(Uint32 min, Uint32 max) {
+ scroll_min = min;
+ scroll_max = max;
+ if (scroll_current < scroll_min) {
+ SetPosition(scroll_min);
+ }
+ if (scroll_current > scroll_max) {
+ SetPosition(scroll_max);
+ }
+}
+
+int PG_ScrollBar::GetMinRange() {
+ return scroll_min;
+}
+
+/** */
+int PG_ScrollBar::GetMaxRange() {
+ return scroll_max;
+}
+
+/** */
+int PG_ScrollBar::ScrollButton::GetPosFromPoint(PG_Point p) {
+ Uint32 range = (GetParent()->scroll_max - GetParent()->scroll_min);
+ int pos = 0;
+
+ if(p.x < 0)
+ p.x = 0;
+ if(p.y < 0)
+ p.y = 0;
+
+ //if(!my_tickMode) {
+ if(GetParent()->sb_direction == VERTICAL) {
+ pos = (int)((double)(p.y - GetParent()->position[2].y) / (((double)GetParent()->position[2].h - (double)GetParent()->position[3].h) / (double)range));
+ } else {
+ pos = (int)((double)(p.x - GetParent()->position[2].x) / (((double)GetParent()->position[2].w - (double)GetParent()->position[3].w) / (double)range));
+ }
+ /*} else {
+ if(GetParent()->sb_direction == VERTICAL) {
+ pos = (int)( (((double)(p.y)) * (double)(range)) / ( (double)GetParent()->position[2].h - (double)GetParent()->position[3].h) + .5 );
+ } else {
+ pos = (int)( (((double)(p.x)) * (double)(range)) / ( (double)GetParent()->position[2].w - (double)GetParent()->position[3].w) + .5 );
+ }
+ }*/
+
+ if(pos < 0)
+ pos = 0;
+
+ pos = GetParent()->scroll_min+pos;
+
+ if(pos > GetParent()->scroll_max) {
+ pos = GetParent()->scroll_max;
+ }
+
+ if(pos < GetParent()->scroll_min) {
+ pos = GetParent()->scroll_min;
+ }
+
+ return pos;
+}
+
+void PG_ScrollBar::SetLineSize(int ls) {
+ my_linesize = ls;
+}
+
+void PG_ScrollBar::SetPageSize(int ps) {
+ my_pagesize = ps;
+}
diff --git a/src/paragui/pgscrollbar.h b/src/paragui/pgscrollbar.h
new file mode 100644
index 0000000..6c92a26
--- /dev/null
+++ b/src/paragui/pgscrollbar.h
@@ -0,0 +1,180 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgscrollbar.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#ifndef PG_SCROLLBAR_H
+#define PG_SCROLLBAR_H
+
+#include "pgwidget.h"
+#include "pgbutton.h"
+
+/**
+ @author Alexander Pipelka
+
+ @short A vertical or horizontal scrollbar
+
+ Doesn't actually tie itself to any object to be scrolled, just get's told
+ it's current state through function calls.
+*/
+
+#define PG_WIDGETID_INTERNAL 10000
+
+
+class PG_ScrollBar : public PG_Widget {
+
+protected:
+
+#ifndef DOXYGEN_SKIP
+class ScrollButton : public PG_Button {
+ public:
+
+ ScrollButton(PG_ScrollBar* parent, const PG_Rect& r = PG_Rect::null);
+ virtual ~ScrollButton();
+
+ void SetTickMode(bool on);
+
+ protected:
+
+ /** */
+ bool eventMouseButtonDown(const SDL_MouseButtonEvent* button);
+ /** */
+ bool eventMouseMotion(const SDL_MouseMotionEvent* motion);
+ /** */
+ PG_ScrollBar* GetParent();
+ /** */
+ bool eventMouseButtonUp(const SDL_MouseButtonEvent* button);
+ /** */
+ int GetPosFromPoint(PG_Point p);
+
+ private:
+
+ /** */
+ PG_Point offset;
+
+ /** */
+ bool my_tickMode;
+
+ };
+#endif // DOXYGEN_SKIP
+
+
+public:
+
+ //! ScrollbarType
+ typedef enum {
+ VERTICAL, //!< vertical scrollbar
+ HORIZONTAL //!< horizontal scrollbar
+ } ScrollDirection;
+
+ //! Widget ID's
+ enum {
+ IDSCROLLBAR_UP = PG_WIDGETID_INTERNAL + 1, //!<ID Scrollbar Button "up"
+ IDSCROLLBAR_DOWN = PG_WIDGETID_INTERNAL + 2, //!< ID Scrollbar Button "down"
+ IDSCROLLBAR_LEFT = PG_WIDGETID_INTERNAL + 3, //!< ID Scrollbar Button "left"
+ IDSCROLLBAR_RIGHT = PG_WIDGETID_INTERNAL + 4, //!< ID Scrollbar Button "right"
+ IDSCROLLBAR_DRAG = PG_WIDGETID_INTERNAL + 5 //!< ID Scrollbar Button "drag"
+ };
+
+ /**
+ Signal type declaration
+ **/
+ template<class datatype> class SignalScrollPos : public PG_Signal2<PG_ScrollBar*, datatype> {};
+ template<class datatype> class SignalScrollTrack : public PG_Signal2<PG_ScrollBar*, datatype> {};
+
+ /** */
+ PG_ScrollBar(PG_Widget* parent, const PG_Rect& r = PG_Rect::null, ScrollDirection direction = VERTICAL, int id = -1, const char* style="Scrollbar");
+
+ /** */
+ virtual ~PG_ScrollBar();
+
+ // void LoadThemeStyle(const char* widgettype);
+
+ /** */
+ void SetPosition(int pos);
+
+ /** */
+ int GetPosition();
+
+ /** */
+ void SetRange(Uint32 min, Uint32 max);
+
+ /** */
+ int GetMinRange();
+
+ /** */
+ int GetMaxRange();
+
+ /** */
+ void SetLineSize(int ls);
+
+ /** */
+ void SetPageSize(int ps);
+
+ SignalScrollPos<long> sigScrollPos;
+ SignalScrollTrack<long> sigScrollTrack;
+
+protected:
+
+ /** */
+ void eventSizeWidget(Uint16 w, Uint16 h);
+
+ /** */
+ bool eventMouseMotion(const SDL_MouseMotionEvent* motion);
+
+ /** */
+ bool eventMouseButtonDown(const SDL_MouseButtonEvent* button);
+
+ /** */
+ virtual bool handleButtonClick(PG_Button* button);
+
+ /** */
+ bool eventMouseButtonUp(const SDL_MouseButtonEvent* button);
+
+ int scroll_min;
+ int scroll_max;
+ int scroll_current;
+ int my_linesize;
+ int my_pagesize;
+
+ PG_Button* scrollbutton[2];
+ ScrollButton* dragbutton;
+ PG_Rect position[4];
+
+ ScrollDirection sb_direction;
+
+ virtual void RecalcPositions();
+
+ friend class ScrollButton;
+
+private:
+
+ PG_ScrollBar(const PG_ScrollBar&);
+ PG_ScrollBar& operator=(PG_ScrollBar&);
+
+};
+
+#endif // PG_SCROLLBAR_H
diff --git a/src/paragui/pgscrollwidget.cpp b/src/paragui/pgscrollwidget.cpp
new file mode 100644
index 0000000..635290b
--- /dev/null
+++ b/src/paragui/pgscrollwidget.cpp
@@ -0,0 +1,332 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgscrollwidget.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pgscrollwidget.h"
+#include "pgscrollarea.h"
+
+PG_ScrollWidget::PG_ScrollWidget(PG_Widget* parent, const PG_Rect& r, const char* style) :
+PG_Widget(parent, r),
+my_objVerticalScrollbar(NULL),
+my_objHorizontalScrollbar(NULL) ,
+my_scrollarea(NULL)
+{
+ my_enableVerticalScrollbar = true;
+ my_enableHorizontalScrollbar = true;
+ my_widthScrollbar = my_heightHorizontalScrollbar = 14;
+
+ // It is important to make sure that the substractions below won't
+ // render values < 0 and, eventually,
+ // surface widths such as 32768 or 65535 when cast to an unsigned type.
+ // This can lead to segfaults later on in, for example, DrawGradient...
+ if (my_widthScrollbar > r.my_width)
+ my_widthScrollbar = r.my_width;
+
+ if (my_heightHorizontalScrollbar > r.my_height)
+ my_heightHorizontalScrollbar = r.my_height;
+
+ my_objVerticalScrollbar = new PG_ScrollBar(this, PG_Rect(0,0,my_widthScrollbar,r.h), PG_ScrollBar::VERTICAL, IDWIDGETLIST_VSCROLL, style);
+ my_objVerticalScrollbar->SetRange(0,0);
+ my_widthScrollbar = my_objVerticalScrollbar->Width();
+ my_objVerticalScrollbar->Hide();
+ my_objVerticalScrollbar->sigScrollPos.connect(slot(*this, &PG_ScrollWidget::handleScrollPos));
+ my_objVerticalScrollbar->sigScrollTrack.connect(slot(*this, &PG_ScrollWidget::handleScrollTrack));
+
+ my_objHorizontalScrollbar = new PG_ScrollBar(this, PG_Rect(0,0,r.w, my_heightHorizontalScrollbar), PG_ScrollBar::HORIZONTAL, IDWIDGETLIST_HSCROLL, style);
+ my_objHorizontalScrollbar->SetRange(0,0);
+ my_heightHorizontalScrollbar = my_objHorizontalScrollbar->Height();
+ my_objHorizontalScrollbar->Hide();
+ my_objHorizontalScrollbar->sigScrollPos.connect(slot(*this, &PG_ScrollWidget::handleScrollPos));
+ my_objHorizontalScrollbar->sigScrollTrack.connect(slot(*this, &PG_ScrollWidget::handleScrollTrack));
+
+ my_scrollarea = new PG_ScrollArea(this);
+ my_scrollarea->sigAreaChangedHeight.connect(slot(*this, &PG_ScrollWidget::handleAreaChangedHeight));
+ my_scrollarea->sigAreaChangedWidth.connect(slot(*this, &PG_ScrollWidget::handleAreaChangedWidth));
+ my_scrollarea->SetShiftOnRemove(false, false);
+
+ /*if(strcmp(style, "ScrollWidget") != 0) {
+ LoadThemeStyle("ScrollWidget");
+ }
+ LoadThemeStyle(style);*/
+}
+
+PG_ScrollWidget::~PG_ScrollWidget() {
+ my_scrollarea->DeleteAll();
+}
+
+void PG_ScrollWidget::RecalcPositions(bool bV, bool bH) {
+
+ // only vertical
+ if(bV && !bH) {
+ my_rectVerticalScrollbar.SetRect(
+ my_width - (my_widthScrollbar + my_bordersize),
+ my_bordersize,
+ my_widthScrollbar,
+ my_height - my_bordersize*2);
+ my_rectHorizontalScrollbar.SetRect(0,0,0,0);
+ }
+
+ // only horizontal
+ if(!bV && bH) {
+ my_rectHorizontalScrollbar.SetRect(
+ my_bordersize,
+ my_height - (my_heightHorizontalScrollbar + my_bordersize),
+ my_width - my_bordersize*2,
+ my_heightHorizontalScrollbar);
+ my_rectVerticalScrollbar.SetRect(0,0,0,0);
+ }
+
+ // both
+ if(bV && bH) {
+ my_rectVerticalScrollbar.SetRect(
+ my_width - (my_widthScrollbar + my_bordersize),
+ my_bordersize,
+ my_widthScrollbar,
+ my_height - (my_heightHorizontalScrollbar + my_bordersize*2));
+
+ my_rectHorizontalScrollbar.SetRect(
+ my_bordersize,
+ my_height - (my_heightHorizontalScrollbar + my_bordersize),
+ my_width - (my_widthScrollbar+my_bordersize*2),
+ my_heightHorizontalScrollbar);
+ }
+
+ // scrollarea
+ my_rectList.SetRect(
+ my_bordersize, my_bordersize,
+ my_width - (my_rectVerticalScrollbar.w + my_bordersize*2),
+ my_height - (my_rectHorizontalScrollbar.h + my_bordersize*2));
+
+ if(*my_objVerticalScrollbar != my_rectVerticalScrollbar) {
+ my_objVerticalScrollbar->MoveWidget(my_rectVerticalScrollbar);
+ }
+
+ if(*my_objHorizontalScrollbar != my_rectHorizontalScrollbar) {
+ my_objHorizontalScrollbar->MoveWidget(my_rectHorizontalScrollbar);
+ }
+
+ if(*my_scrollarea != my_rectList) {
+ my_scrollarea->MoveWidget(my_rectList);
+ }
+}
+/*
+void PG_ScrollWidget::LoadThemeStyle(const char* widgettype) {
+ PG_ThemeWidget::LoadThemeStyle(widgettype);
+ my_objVerticalScrollbar->LoadThemeStyle(widgettype);
+ my_objHorizontalScrollbar->LoadThemeStyle(widgettype);
+
+ my_widthScrollbar = my_objVerticalScrollbar->Width();
+ my_heightHorizontalScrollbar = my_objHorizontalScrollbar->Height();
+ RecalcPositions(my_objVerticalScrollbar->IsVisible(), my_objHorizontalScrollbar->IsVisible());
+}
+*/
+void PG_ScrollWidget::eventSizeWidget(Uint16 w, Uint16 h) {
+
+ PG_Widget::eventSizeWidget(w,h);
+
+ if(h != my_height) {
+ my_height = h;
+ handleAreaChangedHeight(my_scrollarea, GetListHeight());
+ }
+
+ if(w != my_width) {
+ my_width = w;
+ handleAreaChangedWidth(my_scrollarea, GetListWidth());
+ }
+}
+
+bool PG_ScrollWidget::handleScrollPos(PG_ScrollBar* widget, long data) {
+ if(widget == my_objVerticalScrollbar) {
+ my_scrollarea->ScrollTo(my_scrollarea->GetScrollPosX(), data);
+ return true;
+ }
+
+ if(widget == my_objHorizontalScrollbar) {
+ my_scrollarea->ScrollTo(data, my_scrollarea->GetScrollPosY());
+ return true;
+ }
+
+ return true;
+}
+
+bool PG_ScrollWidget::handleScrollTrack(PG_ScrollBar* widget, long data) {
+ if(widget == my_objVerticalScrollbar) {
+ my_scrollarea->ScrollTo(my_scrollarea->GetScrollPosX(), data);
+ return true;
+ }
+
+ if(widget == my_objHorizontalScrollbar) {
+ my_scrollarea->ScrollTo(data, my_scrollarea->GetScrollPosY());
+ return true;
+ }
+
+ return true;
+}
+
+void PG_ScrollWidget::AddChild(PG_Widget* w) {
+ if(w == NULL) {
+ return;
+ }
+
+ if (my_objVerticalScrollbar == NULL || my_objHorizontalScrollbar == NULL || my_scrollarea == NULL) {
+ PG_Widget::AddChild(w);
+ return;
+ }
+
+ my_scrollarea->AddChild(w);
+}
+
+void PG_ScrollWidget::CheckScrollBars() {
+ int ls = 0, i;
+ PG_ScrollBar *scrollBars[] = { my_objVerticalScrollbar, my_objHorizontalScrollbar };
+ Uint32 listsizes[] = { GetListHeight(), GetListWidth() };
+ Uint16 sizes[] = { my_scrollarea->Height(), my_scrollarea->Width() };
+ Uint16 pos[] = { my_scrollarea->GetScrollPosY(), my_scrollarea->GetScrollPosX() };
+ for (i = 0; i < 2; i++) {
+ if(GetWidgetCount() != 0) {
+ ls = listsizes[i] / GetWidgetCount();
+
+ if(ls == 0) {
+ ls = 1;
+ }
+ scrollBars[i]->SetLineSize(ls);
+ }
+ else {
+ scrollBars[i]->SetLineSize(10);
+ }
+ scrollBars[i]->SetRange(0, listsizes[i] - sizes[i]);
+ scrollBars[i]->SetPageSize(sizes[i]);
+ scrollBars[i]->SetPosition(pos[i]);
+ }
+
+}
+
+void PG_ScrollWidget::EnableScrollBar(bool enable, PG_ScrollBar::ScrollDirection direction) {
+ if (direction == PG_ScrollBar::VERTICAL) {
+ my_enableVerticalScrollbar = enable;
+ } else if (direction == PG_ScrollBar::HORIZONTAL) {
+ my_enableHorizontalScrollbar = enable;
+ }
+ RecalcPositions(my_objVerticalScrollbar->IsVisible(), my_objHorizontalScrollbar->IsVisible());
+ CheckScrollBars();
+}
+
+void PG_ScrollWidget::ScrollToWidget(PG_Widget* widget, bool bVertical) {
+ my_scrollarea->ScrollToWidget(widget, bVertical);
+ RecalcPositions(my_objVerticalScrollbar->IsVisible(), my_objHorizontalScrollbar->IsVisible());
+ CheckScrollBars();
+}
+
+Uint16 PG_ScrollWidget::GetListHeight() {
+ return my_scrollarea->GetAreaHeight();
+}
+
+Uint16 PG_ScrollWidget::GetListWidth() {
+ return my_scrollarea->GetAreaWidth();
+}
+
+Uint16 PG_ScrollWidget::GetWidgetCount() {
+ return my_scrollarea->GetWidgetCount();
+}
+
+bool PG_ScrollWidget::handleAreaChangedHeight(PG_ScrollArea* area, Uint16 h) {
+ if(h > my_scrollarea->h && my_enableVerticalScrollbar) {
+ RecalcPositions(true, my_objHorizontalScrollbar->IsVisible());
+ my_objVerticalScrollbar->Show();
+ }
+ else {
+ my_objVerticalScrollbar->Hide();
+ RecalcPositions(false, my_objHorizontalScrollbar->IsVisible());
+ }
+
+ Sint32 max_y = my_scrollarea->GetAreaHeight() - my_scrollarea->GetScrollPosY();
+ if(max_y < my_scrollarea->my_height) {
+ max_y = my_scrollarea->GetAreaHeight() - my_scrollarea->my_height;
+ if(max_y < 0) {
+ max_y = 0;
+ }
+ my_scrollarea->ScrollTo(my_scrollarea->GetScrollPosX(), max_y);
+ }
+
+ CheckScrollBars();
+ return true;
+}
+
+bool PG_ScrollWidget::handleAreaChangedWidth(PG_ScrollArea* area, Uint16 w) {
+ if(w > my_scrollarea->w && my_enableHorizontalScrollbar) {
+ RecalcPositions(my_objVerticalScrollbar->IsVisible(), true);
+ my_objHorizontalScrollbar->Show();
+ }
+ else {
+ my_objHorizontalScrollbar->Hide();
+ RecalcPositions(my_objVerticalScrollbar->IsVisible(), false);
+ }
+
+ Sint32 max_x = my_scrollarea->GetAreaWidth() - my_scrollarea->GetScrollPosX();
+ if(max_x < my_scrollarea->my_width) {
+ max_x = my_scrollarea->GetAreaWidth() - my_scrollarea->my_width;
+ if(max_x < 0) {
+ max_x = 0;
+ }
+ my_scrollarea->ScrollTo(max_x, my_scrollarea->GetScrollPosY());
+ }
+
+ CheckScrollBars();
+ return true;
+}
+
+PG_Widget* PG_ScrollWidget::GetFirstInList() {
+ return my_scrollarea->GetFirstInList();
+}
+
+void PG_ScrollWidget::ScrollTo(Uint16 x, Uint16 y) {
+ my_scrollarea->ScrollTo(x, y);
+}
+
+void PG_ScrollWidget::DeleteAll() {
+ my_scrollarea->DeleteAll();
+}
+
+void PG_ScrollWidget::RemoveAll() {
+ my_scrollarea->RemoveAll();
+}
+
+void PG_ScrollWidget::SetShiftOnRemove(bool shiftx, bool shifty) {
+ my_scrollarea->SetShiftOnRemove(shiftx, shifty);
+}
+
+Uint16 PG_ScrollWidget::GetScrollPosX() {
+ return my_scrollarea->GetScrollPosX();
+}
+
+Uint16 PG_ScrollWidget::GetScrollPosY() {
+ return my_scrollarea->GetScrollPosY();
+}
+
+void PG_ScrollWidget::SetAutoResize(bool bRemove, bool bAdd) {
+ my_scrollarea->SetResizeParent(bRemove, bAdd);
+}
diff --git a/src/paragui/pgscrollwidget.h b/src/paragui/pgscrollwidget.h
new file mode 100644
index 0000000..60401a0
--- /dev/null
+++ b/src/paragui/pgscrollwidget.h
@@ -0,0 +1,165 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgscrollwidget.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#ifndef PG_SCROLLWIDGET_H
+#define PG_SCROLLWIDGET_H
+
+#include "pgscrollbar.h"
+
+class PG_ScrollArea;
+
+/**
+ @author Alexander Pipelka
+
+ @short Encapsulation of the PG_ScrollArea widget providing scrollbars.
+
+ Generally used to make a large 'pane' of widgets that can be scrolled
+ through in a smaller 'portal' with scrollbars.
+*/
+
+class PG_ScrollWidget : public PG_Widget {
+public:
+
+ enum {
+ IDWIDGETLIST_VSCROLL = PG_WIDGETID_INTERNAL + 10, IDWIDGETLIST_HSCROLL
+ };
+
+ /**
+ Constructor of the PG_Widget class
+ */
+ PG_ScrollWidget(PG_Widget* parent, const PG_Rect& r = PG_Rect::null, const char* style="ScrollWidget");
+
+ /**
+ Destructor of the PG_Widget class
+ */
+ ~PG_ScrollWidget();
+
+ /** */
+// void LoadThemeStyle(const char* widgettype);
+
+ /**
+ Enable / disable the Scrollbar (override automatic display)
+ @param enable true - enable scrollbar / false - disable scrollbar
+ @param direction modified scrollbar (PG_ScrollBar::VERTICAL | PG_ScrollBar::HORIZONTAL)
+ */
+ void EnableScrollBar(bool enable, PG_ScrollBar::ScrollDirection direction = PG_ScrollBar::VERTICAL);
+
+ /**
+ scroll to a give X/Y-Coordinate within the client area.
+ @param x X-Position
+ @param y Y-Position
+ */
+ void ScrollTo(Uint16 x, Uint16 y);
+
+ /**
+ Scroll to a widget
+ @param widget the target widget
+ @param bVertical scroll direction
+ */
+ void ScrollToWidget(PG_Widget* widget, bool bVertical = true);
+
+ Uint16 GetListHeight();
+
+ Uint16 GetListWidth();
+
+ Uint16 GetWidgetCount();
+
+ PG_Widget* GetFirstInList();
+
+ virtual void DeleteAll();
+
+ virtual void RemoveAll();
+
+ void AddChild(PG_Widget* child);
+
+ /**
+ Shift widgets on removal.
+ @param shiftx shift all widgets to the right of the removed widgets.
+ @param shift shift all widgets beneath the removed one.
+ This method controls the behaviour if a widget will be removed from the client
+ context.
+ */
+ void SetShiftOnRemove(bool shiftx, bool shifty);
+
+ /**
+ Get x offset of current scroll position.
+ */
+ Uint16 GetScrollPosX();
+
+ /**
+ Get y offset of current scroll position.
+ */
+ Uint16 GetScrollPosY();
+
+ /**
+ Automatically adjusts the widget's size to the actual scroll area size;
+ @param bRemove adjusts size when removing a child
+ @param bAdd adjusts size when adding a child
+ */
+ void SetAutoResize(bool bRemove, bool bAdd);
+
+protected:
+
+ /** */
+ void eventSizeWidget(Uint16 w, Uint16 h);
+
+ /** */
+ bool handleScrollPos(PG_ScrollBar* widget, long data);
+
+ /** */
+ bool handleScrollTrack(PG_ScrollBar* widget, long data);
+
+ bool handleAreaChangedHeight(PG_ScrollArea* area, Uint16 h);
+
+ bool handleAreaChangedWidth(PG_ScrollArea* area, Uint16 w);
+
+ PG_ScrollBar* my_objVerticalScrollbar;
+ PG_ScrollBar* my_objHorizontalScrollbar;
+ PG_ScrollArea* my_scrollarea;
+
+ PG_Rect my_rectVerticalScrollbar;
+ PG_Rect my_rectHorizontalScrollbar;
+ PG_Rect my_rectList;
+
+ int my_widthScrollbar;
+ int my_heightHorizontalScrollbar;
+
+ bool my_enableVerticalScrollbar;
+ bool my_enableHorizontalScrollbar;
+
+ void CheckScrollBars();
+
+private:
+
+ PG_ScrollWidget(const PG_ScrollWidget&);
+ PG_ScrollWidget& operator=(const PG_ScrollWidget&);
+
+ void RecalcPositions(bool bV, bool bH);
+};
+
+#endif // PG_SCROLLWIDGET_H
diff --git a/src/paragui/pgsetpixel.cpp b/src/paragui/pgsetpixel.cpp
new file mode 100644
index 0000000..c52b6a1
--- /dev/null
+++ b/src/paragui/pgsetpixel.cpp
@@ -0,0 +1,84 @@
+/*
+ ParaGUI - crossplatform widgetset
+ setpixel - draw a single pixel onto a surface
+
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgsetpixel.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pgdraw.h"
+
+void PG_Draw::SetPixel(int x, int y, const PG_Color& c, SDL_Surface * surface) {
+ static PG_Color old;
+ Uint8 ri,gi,bi;
+
+ static Uint32 pixel;
+ static Uint8 *bits;
+ static Uint8 bpp;
+
+ static SDL_Rect rect;
+ SDL_GetClipRect(surface, &rect);
+
+ if((x < rect.x) || (y < rect.y)) {
+ return;
+ }
+
+ if((x >= rect.x+rect.w) || (y >= rect.y+rect.h)) {
+ return;
+ }
+
+ bpp = surface->format->BytesPerPixel;
+ bits = ((Uint8 *) surface->pixels) + y * surface->pitch + x * bpp;
+
+ if(old != c) {
+ pixel = c.MapRGB(surface->format);
+ old = c;
+ }
+
+ /* Set the pixel */
+ switch (bpp) {
+ case 1:
+ *((Uint8 *) (bits)) = (Uint8) pixel;
+ break;
+
+ case 2:
+ *((Uint16 *) (bits)) = (Uint16) pixel;
+ break;
+
+ case 3: { /* Format/endian independent */
+ ri = (pixel >> surface->format->Rshift) & 0xFF;
+ gi = (pixel >> surface->format->Gshift) & 0xFF;
+ bi = (pixel >> surface->format->Bshift) & 0xFF;
+ *((bits) + surface->format->Rshift / 8) = ri;
+ *((bits) + surface->format->Gshift / 8) = gi;
+ *((bits) + surface->format->Bshift / 8) = bi;
+ }
+ break;
+
+ case 4:
+ *((Uint32 *) (bits)) = (Uint32) pixel;
+ break;
+ }
+}
diff --git a/src/paragui/pgsignals.h b/src/paragui/pgsignals.h
new file mode 100644
index 0000000..5a51d36
--- /dev/null
+++ b/src/paragui/pgsignals.h
@@ -0,0 +1,139 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgsignals.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#ifndef PG_SIGNALS_H
+#define PG_SIGNALS_H
+
+#include <sigc++/sigc++.h>
+//#include "pgsigconvert.h"
+
+#ifndef DOXYGEN_SKIP
+using namespace SigC;
+//@ using namespace SigCX;
+#endif // DOXYGEN_SKIP
+
+typedef void* PG_Pointer;
+
+template<class datatype = PG_Pointer> class PG_Signal0 : public Signal0<bool> {
+public:
+
+ Connection connect(const Slot1<bool, datatype>& s, datatype data) {
+ return Signal0<bool>::connect(bind(s, data));
+ };
+
+};
+
+template<class P1, class datatype = PG_Pointer> class PG_Signal1 : public Signal1<bool, P1> {
+
+ static bool sig_convert0(Slot0<bool>& s, P1 p1) {
+ return s();
+ }
+
+public:
+
+ Connection connect(const Slot2<bool, P1, datatype>& s, datatype data) {
+ return Signal1<bool, P1>::connect(bind(s, data));
+ };
+
+ Connection connect(const Slot1<bool, datatype>& s, datatype data) {
+ return connect(bind(s, data));
+ }
+
+ Connection connect(const Slot1<bool, P1>& s) {
+ return Signal1<bool, P1>::connect(s);
+ }
+
+ Connection connect(const Slot0<bool>& s) {
+ return Signal1<bool, P1>::connect(convert(s, sig_convert0));
+ }
+
+ PG_Signal1& operator=(const PG_Signal1&);
+};
+
+
+template<class P1, class P2, class datatype = PG_Pointer> class PG_Signal2 : public Signal2<bool, P1, P2> {
+
+ static bool sig_convert_p2(Slot1<bool, P2>& s, P1 p1, P2 p2) {
+ return s(p2);
+ }
+
+ static bool sig_convert_p1(Slot1<bool, P1>& s, P1 p1, P2 p2) {
+ return s(p1);
+ }
+
+ static bool sig_convert0(Slot0<bool>& s, P1 p1, P2 p2) {
+ return s();
+ }
+public:
+
+ Connection connect(const Slot3<bool, P1, P2, datatype>& s, datatype data) {
+ return Signal2<bool, P1, P2>::connect(bind(s, data));
+ }
+
+ Connection connect(const Slot2<bool, P1, datatype>& s, datatype data) {
+ return Signal2<bool, P1, P2>::connect(bind(s, data));
+ };
+
+ Connection connect(const Slot2<bool, P1, P2>& s) {
+ return Signal2<bool, P1, P2>::connect(s);
+ }
+
+ Connection connect(const Slot1<bool, P2>& s) {
+ return Signal2<bool, P1, P2>::connect(convert(s, sig_convert_p2));
+ }
+
+ Connection connect(const Slot1<bool, P1>& s) {
+ return Signal2<bool, P1, P2>::connect(convert(s, sig_convert_p2));
+ }
+
+ Connection connect(const Slot0<bool>& s) {
+ return Signal2<bool, P1, P2>::connect(convert(s, sig_convert0));
+ }
+
+private:
+ PG_Signal2& operator=(const PG_Signal2&);
+
+};
+
+/*
+typedef PG_Signal1<PG_MessageObject*> PG_SignalAppIdle;
+
+typedef PG_Signal1<PG_Application*> PG_SignalAppQuit;
+
+typedef PG_Signal1<const SDL_ResizeEvent*> PG_SignalVideoResize;
+
+typedef PG_Signal2<PG_TabBar*, PG_Button*> PG_SignalTabSelect;
+
+typedef Slot1<bool, PG_Button*> PG_TabSelectSlot;
+
+typedef PG_Signal2<PG_NoteBook*, PG_Widget*> PG_PageSelect;
+
+typedef Slot1<bool, PG_Widget*> PG_PageSelectSlot;
+*/
+
+#endif // PG_SIGNALS_H
diff --git a/src/paragui/pgsurface.cpp b/src/paragui/pgsurface.cpp
new file mode 100644
index 0000000..5e1b279
--- /dev/null
+++ b/src/paragui/pgsurface.cpp
@@ -0,0 +1,437 @@
+/*
+ ParaGUI - crossplatform widgetset
+ surface - surface creation and manipulation functions
+
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgsurface.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pgdraw.h"
+#include "common.h"
+
+SDL_Surface* PG_Draw::CreateRGBSurface(Uint16 w, Uint16 h, int flags) {
+ SDL_Surface* screen = SDL_GetVideoSurface();
+
+ // credits to Peter Kasting!
+ if (screen == NULL) {
+ debug("CreateRGBSurface() failed: current display surface invalid or n/a.");
+ return NULL;
+ }
+
+ return SDL_CreateRGBSurface (
+ flags,
+ w, h,
+ screen->format->BitsPerPixel,
+ screen->format->Rmask,
+ screen->format->Gmask,
+ screen->format->Bmask,
+ 0);
+}
+
+static void Draw3TileH(SDL_Surface* src, const PG_Rect& r, SDL_Surface* dst, Uint8 blend = 0) {
+ PG_Rect srcrect;
+ PG_Rect dstrect;
+ SDL_Surface* temp;
+ int w,h;
+
+ // source rectangles
+ h = r.h;
+ w = (int)( ( (double)h / (double)src->h) * (double)src->w );
+ srcrect.SetRect(0,0,w,h);
+ w /= 3;
+
+ if (!w) {
+ return;
+ }
+
+ // rescale surface
+
+ if(h == src->h) {
+ temp = src;
+ }
+ else {
+ temp = PG_Draw::ScaleSurface(src, srcrect);
+ }
+
+ // set per surface alpha
+ if(blend > 0) {
+ SDL_SetAlpha(temp, SDL_SRCALPHA, 255-blend);
+ } else {
+ SDL_SetAlpha(temp, 0, 0);
+ }
+
+ // blit part 1 (left)
+
+ SDL_SetClipRect(dst, NULL);
+ dstrect.SetRect(r.x,r.y,w,h);
+ srcrect.SetRect(0, 0, w, h);
+ PG_Draw::BlitSurface(temp, srcrect, dst, dstrect);
+
+ // blit part 2 (middle)
+
+ dstrect.SetRect(r.x+w, r.y, r.w-w*2, h);
+ SDL_SetClipRect(dst, &dstrect);
+
+ // blit it
+ srcrect.SetRect(w, 0, w, h);
+ for(int i = 1; i<(r.w/w); i++) {
+ dstrect.SetRect(r.x+w*i, r.y, w, h);
+ PG_Draw::BlitSurface(temp, srcrect, dst, dstrect);
+ }
+ SDL_SetClipRect(dst, NULL);
+
+ // blit part 3 (right)
+
+ dstrect.SetRect(r.x+r.w-w, r.y,w,h);
+ srcrect.SetRect(w*2, 0, w, h);
+ PG_Draw::BlitSurface(temp, srcrect, dst, dstrect);
+
+ // free temp surface
+ if(h != src->h) {
+ SDL_FreeSurface(temp);
+ }
+
+}
+
+static void Draw3TileV(SDL_Surface* src, const PG_Rect& r, SDL_Surface* dst, Uint8 blend = 0) {
+ PG_Rect srcrect;
+ PG_Rect dstrect;
+ SDL_Surface* temp;
+ int w,h;
+
+ // source rectangles
+ w = r.w;
+ h = (int)( ( (double)w / (double)src->w) * (double)src->h );
+ srcrect.SetRect(0,0,w,h);
+ h /= 3;
+
+ if (!h) {
+ return;
+ }
+
+ // rescale surface
+
+ if(w == src->w) {
+ temp = src;
+ }
+ else {
+ temp = PG_Draw::ScaleSurface(src, srcrect);
+ }
+
+ // set per surface alpha
+ if(blend > 0) {
+ SDL_SetAlpha(temp, SDL_SRCALPHA, 255-blend);
+ } else {
+ SDL_SetAlpha(temp, 0, 0);
+ }
+
+ // blit part 1 (top)
+
+ SDL_SetClipRect(dst, NULL);
+ dstrect.SetRect(r.x,r.y,w,h);
+ srcrect.SetRect(0, 0, w, h);
+ PG_Draw::BlitSurface(temp, srcrect, dst, dstrect);
+
+ // blit part 2 (middle)
+
+ // set cliprect
+ dstrect.SetRect(r.x,r.y+h,w,r.h-h*2);
+ SDL_SetClipRect(dst, &dstrect);
+
+ // blit it
+ srcrect.SetRect(0, h, w, h);
+ for(int i = 1; i<(r.h/h); i++) {
+ dstrect.SetRect(r.x, r.y+h*i, w, h);
+ PG_Draw::BlitSurface(temp, srcrect, dst, dstrect);
+ }
+ SDL_SetClipRect(dst, NULL);
+
+ // blit part 3 (bottom)
+
+ dstrect.SetRect(r.x,r.y+r.h-h,w,h);
+ srcrect.SetRect(0, h*2, w, h);
+ PG_Draw::BlitSurface(temp, srcrect, dst, dstrect);
+
+ // free temp surface
+ if(w != src->w) {
+ SDL_FreeSurface(temp);
+ }
+
+}
+
+static void DrawTileSurface(SDL_Surface* src, const PG_Rect& r, SDL_Surface* dst, Uint8 blend = 0) {
+ PG_Rect srcrect;
+ PG_Rect dstrect;
+
+ // tile the background image over the r in surface
+ dstrect = r;
+
+ srcrect.SetRect(0, 0, src->w, src->h);
+
+ int yc = (r.my_height / src->h) +1;
+ int xc = (r.my_width / src->w) +1;
+
+ if(blend > 0) {
+ SDL_SetAlpha(src, SDL_SRCALPHA, 255-blend);
+ }
+ else {
+ SDL_SetAlpha(src, 0, 0);
+ }
+
+ srcrect.my_width = src->w;
+ srcrect.my_height = src->h;
+ dstrect.my_width = src->w;
+ dstrect.my_height = src->h;
+
+ SDL_SetClipRect(dst, &r);
+ for(int y=0; y<yc; y++) {
+ for(int x=0; x<xc; x++) {
+ dstrect.x = r.my_xpos + src->w * x;
+ dstrect.y = r.my_ypos + src->h * y;
+
+ PG_Draw::BlitSurface(src, srcrect, dst, dstrect);
+ }
+ }
+ SDL_SetClipRect(dst, NULL);
+}
+
+/*
+** 9TILE
+**
+** ABC
+** DEF
+** GHI
+**
+** v
+**
+** ABBBBBBC
+** DEEEEEEEF
+** DEEEEEEEF
+** DEEEEEEEF
+** DEEEEEEEF
+** DEEEEEEEF
+** GHHHHHHI
+*/
+static void Draw9Tile(SDL_Surface* src, const PG_Rect& r, SDL_Surface* dst, Uint8 blend = 0) {
+ PG_Rect srcrect;
+ PG_Rect dstrect;
+ int i = 0;
+
+ // 3 source stripes (ABC, DEF, HGI)
+ SDL_Surface* src_stripe[3];
+ int h_src_stripe = src->h / 3;
+
+ // copy source stripes
+ dstrect.SetRect(0, 0, src->w, h_src_stripe);
+ for(i=0; i<3; i++) {
+ // set source rect
+ srcrect.SetRect(0, i*h_src_stripe, src->w, h_src_stripe);
+
+ // create stripe surface
+ src_stripe[i] = SDL_CreateRGBSurface(
+ SDL_SWSURFACE,
+ srcrect.w,
+ srcrect.h,
+ 32, //src->format->BitsPerPixel,
+ 0, //src->format->Rmask,
+ 0, //src->format->Gmask,
+ 0, //src->format->Bmask,
+ 0 //src->format->Amask
+ );
+
+ // copy stripe
+ PG_Draw::BlitSurface(src, srcrect, src_stripe[i], dstrect);
+ }
+
+ // 3 destination stripes (ABBBBBBC, DEEEEEEEF, GHHHHHHI)
+ SDL_Surface* dst_stripe[3];
+ int h_dst_stripe = src->h / 3;
+
+ // create destination stripes
+ dstrect.SetRect(0, 0, r.w, h_dst_stripe);
+ for(i=0; i<3; i++) {
+ // create dest. stripe
+ dst_stripe[i] = SDL_CreateRGBSurface(
+ SDL_SWSURFACE,
+ dstrect.w,
+ dstrect.h,
+ 32, //src->format->BitsPerPixel,
+ 0, //src->format->Rmask,
+ 0, //src->format->Gmask,
+ 0, //src->format->Bmask,
+ 0 //src->format->Amask
+ );
+
+ // 3TILEH the source to the dest. stripe
+ Draw3TileH(src_stripe[i], dstrect, dst_stripe[i], blend);
+ // set alpha
+ /*if(blend > 0) {
+ SDL_SetAlpha(dst_stripe[i], SDL_SRCALPHA, 255-blend);
+ } else {
+ SDL_SetAlpha(dst_stripe[i], 0, 0);
+ }*/
+ }
+
+ // copy stripe 0 (top)
+ srcrect.SetRect(0, 0, dst_stripe[0]->w, dst_stripe[0]->h);
+ dstrect.SetRect(r.x, r.y, r.w, dst_stripe[0]->h);
+ PG_Draw::BlitSurface(dst_stripe[0], srcrect, dst, dstrect);
+
+ // tile stripe 1 (middle part)
+ dstrect.SetRect(r.x, r.y + dst_stripe[0]->h, r.w, r.h - 2*dst_stripe[0]->h);
+ DrawTileSurface(dst_stripe[1], dstrect, dst, blend);
+
+ // copy stripe 2 (bottom)
+ srcrect.SetRect(0, 0, dst_stripe[2]->w, dst_stripe[2]->h);
+ dstrect.SetRect(r.x, r.y+r.h-dst_stripe[2]->h, r.w, dst_stripe[2]->h);
+ PG_Draw::BlitSurface(dst_stripe[2], srcrect, dst, dstrect);
+
+ // cleanup
+ for(i=0; i<3; i++) {
+ SDL_FreeSurface(src_stripe[i]);
+ SDL_FreeSurface(dst_stripe[i]);
+ }
+
+}
+
+void PG_Draw::DrawThemedSurface(SDL_Surface* surface, const PG_Rect& r, PG_Gradient* gradient,SDL_Surface* background, int bkmode, Uint8 blend) {
+ static PG_Rect srcrect;
+ static PG_Rect dstrect;
+ //int x,y;
+ bool bColorKey = false;
+ PG_Color uColorKey;
+ Uint32 c;
+ PG_Rect oldclip;
+
+ // check if we have anything to do
+ if (!surface || !r.h || !r.w)
+ return;
+
+ // draw the gradient first
+ if((background == NULL) || (background && (blend > 0))) {
+ if(gradient != NULL) {
+ if(SDL_MUSTLOCK(surface)) {
+ SDL_LockSurface(surface); //!
+ }
+ DrawGradient(surface, r, *gradient);
+ if(SDL_MUSTLOCK(surface)) {
+ SDL_UnlockSurface(surface); //!
+ }
+ }
+ }
+
+ if(!background)
+ return;
+
+ if (!background->w || !background->h)
+ return;
+
+ //int yc;
+ //int xc;
+ SDL_Surface* temp;
+ //int w,h;
+
+ bColorKey = (background->flags & SDL_SRCCOLORKEY) != 0;
+ Uint8 rc,gc,bc;
+
+ SDL_GetRGB(background->format->colorkey, background->format, &rc, &gc, &bc);
+ uColorKey = (Uint32)((rc << 16) | (gc << 8) | bc);
+
+ if(((gradient == NULL) || (blend == 0)) && bColorKey) {
+ SDL_SetColorKey(background, 0, 0);
+ }
+
+ SDL_GetClipRect(surface, &oldclip);
+
+ switch(bkmode) {
+
+ //
+ // BKMODE_TILE
+ //
+
+ case BKMODE_TILE:
+ DrawTileSurface(background, r, surface, blend);
+ break;
+
+ //
+ // BKMODE_STRETCH
+ //
+
+ case BKMODE_STRETCH:
+ // stretch the background to fit the surface
+
+ // Scale the background to fit this widget, using
+ // anti-aliasing
+ temp = PG_Draw::ScaleSurface(background, r);
+
+ // set per surface alpha
+ if(blend > 0) {
+ SDL_SetAlpha(temp, SDL_SRCALPHA, 255-blend);
+ } else {
+ SDL_SetAlpha(temp, 0, 0);
+ }
+
+ // blit it
+ SDL_BlitSurface(temp, NULL, surface, (PG_Rect*)&r);
+
+ // free the temp surface
+ SDL_FreeSurface(temp);
+ break;
+
+ //
+ // BKMODE_3TILEH
+ //
+
+ case BKMODE_3TILEH:
+ Draw3TileH(background, r, surface, blend);
+ break;
+
+ //
+ // BKMODE_3TILEV
+ //
+
+ case BKMODE_3TILEV:
+ Draw3TileV(background, r, surface, blend);
+ break;
+
+ //
+ // BKMODE_9TILE
+ //
+
+ case BKMODE_9TILE:
+ Draw9Tile(background, r, surface, blend);
+ break;
+
+ }
+
+ SDL_SetClipRect(surface, (SDL_Rect*)&oldclip);
+
+ if((/*(gradient == NULL) ||*/ (blend == 0)) && bColorKey) {
+ c = uColorKey.MapRGB(background->format);
+ SDL_SetColorKey(background, SDL_SRCCOLORKEY, c);
+ c = uColorKey.MapRGB(surface->format);
+ SDL_SetColorKey(surface, SDL_SRCCOLORKEY, c);
+ }
+}
diff --git a/src/paragui/pgwidget.cpp b/src/paragui/pgwidget.cpp
new file mode 100644
index 0000000..064cf2e
--- /dev/null
+++ b/src/paragui/pgwidget.cpp
@@ -0,0 +1,1828 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgwidget.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+ */
+
+#include <cstring>
+#include <stdarg.h>
+
+#include "pgrectlist.h"
+#include "pgwidget.h"
+#include "pgdraw.h"
+#include "common.h"
+//#include "pgtheme.h"
+
+
+extern SDL_Surface *g_poBackground;
+
+
+#define TXT_HEIGHT_UNDEF 0xFFFF
+
+
+PG_RectList PG_Widget::widgetList;
+int PG_Widget::my_ObjectCounter = 0;
+
+class PG_WidgetDataInternal {
+public:
+ PG_WidgetDataInternal() : modalstatus(0), inDestruct(false), inMouseLeave(false), font(NULL), dirtyUpdate(false), id(-1),
+ transparency(0), quitModalLoop(false), visible(false), hidden(false), firstredraw(true),
+ childList(NULL), haveTooltip(false), fadeSteps(10), mouseInside(false), userdata(NULL),
+ userdatasize(0), widthText(TXT_HEIGHT_UNDEF), heightText(TXT_HEIGHT_UNDEF) {};
+
+ int modalstatus;
+ bool inDestruct;
+ bool inMouseLeave;
+ PG_Font* font;
+ bool dirtyUpdate;
+ int id;
+ Uint8 transparency;
+ bool quitModalLoop;
+ bool visible;
+ bool hidden;
+ bool firstredraw;
+ PG_RectList* childList;
+ bool haveTooltip;
+ int fadeSteps;
+ bool mouseInside;
+ char* userdata;
+ int userdatasize;
+ Uint16 widthText;
+ Uint16 heightText;
+
+ PG_Widget* widgetParent;
+ PG_Point ptDragStart;
+ PG_Rect rectClip;
+ bool havesurface;
+ std::string name;
+
+};
+
+PG_Widget::PG_Widget(PG_Widget* parent, const PG_Rect& rect, bool bObjectSurface) :
+ PG_Rect(rect), my_srfObject(NULL)
+{
+ my_bordersize= 0;
+ my_canReceiveMessages= true;
+
+ _mid = new PG_WidgetDataInternal;
+
+ _mid->widgetParent = NULL;
+ _mid->havesurface = bObjectSurface;
+
+ //Set default font
+ if(PG_Font::GetDefaultFont() != NULL) {
+ _mid->font = new PG_Font(
+ PG_Font::GetDefaultFont()->GetName(),
+ PG_Font::GetDefaultFont()->GetSize());
+ }
+ else {
+ debug("Unable to get default font! Did you load a theme ?");
+ }
+
+ //my_srfScreen = gamescreen;
+
+ if(_mid->havesurface) {
+ my_srfObject = PG_Draw::CreateRGBSurface(w, h);
+ }
+
+ // ??? - How can i do this better - ???
+ char buffer[15];
+ sprintf(buffer, "Object%d", ++my_ObjectCounter);
+ _mid->name = buffer;
+
+ // default border colors
+ my_colorBorder[0][0].r = 255;
+ my_colorBorder[0][0].g = 255;
+ my_colorBorder[0][0].b = 255;
+
+ my_colorBorder[0][1].r = 239;
+ my_colorBorder[0][1].g = 239;
+ my_colorBorder[0][1].b = 239;
+
+ my_colorBorder[1][0].r = 89;
+ my_colorBorder[1][0].g = 89;
+ my_colorBorder[1][0].b = 89;
+
+ my_colorBorder[1][1].r = 134;
+ my_colorBorder[1][1].g = 134;
+ my_colorBorder[1][1].b = 134;
+
+ if (parent) {
+ //my_xpos = _mid->widgetParent->my_xpos + my_xpos;
+ //my_ypos = _mid->widgetParent->my_ypos + my_ypos;
+ parent->AddChild(this);
+ }
+ else {
+ AddToWidgetList();
+ }
+ //_mid->rectClip = *this;
+}
+
+void PG_Widget::RemoveAllChilds() {
+
+ // remove all child widgets
+ if(_mid->childList != NULL) {
+
+ PG_Widget* i = _mid->childList->first();
+ while(i != NULL) {
+ PG_Widget* w = i;
+ i = i->next();
+
+ RemoveChild(w);
+ delete w;
+ }
+ _mid->childList->clear();
+ }
+
+}
+
+PG_Widget::~PG_Widget() {
+
+ _mid->inDestruct = true;
+
+ if(!_mid->havesurface && my_srfObject) {
+ debug("DrawObject declared without a surface has unexpectedly born one ?");
+ }
+ SDL_FreeSurface(my_srfObject);
+ my_srfObject = NULL;
+
+ Hide();
+
+ RemoveAllChilds();
+
+ // remove myself from my parent's childlist (if any parent)
+
+ if (GetParent() != NULL) {
+ GetParent()->RemoveChild(this);
+ }
+ else {
+ RemoveFromWidgetList();
+ }
+
+ // remove childlist
+ delete _mid->childList;
+ _mid->childList = NULL;
+
+ if (_mid->userdata != NULL) {
+ delete[] _mid->userdata;
+ }
+
+ // remove the font
+ delete _mid->font;
+
+ // remove my private data
+ delete _mid;
+
+ //cout << "Removed widget '" << GetName() << "'" << endl;
+}
+
+void PG_Widget::RemoveFromWidgetList() {
+ widgetList.Remove(this);
+}
+
+void PG_Widget::AddToWidgetList() {
+ if(!GetParent()) {
+ widgetList.Add(this);
+ }
+}
+
+/** Check if we can accept the event */
+
+bool PG_Widget::AcceptEvent(const SDL_Event * event) {
+
+ if (!IsVisible() || IsHidden()) {
+ return false;
+ }
+
+ switch (event->type) {
+ case SDL_MOUSEMOTION:
+ if ((event->motion.x < _mid->rectClip.my_xpos) ||
+ (event->motion.x > (_mid->rectClip.my_xpos + _mid->rectClip.my_width - 1))) {
+ if (_mid->mouseInside) {
+ eventMouseLeave();
+ }
+ return false;
+ }
+ if ((event->motion.y < _mid->rectClip.my_ypos) ||
+ (event->motion.y > (_mid->rectClip.my_ypos + _mid->rectClip.my_height - 1))) {
+ if (_mid->mouseInside) {
+ eventMouseLeave();
+ }
+ return false;
+ }
+ if (!_mid->mouseInside) {
+ _mid->mouseInside = true;
+ eventMouseEnter();
+ return true;
+ }
+ break;
+
+ case SDL_MOUSEBUTTONUP:
+ case SDL_MOUSEBUTTONDOWN:
+ if ((event->button.x < _mid->rectClip.my_xpos) ||
+ (event->button.x > (_mid->rectClip.my_xpos + _mid->rectClip.my_width - 1)))
+ return false;
+
+ if ((event->button.y < _mid->rectClip.my_ypos) ||
+ (event->button.y > (_mid->rectClip.my_ypos + _mid->rectClip.my_height - 1)))
+ return false;
+
+ break;
+ }
+
+ return true; // accept the event as default
+}
+
+
+/** */
+void PG_Widget::eventMouseEnter() {}
+
+
+/** */
+void PG_Widget::eventMouseLeave() {
+ _mid->mouseInside = false;
+
+ if(GetParent() != NULL && !GetParent()->IsMouseInside()) {
+ GetParent()->eventMouseLeave();
+ }
+
+ /*if(GetParent()) {
+ GetParent()->eventMouseLeave();
+ }*/
+}
+
+/** */
+void PG_Widget::eventShow() {}
+
+/** */
+void PG_Widget::eventHide() {}
+
+/** */
+PG_Point PG_Widget::ClientToScreen(int sx, int sy) {
+ return PG_Point(sx + my_xpos, sy + my_ypos);
+}
+
+PG_Point PG_Widget::ScreenToClient(int x, int y) {
+ return PG_Point(x - my_xpos, y - my_ypos);
+}
+
+void PG_Widget::AddChild(PG_Widget * child) {
+
+ if (!child)
+ return;
+
+ // remove our new child from previous lists
+ if(child->GetParent()) {
+ child->GetParent()->RemoveChild(child);
+ }
+ else {
+ child->RemoveFromWidgetList();
+ }
+
+ child->MoveRect(child->my_xpos + my_xpos, child->my_ypos + my_ypos);
+ child->_mid->widgetParent = this;
+
+ if (_mid->childList == NULL) {
+ _mid->childList = new PG_RectList;
+ }
+
+ _mid->childList->Add(child);
+}
+
+bool PG_Widget::MoveWidget(int x, int y, bool update) {
+ SDL_Surface* screen = gamescreen;
+
+ if (GetParent() != NULL) {
+ x += GetParent()->my_xpos;
+ y += GetParent()->my_ypos;
+ }
+ if(x == my_xpos && y == my_ypos) {
+ // Optimization: We haven't moved, so do nothing.
+ return false;
+ }
+
+ if(!IsVisible() || IsHidden() || !update) {
+ MoveRect(x, y);
+ return true;
+ }
+
+ // delta x,y
+ int dx = x - my_xpos;
+ int dy = y - my_ypos;
+
+ // calculate vertical update rect
+
+ PG_Rect vertical(0, 0, abs(dx), my_height + abs(dy));
+
+ if(dx >= 0) {
+ vertical.my_xpos = my_xpos;
+ } else {
+ vertical.my_xpos = my_xpos + my_width + dx;
+ }
+
+ vertical.my_ypos = my_ypos;
+
+ // calculate vertical update rect
+
+ PG_Rect horizontal(0, 0, my_width + abs(dx), abs(dy));
+
+ horizontal.my_xpos = my_xpos;
+
+ if(dy >= 0) {
+ horizontal.my_ypos = my_ypos;
+ } else {
+ horizontal.my_ypos = my_ypos + my_height + dy;
+ }
+
+ // move rectangle and store new background
+ MoveRect(x, y);
+
+ if(vertical.my_xpos + vertical.my_width > screen->w) {
+ vertical.my_width = screen->w - vertical.my_xpos;
+ }
+ if(vertical.my_ypos + vertical.my_height > screen->h) {
+ vertical.my_height = screen->h - vertical.my_ypos;
+ }
+
+ if(horizontal.my_xpos + horizontal.my_width > screen->w) {
+ horizontal.my_width = screen->w- horizontal.my_xpos;
+ }
+ if(horizontal.my_ypos + horizontal.my_height > screen->h) {
+ horizontal.my_height = screen->h - horizontal.my_ypos;
+ }
+
+// if(!PG_Application::GetBulkMode())
+ {
+
+ // I'm experimenting with cairo - this change was needed to
+ // make rendering work as expected -- Alex
+
+ /*UpdateRect(vertical);
+ UpdateRect(horizontal);
+ UpdateRect(_mid->rectClip);
+ //@ SDL_LockSurface(gamescreen);
+ SDL_Rect rects[3] = {_mid->rectClip, vertical, horizontal};
+ SDL_UpdateRects(screen, 3, rects);
+ //@ SDL_UnlockSurface(gamescreen);*/
+
+ int minx, maxx;
+ int miny, maxy;
+ minx = omMIN(vertical.x, horizontal.x);
+ minx = omMIN(minx, _mid->rectClip.x);
+ maxx = omMAX(vertical.x+vertical.w, horizontal.x+horizontal.w);
+ maxx = omMAX(maxx, _mid->rectClip.x+_mid->rectClip.w);
+
+ miny = omMIN(vertical.y, horizontal.y);
+ miny = omMIN(miny, _mid->rectClip.y);
+ maxy = omMAX(vertical.y+vertical.h, horizontal.y+horizontal.h);
+ maxy = omMAX(maxy, _mid->rectClip.y+_mid->rectClip.h);
+
+ //@ SDL_LockSurface(gamescreen);
+ PG_Rect rect(minx,miny,maxx-minx,maxy-miny);
+ UpdateRect(rect);
+ SDL_UpdateRects(screen, 1, &rect);
+ //@ SDL_UnlockSurface(gamescreen);
+ }
+
+ return true;
+}
+
+bool PG_Widget::MoveWidget(const PG_Rect& r, bool update) {
+ SizeWidget(r.w, r.h, update);
+ MoveWidget(r.x, r.y, update);
+
+ return true;
+}
+
+bool PG_Widget::SizeWidget(Uint16 w, Uint16 h, bool update) {
+ Uint16 old_w = my_width;
+ Uint16 old_h = my_height;
+
+ if(my_width == w && my_height == h) {
+ return false;
+ }
+
+ // create new widget drawsurface
+ if(my_srfObject) {
+ SDL_FreeSurface(my_srfObject);
+
+ if(w > 0 && h > 0) {
+ my_srfObject = PG_Draw::CreateRGBSurface(w, h);
+ }
+ else {
+ my_srfObject = NULL;
+ }
+ }
+
+ eventSizeWidget(w, h);
+
+ my_width = w;
+ my_height = h;
+
+ if(!IsVisible() || IsHidden() || !update) {
+ return true;
+ }
+
+ if(my_srfObject) {
+ Redraw();
+ }
+ else {
+ if(old_w > w || old_h > h) {
+ PG_Rect u(
+ my_xpos,
+ my_ypos,
+ (old_w > w) ? old_w : w,
+ (old_h > h) ? old_h : h);
+ UpdateRect(u);
+ SDL_UpdateRects(gamescreen, 1, &u);
+ }
+ else {
+ Update();
+ }
+ }
+
+ return true;
+}
+
+/** */
+bool PG_Widget::ProcessEvent(const SDL_Event * event, bool bModal) {
+
+ bool processed = false;
+ // do i have a capturehook set ? (modal)
+ if(bModal) {
+ // i will send that event to my children
+
+ if(_mid->childList != NULL) {
+ PG_Widget* list = _mid->childList->first();
+
+ while (!processed && (list != NULL)) {
+ processed = list->ProcessEvent(event, true);
+ list = list->next();
+ }
+ }
+
+ if(processed) {
+ return processed;
+ }
+ }
+
+ if(PG_MessageObject::ProcessEvent(event)) {
+ return true;
+ }
+
+ if(bModal) {
+ return processed;
+ }
+
+ // ask my parent to process the event
+
+ if(GetParent()) {
+ if(GetParent()->ProcessEvent(event)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool PG_Widget::RemoveChild(PG_Widget * child) {
+ if(_mid->childList == NULL || child == NULL) {
+ return false;
+ }
+
+ if(_mid->childList->Remove(child)) {
+ child->MoveRect(child->my_xpos - my_xpos, child->my_ypos - my_ypos);
+ return true;
+ }
+
+ return false;
+}
+
+bool PG_Widget::IsMouseInside() {
+ PG_Point p;
+ int x, y;
+
+ SDL_GetMouseState(&x, &y);
+ p.x = static_cast<Sint16>(x);
+ p.y = static_cast<Sint16>(y);
+ _mid->mouseInside = IsInside(p);
+
+ return _mid->mouseInside;
+}
+
+/** */
+bool PG_Widget::Redraw(bool update) {
+ PG_Rect r(0, 0, my_width, my_height);
+
+ if(my_srfObject != NULL) {
+ eventDraw(my_srfObject, r);
+ }
+
+ if(_mid->childList != NULL) {
+ for(PG_Widget* i = _mid->childList->first(); i != NULL; i = i->next()) {
+ i->Redraw(false);
+ }
+ }
+
+ if (update) {
+ Update();
+ }
+ return true;
+}
+
+void PG_Widget::SetVisible(bool visible) {
+
+ if(IsHidden()) {
+ return;
+ }
+
+ // Attempt to make object visible
+ if(visible) {
+ if(_mid->visible) { // Object already visible
+ return;
+ } else { // Display object
+ _mid->visible = visible;
+ if(_mid->firstredraw) {
+ Redraw(false);
+ _mid->firstredraw = false;
+ }
+ }
+
+ }
+
+ // Attempt to make object invisible
+ if(!visible) {
+ if(!_mid->visible) { // Object is already invisible
+ return;
+ } else { // Hide object
+ RestoreBackground();
+ _mid->visible = visible;
+ }
+ }
+
+ if(_mid->childList != NULL) {
+ for(PG_Widget* i = _mid->childList->first(); i != NULL; i = i->next()) {
+ i->SetVisible(visible);
+ if(!i->IsHidden()) {
+ if(visible) {
+ i->eventShow();
+ } else {
+ i->eventHide();
+ }
+ }
+ }
+ }
+}
+
+/** */
+void PG_Widget::Show(bool fade) {
+
+ if(fade && IsVisible() && !IsHidden()) {
+ fade = false;
+ }
+
+ PG_Widget* parent = GetParent();
+ if(parent == NULL) {
+ widgetList.BringToFront(this);
+ }
+ else {
+ parent->GetChildList()->BringToFront(this);
+ }
+
+ SetHidden(false);
+
+ if(parent != NULL && (!parent->IsVisible() || parent->IsHidden())) {
+ return;
+ }
+
+ SetVisible(true);
+ eventShow();
+
+ if (fade) {
+ FadeIn();
+ }
+
+ if(IsMouseInside()) {
+ eventMouseEnter();
+ }
+
+ //SDL_SetClipRect(my_srfScreen, NULL);
+ Update();
+
+ return;
+}
+
+/** */
+void PG_Widget::Hide(bool fade) {
+ SDL_Surface* screen = gamescreen;
+
+ if(!IsVisible()) {
+ SetHidden(true);
+ eventHide();
+ return;
+ }
+
+ RecalcClipRect();
+
+ if(!_mid->inDestruct && !_mid->inMouseLeave) {
+ _mid->inMouseLeave = true;
+ eventMouseLeave();
+ _mid->inMouseLeave = false;
+ }
+
+ if (fade) {
+ FadeOut();
+ }
+
+ SetVisible(false);
+ eventHide();
+
+ SDL_SetClipRect(screen, NULL);
+
+ UpdateRect(_mid->rectClip);
+ //@ SDL_LockSurface(gamescreen);
+ SDL_UpdateRects(screen, 1, &_mid->rectClip);
+ //@ SDL_UnlockSurface(gamescreen);
+
+ SetHidden(true);
+
+ return;
+}
+
+/** */
+void PG_Widget::MoveRect(int x, int y) {
+ int dx = x - my_xpos;
+ int dy = y - my_ypos;
+
+ // recalc cliprect
+ RecalcClipRect();
+
+ my_xpos = x;
+ my_ypos = y;
+ _mid->rectClip.my_xpos += dx;
+ _mid->rectClip.my_ypos += dy;
+
+ // recalc cliprect
+ RecalcClipRect();
+
+ if(_mid->childList != NULL) {
+ for(PG_Widget* i = _mid->childList->first(); i != NULL; i = i->next()) {
+ i->MoveRect(i->my_xpos + dx, i->my_ypos + dy);
+ }
+ }
+
+ eventMoveWidget(x, y);
+}
+
+void PG_Widget::Blit(bool recursive, bool restore) {
+
+ if(!_mid->visible || _mid->hidden) {
+ return;
+ }
+
+ // recalc clipping rectangle
+ RecalcClipRect();
+
+ // don't draw a null rect
+ if(_mid->rectClip.w == 0 || _mid->rectClip.h == 0) {
+ return;
+ }
+
+ PG_Rect src;
+ PG_Rect dst;
+ //@ SDL_LockSurface(gamescreen);
+
+ // restore the background
+ if(restore) {
+ RestoreBackground(&_mid->rectClip);
+ }
+
+ // get source & destination rectangles
+ src.SetRect(_mid->rectClip.x - my_xpos, _mid->rectClip.y - my_ypos, _mid->rectClip.w, _mid->rectClip.h);
+ dst = _mid->rectClip;
+
+ // call the blit handler
+ eventBlit(my_srfObject, src, dst);
+
+ // should we draw our children
+ if(recursive) {
+ // draw the children-list
+ if(_mid->childList != NULL) {
+ _mid->childList->Blit(_mid->rectClip);
+ }
+ }
+
+ //@ SDL_UnlockSurface(gamescreen);
+}
+
+/** */
+void PG_Widget::Update(bool doBlit) {
+ static PG_Rect src;
+ static PG_Rect dst;
+
+ if(!_mid->visible || _mid->hidden) {
+ return;
+ }
+
+ // recalc cliprect
+ RecalcClipRect();
+
+ if(_mid->rectClip.w == 0 || _mid->rectClip.h == 0) {
+ return;
+ }
+
+ //@ SDL_LockSurface(gamescreen);
+
+ // BLIT
+ if(doBlit) {
+
+ SDL_SetClipRect(gamescreen, &_mid->rectClip);
+ RestoreBackground(&_mid->rectClip);
+
+ src.SetRect(_mid->rectClip.x - my_xpos, _mid->rectClip.y - my_ypos, _mid->rectClip.w, _mid->rectClip.h);
+ dst = _mid->rectClip;
+
+ eventBlit(my_srfObject, src, dst);
+
+ if(_mid->childList != NULL) {
+ _mid->childList->Blit(_mid->rectClip);
+ }
+
+ // check if other children of my parent overlap myself
+ if(GetParent() != NULL) {
+ PG_RectList* children = GetParent()->GetChildList();
+ if(children) {
+ children->Blit(_mid->rectClip, this->next());
+ }
+ }
+
+ // find the toplevel widget
+ PG_Widget* obj = GetToplevelWidget();
+ widgetList.Blit(_mid->rectClip, obj->next());
+
+ }
+
+ // Update screen surface
+#ifdef DEBUG
+ PG_LogDBG("UPD: x:%d y:%d w:%d h:%d",dst.x,dst.y,dst.w,dst.h);
+#endif // DEBUG
+
+ SDL_UpdateRects(gamescreen, 1, &_mid->rectClip);
+
+ SDL_SetClipRect(gamescreen, NULL);
+ //@ SDL_UnlockSurface(gamescreen);
+}
+
+/** */
+void PG_Widget::SetChildTransparency(Uint8 t) {
+ if(_mid->childList == NULL) {
+ return;
+ }
+
+ for(PG_Widget* i = _mid->childList->first(); i != NULL; i = i->next()) {
+ i->SetTransparency(t);
+ }
+ Update();
+}
+
+void PG_Widget::StartWidgetDrag() {
+ int x, y;
+
+ SDL_GetMouseState(&x, &y);
+ _mid->ptDragStart.x = static_cast<Sint16>(x) - my_xpos;
+ _mid->ptDragStart.y = static_cast<Sint16>(y) - my_ypos;
+}
+
+void PG_Widget::WidgetDrag(int x, int y) {
+
+ x -= _mid->ptDragStart.x;
+ y -= _mid->ptDragStart.y;
+
+ if(x < 0)
+ x=0;
+ if(y < 0)
+ y=0;
+ if(x > (gamescreen->w - my_width -1))
+ x = (gamescreen->w - my_width -1);
+ if(y > (gamescreen->h - my_height -1))
+ y = (gamescreen->h - my_height -1);
+
+ MoveWidget(x,y);
+}
+
+void PG_Widget::EndWidgetDrag(int x, int y) {
+ WidgetDrag(x,y);
+ _mid->ptDragStart.x = 0;
+ _mid->ptDragStart.y = 0;
+}
+
+void PG_Widget::HideAll() {
+ for(PG_Widget* i = widgetList.first(); i != NULL; i = i->next()) {
+ i->Hide();
+ }
+}
+
+/*void PG_Widget::BulkUpdate() {
+ bBulkUpdate = true;
+
+ for(PG_Widget* i = widgetList.first(); i != NULL; i = i->next()) {
+ if(i->IsVisible()) {
+ i->Update();
+ }
+ }
+
+ bBulkUpdate = false;
+}*/
+
+void PG_Widget::BulkBlit() {
+ //bBulkUpdate = true;
+ widgetList.Blit();
+ //PG_Application::DrawCursor();
+ //bBulkUpdate = false;
+}
+
+/*
+void PG_Widget::LoadThemeStyle(const char* widgettype, const char* objectname) {
+ PG_Theme* t = PG_Application::GetTheme();
+ PG_Color c;
+
+ const char *font = t->FindFontName(widgettype, objectname);
+ int fontsize = t->FindFontSize(widgettype, objectname);
+ PG_Font::Style fontstyle = t->FindFontStyle(widgettype, objectname);
+
+ if(font != NULL)
+ SetFontName(font, true);
+
+ if (fontsize > 0)
+ SetFontSize(fontsize, true);
+
+ if (fontstyle >= 0)
+ SetFontStyle(fontstyle, true);
+
+ c = GetFontColor();
+ t->GetColor(widgettype, objectname, "textcolor", c);
+ SetFontColor(c);
+
+ t->GetColor(widgettype, objectname, "bordercolor0", my_colorBorder[0][0]);
+ t->GetColor(widgettype, objectname, "bordercolor1", my_colorBorder[1][0]);
+}
+
+void PG_Widget::LoadThemeStyle(const char* widgettype) {}
+*/
+void PG_Widget::FadeOut() {
+ PG_Rect r(0, 0, my_width, my_height);
+
+ // blit the widget to screen (invisible)
+ Blit();
+
+ // create a temp surface
+ SDL_Surface* srfFade = PG_Draw::CreateRGBSurface(my_width, my_height);
+ SDL_Surface* screen = gamescreen;
+
+ int d = (255-_mid->transparency)/ _mid->fadeSteps;
+ if(!d) {
+ d = 1;
+ } // minimum step == 1
+
+ //@ SDL_LockSurface(gamescreen);
+
+ // blit the widget to temp surface
+ PG_Draw::BlitSurface(screen, *this, srfFade, r);
+
+ for(int i=_mid->transparency; i<255; i += d) {
+ RestoreBackground(NULL, true);
+ SDL_SetAlpha(srfFade, SDL_SRCALPHA, 255-i);
+ SDL_BlitSurface(srfFade, NULL, screen, this);
+ SDL_UpdateRects(screen, 1, &_mid->rectClip);
+ }
+
+ RestoreBackground(NULL, true);
+ SDL_SetAlpha(srfFade, SDL_SRCALPHA, 0);
+ SDL_BlitSurface(srfFade, NULL, screen, this);
+ SetVisible(false);
+ //@ SDL_UnlockSurface(gamescreen);
+
+ Update(false);
+
+ SDL_FreeSurface(srfFade);
+}
+
+void PG_Widget::FadeIn() {
+ SDL_Surface* screen = gamescreen;
+
+ // blit the widget to screen (invisible)
+ SDL_SetClipRect(screen, NULL);
+ Blit();
+
+ PG_Rect src(
+ 0,
+ 0,
+ (my_xpos < 0) ? my_width + my_xpos : my_width,
+ (my_ypos < 0) ? my_height + my_ypos : my_height);
+
+ // create a temp surface
+ SDL_Surface* srfFade = PG_Draw::CreateRGBSurface(w, h);
+
+ //@ SDL_LockSurface(gamescreen);
+
+ // blit the widget to temp surface
+ PG_Draw::BlitSurface(screen, _mid->rectClip, srfFade, src);
+
+ int d = (255-_mid->transparency)/ _mid->fadeSteps;
+
+ if(!d) {
+ d = 1;
+ } // minimum step == 1
+ for(int i=255; i>_mid->transparency; i -= d) {
+ RestoreBackground(NULL, true);
+ SDL_SetAlpha(srfFade, SDL_SRCALPHA, 255-i);
+ PG_Draw::BlitSurface(srfFade, src, screen, _mid->rectClip);
+ SDL_UpdateRects(screen, 1, &_mid->rectClip);
+ }
+
+ //@ SDL_UnlockSurface(gamescreen);
+
+ Update();
+
+ SDL_FreeSurface(srfFade);
+}
+
+void PG_Widget::SetFadeSteps(int steps) {
+ _mid->fadeSteps = steps;
+}
+
+bool PG_Widget::Action(KeyAction action) {
+ int x = my_xpos + my_width / 2;
+ int y = my_ypos + my_height / 2;
+
+ switch(action) {
+ case ACT_ACTIVATE:
+ SDL_WarpMouse(x,y);
+ eventMouseEnter();
+ break;
+
+ case ACT_DEACTIVATE:
+ eventMouseLeave();
+ break;
+
+ case ACT_OK:
+ SDL_MouseButtonEvent button;
+ button.button = 1;
+ button.x = x;
+ button.y = y;
+ eventMouseButtonDown(&button);
+ SDL_Delay(200);
+ eventMouseButtonUp(&button);
+ Action(ACT_ACTIVATE);
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void PG_Widget::RedrawBackground(const PG_Rect *clip)
+{
+ PG_Rect rect= *clip;
+ SDL_BlitSurface(g_poBackground, (SDL_Rect*)&rect, gamescreen, (SDL_Rect*)&rect);
+}
+
+bool PG_Widget::RestoreBackground(PG_Rect* clip, bool force) {
+
+ if(_mid->dirtyUpdate && (_mid->transparency == 0) && !force) {
+ return false;
+ }
+
+ if(clip == NULL) {
+ clip = &_mid->rectClip;
+ }
+
+ if(GetParent() == NULL) {
+ RedrawBackground(clip);
+
+ if(widgetList.first() != this) {
+ SDL_SetClipRect(gamescreen, clip);
+ widgetList.Blit(*clip, widgetList.first(), this);
+ SDL_SetClipRect(gamescreen, NULL);
+ }
+ return true;
+ }
+
+ GetParent()->RestoreBackground(clip);
+ SDL_SetClipRect(gamescreen, clip);
+ GetParent()->Blit(false, false);
+ SDL_SetClipRect(gamescreen, NULL);
+
+ return true;
+}
+
+PG_Widget* PG_Widget::FindWidgetFromPos(int x, int y) {
+ PG_Point p;
+ p.x = x;
+ p.y = y;
+ bool finished = false;
+
+ PG_Widget* toplevel = widgetList.IsInside(p);
+ PG_Widget* child = NULL;
+
+ if(!toplevel) {
+ return NULL;
+ }
+
+ while(!finished) {
+
+ if(toplevel->GetChildList()) {
+ child = toplevel->GetChildList()->IsInside(p);
+
+ if(child) {
+ toplevel = child;
+ child = NULL;
+ } else {
+ finished = true;
+ }
+
+ } else {
+ finished = true;
+ }
+ }
+
+ return toplevel;
+}
+
+void PG_Widget::UpdateRect(const PG_Rect& r) {
+ SDL_Surface* screen = gamescreen;
+
+ //@ SDL_LockSurface(gamescreen);
+ RedrawBackground(&r);
+ SDL_SetClipRect(screen, (PG_Rect*)&r);
+ widgetList.Blit(r);
+ SDL_SetClipRect(screen, NULL);
+ //@ SDL_UnlockSurface(gamescreen);
+}
+
+void PG_Widget::UpdateScreen() {
+ UpdateRect(
+ PG_Rect(0, 0, gamescreen->w, gamescreen->h)
+ );
+}
+
+bool PG_Widget::IsInFrontOf(PG_Widget* widget) {
+ PG_Widget* w1 = NULL;
+ PG_Widget* w2 = NULL;
+ PG_RectList* list = &widgetList;
+
+ // do both widgets have the same parent ?
+ if((GetParent() != NULL) && (GetParent() == widget->GetParent())) {
+ w1 = this;
+ w2 = widget;
+ list = GetParent()->GetChildList();
+ } else {
+ w1 = this->GetToplevelWidget();
+ w2 = widget->GetToplevelWidget();
+ }
+
+ return (w1->index > w2->index);
+}
+
+PG_Widget* PG_Widget::GetToplevelWidget() {
+ if(GetParent() == NULL) {
+ return this;
+ }
+
+ return GetParent()->GetToplevelWidget();
+}
+
+void PG_Widget::SendToBack() {
+ if(GetParent() == NULL) {
+ widgetList.SendToBack(this);
+ } else {
+ GetParent()->GetChildList()->SendToBack(this);
+ }
+ Update();
+}
+
+void PG_Widget::BringToFront() {
+ if(GetParent() == NULL) {
+ widgetList.BringToFront(this);
+ } else {
+ GetParent()->GetChildList()->BringToFront(this);
+ }
+ Update();
+}
+
+void PG_Widget::RecalcClipRect() {
+ PG_Rect pr;
+
+ if (_mid->widgetParent != NULL) {
+ pr = *(_mid->widgetParent->GetClipRect());
+ } else {
+ pr.SetRect(
+ 0,
+ 0,
+ gamescreen->w,
+ gamescreen->h);
+ }
+
+ PG_Rect ir = IntersectRect(pr);
+ SetClipRect(ir);
+}
+/*
+bool PG_Widget::LoadLayout(const char *name) {
+ bool rc = PG_Layout::Load(this, name, NULL, NULL);
+ Update();
+ return rc;
+}
+
+bool PG_Widget::LoadLayout(const char *name, void (* WorkCallback)(int now, int max)) {
+ bool rc = PG_Layout::Load(this, name, WorkCallback, NULL);
+ Update();
+ return rc;
+
+}
+
+bool PG_Widget::LoadLayout(const char *name, void (* WorkCallback)(int now, int max),void *UserSpace) {
+ bool rc = PG_Layout::Load(this, name, WorkCallback, UserSpace);
+ Update();
+ return rc;
+}
+*/
+void PG_Widget::SetUserData(void *userdata, int size) {
+ _mid->userdata = new char[size];
+ memcpy(_mid->userdata, userdata, size);
+ _mid->userdatasize = size;
+}
+
+int PG_Widget::GetUserDataSize() {
+ return _mid->userdatasize;
+}
+
+void PG_Widget::GetUserData(void *userdata) {
+ if (_mid->userdata == NULL)
+ return;
+
+ memcpy(userdata, _mid->userdata, _mid->userdatasize);
+}
+
+void PG_Widget::ReleaseUserData() {
+ if (_mid->userdata != NULL)
+ delete[] _mid->userdata;
+ _mid->userdatasize = 0;
+}
+
+void PG_Widget::AddText(const char* text, bool update) {
+ my_text += text;
+ _mid->widthText = TXT_HEIGHT_UNDEF;
+ _mid->heightText = TXT_HEIGHT_UNDEF;
+
+ //TO-DO : Optimalize this !!! - because of widget functions overloading SetText()
+ if (update) {
+ SetText(GetText());
+ }
+}
+
+void PG_Widget::SetText(const char* text) {
+
+ _mid->widthText = TXT_HEIGHT_UNDEF;
+ _mid->heightText = TXT_HEIGHT_UNDEF;
+
+ if(text == NULL) {
+ my_text = "";
+ return;
+ }
+
+ my_text = std::string(text);
+ Update();
+}
+
+void PG_Widget::SetTextFormat(const char* text, ...) {
+ va_list ap;
+ va_start(ap, text);
+ char temp[256];
+
+ if(text == NULL) {
+ my_text = "";
+ return;
+ }
+
+ if(text[0] == 0) {
+ my_text = "";
+ return;
+ }
+
+ vsprintf(temp, text, ap);
+ SetText(temp);
+ va_end(ap);
+}
+
+void PG_Widget::SetFontColor(const PG_Color& Color, bool bRecursive) {
+ _mid->font->SetColor(Color);
+
+ if(!bRecursive || (GetChildList() == NULL)) {
+ return;
+ }
+
+ for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
+ i->SetFontColor(Color, true);
+ }
+}
+
+void PG_Widget::SetFontAlpha(int Alpha, bool bRecursive) {
+ _mid->font->SetAlpha(Alpha);
+
+ if(!bRecursive || (GetChildList() == NULL)) {
+ return;
+ }
+
+ for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
+ i->SetFontAlpha(Alpha, true);
+ }
+}
+
+void PG_Widget::SetFontStyle(PG_Font::Style Style, bool bRecursive) {
+ _mid->font->SetStyle(Style);
+
+ if(!bRecursive || (GetChildList() == NULL)) {
+ return;
+ }
+
+ for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
+ i->SetFontStyle(Style, true);
+ }
+}
+
+int PG_Widget::GetFontSize() {
+ return _mid->font->GetSize();
+}
+
+void PG_Widget::SetFontSize(int Size, bool bRecursive) {
+ _mid->font->SetSize(Size);
+
+ if(!bRecursive || (GetChildList() == NULL)) {
+ return;
+ }
+
+ for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
+ i->SetFontSize(Size, true);
+ }
+
+}
+
+void PG_Widget::SetFontIndex(int Index, bool bRecursive) {
+// _mid->font->SetIndex(Index);
+}
+
+void PG_Widget::SetFontName(const char *Name, bool bRecursive) {
+ _mid->font->SetName(Name);
+
+ if(!bRecursive || (GetChildList() == NULL)) {
+ return;
+ }
+
+ for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
+ i->SetFontName(Name, true);
+ }
+
+}
+
+void PG_Widget::SetSizeByText(int Width, int Height, const char *Text) {
+ Uint16 w,h;
+ int baselineY;
+
+ if (Text == NULL) {
+ Text = my_text.c_str();
+ }
+
+ if (!PG_FontEngine::GetTextSize(Text, _mid->font, &w, &h, &baselineY)) {
+ return;
+ }
+
+ if (my_width == 0 && my_height > 0 && Width == 0) {
+ my_width = w;
+ my_ypos += (my_height - h - baselineY) >> 1;
+ my_height = h + baselineY;
+ }
+ else if (my_height == 0 && my_width > 0 && Height == 0) {
+ my_xpos += (my_width - w) >> 1;
+ my_width = w;
+ my_height = h + baselineY;
+ }
+ else {
+ my_width = w + Width;
+ my_height = h + Height + baselineY;
+ }
+
+}
+
+void PG_Widget::SetFont(PG_Font* font) {
+ if(_mid->font != NULL) {
+ delete _mid->font;
+ }
+
+ _mid->font = new PG_Font(font->GetName(), font->GetSize());
+}
+
+void PG_Widget::GetTextSize(Uint16& w, Uint16& h, const char* text) {
+ if(text == NULL) {
+ if(_mid->widthText != TXT_HEIGHT_UNDEF) {
+ w = _mid->widthText;
+ h = _mid->heightText;
+ return;
+ }
+ text = my_text.c_str();
+ }
+
+ GetTextSize(w, h, text, _mid->font);
+
+ if(text == NULL) {
+ _mid->widthText = w;
+ _mid->heightText = h;
+ }
+}
+
+void PG_Widget::GetTextSize(Uint16& w, Uint16& h, const char* text, PG_Font* font) {
+ PG_FontEngine::GetTextSize(text, font, &w);
+ h = font->GetFontHeight();
+}
+
+int PG_Widget::GetTextWidth() {
+
+ if(_mid->widthText != TXT_HEIGHT_UNDEF) {
+ return _mid->widthText;
+ }
+
+ GetTextSize(_mid->widthText, _mid->heightText);
+
+ return _mid->widthText;
+}
+
+int PG_Widget::GetTextHeight() {
+ return _mid->font->GetFontAscender();
+}
+
+void PG_Widget::DrawText(const PG_Rect& rect, const char* text) {
+ if(my_srfObject == NULL) {
+ PG_FontEngine::RenderText(gamescreen, _mid->rectClip, my_xpos+ rect.x, my_ypos + rect.y + GetFontAscender(), text, _mid->font);
+ }
+ else {
+ PG_FontEngine::RenderText(my_srfObject, PG_Rect(0,0,Width(),Height()), rect.x, rect.y + GetFontAscender(), text, _mid->font);
+ }
+}
+
+void PG_Widget::DrawText(int x, int y, const char* text) {
+ DrawText(PG_Rect(x,y,w-x,h-y), text);
+}
+
+void PG_Widget::DrawText(int x, int y, const char* text, const PG_Rect& cliprect) {
+ if(my_srfObject == NULL) {
+ PG_Rect rect = cliprect;
+ rect.x += my_xpos;
+ rect.y += my_ypos;
+// PG_Rect r = this->IntersectRect(rect);
+ PG_FontEngine::RenderText(gamescreen, rect, my_xpos + x, my_ypos + y + GetFontAscender(), text, _mid->font);
+ }
+ else {
+// PG_Rect rect = this->IntersectRect(cliprect);
+ PG_FontEngine::RenderText(my_srfObject, cliprect, x, y + GetFontAscender(), text, _mid->font);
+ }
+}
+
+void PG_Widget::DrawText(const PG_Rect& rect, const char* text, const PG_Color& c) {
+ SetFontColor(c);
+ DrawText(rect, text);
+}
+
+void PG_Widget::DrawText(int x, int y, const char* text, const PG_Color& c) {
+ DrawText(PG_Rect(x,y,w,h), text, c);
+}
+
+void PG_Widget::QuitModal() {
+ eventQuitModal(GetID(), this, 0);
+}
+
+bool PG_Widget::WillQuitModal()
+{
+ return _mid->quitModalLoop;
+}
+
+void PG_Widget::StopQuitModal() {
+ _mid->quitModalLoop = false;
+}
+
+int PG_Widget::RunModal() {
+ SDL_Event event;
+ _mid->quitModalLoop = false;
+
+ // run while in modal mode
+ while(!_mid->quitModalLoop) {
+ SDL_WaitEvent(&event);
+ //@ PG_Application::ClearOldMousePosition();
+ ProcessEvent(&event, true);
+ //@ PG_Application::DrawCursor();
+ }
+
+ return _mid->modalstatus;
+}
+
+bool PG_Widget::eventQuitModal(int id, PG_MessageObject* widget, unsigned long data) {
+ _mid->quitModalLoop = true;
+ return true;
+}
+
+const char* PG_Widget::GetText() {
+ return my_text.c_str();
+}
+
+void PG_Widget::eventBlit(SDL_Surface* srf, const PG_Rect& src, const PG_Rect& dst) {
+
+ // Don't blit an object without a surface
+
+ if(srf == NULL) {
+ return;
+ }
+
+ // Set alpha
+ Uint8 a = 255-_mid->transparency;
+ if(a != 0) {
+//@ SDL_SetAlpha(srf, SDL_SRCALPHA, a);
+
+ // Blit widget surface to screen
+#ifdef DEBUG
+ PG_LogDBG("SRC BLIT: x:%d y:%d w:%d h:%d",src.x,src.y,src.w,src.h);
+ PG_LogDBG("DST BLIT: x:%d y:%d w:%d h:%d",dst.x,dst.y,dst.w,dst.h);
+#endif // DEBUG
+
+ //@ SDL_LockSurface(gamescreen);
+ PG_Draw::BlitSurface(srf, src, gamescreen, dst);
+ //@ SDL_UnlockSurface(gamescreen);
+ }
+}
+
+void PG_Widget::DrawBorder(const PG_Rect& r, int size, bool up) {
+ int i0, i1;
+
+ if(!IsVisible()) {
+ return;
+ }
+
+ i0 = (up) ? 0 : 1;
+ i1 = (up) ? 1 : 0;
+
+ SDL_LockSurface(gamescreen); //!
+
+ // outer frame
+ if (size >= 1) {
+ DrawHLine(r.x + 0, r.y + 0, r.w, my_colorBorder[i0][0]);
+ DrawVLine(r.x + 0, r.y + 0, r.h - 1, my_colorBorder[i0][0]);
+
+ DrawHLine(r.x + 0, r.y + r.h - 1, r.w - 1, my_colorBorder[i1][0]);
+ DrawVLine(r.x + r.w - 1, r.y + 1, r.h - 1, my_colorBorder[i1][0]);
+ }
+ // inner frame
+ if (size >= 2) {
+ DrawHLine(r.x + 1, r.y + 1, r.w - 1, my_colorBorder[i0][1]);
+ DrawVLine(r.x + 1, r.y + 1, r.h - 2, my_colorBorder[i0][1]);
+
+ DrawHLine(r.x + 1, r.y + r.h - 2, r.w - 2, my_colorBorder[i1][1]);
+ DrawVLine(r.x + r.w - 2, r.y + 2, r.h - 2, my_colorBorder[i1][1]);
+ }
+
+ SDL_UnlockSurface(gamescreen); //!
+}
+
+void PG_Widget::SetTransparency(Uint8 t, bool bRecursive) {
+ _mid->transparency = t;
+
+ if(!bRecursive || (GetChildList() == NULL)) {
+ return;
+ }
+
+ for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
+ i->SetTransparency(t, true);
+ }
+}
+
+void PG_Widget::SetClipRect(PG_Rect& r) {
+ _mid->rectClip = r;
+}
+
+void PG_Widget::GetClipRects(PG_Rect& src, PG_Rect& dst, const PG_Rect& rect) {
+
+ dst = IntersectRect(_mid->rectClip, rect);
+
+ int dx = dst.my_xpos - rect.my_xpos;
+ int dy = dst.my_ypos - rect.my_ypos;
+
+ if(dx < 0) {
+ dx = 0;
+ }
+
+ if(dy < 0) {
+ dy = 0;
+ }
+
+ src.my_xpos = dx;
+ src.my_ypos = dy;
+ src.my_width = dst.my_width;
+ src.my_height = dst.my_height;
+}
+
+void PG_Widget::SetPixel(int x, int y, const PG_Color& c) {
+ static PG_Point p;
+
+ if(my_srfObject == NULL) {
+ p.x = my_xpos + x;
+ p.y = my_ypos + y;
+ if(_mid->rectClip.IsInside(p)) {
+ PG_Draw::SetPixel(p.x, p.y, c, gamescreen);
+ }
+ } else {
+ PG_Draw::SetPixel(x, y, c, my_srfObject);
+ }
+}
+
+void PG_Widget::DrawHLine(int x, int y, int w, const PG_Color& color) {
+ static PG_Rect rect;
+ SDL_Surface* surface = my_srfObject;
+
+ if(my_srfObject == NULL) {
+ surface = gamescreen;
+ SDL_LockSurface(gamescreen); //!
+ }
+
+ x += my_xpos;
+ y += my_ypos;
+
+ if((y < _mid->rectClip.y) || (y >= (_mid->rectClip.y+_mid->rectClip.h))) {
+ if(my_srfObject == NULL) {
+ surface = gamescreen;
+ SDL_UnlockSurface(gamescreen); //!
+ }
+ return;
+ }
+
+ // clip to widget cliprect
+ int x0 = omMAX(x, _mid->rectClip.x);
+ int x1 = omMIN(x+w, _mid->rectClip.x+_mid->rectClip.w);
+ Uint32 c = color.MapRGB(surface->format);
+
+ int wl = (x1-x0);
+
+ if(wl <= 0) {
+ if(my_srfObject == NULL) {
+ surface = gamescreen;
+ SDL_UnlockSurface(gamescreen); //!
+ }
+ return;
+ }
+
+ if(my_srfObject != NULL) {
+ x0 -= my_xpos;
+ y -= my_ypos;
+ }
+
+ rect.SetRect(x0, y, wl, 1);
+ SDL_FillRect(surface, &rect, c);
+
+ if (my_srfObject == NULL) {
+ SDL_UnlockSurface(gamescreen); //!
+ }
+}
+
+void PG_Widget::DrawVLine(int x, int y, int h, const PG_Color& color) {
+ static PG_Rect rect;
+ SDL_Surface* surface = my_srfObject;
+
+ if(my_srfObject == NULL) {
+ surface = gamescreen;
+ SDL_LockSurface(gamescreen);
+ }
+
+ x += my_xpos;
+ y += my_ypos;
+
+ if((x < _mid->rectClip.x) || (x >= (_mid->rectClip.x+_mid->rectClip.w))) {
+ if(my_srfObject == NULL) {
+ surface = gamescreen;
+ SDL_UnlockSurface(gamescreen);
+ }
+ return;
+ }
+
+ // clip to widget cliprect
+ int y0 = omMAX(y, _mid->rectClip.y);
+ int y1 = omMIN(y+h, _mid->rectClip.y+_mid->rectClip.h);
+ Uint32 c = color.MapRGB(surface->format);
+
+ int hl = (y1-y0);
+
+ if(hl <= 0) {
+ if(my_srfObject == NULL) {
+ surface = gamescreen;
+ SDL_UnlockSurface(gamescreen);
+ }
+ return;
+ }
+
+ if(my_srfObject != NULL) {
+ y0 -= my_ypos;
+ x -= my_xpos;
+ }
+
+ rect.SetRect(x, y0, 1, hl);
+ SDL_FillRect(surface, &rect, c);
+
+ if (my_srfObject == NULL) {
+ SDL_UnlockSurface(gamescreen);
+ }
+}
+
+/** */
+void PG_Widget::DrawRectWH(int x, int y, int w, int h, const PG_Color& c) {
+
+ DrawHLine(x, y, w, c);
+ DrawHLine(x, y + h - 1, w, c);
+ DrawVLine(x, y, h, c);
+ DrawVLine(x + w - 1, y, h, c);
+
+}
+
+void PG_Widget::DrawLine(Uint32 x0, Uint32 y0, Uint32 x1, Uint32 y1, const PG_Color& color, Uint8 width) {
+ SDL_Surface* surface = my_srfObject;
+
+ if(surface == NULL) {
+ surface = gamescreen;
+ x0 += my_xpos;
+ y0 += my_ypos;
+ x1 += my_xpos;
+ y1 += my_ypos;
+ }
+
+ PG_Draw::DrawLine(surface, x0, y0, x1, y1, color, width);
+}
+
+void PG_Widget::eventDraw(SDL_Surface* surface, const PG_Rect& rect) {
+}
+
+void PG_Widget::eventMoveWidget(int x, int y) {
+}
+
+/*void PG_Widget::eventMoveWindow(int x, int y) {
+}*/
+
+/*void PG_Widget::eventSizeWindow(Uint16 w, Uint16 h) {
+}*/
+
+void PG_Widget::eventSizeWidget(Uint16 w, Uint16 h) {
+}
+
+SDL_Surface* PG_Widget::GetWidgetSurface() {
+ return my_srfObject;
+}
+
+/*SDL_Surface* PG_Widget::GetScreenSurface() {
+ return my_srfScreen;
+}*/
+
+bool PG_Widget::IsVisible() {
+ return _mid->visible;
+}
+
+PG_Widget* PG_Widget::GetParent() {
+ return _mid->widgetParent;
+}
+
+int PG_Widget::GetID() {
+ return _mid->id;
+}
+
+PG_Widget* PG_Widget::FindChild(int id) {
+ if(_mid->childList == NULL) {
+ return NULL;
+ }
+ return _mid->childList->Find(id);
+}
+
+PG_Widget* PG_Widget::FindChild(const char *name) {
+ if(_mid->childList == NULL) {
+ return NULL;
+ }
+ return _mid->childList->Find(name);
+}
+
+PG_RectList* PG_Widget::GetChildList() {
+ return _mid->childList;
+}
+
+int PG_Widget::GetChildCount() {
+ return _mid->childList ? _mid->childList->size() : 0;
+}
+
+PG_RectList* PG_Widget::GetWidgetList() {
+ return &widgetList;
+}
+
+void PG_Widget::SetName(const char *name) {
+ _mid->name = name;
+}
+
+const char* PG_Widget::GetName() {
+ return _mid->name.c_str();
+}
+
+int PG_Widget::GetFontAscender() {
+ return _mid->font->GetFontAscender();
+}
+
+int PG_Widget::GetFontHeight() {
+ return _mid->font->GetFontHeight();
+}
+
+PG_Color PG_Widget::GetFontColor() {
+ return _mid->font->GetColor();
+}
+
+PG_Font* PG_Widget::GetFont() {
+ return _mid->font;
+}
+
+Uint8 PG_Widget::GetTransparency() {
+ return _mid->transparency;
+}
+
+PG_Rect* PG_Widget::GetClipRect() {
+ RecalcClipRect();
+ return &_mid->rectClip;
+}
+
+bool PG_Widget::IsClippingEnabled() {
+ return ((_mid->rectClip.my_width != my_width) || (_mid->rectClip.my_height != my_height));
+}
+
+void PG_Widget::GetClipRects(PG_Rect& src, PG_Rect& dst) {
+ GetClipRects(src, dst, *this);
+}
+
+void PG_Widget::SetID(int id) {
+ _mid->id = id;
+}
+
+void PG_Widget::SetDirtyUpdate(bool bDirtyUpdate) {
+ _mid->dirtyUpdate = bDirtyUpdate;
+}
+
+bool PG_Widget::GetDirtyUpdate() {
+ return _mid->dirtyUpdate;
+}
+
+void PG_Widget::SetHidden(bool hidden) {
+ _mid->hidden = hidden;
+}
+
+
+bool PG_Widget::IsHidden() {
+ return _mid->hidden;
+}
+
+void PG_Widget::SetParent(PG_Widget* parent) {
+ _mid->widgetParent = parent;
+}
+
+void PG_Widget::SetModalStatus(int status) {
+ _mid->modalstatus = status;
+}
+
+void PG_Widget::EnableReceiver(bool enable, bool bRecursive) {
+ my_canReceiveMessages= enable;
+
+ if(!bRecursive || (GetChildList() == NULL)) {
+ return;
+ }
+
+ for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
+ i->EnableReceiver(enable, true);
+ }
+}
diff --git a/src/paragui/pgwidget.h b/src/paragui/pgwidget.h
new file mode 100644
index 0000000..08f8982
--- /dev/null
+++ b/src/paragui/pgwidget.h
@@ -0,0 +1,892 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgwidget.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#ifndef PG_WIDGET_H
+#define PG_WIDGET_H
+
+#include "pgmessageobject.h"
+#include "pgrectlist.h"
+#include "pgrect.h"
+#include "pgfont.h"
+//@ #include "pgstring.h"
+
+
+//#include MAP_INC
+
+class PG_Widget;
+class PG_WidgetDataInternal;
+
+/**
+ @author Alexander Pipelka
+
+ @short Base class of all widgets.
+
+ Provides graphics context and message handling functionality.
+
+ \anchor theme_PG_Widget
+
+ <h2>Theme support</h2><p>
+
+ This class provides themeing capabilities only for subclassed widgets.<p>
+
+ <b>widget type:</b> none (managed through subclass)<br>
+ <b>object name:</b> none (managed through subclass)<br>
+
+ <h3>Theme sample:</h3>
+
+ \code
+ <widget>
+ <type value="xxx"/>
+ <object>
+ <name value="xxx"/>
+ <property color="textcolor" value="0x00FFFFFF"/>
+ <property color="bordercolor0" value="0x00202020"/>
+ <property color="bordercolor1" value="0x00E0E0E0"/>
+ </object>
+ </widget>
+ \endcode
+ <p>
+ <h2>Code:</h2><p>
+*/
+
+class PG_Widget : public PG_MessageObject, public PG_Rect {
+public:
+
+
+ //! Keyevent actions
+ typedef enum {
+ ACT_ACTIVATE, //!< Widget got the input focus
+ ACT_DEACTIVATE, //!< Widget has lost the input focus
+ ACT_OK, //!< Widget action event (e.g. button press on a PG_Button object)
+ ACT_CANCEL, //!< Widget cancel-action
+ ACT_LEFT, //!< Cursor left was pressed
+ ACT_RIGHT, //!< Cursor right was pressed
+ ACT_UP, //!< Cursor up was pressed
+ ACT_DOWN //!< Cursor down was pressed
+ } KeyAction;
+
+ /**
+ Creates a PG_Widget without an object-surface
+
+ @param parent the parentobject for the new widget or NULL if it is a toplevel widget
+ @param rect initial position for the widget
+
+ This is the constructor for the PG_Widget class (really!)
+ */
+ //PG_Widget(PG_Widget* parent, const PG_Rect& rect);
+
+ /**
+ Creates a PG_Widget with an internal object surface
+
+ @param parent the parentobject for the new widget or NULL if it is a toplevel widget
+ @param rect initial position for the widget
+ @param bObjectSurface flag if a surface for the object should be created
+ */
+ PG_Widget(PG_Widget* parent, const PG_Rect& rect = PG_Rect::null, bool bObjectSurface = false);
+
+ /**
+ Destroys a PG_Widget
+
+ This is the destructor for the PG_Widget class
+ */
+ virtual ~PG_Widget();
+
+ /**
+ Load a style from the theme definition
+
+ @param widgettype name of the widgettype
+
+ Loads the defined style for a given widgettype
+ */
+ //void LoadThemeStyle(const char* widgettype);
+
+ /**
+ Load a style from the theme definition
+
+ @param widgettype name of the widgettype
+ @param objectname name of the object
+
+ Loads the defined style of a given widgettype and objectname.
+ */
+ //virtual void LoadThemeStyle(const char* widgettype, const char* objectname);
+
+ /**
+ Start to drag a widget
+
+ StartWidgetDrag prepares to widget to be dragged.
+ */
+ void StartWidgetDrag();
+
+ /**
+ Drag the widget to a given position (in screen coordinates)
+
+ @param x x-position
+ @param y y-position
+ */
+ void WidgetDrag(int x, int y);
+
+ /**
+ Finishes a drag operation
+
+ @param x x endposition
+ @param y y endposition
+ */
+ void EndWidgetDrag(int x, int y);
+
+ /**
+ Move a widget
+
+ @param x new x-position (in parent context)
+ @param y new y-position (in parent context)
+ @param update true - update screen content / false - no screen update
+ @return function succeeded
+
+ This function moves the widget
+ */
+ bool MoveWidget(int x, int y, bool update = true);
+
+ /**
+ Move and resize widget
+
+ @param r new widget rectangle (client coordinates)
+ @param update is the update true
+ @return function succeeded
+
+ This function moves and resizes the widget to fit the given rectangle.
+ */
+ bool MoveWidget(const PG_Rect& r, bool update = true);
+
+ /**
+ Resize a widget
+
+ @param w new widget-width
+ @param h new widget-height
+ @param update true - update widget after resizing / false - do not display changes
+ @return function succeeded
+
+ This function resizes the widget
+ */
+ virtual bool SizeWidget(Uint16 w, Uint16 h, bool update = true);
+
+ /**
+ Convert a client (widget) coordinate to a screen position
+
+ @param x x - widgetcoordinate
+ @param y y - widgetcoordinate
+ @return PG_Point structure with the screen position
+ */
+ PG_Point ClientToScreen(int x, int y);
+
+ /**
+ Convert a screen position to a client (widget) coordinate
+
+ @param x x - screenposition
+ @param y y - screenposition
+ @return PG_Point structure with the client position
+ */
+ PG_Point ScreenToClient(int x, int y);
+
+ /**
+ Return the pointer to the widget's drawing surface
+
+ @return SDL_Surface pointer to the drawing surface
+ */
+ SDL_Surface* GetWidgetSurface();
+
+ /**
+ Check if the object is visible
+ @return true if object is visible
+ */
+ bool IsVisible();
+
+ /**
+ Get the parentwidget of a widget
+
+ @return a pointer to the parentwidget or NULL if there is no parentwidget
+ */
+ PG_Widget* GetParent();
+
+ /**
+ Add a clientwidget (which will be embedded into this widget)
+
+ @param child the widget to add
+ */
+ virtual void AddChild(PG_Widget* child);
+
+ /**
+ Process a native PG_ event
+
+ @param event PG_ event to process
+ @param bModal set to true if processing takes place in a modal loop
+ @return true if the event was sucessfully processed
+
+ ProcessEvent asks the widget to process a given event. It also asks its
+ parent and, if bModal is true, its children.
+ */
+ virtual bool ProcessEvent(const SDL_Event* event, bool bModal = false);
+
+ /**
+ Set the widgetid
+
+ @param id a number which can be used to identify the widget
+
+ This id can be used in callbacks or eventhandlers to identify the
+ widget. It can also be used to find a child within the group of
+ children.
+ */
+ void SetID(int id);
+
+ /**
+ Return the widgetid
+ @return id of the widget
+ */
+ int GetID();
+
+ /**
+ Find a child that is identified by the given ID.
+ @param id the id of the child to return
+ @return A pointer to the child with the given ID or 0 if no such child exists.
+ */
+ PG_Widget* FindChild(int id);
+
+ /**
+ Find a child that is identified by the given name.
+ @param name the name of the child to return
+ @return A pointer to the child with the given name or 0 if no such child exists.
+ */
+ PG_Widget* FindChild(const char *name);
+
+ /**
+ Check if the mousepointer is currently inside the widget
+ @return true if the mousepointer is inside
+ */
+ bool IsMouseInside();
+
+ /**
+ Redraw the widget and all embedded child widgets
+ @param update if true Update() is called after the redraw
+ @return true if the redraw operation succeeded
+ */
+ bool Redraw(bool update = true);
+
+ /**
+ Blit the widget to the screen
+ @param recursive if true all embedded widget will also be blitted to screen
+ @param restore restore the background before blitting if true
+ This function only performs a SDL_BlitSurface() the screen content will NOT be updated
+ */
+ virtual void Blit(bool recursive = true, bool restore = true);
+
+ /**
+ Update the widget's screen area
+ @param doBlit if true a Blit() operation is done before the update
+ */
+ void Update(bool doBlit = true);
+
+ /**
+ Update a screen area
+ @param r update rectangle
+ */
+ static void UpdateRect(const PG_Rect& r);
+
+ /**
+ Update (render) the whole application screen
+ */
+ static void UpdateScreen();
+
+ /**
+ Make a widget visible
+ @param fade do a smooth fade in if true
+ */
+ void Show(bool fade = false);
+
+ /**
+ Hide a widget
+ @param fade do a smooth fade out if true
+ */
+ void Hide(bool fade = false);
+
+ /**
+ Check if the widget is in front of another one
+ */
+ bool IsInFrontOf(PG_Widget*);
+
+ /**
+ Send the widget back to the end of the list
+ */
+ void SendToBack();
+
+ /**
+ Reorder the widget in front of all others
+ */
+ void BringToFront();
+
+ /**
+ Get the toplevel widget
+ */
+ PG_Widget* GetToplevelWidget();
+
+ /**
+ Hide all widgets of an application
+ */
+ static void HideAll();
+
+ void RecalcClipRect();
+
+ static void RedrawBackground(const PG_Rect *clip);
+
+ /**
+ Restore the background (all widgets behind this one)
+ @param clip clipping rectangle
+ @param force force to redraw the background even if dirty updates are enabled.
+ */
+ virtual bool RestoreBackground(PG_Rect* clip = NULL, bool force = false);
+
+ static PG_Widget* FindWidgetFromPos(int x, int y);
+
+ /**
+ Set the visiblility of a widget with updating the screen contents
+ @param visible true - visible / false - invisible
+ */
+ void SetVisible(bool visible);
+
+ /**
+ Set the number of steps for fading in/out widgets
+ @param steps number of steps
+ */
+ void SetFadeSteps(int steps);
+
+ /**
+ Set the transparency of all child widgets
+ @param t transparency 0 - opaque / 255 - full transparent
+ */
+ void SetChildTransparency(Uint8 t);
+
+ /**
+ Get a list of child widgets
+
+ @return pointer to childlist
+ */
+ PG_RectList* GetChildList();
+
+ /**
+ Get the number of childwidgets
+
+ @return number of childwidgets
+ */
+ int GetChildCount();
+
+ /** */
+ void MoveRect(int x, int y);
+
+ /** */
+ //static void BulkUpdate();
+
+ /** */
+ static void BulkBlit();
+
+ // Navigation
+
+ /** */
+ virtual bool Action(KeyAction action);
+
+ /**
+ Get a list of all toplevel widgets
+ @return pointer to a PG_RectList object
+ */
+ static PG_RectList* GetWidgetList();
+
+ /**
+ Set the name for the widget
+ @param name Name of the widget - size of the name is defined in PG_NAMESIZE
+ */
+ void SetName(const char *name);
+
+ /**
+ Get the name for the widget
+ @return name of the widget
+ */
+ const char* GetName();
+
+ /**
+ Load layout from the XML file to the current widget
+ @param name name of the xml file
+ @return returns non-zero on success or 0 if not succes
+ */
+ bool LoadLayout(const char *name);
+
+ /**
+ Load layout from the XML file to the current widget
+ @param name name of the xml file
+ @param WorkCallback address of function to show progress of loading layout
+ @return returns non-zero on success or 0 if not succes
+ */
+ bool LoadLayout(const char *name, void (* WorkCallback)(int now, int max));
+
+ /**
+ Load layout from the XML file to the current widget
+ @param name name of the xml file
+ @param WorkCallback address of function to show progress of loading layout
+ @param UserSpace address of user data witch are passed to Processing Instruction handler etc.
+ @return returns non-zero on success or 0 if not succes
+ */
+ bool LoadLayout(const char *name, void (* WorkCallback)(int now, int max), void *UserSpace);
+
+ /**
+ Removes all childs
+ */
+ void RemoveAllChilds();
+
+ /**
+ Sets user data to the widget (malloc inside)
+ @param userdata points to data to copy in
+ @param size size of data
+ */
+ void SetUserData(void *userdata, int size);
+
+ /**
+ Sets user data to the widget (malloc inside)
+ @return size of stored user data (0 = no data stored in)
+ */
+ virtual int GetUserDataSize();
+
+ /**
+ Gets user data from the widget
+ @param userdata where to write data (must be allocated space with size from GetUserDataSize())
+ */
+ virtual void GetUserData(void *userdata);
+
+ /**
+ Releases user data
+ */
+ void ReleaseUserData();
+
+ /** */
+ bool virtual RemoveChild(PG_Widget* child);
+
+ /**
+ Sets text
+ @param text Set the widget text and update widget
+ */
+ virtual void SetText(const char* text);
+
+ /**
+ Adds text
+ @param text Add text to the widget text
+ @param update Do the update
+ */
+ void AddText(const char* text, bool update = false);
+
+ /**
+ Sets formated text
+ @param text Set the widget text (like printf) and update widget
+ */
+ virtual void SetTextFormat(const char* text, ...);
+
+ /** Returns text
+ @return Pointer to the text of the widget (read-only)
+ */
+ virtual const char* GetText();
+
+ void GetTextSize(Uint16& w, Uint16& h, const char* text = NULL);
+
+ static void GetTextSize(Uint16& w, Uint16& h, const char* text, PG_Font* font);
+
+ int GetTextWidth();
+
+ int GetTextHeight();
+
+ int GetFontAscender();
+
+ int GetFontHeight();
+
+ /**
+ Return the current text color
+ @return PG_Color
+ */
+ PG_Color GetFontColor();
+
+ /**
+ Set font color
+ @param Color PG_Color class contains color information (RGB)
+ */
+ void SetFontColor(const PG_Color& Color, bool bRecursive = false);
+
+ /**
+ Set font transparency (!!!)
+ @param Alpha Value 0 - 255 (0 = invisible, 255 = fully visible)
+ @param bRecursive alter all child widgets
+ */
+ void SetFontAlpha(int Alpha, bool bRecursive = false);
+
+ /**
+ Set font style
+ @param Style Binary combination (OR) of PG_Font::NORMAL, PG_Font::BOLD, PG_Font::ITALIC and PG_Font::UNDERLINE
+ @param bRecursive alter all child widgets
+ */
+ void SetFontStyle(PG_Font::Style Style, bool bRecursive = false);
+
+ /**
+ Set font size
+ @param Size size of the font
+ @param bRecursive alter all child widgets
+ */
+ void SetFontSize(int Size, bool bRecursive = false);
+
+ /**
+ Set font index
+ @param Index Index of the desired font face in the font file (usualy 0)
+ @param bRecursive alter all child widgets
+ */
+ void SetFontIndex(int Index, bool bRecursive = false);
+
+ /**
+ Set font name
+ @param Name Filename of the font (this function don`t load the font - or check presention of the file !!!)
+ @param bRecursive alter all child widgets
+ */
+ void SetFontName(const char *Name, bool bRecursive = false);
+
+ /**
+ Set widget size by size of text (should be used before Show() or AddWidget())
+ @param Width Value witch is added to text width (default = 0)
+ @param Height Value witch is added to text height (default = 0)
+ @param Text Text to get size from, if NULL my_text is used
+ */
+ void SetSizeByText(int Width = 0, int Height = 0, const char *Text = NULL);
+
+ /**
+ Get the size of the font
+ */
+ int GetFontSize();
+
+ /**
+ Get the current font parameters
+ @return pointer to the PG_Font object
+ */
+ PG_Font* GetFont();
+
+ /**
+ Set the current font parameters
+ @param font pointer to PG_Font object
+ */
+ void SetFont(PG_Font* font);
+
+ /**
+ Render text inside the widget
+ @param rect rectangle where the text should appear
+ @param text pointer to text string
+ */
+ void DrawText(const PG_Rect& rect, const char* text);
+
+ /**
+ Render text inside the widget
+ @param x x-position where the text should appear
+ @param y y-position where the text should appear
+ @param text pointer to text string
+ */
+ void DrawText(int x, int y, const char* text);
+
+ /**
+ Render text inside the widget and clip to a given clipping rectangle
+ @param x x-position where the text should appear
+ @param y y-position where the text should appear
+ @param text pointer to text string
+ @param cliprect text bounding rectangle
+ */
+ void DrawText(int x, int y, const char* text, const PG_Rect& cliprect);
+
+ /**
+ Render text inside the widget and set the font color
+ @param rect rectangle where the text should appear
+ @param text pointer to text string
+ @param c color of the rendered text
+ */
+ void DrawText(const PG_Rect& rect, const char* text, const PG_Color& c);
+
+ /**
+ Render text inside the widget and set the font color
+ @param x x-position where the text should appear
+ @param y y-position where the text should appear
+ @param text pointer to text string
+ @param c color of the rendered text
+ */
+ void DrawText(int x, int y, const char* text, const PG_Color& c);
+
+ /** */
+ void DrawBorder(const PG_Rect& r, int size, bool up = true);
+
+ /**
+ Set the transparency of the drawing object
+ @param t transparency (0 - opaque / 255 - fully transparent)
+ @param bRecursive are transparency changes recursive
+ */
+ virtual void SetTransparency(Uint8 t, bool bRecursive = false);
+
+ /**
+ Get the transparency of the drawing object
+ @return transparency (0 - opaque / 255 - fully transparent)
+ */
+ Uint8 GetTransparency();
+
+ /**
+ Set the clipping rectangle for the object
+ @param r clipping rectangle
+ */
+ void SetClipRect(PG_Rect& r);
+
+ /**
+ Get the current clipping rectangle
+ @return the clipping rectangle
+ */
+ PG_Rect* GetClipRect();
+
+ /**
+ Check if there is a clipping rectangle assigned to the object
+ @return true / false
+ */
+ bool IsClippingEnabled();
+
+ /** */
+ void GetClipRects(PG_Rect& src, PG_Rect& dst);
+
+ /** */
+ void GetClipRects(PG_Rect& src, PG_Rect& dst, const PG_Rect& displayrect);
+
+ /** */
+ void SetPixel(int x, int y, const PG_Color& c);
+
+ /** */
+ void DrawHLine(int x, int y, int w, const PG_Color& c);
+
+ /** */
+ void DrawVLine(int x, int y, int h, const PG_Color& c);
+
+ /** */
+ void DrawRectWH(int x, int y, int w, int h, const PG_Color& c);
+
+ /** */
+ void DrawLine(Uint32 x0, Uint32 y0, Uint32 x1, Uint32 y1, const PG_Color& color, Uint8 width=1);
+
+ /**
+ Enter modal mode
+ */
+ virtual int RunModal();
+
+ /**
+ Quit modal mode
+ */
+ void QuitModal();
+
+ bool WillQuitModal();
+
+ void StopQuitModal();
+
+ /**
+ Set the dirty update mode
+ @param bDirtyUpdate true - enable / false - disable
+ This function sets the dirty update mode of a widget. This greatly improves the rendering speed
+ because the underlying widgets are not redrawn if the widgets transparency is equal to 0.
+ It will cause render failures wrong if there is an alpha channel in the widget's drawing surface.
+ If you encounter problems with activated dirty updates simple disable it.
+ */
+ void SetDirtyUpdate(bool bDirtyUpdate);
+
+ /**
+ return if the dirty update mode is enabled
+ @return true - dirty updates enabled
+ */
+ bool GetDirtyUpdate();
+
+ /**
+ eventhandler for mouse movements.
+ This overrideable handler is called everytime the mouse cursor is leaving the widget area.
+ */
+ virtual void eventMouseLeave();
+
+ /**
+ eventhandler for mouse movements.
+ This overrideable handler is called everytime the mouse cursor is entering the widget area.
+ */
+ virtual void eventMouseEnter();
+
+ void SetHidden(bool hidden);
+
+ bool IsHidden();
+
+ /**
+ Set the return status of the modal eventloop.
+ @param status returnstatus
+ The specified status will be returned by the RunModal method
+ */
+ void SetModalStatus(int status);
+
+ void EnableReceiver(bool enable, bool bRecursive = false);
+
+protected:
+
+ /**
+ main eventhandler for messages
+ @param msg pointer to a MSG_MESSAGE structure
+ @return this eventhandler should return "true" if the message was proccessed.
+ This messagehandler can be overridden to perform custom operations.
+ */
+ //bool eventMessage(MSG_MESSAGE* msg);
+
+ /**
+ Callback for the MoveWidget event
+ @param x new x position
+ @param y new y position
+ This virtual function can be used to implement custom behavior for
+ MoveWidget events.
+ */
+ virtual void eventMoveWidget(int x, int y);
+
+ /**
+ Callback for the MoveWidget event -- OBSOLETE
+ @param x new x position
+ @param y new y position
+ This virtual function can be used to implement custom behavior for
+ MoveWidget events.
+ CAUTION: This function will be removed in the final version
+ */
+ //virtual void eventMoveWindow(int x, int y);
+
+ /**
+ Callback for the SizeWidget event
+ @param w new width
+ @param h new height
+ This virtual function can be used to implement custom behavior for
+ SizeWidget events.
+ */
+ virtual void eventSizeWidget(Uint16 w, Uint16 h);
+
+ /**
+ Callback for the SizeWidget event
+ @param w new width
+ @param h new height
+ This virtual function can be used to implement custom behavior for
+ SizeWidget events.
+ CAUTION: This function will be removed in the final version
+ */
+ //virtual void eventSizeWindow(Uint16 w, Uint16 h);
+
+ /**
+ overridable eventhandler to draw the object surface
+ @param surface the widgets drawing surface.
+ @param rect rectangle to draw within.
+ This eventhandler is called whenevener the widget contents should be redrawn.
+ @note Only widgets with drawing surfaces (see the constructor) will call this eventhandler.
+ */
+ virtual void eventDraw(SDL_Surface* surface, const PG_Rect& rect);
+
+ /**
+ overridable eventhandler to blit the widget contents to the screen
+ @param surface pointer to SDL_Surface to be blitted
+ @param src source rectangle (client coordinates)
+ @param dst destination rectangle (screen coordinates)
+ Override this eventhandler to perform custom blitting behaviour (without drawing onto the widget surface).
+ */
+ virtual void eventBlit(SDL_Surface* surface, const PG_Rect& src, const PG_Rect& dst);
+
+ /**
+ overridable eventhandler called whenever the widget gets shown.
+ */
+ virtual void eventShow();
+
+ /**
+ overridable eventhandler called whenever the widget gets hidden.
+ */
+ virtual void eventHide();
+
+
+ /**
+ overridable eventhandler called when leaving a modal eventloop
+ @param id id of the widget that send the quit signal
+ @param widget pointer to the widget
+ @param data event specific data
+ @return true if the message was processed
+ */
+ virtual bool eventQuitModal(int id, PG_MessageObject* widget, unsigned long data);
+
+ void SetParent(PG_Widget* parent);
+
+ /** */
+ void FadeOut();
+
+ /** */
+ void FadeIn();
+
+ /** */
+ bool AcceptEvent(const SDL_Event* event);
+
+ /** */
+ void RemoveFromWidgetList();
+
+ /** */
+ void AddToWidgetList();
+
+ /**
+ pointer to the widgets drawing surface or NULL
+ */
+ SDL_Surface* my_srfObject;
+
+ /**
+ pointer to the screen surface
+ */
+ //SDL_Surface* my_srfScreen;
+
+ /**
+ text attached to the widget
+ */
+ PG_String my_text;
+
+ /**
+ array of border colors
+ */
+ PG_Color my_colorBorder[2][2];
+
+private:
+
+ PG_Widget(const PG_Widget&);
+ PG_Widget& operator=(const PG_Widget&);
+
+ //static bool bBulkUpdate;
+ static int my_ObjectCounter;
+ static PG_RectList widgetList;
+
+ // this is a bit rude but neccessary for future binary compatibility
+ // because adding non-static data members would break the ABI.
+ // For this we put all private data into a dynamically created struct.
+ PG_WidgetDataInternal* _mid;
+ bool my_canReceiveMessages;
+protected:
+ int my_bordersize;
+};
+
+#endif // PG_WIDGET_H
diff --git a/src/paragui/pgwidgetlist.cpp b/src/paragui/pgwidgetlist.cpp
new file mode 100644
index 0000000..a6b4502
--- /dev/null
+++ b/src/paragui/pgwidgetlist.cpp
@@ -0,0 +1,125 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgwidgetlist.cpp,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#include "pgwidgetlist.h"
+#include "pgscrollarea.h"
+
+
+PG_WidgetList::PG_WidgetList(PG_Widget* parent, const PG_Rect& r, const char* style) :
+PG_ScrollWidget(parent, r, style)
+{
+ my_scrollarea->SetShiftOnRemove(false, true);
+
+// if(strcmp(style, "WidgetList") != 0) {
+// LoadThemeStyle("WidgetList");
+// }
+// LoadThemeStyle(style);
+}
+
+PG_WidgetList::~PG_WidgetList() {
+}
+
+void PG_WidgetList::AddChild(PG_Widget* w) {
+ if(w == NULL) {
+ return;
+ }
+
+ if (my_objVerticalScrollbar == NULL || my_objHorizontalScrollbar == NULL || my_scrollarea == NULL) {
+ PG_Widget::AddChild(w);
+ return;
+ }
+
+ w->MoveRect(0, w->my_ypos + my_scrollarea->GetAreaHeight());
+ my_scrollarea->AddChild(w);
+}
+
+PG_Widget* PG_WidgetList::GetWidgetFromPos(Sint32 y) {
+ Uint32 dy = 0;
+ Uint32 min_dy = 100000000;
+
+ PG_Widget* result = NULL;
+
+ PG_Widget* list = GetChildList()->first();
+ for( ; list != NULL; list = list->next()) {
+ dy = abs(0- (list->my_ypos - my_ypos));
+
+ if(dy < min_dy) {
+ min_dy = dy;
+ result = list;
+ }
+ }
+
+ return result;
+}
+
+PG_Widget* PG_WidgetList::FindWidget(int index) {
+
+ if((index < 0) || (index >= GetWidgetCount())) {
+ return NULL;
+ }
+
+ int i = 0;
+ PG_Widget* list = my_scrollarea->GetChildList()->first();
+ for( ; list != NULL; list = list->next()) {
+ if(i == index) {
+ return list;
+ }
+ i++;
+ }
+
+ return NULL;
+}
+
+int PG_WidgetList::FindIndex(PG_Widget* w) {
+ int index = 0;
+
+ PG_Widget* list = my_scrollarea->GetChildList()->first();
+ for( ; list != NULL; list = list->next()) {
+ if(list == w) {
+ return index;
+ }
+ index++;
+ }
+
+ return -1;
+}
+
+void PG_WidgetList::ScrollTo(Uint16 ypos) {
+ my_scrollarea->ScrollTo(my_scrollarea->GetScrollPosX(), ypos);
+ CheckScrollBars();
+}
+
+void PG_WidgetList::PageUp() {
+ my_scrollarea->ScrollTo(my_scrollarea->GetScrollPosX(), my_scrollarea->GetScrollPosY() - my_height );
+ CheckScrollBars();
+}
+
+void PG_WidgetList::PageDown() {
+ my_scrollarea->ScrollTo(my_scrollarea->GetScrollPosX(), my_scrollarea->GetScrollPosY() + my_height );
+ CheckScrollBars();
+}
diff --git a/src/paragui/pgwidgetlist.h b/src/paragui/pgwidgetlist.h
new file mode 100644
index 0000000..0ced5bc
--- /dev/null
+++ b/src/paragui/pgwidgetlist.h
@@ -0,0 +1,107 @@
+/*
+ ParaGUI - crossplatform widgetset
+ Copyright (C) 2000,2001,2002 Alexander Pipelka
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Alexander Pipelka
+ pipelka@teleweb.at
+
+ Last Update: $Author: upi $
+ Update Date: $Date: 2006/12/04 09:34:33 $
+ Source File: $Source: /cvsroot/openmortal/openmortal/src/paragui/pgwidgetlist.h,v $
+ CVS/RCS Revision: $Revision: 1.1 $
+ Status: $State: Exp $
+*/
+
+#ifndef PG_WIDGETLIST_H
+#define PG_WIDGETLIST_H
+
+#include "pgscrollwidget.h"
+
+/**
+ @author Alexander Pipelka
+
+ @short A group of widgets arranged in a list.
+ Generally used to make a large 'pane' of widgets that can be scrolled
+ through in a smaller 'portal' with scrollbars.
+*/
+
+class PG_WidgetList : public PG_ScrollWidget {
+public:
+
+ /**
+ Constructor of the PG_Widget class
+ */
+ PG_WidgetList(PG_Widget* parent, const PG_Rect& r = PG_Rect::null, const char* style="WidgetList");
+
+ /**
+ Destructor of the PG_Widget class
+ */
+ ~PG_WidgetList();
+
+ /**
+ Find a widget by a given index
+
+ @param index index of the widget to find
+ @return pointer to the widget
+ */
+ PG_Widget* FindWidget(int index);
+
+ /**
+ Find the index of a given widget
+
+ @param widget pointer to the widget
+ @return index of the widget
+ */
+ int FindIndex(PG_Widget* widget);
+
+ /**
+ Scroll to the specified Y-Position
+ @param ypos new Y-Position
+ Will scroll to the new position and update the scrollbars.
+ */
+ void ScrollTo(Uint16 ypos);
+
+ /**
+ Scroll one page up
+ */
+ void PageUp();
+
+ /**
+ Scroll one page down
+ */
+ void PageDown();
+
+ void AddChild(PG_Widget* child);
+
+protected:
+
+ /**
+ Search for a widget at a given y-position
+
+ @param y the position
+ @return pointer to the widget or NULL
+ */
+ PG_Widget* GetWidgetFromPos(Sint32 y);
+
+private:
+
+ PG_WidgetList(const PG_WidgetList&);
+ PG_WidgetList& operator=(const PG_WidgetList&);
+
+};
+
+#endif // PG_WIDGETLIST_H
diff --git a/src/pgtest.cpp b/src/pgtest.cpp
new file mode 100644
index 0000000..46188cb
--- /dev/null
+++ b/src/pgtest.cpp
@@ -0,0 +1,159 @@
+#include "paragui/pgmultilineedit.h"
+#include "paragui/pglistbox.h"
+#include "paragui/pglistboxitem.h"
+#include "gfx.h"
+#include "State.h"
+#include "common.h"
+
+
+SDL_Surface *g_poBackground = NULL;
+
+class CMortalNetUI: public SigC::Object
+{
+ PG_MultiLineEdit *m_poConsole;
+ PG_LineEdit *m_poInputLine;
+ PG_Button *m_poChallengeButton;
+ PG_ListBox *m_poPeople;
+
+ PG_FontEngine m_oFontEngine;
+ PG_Font m_oFont;
+
+public:
+ CMortalNetUI();
+ ~CMortalNetUI();
+
+ void Init();
+ void Run();
+ bool OnChallenge( PG_Button *a_poSource );
+};
+
+
+CMortalNetUI::CMortalNetUI() :
+ m_oFont(DATADIR "/fonts/bradybun.ttf", 24)
+{
+ m_poConsole= NULL;
+ m_poInputLine= NULL;
+ m_poChallengeButton= NULL;
+ m_poPeople= NULL;
+}
+
+CMortalNetUI::~CMortalNetUI()
+{
+ delete m_poConsole; m_poConsole= NULL;
+ delete m_poInputLine; m_poInputLine= NULL;
+ delete m_poChallengeButton; m_poChallengeButton= NULL;
+ delete m_poPeople; m_poPeople= NULL;
+ SDL_FreeSurface( g_poBackground );
+}
+
+void CMortalNetUI::Init()
+{
+ SDL_EnableUNICODE(1);
+
+ g_poBackground= LoadBackground("FighterStats.jpg", 64);
+ SDL_BlitSurface(g_poBackground, NULL, gamescreen, NULL);
+ SDL_Flip(gamescreen);
+
+ int i;
+
+ // LAYOUT VARIABLES
+
+ int FontHeight= m_oFont.GetFontHeight();
+ int LayoutSpacing= 10;
+ int LayoutMargin= 15;
+ int HorizontalDivide= gamescreen->w * 3 / 4;
+ int DivideWidth= gamescreen->w - HorizontalDivide - LayoutSpacing - LayoutMargin;
+
+ // LINEEDIT
+
+ int EditHeight= FontHeight;
+ int EditTop= gamescreen->h - LayoutMargin - EditHeight;
+ PG_Rect r( LayoutMargin, EditTop,
+ gamescreen->w - 2*LayoutMargin, EditHeight );
+ m_poInputLine = new PG_LineEdit(NULL, r);
+ m_poInputLine->SetText("Ez itt, KノREM az input sor");
+ m_poInputLine->SetEditable(true);
+ m_poInputLine->Show();
+
+ // BUTTONS
+
+ int ButtonTop= EditTop - FontHeight - 4 - LayoutSpacing;
+ r.SetRect( HorizontalDivide + LayoutSpacing, ButtonTop,
+ DivideWidth, FontHeight + 4 );
+ m_poChallengeButton = new PG_Button( NULL, r );
+ m_poChallengeButton->SetText("Challenge!");
+ m_poChallengeButton->Show();
+ m_poChallengeButton->sigClick.connect(slot(*this, &CMortalNetUI::OnChallenge));
+
+// my_vscroll->sigScrollPos.connect(slot(*this, &PG_MultiLineEdit::handleScroll));
+
+ // LISTBOX
+
+ r.SetRect( HorizontalDivide + LayoutMargin, LayoutMargin,
+ DivideWidth, ButtonTop - LayoutMargin - LayoutSpacing );
+ m_poPeople = new PG_ListBox( NULL, r );
+ m_poPeople->Show();
+
+ new PG_ListBoxItem( m_poPeople, FontHeight, "Egy vizilo" );
+ new PG_ListBoxItem( m_poPeople, FontHeight, "Nagyon hosszu valami" );
+ for ( i= 0; i<30; ++i )
+ {
+ char Buffer[128];
+ sprintf( Buffer, "%d v?zil?!", i);
+ new PG_ListBoxItem( m_poPeople, FontHeight, Buffer );
+ }
+
+ // MULTILINEEDIT
+
+ int MultiLineEditHeight= gamescreen->h - 3*LayoutMargin - EditHeight;
+ MultiLineEditHeight= (MultiLineEditHeight) / FontHeight * FontHeight;
+ r.SetRect( LayoutMargin, LayoutMargin,
+ HorizontalDivide - LayoutMargin, MultiLineEditHeight );
+ m_poConsole = new PG_MultiLineEdit(NULL, r);
+ m_poConsole->SetText("Welcome to MortalNet!");
+ m_poConsole->SetEditable(true);
+ m_poConsole->Show();
+}
+
+bool CMortalNetUI::OnChallenge( PG_Button *a_poSource )
+{
+ PG_ListBoxBaseItem *Item = m_poPeople->GetCurrentItem();
+ if (NULL == Item)
+ {
+ m_poConsole->AddText("Fogalmam sincs, hogy mit akarsz", C_LIGHTRED, true);
+ }
+ else
+ {
+ std::string Message("Van egy ?tletem. Mi lenne, ha kih?vn?nk ");
+ Message += Item->GetText();
+ Message += "-t?";
+
+ int Index = m_poPeople->FindIndex(Item);
+
+ PG_Color Color( 128, (Index % 2) ? 128 : 192, 255 );
+
+ m_poConsole->AddText(Message.c_str(), Color, true);
+ }
+
+ return false;
+}
+
+void CMortalNetUI::Run()
+{
+ SDL_Event Event;
+
+ while (SDL_WaitEvent(&Event))
+ {
+ if (Event.type== SDL_QUIT) break;
+ if (Event.type == SDL_KEYDOWN && Event.key.keysym.sym == SDLK_ESCAPE) break;
+ PG_MessageObject::HandleEvent(&Event);
+ }
+}
+
+
+void PgTest()
+{
+ CMortalNetUI oUi;
+ oUi.Init();
+ oUi.Run();
+}
diff --git a/src/sigc++/adaptor.cpp b/src/sigc++/adaptor.cpp
new file mode 100644
index 0000000..c27b518
--- /dev/null
+++ b/src/sigc++/adaptor.cpp
@@ -0,0 +1,55 @@
+// -*- c++ -*-
+/*
+ Copyright 2000, Karl Einar Nelson
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#include "sigc++/adaptor.h"
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+AdaptorSlotNode::AdaptorSlotNode(FuncPtr proxy,const Node& s)
+ : SlotNode(proxy), slot_(s)
+ {
+ static_cast<SlotNode*>(slot_.impl())->add_dependency(this);
+ }
+
+
+void AdaptorSlotNode::notify(bool from_child)
+ {
+ if (from_child)
+ slot_.clear();
+ else
+ static_cast<SlotNode*>(slot_.impl())->remove_dependency(this);
+ SlotNode::notify(from_child);
+ }
+
+NodeBase::Link* AdaptorSlotNode::link()
+ { return &link_; }
+
+AdaptorSlotNode::~AdaptorSlotNode()
+ {
+ if (!notified_)
+ static_cast<SlotNode*>(slot_.impl())->remove_dependency(this);
+ slot_.clear();
+ }
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
diff --git a/src/sigc++/adaptor.h b/src/sigc++/adaptor.h
new file mode 100644
index 0000000..9e4c27f
--- /dev/null
+++ b/src/sigc++/adaptor.h
@@ -0,0 +1,47 @@
+// -*- c++ -*-
+/*
+ Copyright 2000, Karl Einar Nelson
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#ifndef SIGC_ADAPTOR_SLOT
+#define SIGC_ADAPTOR_SLOT
+#include <sigc++/slot.h>
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+// (internal)
+struct LIBSIGC_API AdaptorSlotNode : public SlotNode
+ {
+ Node slot_;
+ Link link_;
+
+ virtual Link* link();
+ virtual void notify(bool from_child);
+
+ AdaptorSlotNode(FuncPtr proxy,const Node& s);
+
+ virtual ~AdaptorSlotNode();
+ };
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+
+#endif // SIGC_ADAPTOR_SLOT
diff --git a/src/sigc++/bind.cpp b/src/sigc++/bind.cpp
new file mode 100644
index 0000000..8b4afa9
--- /dev/null
+++ b/src/sigc++/bind.cpp
@@ -0,0 +1,44 @@
+// -*- c++ -*-
+/*
+ Copyright 2000, Karl Einar Nelson
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#include "sigc++/bind.h"
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+
+AdaptorBindSlotNode::~AdaptorBindSlotNode()
+ {
+ typedef void (*Dtor)(AdaptorBindSlotNode*);
+
+ if (dtor_)
+ ((Dtor)dtor_)(this);
+ }
+
+AdaptorBindSlotNode::AdaptorBindSlotNode(FuncPtr proxy, const Node& s, FuncPtr dtor)
+ : AdaptorSlotNode(proxy, s), dtor_(dtor)
+ {}
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+
+
diff --git a/src/sigc++/bind.h b/src/sigc++/bind.h
new file mode 100644
index 0000000..9645306
--- /dev/null
+++ b/src/sigc++/bind.h
@@ -0,0 +1,419 @@
+// -*- c++ -*-
+// Copyright 2000, Karl Einar Nelson
+/* This is a generated file, do not edit. Generated from template.macros.m4 */
+
+#ifndef SIGC_BIND_H
+#define SIGC_BIND_H
+#include <sigc++/adaptor.h>
+
+/** @defgroup bind
+ *
+ * SigC::bind() alters a SigC::Slot by fixing arguments to certain values.
+ *
+ * Argument fixing starts from the last argument.
+ * Up to two arguments can be bound at a time.
+ *
+ * Simple sample usage:
+ * @code
+ * void f(int, int);
+ * SigC:Slot2<void, int, int> s1 = SigC::slot(f);
+ *
+ * SigC::Slot1<void, int> s2 = SigC::bind(s1,1);
+ * s2(2); // call f with arguments 2,1
+ * @endcode
+ *
+ * Multibinding usage:
+ *
+ * @code
+ * void f(int,int);
+ * SigC::Slot2<void, int, int> s1 = SigC::slot(f);
+ *
+ * SigC::Slot0<void> s2 = SigC::bind(s1, 1, 2);
+ * s2(); // call f with arguments 1, 2
+ * @endcode
+ *
+ * Type specified usage:
+ *
+ * @code
+ * class A {};
+ * class B : public A {};
+ * B* b;
+ * SigC::Slot0<void, A*> s1;
+ *
+ * SigC::Slot0<void> s2 = SIgC::bind(s1, b); // B* converted to A*
+ * @endcode
+ *
+ *
+ * SigC::bind_return() alters a Slot by fixing the return value to certain values
+ *
+ * Return value fixing ignores any slot return value. The slot is
+ * destroyed in the process and a new one is created, so references
+ * to the slot will no longer be valid.
+ *
+ * Typecasting may be necessary to match arguments between the
+ * slot and the bound return value. Types must be an exact match.
+ * To ensure the proper type, the type can be explicitly specified
+ * on template instantation.
+ *
+ * Simple sample usage:
+ * @code
+ * void f(int, int);
+ * SigC::Slot1<int, int, int> s1 = SigC::bind_return(slot(&f), 1);
+ * std::cout << "s2: " << s1(2, 1) << std::endl;
+ * @endcode
+ *
+ * Type specified usage:
+ * @code
+ * class A {};
+ * class B : public A {};
+ * B* b;
+ * SigC::Slot1<void> s1;
+ *
+ * SigC::Slot0<A*> s2 = SigC::bind_return<A*>(s1, b); // B* must be told to match A*
+ * @endcode
+ *
+ */
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+
+/**************************************************************/
+// These are internal classes used to represent function varients of slots
+
+// (internal)
+struct LIBSIGC_API AdaptorBindSlotNode : public AdaptorSlotNode
+ {
+ FuncPtr dtor_;
+
+ AdaptorBindSlotNode(FuncPtr proxy, const Node& s, FuncPtr dtor);
+
+ virtual ~AdaptorBindSlotNode();
+ };
+
+
+
+
+
+
+
+template <class C1>
+struct AdaptorBindData1_
+ {
+ typedef AdaptorBindData1_ Self;
+ AdaptorBindSlotNode adaptor;
+ C1 c1_;
+ AdaptorBindData1_(FuncPtr p, const Node& s ,FuncPtr d,
+ C1 c1)
+ : adaptor(p, s, d), c1_(c1)
+ {}
+
+ static void dtor(void* data)
+ {
+ Self& node = *reinterpret_cast<Self*>(data);
+ node.c1_.~C1();
+ }
+ };
+
+
+template <class C1,class C2>
+struct AdaptorBindData2_
+ {
+ typedef AdaptorBindData2_ Self;
+ AdaptorBindSlotNode adaptor;
+ C1 c1_;
+ C2 c2_;
+ AdaptorBindData2_(FuncPtr p, const Node& s ,FuncPtr d,
+ C1 c1,C2 c2)
+ : adaptor(p, s, d), c1_(c1),c2_(c2)
+ {}
+
+ static void dtor(void* data)
+ {
+ Self& node = *reinterpret_cast<Self*>(data);
+ node.c1_.~C1();
+ node.c2_.~C2();
+ }
+ };
+
+
+
+template <class R,class C1>
+struct AdaptorBindSlot0_1_
+ {
+ typedef typename Trait<R>::type RType;
+ typedef typename Slot1<R,C1>::Proxy Proxy;
+ static RType proxy(void *data)
+ {
+ typedef AdaptorBindData1_<C1> Data;
+ Data& node=*reinterpret_cast<Data*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.adaptor.slot_.impl());
+ return ((Proxy)(slot->proxy_))
+ (node.c1_,slot);
+ }
+
+ };
+
+/// @ingroup bind
+template <class A1,class R,class C1>
+Slot0<R>
+ bind(const Slot1<R,C1>& s,
+ A1 a1)
+ {
+ typedef AdaptorBindData1_<C1> Data;
+ typedef AdaptorBindSlot0_1_<R,C1> Adaptor;
+ return reinterpret_cast<SlotNode*>(
+ new Data((FuncPtr)(&Adaptor::proxy),s,
+ (FuncPtr)(&Data::dtor),a1));
+ }
+
+
+template <class R,class P1,class C1>
+struct AdaptorBindSlot1_1_
+ {
+ typedef typename Trait<R>::type RType;
+ typedef typename Slot2<R,P1,C1>::Proxy Proxy;
+ static RType proxy(typename Trait<P1>::ref p1,void *data)
+ {
+ typedef AdaptorBindData1_<C1> Data;
+ Data& node=*reinterpret_cast<Data*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.adaptor.slot_.impl());
+ return ((Proxy)(slot->proxy_))
+ (p1,node.c1_,slot);
+ }
+
+ };
+
+/// @ingroup bind
+template <class A1,class R,class P1,class C1>
+Slot1<R,P1>
+ bind(const Slot2<R,P1,C1>& s,
+ A1 a1)
+ {
+ typedef AdaptorBindData1_<C1> Data;
+ typedef AdaptorBindSlot1_1_<R,P1,C1> Adaptor;
+ return reinterpret_cast<SlotNode*>(
+ new Data((FuncPtr)(&Adaptor::proxy),s,
+ (FuncPtr)(&Data::dtor),a1));
+ }
+
+
+template <class R,class P1,class P2,class C1>
+struct AdaptorBindSlot2_1_
+ {
+ typedef typename Trait<R>::type RType;
+ typedef typename Slot3<R,P1,P2,C1>::Proxy Proxy;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void *data)
+ {
+ typedef AdaptorBindData1_<C1> Data;
+ Data& node=*reinterpret_cast<Data*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.adaptor.slot_.impl());
+ return ((Proxy)(slot->proxy_))
+ (p1,p2,node.c1_,slot);
+ }
+
+ };
+
+/// @ingroup bind
+template <class A1,class R,class P1,class P2,class C1>
+Slot2<R,P1,P2>
+ bind(const Slot3<R,P1,P2,C1>& s,
+ A1 a1)
+ {
+ typedef AdaptorBindData1_<C1> Data;
+ typedef AdaptorBindSlot2_1_<R,P1,P2,C1> Adaptor;
+ return reinterpret_cast<SlotNode*>(
+ new Data((FuncPtr)(&Adaptor::proxy),s,
+ (FuncPtr)(&Data::dtor),a1));
+ }
+
+
+template <class R,class P1,class P2,class P3,class C1>
+struct AdaptorBindSlot3_1_
+ {
+ typedef typename Trait<R>::type RType;
+ typedef typename Slot4<R,P1,P2,P3,C1>::Proxy Proxy;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void *data)
+ {
+ typedef AdaptorBindData1_<C1> Data;
+ Data& node=*reinterpret_cast<Data*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.adaptor.slot_.impl());
+ return ((Proxy)(slot->proxy_))
+ (p1,p2,p3,node.c1_,slot);
+ }
+
+ };
+
+/// @ingroup bind
+template <class A1,class R,class P1,class P2,class P3,class C1>
+Slot3<R,P1,P2,P3>
+ bind(const Slot4<R,P1,P2,P3,C1>& s,
+ A1 a1)
+ {
+ typedef AdaptorBindData1_<C1> Data;
+ typedef AdaptorBindSlot3_1_<R,P1,P2,P3,C1> Adaptor;
+ return reinterpret_cast<SlotNode*>(
+ new Data((FuncPtr)(&Adaptor::proxy),s,
+ (FuncPtr)(&Data::dtor),a1));
+ }
+
+
+template <class R,class P1,class P2,class P3,class P4,class C1>
+struct AdaptorBindSlot4_1_
+ {
+ typedef typename Trait<R>::type RType;
+ typedef typename Slot5<R,P1,P2,P3,P4,C1>::Proxy Proxy;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,void *data)
+ {
+ typedef AdaptorBindData1_<C1> Data;
+ Data& node=*reinterpret_cast<Data*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.adaptor.slot_.impl());
+ return ((Proxy)(slot->proxy_))
+ (p1,p2,p3,p4,node.c1_,slot);
+ }
+
+ };
+
+/// @ingroup bind
+template <class A1,class R,class P1,class P2,class P3,class P4,class C1>
+Slot4<R,P1,P2,P3,P4>
+ bind(const Slot5<R,P1,P2,P3,P4,C1>& s,
+ A1 a1)
+ {
+ typedef AdaptorBindData1_<C1> Data;
+ typedef AdaptorBindSlot4_1_<R,P1,P2,P3,P4,C1> Adaptor;
+ return reinterpret_cast<SlotNode*>(
+ new Data((FuncPtr)(&Adaptor::proxy),s,
+ (FuncPtr)(&Data::dtor),a1));
+ }
+
+
+
+template <class R,class C1,class C2>
+struct AdaptorBindSlot0_2_
+ {
+ typedef typename Trait<R>::type RType;
+ typedef typename Slot2<R,C1,C2>::Proxy Proxy;
+ static RType proxy(void *data)
+ {
+ typedef AdaptorBindData2_<C1,C2> Data;
+ Data& node=*reinterpret_cast<Data*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.adaptor.slot_.impl());
+ return ((Proxy)(slot->proxy_))
+ (node.c1_,node.c2_,slot);
+ }
+
+ };
+
+/// @ingroup bind
+template <class A1,class A2,class R,class C1,class C2>
+Slot0<R>
+ bind(const Slot2<R,C1,C2>& s,
+ A1 a1,A2 a2)
+ {
+ typedef AdaptorBindData2_<C1,C2> Data;
+ typedef AdaptorBindSlot0_2_<R,C1,C2> Adaptor;
+ return reinterpret_cast<SlotNode*>(
+ new Data((FuncPtr)(&Adaptor::proxy),s,
+ (FuncPtr)(&Data::dtor),a1,a2));
+ }
+
+
+template <class R,class P1,class C1,class C2>
+struct AdaptorBindSlot1_2_
+ {
+ typedef typename Trait<R>::type RType;
+ typedef typename Slot3<R,P1,C1,C2>::Proxy Proxy;
+ static RType proxy(typename Trait<P1>::ref p1,void *data)
+ {
+ typedef AdaptorBindData2_<C1,C2> Data;
+ Data& node=*reinterpret_cast<Data*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.adaptor.slot_.impl());
+ return ((Proxy)(slot->proxy_))
+ (p1,node.c1_,node.c2_,slot);
+ }
+
+ };
+
+/// @ingroup bind
+template <class A1,class A2,class R,class P1,class C1,class C2>
+Slot1<R,P1>
+ bind(const Slot3<R,P1,C1,C2>& s,
+ A1 a1,A2 a2)
+ {
+ typedef AdaptorBindData2_<C1,C2> Data;
+ typedef AdaptorBindSlot1_2_<R,P1,C1,C2> Adaptor;
+ return reinterpret_cast<SlotNode*>(
+ new Data((FuncPtr)(&Adaptor::proxy),s,
+ (FuncPtr)(&Data::dtor),a1,a2));
+ }
+
+
+template <class R,class P1,class P2,class C1,class C2>
+struct AdaptorBindSlot2_2_
+ {
+ typedef typename Trait<R>::type RType;
+ typedef typename Slot4<R,P1,P2,C1,C2>::Proxy Proxy;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void *data)
+ {
+ typedef AdaptorBindData2_<C1,C2> Data;
+ Data& node=*reinterpret_cast<Data*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.adaptor.slot_.impl());
+ return ((Proxy)(slot->proxy_))
+ (p1,p2,node.c1_,node.c2_,slot);
+ }
+
+ };
+
+/// @ingroup bind
+template <class A1,class A2,class R,class P1,class P2,class C1,class C2>
+Slot2<R,P1,P2>
+ bind(const Slot4<R,P1,P2,C1,C2>& s,
+ A1 a1,A2 a2)
+ {
+ typedef AdaptorBindData2_<C1,C2> Data;
+ typedef AdaptorBindSlot2_2_<R,P1,P2,C1,C2> Adaptor;
+ return reinterpret_cast<SlotNode*>(
+ new Data((FuncPtr)(&Adaptor::proxy),s,
+ (FuncPtr)(&Data::dtor),a1,a2));
+ }
+
+
+template <class R,class P1,class P2,class P3,class C1,class C2>
+struct AdaptorBindSlot3_2_
+ {
+ typedef typename Trait<R>::type RType;
+ typedef typename Slot5<R,P1,P2,P3,C1,C2>::Proxy Proxy;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void *data)
+ {
+ typedef AdaptorBindData2_<C1,C2> Data;
+ Data& node=*reinterpret_cast<Data*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.adaptor.slot_.impl());
+ return ((Proxy)(slot->proxy_))
+ (p1,p2,p3,node.c1_,node.c2_,slot);
+ }
+
+ };
+
+/// @ingroup bind
+template <class A1,class A2,class R,class P1,class P2,class P3,class C1,class C2>
+Slot3<R,P1,P2,P3>
+ bind(const Slot5<R,P1,P2,P3,C1,C2>& s,
+ A1 a1,A2 a2)
+ {
+ typedef AdaptorBindData2_<C1,C2> Data;
+ typedef AdaptorBindSlot3_2_<R,P1,P2,P3,C1,C2> Adaptor;
+ return reinterpret_cast<SlotNode*>(
+ new Data((FuncPtr)(&Adaptor::proxy),s,
+ (FuncPtr)(&Data::dtor),a1,a2));
+ }
+
+
+
+#ifdef SIGC_CXX_NAMESPACES
+} // namespace
+#endif
+
+#endif // SIGC_BIND_H
diff --git a/src/sigc++/bind_return.h b/src/sigc++/bind_return.h
new file mode 100644
index 0000000..5649388
--- /dev/null
+++ b/src/sigc++/bind_return.h
@@ -0,0 +1,207 @@
+// -*- c++ -*-
+// Copyright 2000, Karl Einar Nelson
+/* This is a generated file, do not edit. Generated from template.macros.m4 */
+
+#ifndef SIGC_BIND_RETURN_H
+#define SIGC_BIND_RETURN_H
+#include <sigc++/bind.h>
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+
+
+/****************************************************************
+***** Adaptor Return Bind Slot 0 arguments
+****************************************************************/
+template <class R1,class R2>
+struct AdaptorBindReturnSlot0_
+ {
+ typedef AdaptorBindData1_<R1> Data;
+ typedef typename Slot0<R2>::Proxy Proxy;
+ static R1 proxy(void *data)
+ {
+ Data& node = *reinterpret_cast<Data*>(data);
+ SlotNode* slot = static_cast<SlotNode*>(node.adaptor.slot_.impl());
+ ((Proxy)(slot->proxy_))
+ (slot);
+ return node.c1_;
+ }
+ };
+
+/// @ingroup bind
+template <class R1,class R2>
+Slot0<R1>
+ bind_return(const Slot0<R2> &s,R1 ret)
+ {
+ typedef AdaptorBindData1_<R1> Data;
+ typedef AdaptorBindReturnSlot0_<R1,R2> Adaptor;
+ return reinterpret_cast<SlotNode*>(
+ new Data((FuncPtr)(&Adaptor::proxy),s,
+ (FuncPtr)(&Data::dtor),ret));
+ }
+
+
+/****************************************************************
+***** Adaptor Return Bind Slot 1 arguments
+****************************************************************/
+template <class R1,class R2,class P1>
+struct AdaptorBindReturnSlot1_
+ {
+ typedef AdaptorBindData1_<R1> Data;
+ typedef typename Slot1<R2,P1>::Proxy Proxy;
+ static R1 proxy(typename Trait<P1>::ref p1,void *data)
+ {
+ Data& node = *reinterpret_cast<Data*>(data);
+ SlotNode* slot = static_cast<SlotNode*>(node.adaptor.slot_.impl());
+ ((Proxy)(slot->proxy_))
+ (p1,slot);
+ return node.c1_;
+ }
+ };
+
+/// @ingroup bind
+template <class R1,class R2,class P1>
+Slot1<R1,P1>
+ bind_return(const Slot1<R2,P1> &s,R1 ret)
+ {
+ typedef AdaptorBindData1_<R1> Data;
+ typedef AdaptorBindReturnSlot1_<R1,R2,P1> Adaptor;
+ return reinterpret_cast<SlotNode*>(
+ new Data((FuncPtr)(&Adaptor::proxy),s,
+ (FuncPtr)(&Data::dtor),ret));
+ }
+
+
+/****************************************************************
+***** Adaptor Return Bind Slot 2 arguments
+****************************************************************/
+template <class R1,class R2,class P1,class P2>
+struct AdaptorBindReturnSlot2_
+ {
+ typedef AdaptorBindData1_<R1> Data;
+ typedef typename Slot2<R2,P1,P2>::Proxy Proxy;
+ static R1 proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void *data)
+ {
+ Data& node = *reinterpret_cast<Data*>(data);
+ SlotNode* slot = static_cast<SlotNode*>(node.adaptor.slot_.impl());
+ ((Proxy)(slot->proxy_))
+ (p1,p2,slot);
+ return node.c1_;
+ }
+ };
+
+/// @ingroup bind
+template <class R1,class R2,class P1,class P2>
+Slot2<R1,P1,P2>
+ bind_return(const Slot2<R2,P1,P2> &s,R1 ret)
+ {
+ typedef AdaptorBindData1_<R1> Data;
+ typedef AdaptorBindReturnSlot2_<R1,R2,P1,P2> Adaptor;
+ return reinterpret_cast<SlotNode*>(
+ new Data((FuncPtr)(&Adaptor::proxy),s,
+ (FuncPtr)(&Data::dtor),ret));
+ }
+
+
+/****************************************************************
+***** Adaptor Return Bind Slot 3 arguments
+****************************************************************/
+template <class R1,class R2,class P1,class P2,class P3>
+struct AdaptorBindReturnSlot3_
+ {
+ typedef AdaptorBindData1_<R1> Data;
+ typedef typename Slot3<R2,P1,P2,P3>::Proxy Proxy;
+ static R1 proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void *data)
+ {
+ Data& node = *reinterpret_cast<Data*>(data);
+ SlotNode* slot = static_cast<SlotNode*>(node.adaptor.slot_.impl());
+ ((Proxy)(slot->proxy_))
+ (p1,p2,p3,slot);
+ return node.c1_;
+ }
+ };
+
+/// @ingroup bind
+template <class R1,class R2,class P1,class P2,class P3>
+Slot3<R1,P1,P2,P3>
+ bind_return(const Slot3<R2,P1,P2,P3> &s,R1 ret)
+ {
+ typedef AdaptorBindData1_<R1> Data;
+ typedef AdaptorBindReturnSlot3_<R1,R2,P1,P2,P3> Adaptor;
+ return reinterpret_cast<SlotNode*>(
+ new Data((FuncPtr)(&Adaptor::proxy),s,
+ (FuncPtr)(&Data::dtor),ret));
+ }
+
+
+/****************************************************************
+***** Adaptor Return Bind Slot 4 arguments
+****************************************************************/
+template <class R1,class R2,class P1,class P2,class P3,class P4>
+struct AdaptorBindReturnSlot4_
+ {
+ typedef AdaptorBindData1_<R1> Data;
+ typedef typename Slot4<R2,P1,P2,P3,P4>::Proxy Proxy;
+ static R1 proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,void *data)
+ {
+ Data& node = *reinterpret_cast<Data*>(data);
+ SlotNode* slot = static_cast<SlotNode*>(node.adaptor.slot_.impl());
+ ((Proxy)(slot->proxy_))
+ (p1,p2,p3,p4,slot);
+ return node.c1_;
+ }
+ };
+
+/// @ingroup bind
+template <class R1,class R2,class P1,class P2,class P3,class P4>
+Slot4<R1,P1,P2,P3,P4>
+ bind_return(const Slot4<R2,P1,P2,P3,P4> &s,R1 ret)
+ {
+ typedef AdaptorBindData1_<R1> Data;
+ typedef AdaptorBindReturnSlot4_<R1,R2,P1,P2,P3,P4> Adaptor;
+ return reinterpret_cast<SlotNode*>(
+ new Data((FuncPtr)(&Adaptor::proxy),s,
+ (FuncPtr)(&Data::dtor),ret));
+ }
+
+
+/****************************************************************
+***** Adaptor Return Bind Slot 5 arguments
+****************************************************************/
+template <class R1,class R2,class P1,class P2,class P3,class P4,class P5>
+struct AdaptorBindReturnSlot5_
+ {
+ typedef AdaptorBindData1_<R1> Data;
+ typedef typename Slot5<R2,P1,P2,P3,P4,P5>::Proxy Proxy;
+ static R1 proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,void *data)
+ {
+ Data& node = *reinterpret_cast<Data*>(data);
+ SlotNode* slot = static_cast<SlotNode*>(node.adaptor.slot_.impl());
+ ((Proxy)(slot->proxy_))
+ (p1,p2,p3,p4,p5,slot);
+ return node.c1_;
+ }
+ };
+
+/// @ingroup bind
+template <class R1,class R2,class P1,class P2,class P3,class P4,class P5>
+Slot5<R1,P1,P2,P3,P4,P5>
+ bind_return(const Slot5<R2,P1,P2,P3,P4,P5> &s,R1 ret)
+ {
+ typedef AdaptorBindData1_<R1> Data;
+ typedef AdaptorBindReturnSlot5_<R1,R2,P1,P2,P3,P4,P5> Adaptor;
+ return reinterpret_cast<SlotNode*>(
+ new Data((FuncPtr)(&Adaptor::proxy),s,
+ (FuncPtr)(&Data::dtor),ret));
+ }
+
+
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+#endif // SIGC_BIND_RETURN_H
diff --git a/src/sigc++/class_slot.cpp b/src/sigc++/class_slot.cpp
new file mode 100644
index 0000000..9ecd34e
--- /dev/null
+++ b/src/sigc++/class_slot.cpp
@@ -0,0 +1,15 @@
+// Copyright 2000, Karl Einar Nelson
+#include "sigc++/class_slot.h"
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+ClassSlotNode::~ClassSlotNode()
+ {}
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
diff --git a/src/sigc++/class_slot.h b/src/sigc++/class_slot.h
new file mode 100644
index 0000000..756367b
--- /dev/null
+++ b/src/sigc++/class_slot.h
@@ -0,0 +1,290 @@
+// -*- c++ -*-
+// Copyright 2000, Karl Einar Nelson
+/* This is a generated file, do not edit. Generated from template.macros.m4 */
+
+
+#ifndef SIGC_CLASS_SLOT
+#define SIGC_CLASS_SLOT
+#include <sigc++/slot.h>
+
+/*
+ SigC::slot_class() (class)
+ -----------------------
+ slot_class() can be applied to a class method to form a Slot with a
+ profile equivalent to the method. At the same time an instance
+ of that class must be specified. This is an unsafe interface.
+
+ This does NOT require that the class be derived from SigC::Object.
+ However, the object should be static with regards to the signal system.
+ (allocated within the global scope.) If it is not and a connected
+ slot is call it will result in a segfault. If the object must
+ be destroyed before the connected slots, all connections must
+ be disconnected by hand.
+
+ Sample usage:
+
+ struct A
+ {
+ void foo(int, int);
+ } a;
+
+ Slot2<void,int,int> s = slot_class(a, &A::foo);
+
+*/
+
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+
+/**************************************************************/
+// These are internal classes used to represent function varients of slots
+
+// (internal)
+struct LIBSIGC_API ClassSlotNode : public SlotNode
+ {
+#ifdef _MSC_VER
+private:
+ /** the sole purpose of this declaration is to introduce a new type that is
+ guaranteed not to be related to any other type. (Ab)using class SigC::Object
+ for this lead to some faulty conversions taking place with MSVC6. */
+ class GenericObject;
+ typedef void (GenericObject::*Method)(void);
+public:
+#else
+ typedef void (SlotNode::*Method)(void);
+#endif
+ void *object_;
+ Method method_;
+
+ template <class T1, class T2>
+ ClassSlotNode(FuncPtr proxy,T1* obj,T2 method)
+ : SlotNode(proxy), object_(obj), method_(reinterpret_cast<Method&>(method))
+ {}
+
+ virtual ~ClassSlotNode();
+ };
+
+
+
+// These do not derive from ClassSlot, they merely are extended
+// ctor wrappers. They introduce how to deal with the proxy.
+template <class R,class Obj>
+struct ClassSlot0_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(void *s)
+ {
+ typedef RType (Obj::*Method)();
+ ClassSlotNode* os = (ClassSlotNode*)(s);
+ return ((Obj*)(os->object_)
+ ->*(reinterpret_cast<Method&>(os->method_)))();
+ }
+ };
+
+template <class R,class Obj>
+ Slot0<R>
+ slot_class(Obj& obj,R (Obj::*method)())
+ {
+ typedef ClassSlot0_<R,Obj> SType;
+ return new ClassSlotNode((FuncPtr)(&SType::proxy),&obj,method);
+ }
+
+template <class R,class Obj>
+ Slot0<R>
+ slot_class(Obj& obj, R (Obj::*method)() const)
+ {
+ typedef ClassSlot0_<R,Obj> SType;
+ return new ClassSlotNode((FuncPtr)(&SType::proxy), &obj, method);
+ }
+
+
+template <class R,class P1,class Obj>
+struct ClassSlot1_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,void *s)
+ {
+ typedef RType (Obj::*Method)(P1);
+ ClassSlotNode* os = (ClassSlotNode*)(s);
+ return ((Obj*)(os->object_)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1);
+ }
+ };
+
+template <class R,class P1,class Obj>
+ Slot1<R,P1>
+ slot_class(Obj& obj,R (Obj::*method)(P1))
+ {
+ typedef ClassSlot1_<R,P1,Obj> SType;
+ return new ClassSlotNode((FuncPtr)(&SType::proxy),&obj,method);
+ }
+
+template <class R,class P1,class Obj>
+ Slot1<R,P1>
+ slot_class(Obj& obj, R (Obj::*method)(P1) const)
+ {
+ typedef ClassSlot1_<R,P1,Obj> SType;
+ return new ClassSlotNode((FuncPtr)(&SType::proxy), &obj, method);
+ }
+
+
+template <class R,class P1,class P2,class Obj>
+struct ClassSlot2_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void *s)
+ {
+ typedef RType (Obj::*Method)(P1,P2);
+ ClassSlotNode* os = (ClassSlotNode*)(s);
+ return ((Obj*)(os->object_)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2);
+ }
+ };
+
+template <class R,class P1,class P2,class Obj>
+ Slot2<R,P1,P2>
+ slot_class(Obj& obj,R (Obj::*method)(P1,P2))
+ {
+ typedef ClassSlot2_<R,P1,P2,Obj> SType;
+ return new ClassSlotNode((FuncPtr)(&SType::proxy),&obj,method);
+ }
+
+template <class R,class P1,class P2,class Obj>
+ Slot2<R,P1,P2>
+ slot_class(Obj& obj, R (Obj::*method)(P1,P2) const)
+ {
+ typedef ClassSlot2_<R,P1,P2,Obj> SType;
+ return new ClassSlotNode((FuncPtr)(&SType::proxy), &obj, method);
+ }
+
+
+template <class R,class P1,class P2,class P3,class Obj>
+struct ClassSlot3_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void *s)
+ {
+ typedef RType (Obj::*Method)(P1,P2,P3);
+ ClassSlotNode* os = (ClassSlotNode*)(s);
+ return ((Obj*)(os->object_)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2,p3);
+ }
+ };
+
+template <class R,class P1,class P2,class P3,class Obj>
+ Slot3<R,P1,P2,P3>
+ slot_class(Obj& obj,R (Obj::*method)(P1,P2,P3))
+ {
+ typedef ClassSlot3_<R,P1,P2,P3,Obj> SType;
+ return new ClassSlotNode((FuncPtr)(&SType::proxy),&obj,method);
+ }
+
+template <class R,class P1,class P2,class P3,class Obj>
+ Slot3<R,P1,P2,P3>
+ slot_class(Obj& obj, R (Obj::*method)(P1,P2,P3) const)
+ {
+ typedef ClassSlot3_<R,P1,P2,P3,Obj> SType;
+ return new ClassSlotNode((FuncPtr)(&SType::proxy), &obj, method);
+ }
+
+
+template <class R,class P1,class P2,class P3,class P4,class Obj>
+struct ClassSlot4_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,void *s)
+ {
+ typedef RType (Obj::*Method)(P1,P2,P3,P4);
+ ClassSlotNode* os = (ClassSlotNode*)(s);
+ return ((Obj*)(os->object_)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2,p3,p4);
+ }
+ };
+
+template <class R,class P1,class P2,class P3,class P4,class Obj>
+ Slot4<R,P1,P2,P3,P4>
+ slot_class(Obj& obj,R (Obj::*method)(P1,P2,P3,P4))
+ {
+ typedef ClassSlot4_<R,P1,P2,P3,P4,Obj> SType;
+ return new ClassSlotNode((FuncPtr)(&SType::proxy),&obj,method);
+ }
+
+template <class R,class P1,class P2,class P3,class P4,class Obj>
+ Slot4<R,P1,P2,P3,P4>
+ slot_class(Obj& obj, R (Obj::*method)(P1,P2,P3,P4) const)
+ {
+ typedef ClassSlot4_<R,P1,P2,P3,P4,Obj> SType;
+ return new ClassSlotNode((FuncPtr)(&SType::proxy), &obj, method);
+ }
+
+
+template <class R,class P1,class P2,class P3,class P4,class P5,class Obj>
+struct ClassSlot5_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,void *s)
+ {
+ typedef RType (Obj::*Method)(P1,P2,P3,P4,P5);
+ ClassSlotNode* os = (ClassSlotNode*)(s);
+ return ((Obj*)(os->object_)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2,p3,p4,p5);
+ }
+ };
+
+template <class R,class P1,class P2,class P3,class P4,class P5,class Obj>
+ Slot5<R,P1,P2,P3,P4,P5>
+ slot_class(Obj& obj,R (Obj::*method)(P1,P2,P3,P4,P5))
+ {
+ typedef ClassSlot5_<R,P1,P2,P3,P4,P5,Obj> SType;
+ return new ClassSlotNode((FuncPtr)(&SType::proxy),&obj,method);
+ }
+
+template <class R,class P1,class P2,class P3,class P4,class P5,class Obj>
+ Slot5<R,P1,P2,P3,P4,P5>
+ slot_class(Obj& obj, R (Obj::*method)(P1,P2,P3,P4,P5) const)
+ {
+ typedef ClassSlot5_<R,P1,P2,P3,P4,P5,Obj> SType;
+ return new ClassSlotNode((FuncPtr)(&SType::proxy), &obj, method);
+ }
+
+
+template <class R,class P1,class P2,class P3,class P4,class P5,class P6,class Obj>
+struct ClassSlot6_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,typename Trait<P6>::ref p6,void *s)
+ {
+ typedef RType (Obj::*Method)(P1,P2,P3,P4,P5,P6);
+ ClassSlotNode* os = (ClassSlotNode*)(s);
+ return ((Obj*)(os->object_)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2,p3,p4,p5,p6);
+ }
+ };
+
+template <class R,class P1,class P2,class P3,class P4,class P5,class P6,class Obj>
+ Slot6<R,P1,P2,P3,P4,P5,P6>
+ slot_class(Obj& obj,R (Obj::*method)(P1,P2,P3,P4,P5,P6))
+ {
+ typedef ClassSlot6_<R,P1,P2,P3,P4,P5,P6,Obj> SType;
+ return new ClassSlotNode((FuncPtr)(&SType::proxy),&obj,method);
+ }
+
+template <class R,class P1,class P2,class P3,class P4,class P5,class P6,class Obj>
+ Slot6<R,P1,P2,P3,P4,P5,P6>
+ slot_class(Obj& obj, R (Obj::*method)(P1,P2,P3,P4,P5,P6) const)
+ {
+ typedef ClassSlot6_<R,P1,P2,P3,P4,P5,P6,Obj> SType;
+ return new ClassSlotNode((FuncPtr)(&SType::proxy), &obj, method);
+ }
+
+
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+#endif /* SIGC_CLASS_SLOT */
+
diff --git a/src/sigc++/connection.cpp b/src/sigc++/connection.cpp
new file mode 100644
index 0000000..9148293
--- /dev/null
+++ b/src/sigc++/connection.cpp
@@ -0,0 +1,91 @@
+// -*- c++ -*-
+/*
+ Copyright 2000, Karl Einar Nelson
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#include "sigc++/connection.h"
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+ConnectionNode::~ConnectionNode()
+ {
+ if (!notified_)
+ slot()->remove_dependency(this);
+ }
+
+ConnectionNode::ConnectionNode(SlotNode* s)
+ : NodeBase(), slot_(s)
+ {
+ if (s) slot()->add_dependency(this);
+ }
+
+NodeBase::Link* ConnectionNode::link()
+ {
+ return &link_;
+ }
+
+bool ConnectionNode::block(bool should_block)
+ {
+ bool old = bool(blocked_);
+ blocked_ = should_block;
+ return old;
+ }
+
+void ConnectionNode::notify(bool from_child)
+ {
+ blocked_ = true;
+
+ if(!from_child && !notified_)
+ slot()->remove_dependency(this);
+
+ slot_.clear();
+ NodeBase::notify(from_child);
+ }
+
+/*************************************************/
+
+void Connection::disconnect()
+ {
+ if (node_)
+ obj()->notify(false); //false = not from_child.
+
+ clear();
+ }
+
+bool Connection::blocked() const
+ {
+ if (!valid())
+ return false;
+
+ return obj()->blocked();
+ }
+
+bool Connection::block(bool should_block)
+ {
+ if (!valid())
+ return false;
+
+ return obj()->block(should_block);
+ }
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+
diff --git a/src/sigc++/connection.h b/src/sigc++/connection.h
new file mode 100644
index 0000000..a2e1efc
--- /dev/null
+++ b/src/sigc++/connection.h
@@ -0,0 +1,102 @@
+// -*- c++ -*-
+/*
+ Copyright 2000, Karl Einar Nelson
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#ifndef SIGC_CONNECTION
+#define SIGC_CONNECTION
+#include <sigc++/slot.h>
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+class Connection;
+
+/** (internal) Base class for use by signals to refer to Slots.
+ * In order to provide a bridge to allow Slots to be severed
+ * or blocked individually, a signal refers to slots indirectly
+ * through a connection. This connection has two parts -
+ * One part is a handle which can be copied and otherwise manipulated.
+ * The other is always dynamic and lives until all connections and
+ * the relation between the signal and slot is destroyed.
+ *
+ * All Signal types should derive their own Connection_ type from this
+ * base class. The derived class should know how to remove the
+ * Connection_ from the signal in case of immediate cleanup.
+ *
+ * A connection must implement the following functions.
+ * disconnect() - message from user that this connection is to be broken.
+ * The derived version must inform the Signal that this Connection_
+ * node is no longer needed. In order to properly inform the base
+ * class, the derived method must also call Connection::disconnect()
+ *
+ * This class handles notification from the slot so you should not
+ * override notify().
+ */
+class LIBSIGC_API ConnectionNode : public NodeBase
+ {
+ public:
+ ConnectionNode(SlotNode*);
+ virtual ~ConnectionNode();
+
+ virtual Link* link();
+ virtual void notify(bool from_child);
+
+ bool blocked() const { return bool(blocked_); }
+ bool block(bool should_block=true);
+ bool unblock() { return block(false); }
+
+ SlotBase& slot()
+ { return static_cast<SlotBase&>(slot_); }
+
+ Link link_;
+ Node slot_;
+ };
+
+/** Represents a signal-slot connection.
+ * Returned by Signal*<>::connect().
+ */
+class LIBSIGC_API Connection : public Node
+ {
+ public:
+ bool connected() const {return valid(); } // returns true if connected
+ void disconnect(); // severs a signal connection
+
+ bool blocked() const; // returns true if blocked
+
+ bool block(bool should_block = true); // blocks/unblocks
+ bool unblock() { return block(false); }
+
+ Connection() : Node() {}
+ Connection(const Connection &c) : Node(c) {}
+ explicit Connection(ConnectionNode *c) : Node() { assign(c); }
+ ~Connection() {}
+
+ Connection& operator=(const Connection& c)
+ { Node::operator=(c); return *this; }
+
+ protected:
+ ConnectionNode* obj() const {return static_cast<ConnectionNode*>(node_);}
+ };
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+
+#endif // SIGC_CONNECTION
diff --git a/src/sigc++/hide.h b/src/sigc++/hide.h
new file mode 100644
index 0000000..3c5a7c9
--- /dev/null
+++ b/src/sigc++/hide.h
@@ -0,0 +1,233 @@
+// -*- c++ -*-
+// Copyright 2000, Martin Schulze <MHL.Schulze@t-online.de>
+// Copyright 2001, Karl Einar Nelson
+/* This is a generated file, do not edit. Generated from template.macros.m4 */
+
+#ifndef SIGC_HIDE_H
+#define SIGC_HIDE_H
+
+/** @defgroup hide
+ * SigC::hide() alters a Slot in that it adds one or two parameters
+ * whose values are ignored on invocation of the Slot.
+ * Thus you can discard one or more of the arguments of a Signal.
+ * You have to specify the type of the parameters to ignore as
+ * template arguments as in
+ * @code
+ * SigC::Slot1<void, int> slot1;
+ * SigC::Slot0<void> slot2 = SigC::hide<int>(slot1);
+ * @endcode
+ *
+ * SigC::hide_return() alters the Slot by
+ * dropping its return value, thus converting it to a void Slot.
+ *
+ * Simple sample usage:
+ *
+ * @code
+ * int f(int);
+ * SigC::Slot1<void, int> s = SigC::hide_return( slot(&f) );
+ * @endcode
+ */
+
+#include <sigc++/adaptor.h>
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+
+template <class R,class H1>
+struct AdaptorHide0_1_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<H1>::ref,void *data)
+ {
+ AdaptorSlotNode& node = *(AdaptorSlotNode*)(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return ((typename Slot0<R>::Proxy)(slot->proxy_))(slot);
+ }
+ };
+
+/// @ingroup hide
+template <class H1,class R>
+Slot1<R,H1>
+hide(const Slot0<R>& s)
+ {
+ return new AdaptorSlotNode( (FuncPtr)(&AdaptorHide0_1_<R,H1>::proxy), s );
+ }
+
+
+template <class R,class H1,class H2>
+struct AdaptorHide0_2_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<H1>::ref,typename Trait<H2>::ref,void *data)
+ {
+ AdaptorSlotNode& node = *(AdaptorSlotNode*)(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return ((typename Slot0<R>::Proxy)(slot->proxy_))(slot);
+ }
+ };
+
+/// @ingroup hide
+template <class H1,class H2,class R>
+Slot2<R,H1,H2>
+hide(const Slot0<R>& s)
+ {
+ return new AdaptorSlotNode( (FuncPtr)(&AdaptorHide0_2_<R,H1,H2>::proxy), s );
+ }
+
+
+template <class R,class P1,class H1>
+struct AdaptorHide1_1_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<H1>::ref,void *data)
+ {
+ AdaptorSlotNode& node = *(AdaptorSlotNode*)(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return ((typename Slot1<R,P1>::Proxy)(slot->proxy_))(p1,slot);
+ }
+ };
+
+/// @ingroup hide
+template <class H1,class R,class P1>
+Slot2<R,P1,H1>
+hide(const Slot1<R,P1>& s)
+ {
+ return new AdaptorSlotNode( (FuncPtr)(&AdaptorHide1_1_<R,P1,H1>::proxy), s );
+ }
+
+
+template <class R,class P1,class H1,class H2>
+struct AdaptorHide1_2_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<H1>::ref,typename Trait<H2>::ref,void *data)
+ {
+ AdaptorSlotNode& node = *(AdaptorSlotNode*)(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return ((typename Slot1<R,P1>::Proxy)(slot->proxy_))(p1,slot);
+ }
+ };
+
+/// @ingroup hide
+template <class H1,class H2,class R,class P1>
+Slot3<R,P1,H1,H2>
+hide(const Slot1<R,P1>& s)
+ {
+ return new AdaptorSlotNode( (FuncPtr)(&AdaptorHide1_2_<R,P1,H1,H2>::proxy), s );
+ }
+
+
+template <class R,class P1,class P2,class H1>
+struct AdaptorHide2_1_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<H1>::ref,void *data)
+ {
+ AdaptorSlotNode& node = *(AdaptorSlotNode*)(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return ((typename Slot2<R,P1,P2>::Proxy)(slot->proxy_))(p1,p2,slot);
+ }
+ };
+
+/// @ingroup hide
+template <class H1,class R,class P1,class P2>
+Slot3<R,P1,P2,H1>
+hide(const Slot2<R,P1,P2>& s)
+ {
+ return new AdaptorSlotNode( (FuncPtr)(&AdaptorHide2_1_<R,P1,P2,H1>::proxy), s );
+ }
+
+
+template <class R,class P1,class P2,class H1,class H2>
+struct AdaptorHide2_2_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<H1>::ref,typename Trait<H2>::ref,void *data)
+ {
+ AdaptorSlotNode& node = *(AdaptorSlotNode*)(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return ((typename Slot2<R,P1,P2>::Proxy)(slot->proxy_))(p1,p2,slot);
+ }
+ };
+
+/// @ingroup hide
+template <class H1,class H2,class R,class P1,class P2>
+Slot4<R,P1,P2,H1,H2>
+hide(const Slot2<R,P1,P2>& s)
+ {
+ return new AdaptorSlotNode( (FuncPtr)(&AdaptorHide2_2_<R,P1,P2,H1,H2>::proxy), s );
+ }
+
+
+template <class R,class P1,class P2,class P3,class H1>
+struct AdaptorHide3_1_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<H1>::ref,void *data)
+ {
+ AdaptorSlotNode& node = *(AdaptorSlotNode*)(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return ((typename Slot3<R,P1,P2,P3>::Proxy)(slot->proxy_))(p1,p2,p3,slot);
+ }
+ };
+
+/// @ingroup hide
+template <class H1,class R,class P1,class P2,class P3>
+Slot4<R,P1,P2,P3,H1>
+hide(const Slot3<R,P1,P2,P3>& s)
+ {
+ return new AdaptorSlotNode( (FuncPtr)(&AdaptorHide3_1_<R,P1,P2,P3,H1>::proxy), s );
+ }
+
+
+template <class R,class P1,class P2,class P3,class H1,class H2>
+struct AdaptorHide3_2_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<H1>::ref,typename Trait<H2>::ref,void *data)
+ {
+ AdaptorSlotNode& node = *(AdaptorSlotNode*)(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return ((typename Slot3<R,P1,P2,P3>::Proxy)(slot->proxy_))(p1,p2,p3,slot);
+ }
+ };
+
+/// @ingroup hide
+template <class H1,class H2,class R,class P1,class P2,class P3>
+Slot5<R,P1,P2,P3,H1,H2>
+hide(const Slot3<R,P1,P2,P3>& s)
+ {
+ return new AdaptorSlotNode( (FuncPtr)(&AdaptorHide3_2_<R,P1,P2,P3,H1,H2>::proxy), s );
+ }
+
+
+template <class R,class P1,class P2,class P3,class P4,class H1>
+struct AdaptorHide4_1_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<H1>::ref,void *data)
+ {
+ AdaptorSlotNode& node = *(AdaptorSlotNode*)(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return ((typename Slot4<R,P1,P2,P3,P4>::Proxy)(slot->proxy_))(p1,p2,p3,p4,slot);
+ }
+ };
+
+/// @ingroup hide
+template <class H1,class R,class P1,class P2,class P3,class P4>
+Slot5<R,P1,P2,P3,P4,H1>
+hide(const Slot4<R,P1,P2,P3,P4>& s)
+ {
+ return new AdaptorSlotNode( (FuncPtr)(&AdaptorHide4_1_<R,P1,P2,P3,P4,H1>::proxy), s );
+ }
+
+
+
+#ifdef SIGC_CXX_NAMESPACES
+} // namespace SigC
+#endif
+
+#endif // SIGC_HIDE_H
diff --git a/src/sigc++/marshal.h b/src/sigc++/marshal.h
new file mode 100644
index 0000000..e9b42d9
--- /dev/null
+++ b/src/sigc++/marshal.h
@@ -0,0 +1,136 @@
+// Copyright 2000, Karl Einar Nelson
+#ifndef SIGCXX_MARSHALLER_H
+#define SIGCXX_MARSHALLER_H
+#include <sigc++/sigcconfig.h>
+#include <sigc++/trait.h>
+
+#ifndef SIGC_CXX_INT_CTOR
+#include <new>
+#endif
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+/*
+
+All classes used to marshal return values should have the following API:
+
+ class SomeMarshal
+ {
+ // both typedefs must be defined.
+ typedef Type1 InType;
+ typedef Type2 OutType;
+
+ public:
+ // Return final return code.
+ OutType value();
+
+ // Captures return codes and returns TRUE to stop emittion.
+ bool marshal(const InType&);
+
+ SomeMarshal();
+ };
+
+It is not necessary for the InType to match the OutType.
+This is to allow for things like list capturing.
+
+*/
+
+/*******************************************************************
+***** Marshal
+*******************************************************************/
+
+// Basic Marshal class.
+template <typename R>
+class Marshal
+ {
+ public:
+ typedef R OutType;
+ typedef typename Trait<R>::type InType;
+ protected:
+#ifdef SIGC_CXX_PARTIAL_SPEC
+ typedef OutType OutType_;
+#else
+ typedef InType OutType_;
+#endif
+ OutType_ value_;
+ public:
+ OutType_& value() {return value_;}
+
+ static OutType_ default_value()
+#ifdef SIGC_CXX_INT_CTOR
+ {return OutType_();}
+#else
+ {OutType_ r; new (&r) OutType_(); return r;}
+#endif
+
+ // This captures return values. Return TRUE to stop emittion process.
+ bool marshal(const InType& newval)
+ {
+ value_=newval;
+ return 0; // continue emittion process
+ };
+ Marshal()
+#ifdef SIGC_CXX_INT_CTOR
+ :value_()
+ {}
+#else
+ {
+ new (&value_) OutType_();
+ }
+#endif
+ };
+
+#ifdef SIGC_CXX_SPECIALIZE_REFERENCES
+// Basic Marshal class.
+template <typename R>
+class Marshal<R&>
+ {
+ public:
+ typedef R& OutType;
+ typedef R& InType;
+ R* value_;
+ OutType value() {return *value_;}
+ static OutType default_value() {return Default;}
+ static R Default;
+
+ // This captures return values. Return TRUE to stop emittion process.
+ bool marshal(InType newval)
+ {
+ value_=&newval;
+ return 0; // continue emittion process
+ };
+ Marshal()
+ :value_(&Default)
+ {}
+ ~Marshal()
+ {}
+ };
+
+template <typename T> T Marshal<T&>::Default;
+#endif
+
+#ifdef SIGC_CXX_PARTIAL_SPEC
+// dummy marshaller for void type.
+template <>
+class Marshal<void>
+ {
+ public:
+ typedef void OutType;
+ static void default_value() {}
+ static void value() {}
+ Marshal()
+ {}
+ ~Marshal()
+ {}
+ };
+#endif
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+
+#endif
diff --git a/src/sigc++/method_slot.cpp b/src/sigc++/method_slot.cpp
new file mode 100644
index 0000000..f1eb4c2
--- /dev/null
+++ b/src/sigc++/method_slot.cpp
@@ -0,0 +1,25 @@
+// Copyright 2000, Karl Einar Nelson
+#include "sigc++/method_slot.h"
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+void MethodSlotNode::init(Method method)
+ { method_=method; }
+
+MethodSlotNode::~MethodSlotNode()
+ {}
+
+void ConstMethodSlotNode::init(Method method)
+ { method_=method; }
+
+ConstMethodSlotNode::~ConstMethodSlotNode()
+ {}
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+
diff --git a/src/sigc++/method_slot.h b/src/sigc++/method_slot.h
new file mode 100644
index 0000000..76eea7b
--- /dev/null
+++ b/src/sigc++/method_slot.h
@@ -0,0 +1,346 @@
+// -*- c++ -*-
+// Copyright 2000, Karl Einar Nelson
+/* This is a generated file, do not edit. Generated from template.macros.m4 */
+
+
+#ifndef SIGC_METHOD_SLOT
+#define SIGC_METHOD_SLOT
+#include <sigc++/slot.h>
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+/**************************************************************/
+// These are internal classes used to represent function varients of slots
+
+class Object;
+// (internal)
+struct LIBSIGC_API MethodSlotNode : public SlotNode
+ {
+#ifdef _MSC_VER
+private:
+ /** the sole purpose of this declaration is to introduce a new type that is
+ guaranteed not to be related to any other type. (Ab)using class SigC::Object
+ for this lead to some faulty conversions taking place with MSVC6. */
+ class GenericObject;
+ typedef void* (GenericObject::*Method)(void*);
+public:
+#else
+ typedef void* (Object::*Method)(void*);
+#endif
+ Method method_;
+
+ template <class T2>
+ MethodSlotNode(FuncPtr proxy,T2 method)
+ : SlotNode(proxy)
+ { init(reinterpret_cast<Method&>(method)); }
+ void init(Method method);
+ virtual ~MethodSlotNode();
+ };
+
+struct LIBSIGC_API ConstMethodSlotNode : public SlotNode
+ {
+#ifdef _MSC_VER
+private:
+ /** the sole purpose of this declaration is to introduce a new type that is
+ guaranteed not to be related to any other type. (Ab)using class SigC::Object
+ for this lead to some faulty conversions taking place with MSVC6. */
+ class GenericObject;
+ typedef void* (GenericObject::*Method)(void*) const;
+public:
+#else
+ typedef void* (Object::*Method)(void*) const;
+#endif
+ Method method_;
+
+ template <class T2>
+ ConstMethodSlotNode(FuncPtr proxy,T2 method)
+ : SlotNode(proxy)
+ { init(reinterpret_cast<Method&>(method)); }
+ void init(Method method);
+ virtual ~ConstMethodSlotNode();
+ };
+
+
+
+// These do not derive from MethodSlot, they merely are extended
+// ctor wrappers. They introduce how to deal with the proxy.
+template <class R,class Obj>
+struct MethodSlot0_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(Obj& obj,void * s)
+ {
+ typedef RType (Obj::*Method)();
+ MethodSlotNode* os = (MethodSlotNode*)s;
+ return ((Obj*)(&obj)
+ ->*(reinterpret_cast<Method&>(os->method_)))();
+ }
+ };
+
+template <class R,class Obj>
+struct ConstMethodSlot0_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(Obj& obj,void * s)
+ {
+ typedef RType (Obj::*Method)() const;
+ ConstMethodSlotNode* os = (ConstMethodSlotNode*)s;
+ return ((Obj*)(&obj)
+ ->*(reinterpret_cast<Method&>(os->method_)))();
+ }
+ };
+
+template <class R,class Obj>
+Slot1<R,Obj&>
+ slot(R (Obj::*method)())
+ {
+ typedef MethodSlot0_<R,Obj> SType;
+ return new MethodSlotNode((FuncPtr)(&SType::proxy),
+ method);
+ }
+
+template <class R,class Obj>
+Slot1<R,const Obj&>
+ slot(R (Obj::*method)() const)
+ {
+ typedef ConstMethodSlot0_<R,Obj> SType;
+ return new ConstMethodSlotNode((FuncPtr)(&SType::proxy),
+ method);
+ }
+
+
+template <class R,class Obj,class P1>
+struct MethodSlot1_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(Obj& obj,typename Trait<P1>::ref p1,void * s)
+ {
+ typedef RType (Obj::*Method)(P1);
+ MethodSlotNode* os = (MethodSlotNode*)s;
+ return ((Obj*)(&obj)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1);
+ }
+ };
+
+template <class R,class Obj,class P1>
+struct ConstMethodSlot1_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(Obj& obj,typename Trait<P1>::ref p1,void * s)
+ {
+ typedef RType (Obj::*Method)(P1) const;
+ ConstMethodSlotNode* os = (ConstMethodSlotNode*)s;
+ return ((Obj*)(&obj)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1);
+ }
+ };
+
+template <class R,class Obj,class P1>
+Slot2<R,Obj&,P1>
+ slot(R (Obj::*method)(P1))
+ {
+ typedef MethodSlot1_<R,Obj,P1> SType;
+ return new MethodSlotNode((FuncPtr)(&SType::proxy),
+ method);
+ }
+
+template <class R,class Obj,class P1>
+Slot2<R,const Obj&,P1>
+ slot(R (Obj::*method)(P1) const)
+ {
+ typedef ConstMethodSlot1_<R,Obj,P1> SType;
+ return new ConstMethodSlotNode((FuncPtr)(&SType::proxy),
+ method);
+ }
+
+
+template <class R,class Obj,class P1,class P2>
+struct MethodSlot2_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(Obj& obj,typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void * s)
+ {
+ typedef RType (Obj::*Method)(P1,P2);
+ MethodSlotNode* os = (MethodSlotNode*)s;
+ return ((Obj*)(&obj)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2);
+ }
+ };
+
+template <class R,class Obj,class P1,class P2>
+struct ConstMethodSlot2_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(Obj& obj,typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void * s)
+ {
+ typedef RType (Obj::*Method)(P1,P2) const;
+ ConstMethodSlotNode* os = (ConstMethodSlotNode*)s;
+ return ((Obj*)(&obj)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2);
+ }
+ };
+
+template <class R,class Obj,class P1,class P2>
+Slot3<R,Obj&,P1,P2>
+ slot(R (Obj::*method)(P1,P2))
+ {
+ typedef MethodSlot2_<R,Obj,P1,P2> SType;
+ return new MethodSlotNode((FuncPtr)(&SType::proxy),
+ method);
+ }
+
+template <class R,class Obj,class P1,class P2>
+Slot3<R,const Obj&,P1,P2>
+ slot(R (Obj::*method)(P1,P2) const)
+ {
+ typedef ConstMethodSlot2_<R,Obj,P1,P2> SType;
+ return new ConstMethodSlotNode((FuncPtr)(&SType::proxy),
+ method);
+ }
+
+
+template <class R,class Obj,class P1,class P2,class P3>
+struct MethodSlot3_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(Obj& obj,typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void * s)
+ {
+ typedef RType (Obj::*Method)(P1,P2,P3);
+ MethodSlotNode* os = (MethodSlotNode*)s;
+ return ((Obj*)(&obj)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2,p3);
+ }
+ };
+
+template <class R,class Obj,class P1,class P2,class P3>
+struct ConstMethodSlot3_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(Obj& obj,typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void * s)
+ {
+ typedef RType (Obj::*Method)(P1,P2,P3) const;
+ ConstMethodSlotNode* os = (ConstMethodSlotNode*)s;
+ return ((Obj*)(&obj)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2,p3);
+ }
+ };
+
+template <class R,class Obj,class P1,class P2,class P3>
+Slot4<R,Obj&,P1,P2,P3>
+ slot(R (Obj::*method)(P1,P2,P3))
+ {
+ typedef MethodSlot3_<R,Obj,P1,P2,P3> SType;
+ return new MethodSlotNode((FuncPtr)(&SType::proxy),
+ method);
+ }
+
+template <class R,class Obj,class P1,class P2,class P3>
+Slot4<R,const Obj&,P1,P2,P3>
+ slot(R (Obj::*method)(P1,P2,P3) const)
+ {
+ typedef ConstMethodSlot3_<R,Obj,P1,P2,P3> SType;
+ return new ConstMethodSlotNode((FuncPtr)(&SType::proxy),
+ method);
+ }
+
+
+template <class R,class Obj,class P1,class P2,class P3,class P4>
+struct MethodSlot4_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(Obj& obj,typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,void * s)
+ {
+ typedef RType (Obj::*Method)(P1,P2,P3,P4);
+ MethodSlotNode* os = (MethodSlotNode*)s;
+ return ((Obj*)(&obj)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2,p3,p4);
+ }
+ };
+
+template <class R,class Obj,class P1,class P2,class P3,class P4>
+struct ConstMethodSlot4_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(Obj& obj,typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,void * s)
+ {
+ typedef RType (Obj::*Method)(P1,P2,P3,P4) const;
+ ConstMethodSlotNode* os = (ConstMethodSlotNode*)s;
+ return ((Obj*)(&obj)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2,p3,p4);
+ }
+ };
+
+template <class R,class Obj,class P1,class P2,class P3,class P4>
+Slot5<R,Obj&,P1,P2,P3,P4>
+ slot(R (Obj::*method)(P1,P2,P3,P4))
+ {
+ typedef MethodSlot4_<R,Obj,P1,P2,P3,P4> SType;
+ return new MethodSlotNode((FuncPtr)(&SType::proxy),
+ method);
+ }
+
+template <class R,class Obj,class P1,class P2,class P3,class P4>
+Slot5<R,const Obj&,P1,P2,P3,P4>
+ slot(R (Obj::*method)(P1,P2,P3,P4) const)
+ {
+ typedef ConstMethodSlot4_<R,Obj,P1,P2,P3,P4> SType;
+ return new ConstMethodSlotNode((FuncPtr)(&SType::proxy),
+ method);
+ }
+
+
+template <class R,class Obj,class P1,class P2,class P3,class P4,class P5>
+struct MethodSlot5_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(Obj& obj,typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,void * s)
+ {
+ typedef RType (Obj::*Method)(P1,P2,P3,P4,P5);
+ MethodSlotNode* os = (MethodSlotNode*)s;
+ return ((Obj*)(&obj)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2,p3,p4,p5);
+ }
+ };
+
+template <class R,class Obj,class P1,class P2,class P3,class P4,class P5>
+struct ConstMethodSlot5_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(Obj& obj,typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,void * s)
+ {
+ typedef RType (Obj::*Method)(P1,P2,P3,P4,P5) const;
+ ConstMethodSlotNode* os = (ConstMethodSlotNode*)s;
+ return ((Obj*)(&obj)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2,p3,p4,p5);
+ }
+ };
+
+template <class R,class Obj,class P1,class P2,class P3,class P4,class P5>
+Slot6<R,Obj&,P1,P2,P3,P4,P5>
+ slot(R (Obj::*method)(P1,P2,P3,P4,P5))
+ {
+ typedef MethodSlot5_<R,Obj,P1,P2,P3,P4,P5> SType;
+ return new MethodSlotNode((FuncPtr)(&SType::proxy),
+ method);
+ }
+
+template <class R,class Obj,class P1,class P2,class P3,class P4,class P5>
+Slot6<R,const Obj&,P1,P2,P3,P4,P5>
+ slot(R (Obj::*method)(P1,P2,P3,P4,P5) const)
+ {
+ typedef ConstMethodSlot5_<R,Obj,P1,P2,P3,P4,P5> SType;
+ return new ConstMethodSlotNode((FuncPtr)(&SType::proxy),
+ method);
+ }
+
+
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+
+#endif // SIGC_SLOT
diff --git a/src/sigc++/node.cpp b/src/sigc++/node.cpp
new file mode 100644
index 0000000..b3784d8
--- /dev/null
+++ b/src/sigc++/node.cpp
@@ -0,0 +1,84 @@
+// -*- c++ -*-
+/*
+ Copyright 2000, Karl Einar Nelson
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#include "sigc++/node.h"
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+NodeBase::Link* NodeBase::link()
+ {
+ return 0;
+ }
+
+
+void NodeBase::notify(bool /*from_child*/)
+ {
+ notified_=1;
+ }
+
+NodeBase::NodeBase()
+ : count_(0), notified_(0), blocked_(0), defered_(0)
+ {}
+
+NodeBase::~NodeBase()
+ {}
+
+/**************************************************************/
+
+bool Node::valid() const
+ {
+ if (node_)
+ if (!node_->notified_)
+ return true;
+ else
+ clear();
+ return false;
+ }
+
+void Node::assign(NodeBase* node)
+ {
+ node_=node;
+ if (node_)
+ node_->reference();
+ }
+
+void Node::clear() const
+ {
+ if (node_)
+ node_->unreference();
+ node_=0;
+ }
+
+Node& Node::operator =(const Node& node)
+ {
+ node.valid();
+ if (node_==node.node_)
+ return *this;
+ clear();
+ assign(node.node_);
+ return *this;
+ }
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+
diff --git a/src/sigc++/node.h b/src/sigc++/node.h
new file mode 100644
index 0000000..eb586c1
--- /dev/null
+++ b/src/sigc++/node.h
@@ -0,0 +1,99 @@
+// -*- c++ -*-
+/*
+ Copyright 2000, Karl Einar Nelson
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#ifndef SIGC_NODE
+#define SIGC_NODE
+#include <sigc++/sigcconfig.h>
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+// common portion of all sigc internals.
+// must be dynamic.
+class LIBSIGC_API NodeBase
+ {
+ public:
+
+ // Type used to build lists.
+ struct Link { NodeBase *next_,*prev_; };
+
+ /* link & notify must be implemented if the object can be a dependency */
+ // Link to list holding dependency
+ virtual Link* link(); // nothrow
+
+ // Called by object on which node depends
+ // TODO: Please document what from_child exactly means, i.e. in
+ // which context is what called a "child", and why there has to be
+ // a distinction between "child" and non-"child". Examples would
+ // be really nice.
+ virtual void notify(bool from_child); // nothrow
+
+ // referencing
+ void reference() // nothrow
+ { count_+=1; }
+ void unreference() // nothrow
+ { if (!--count_) delete this; }
+
+ NodeBase();
+ virtual ~NodeBase();
+
+ // these should be atomics
+ int count_; // reference count
+
+ // flags are shared with derived classes to save space
+ unsigned int notified_ :1; // we have been notified, no need to remove self
+
+ // connection flags
+ unsigned int blocked_ :1; // skip callling.
+ unsigned int defered_ :1; // skip callling.
+
+ private:
+ NodeBase(const NodeBase&); // not copiable
+ NodeBase& operator=(const NodeBase&); // not copiable
+ };
+
+class LIBSIGC_API Node
+ {
+ public:
+ operator bool() const { return valid(); }
+ bool empty() const { return !valid(); }
+ void clear() const;
+
+ Node() : node_(0) {}
+ SIGC_CXX_EXPLICIT_COPY Node(const Node& s)
+ { s.valid(); assign(s.node_); }
+ SIGC_CXX_EXPLICIT Node(NodeBase* s) { assign(s); }
+ ~Node() { clear(); }
+ void* impl() const { return node_; }
+
+ protected:
+ // this verifies the node is valid else severs the link
+ bool valid() const;
+ void assign(NodeBase* node);
+ Node& operator =(const Node&);
+ mutable NodeBase* node_;
+ };
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+
+#endif // SIGC_NODE
diff --git a/src/sigc++/object.cpp b/src/sigc++/object.cpp
new file mode 100644
index 0000000..d01b8d6
--- /dev/null
+++ b/src/sigc++/object.cpp
@@ -0,0 +1,166 @@
+// -*- c++ -*-
+/*
+ Copyright 2000, Karl Einar Nelson
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#include "sigc++/object_slot.h"
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+int sigc_major_version = SIGC_MAJOR_VERSION;
+int sigc_minor_version = SIGC_MINOR_VERSION;
+int sigc_micro_version = SIGC_MICRO_VERSION;
+
+Control_::Control_(const ObjectBase* object)
+ : object_(object), dep_(0), count_(0), ccount_(1), manage_(0)
+ {}
+
+Control_::~Control_()
+{}
+
+void Control_::cref()
+{
+ ccount_ += 1;
+}
+
+void Control_::cunref()
+{
+ if (!--ccount_)
+ delete this;
+}
+
+void Control_::ref()
+{
+ count_++;
+ cref();
+}
+
+void Control_::unref()
+{
+ if ( !(--count_) && manage_ )
+ delete object_;
+
+ cunref();
+}
+
+void Control_::destroy()
+ {
+ object_ = 0;
+ manage_ = 0;
+ NodeBase* n = dep_;
+ while (n)
+ {
+ NodeBase* next = n->link()->next_;
+ n->notify(false);
+ n = next;
+ }
+ dep_ = 0;
+ cunref();
+ }
+
+void Control_::add_dependency(NodeBase* node)
+ {
+ NodeBase::Link* link= node->link();
+ if (!link) return;
+ link->next_ =dep_;
+ link->prev_ = 0;
+ if (dep_)
+ dep_->link()->prev_ = node;
+ dep_ = node;
+ }
+
+void Control_::remove_dependency(NodeBase* node)
+ {
+ NodeBase::Link *link= node->link();
+ NodeBase::Link *nlink,*plink;
+ if (dep_ == node)
+ dep_ = link->next_;
+
+ if (link->next_)
+ {
+ nlink = link->next_->link();
+ nlink->prev_ = link->prev_;
+ }
+
+ if (link->prev_)
+ {
+ plink = link->prev_->link();
+ plink->next_ = link->next_;
+ }
+ }
+
+Object::Object()
+ {}
+Object::~Object()
+ {}
+
+ObjectBase::~ObjectBase()
+ {
+ if (control_)
+ control_->destroy();
+ control_ = 0;
+ }
+
+void ObjectBase::add_dependency(NodeBase* n)
+ {
+ if (!n)
+ return;
+
+ if (!control_)
+ control_ = new Control_(this);
+
+ control_->add_dependency(n);
+ }
+
+void ObjectBase::remove_dependency(NodeBase* n)
+ {
+ if (!n)
+ return;
+
+ if (!control_)
+ control_ = new Control_(this);
+
+ control_->remove_dependency(n);
+ }
+
+void ObjectBase::reference() const
+ {
+ if (!control_)
+ control_ = new Control_(this);
+ control_->ref();
+ }
+
+void ObjectBase::unreference() const
+ {
+ if (!control_)
+ control_ = new Control_(this);
+ control_->unref();
+ }
+
+void ObjectBase::set_manage()
+ {
+ if (!control_)
+ control_ = new Control_(this);
+ control_->manage_ = 1;
+ }
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
diff --git a/src/sigc++/object.h b/src/sigc++/object.h
new file mode 100644
index 0000000..fb3d599
--- /dev/null
+++ b/src/sigc++/object.h
@@ -0,0 +1,200 @@
+// -*- c++ -*-
+/*
+ Copyright 2000, Karl Einar Nelson
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#ifndef SIGC_OBJECT
+#define SIGC_OBJECT
+#include <sigc++/sigcconfig.h>
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+// version numbers
+extern int sigc_micro_version;
+extern int sigc_minor_version;
+extern int sigc_major_version;
+
+class LIBSIGC_API NodeBase;
+class LIBSIGC_API ObjectBase;
+
+// (internal)
+//TODO: What does Control_ do?
+struct LIBSIGC_API Control_
+ {
+ const ObjectBase* object_;
+ NodeBase* dep_; //TODO: What is this used for?
+ unsigned int count_ : 15; //TODO: What does 15 mean?
+ unsigned int ccount_ : 16; //TODO: What does 16 mean?
+ unsigned int manage_ : 1; //TODO: Why not bool?
+
+ void add_dependency(NodeBase* node);
+ void remove_dependency(NodeBase* node);
+
+ void cref();
+ void cunref();
+ void ref();
+ void unref();
+
+ void destroy();
+
+ SIGC_CXX_EXPLICIT Control_(const ObjectBase* object);
+ ~Control_();
+ };
+
+
+class LIBSIGC_API ObjectBase
+ {
+ public:
+ friend class ObjectSlot_;
+ void add_dependency(NodeBase*);
+ void remove_dependency(NodeBase*);
+
+ virtual void reference() const;
+ virtual void unreference() const;
+ virtual void set_manage();
+
+ ObjectBase& operator=(const ObjectBase& /* o */)
+ { return *this; }
+
+ ObjectBase()
+ : control_(0) {}
+
+ SIGC_CXX_EXPLICIT_COPY ObjectBase(const ObjectBase& o)
+ : control_(0) {}
+
+ virtual ~ObjectBase()=0;
+
+ Control_* control()
+ {
+ if (!control_)
+ control_ = new Control_(this);
+
+ return control_;
+ }
+
+ private:
+ mutable Control_* control_;
+ };
+
+/** @defgroup Object
+ * Classes whose member methods are signal handlers (used as Slots) must derive from SigC::Object.
+ * This allows libsigc++ to disconnect signals when the signal handlers' objects are deleted.
+ *
+ * For instance, in gtkmm, all widgets already derive from SigC::Object.
+ *
+ * In case you don't need/want the automatic, safe behaviour, you can also use the
+ * slot_class<> template-functions.
+ */
+
+/// @ingroup Object
+class LIBSIGC_API Object: virtual public ObjectBase
+ {
+ public:
+ Object();
+ virtual ~Object();
+ };
+
+// gtkmm namespaces this as Gtk::manage().
+template <class T>
+T* manage(T* t)
+ { t->set_manage(); return t; }
+
+//Shared reference-counting smart-pointer.
+template <class T>
+class Ptr
+ {
+ public:
+ Ptr()
+ { assign(); }
+
+ Ptr(T* t)
+ { assign(t); }
+
+ template <class T2>
+ Ptr(const Ptr<T2>& p2)
+ {
+ T* test_assignment_ = (T2*)0;
+ assign( p2.get() );
+ }
+
+ Ptr(const Ptr& p)
+ { assign(p.get()); }
+
+ ~Ptr()
+ { if (control_) control_->unref(); }
+
+ Ptr& operator=(T* t)
+ { reset(t); return *this; }
+
+ template <class T2>
+ Ptr& operator=(const Ptr<T2>& p2)
+ { T *test_assignment_=(T2*)0; reset(p2.get()); return *this; }
+
+ Ptr& operator=(const Ptr& p)
+ { reset(p.get()); return *this; }
+
+ T& operator*() const { return *get(); }
+ T* operator->() const { return get(); }
+ operator T*() const { return get(); }
+
+ T* get() const
+ {
+ if (!control_)
+ return 0;
+
+ if (!control_->object_)
+ {
+ control_->cunref();
+ control_ = 0;
+ return 0;
+ }
+ return object_;
+ }
+
+ private:
+ void assign(T* t = 0)
+ {
+ object_ = t;
+ control_ = (object_ ? object_->control() : 0 );
+ if (control_)
+ control_->ref();
+ }
+
+ void reset(T* t = 0)
+ {
+ if (object_ == t)
+ return;
+
+ if (control_)
+ control_->unref();
+
+ assign(t);
+ }
+
+ mutable Control_* control_;
+ T* object_;
+ };
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+
+#endif // SIGC_OBJECT
+
diff --git a/src/sigc++/object_slot.cpp b/src/sigc++/object_slot.cpp
new file mode 100644
index 0000000..e6b144f
--- /dev/null
+++ b/src/sigc++/object_slot.cpp
@@ -0,0 +1,37 @@
+// Copyright 2000, Karl Einar Nelson
+#include "sigc++/object_slot.h"
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+NodeBase::Link* ObjectSlotNode::link()
+ { return &link_; }
+
+void ObjectSlotNode::init(Object* control, void* object, Method method)
+ {
+ control_=control->control();
+ object_=object;
+ method_=method;
+ control_->add_dependency(this);
+ }
+
+void ObjectSlotNode::notify(bool from_child)
+ {
+ if (!from_child)
+ control_->remove_dependency(this);
+ SlotNode::notify(from_child);
+ }
+
+ObjectSlotNode::~ObjectSlotNode()
+ {
+ if (!notified_)
+ control_->remove_dependency(this);
+ }
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+
diff --git a/src/sigc++/object_slot.h b/src/sigc++/object_slot.h
new file mode 100644
index 0000000..b8d1ec7
--- /dev/null
+++ b/src/sigc++/object_slot.h
@@ -0,0 +1,327 @@
+// -*- c++ -*-
+// Copyright 2000, Karl Einar Nelson
+/* This is a generated file, do not edit. Generated from template.macros.m4 */
+
+
+#ifndef SIGC_OBJECT_SLOT
+#define SIGC_OBJECT_SLOT
+#include <sigc++/slot.h>
+#include <sigc++/object.h>
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+/**************************************************************/
+// These are internal classes used to represent function varients of slots
+
+// (internal)
+struct LIBSIGC_API ObjectSlotNode : public SlotNode
+ {
+#ifdef _MSC_VER
+private:
+ /** the sole purpose of this declaration is to introduce a new type that is
+ guaranteed not to be related to any other type. (Ab)using class SigC::Object
+ for this lead to some faulty conversions taking place with MSVC6. */
+ class GenericObject;
+ typedef void (GenericObject::*Method)(void);
+public:
+#else
+ typedef void (Object::*Method)(void);
+#endif
+ Control_ *control_;
+ void *object_;
+ Method method_;
+ Link link_;
+
+ // Can be a dependency
+ virtual Link* link();
+ virtual void notify(bool from_child);
+
+ template <class T,class T2>
+ ObjectSlotNode(FuncPtr proxy,T* control,void *object,T2 method)
+ : SlotNode(proxy)
+ { init(control,object,reinterpret_cast<Method&>(method)); }
+ void init(Object* control, void* object, Method method);
+ virtual ~ObjectSlotNode();
+ };
+
+
+
+// These do not derive from ObjectSlot, they merely are extended
+// ctor wrappers. They introduce how to deal with the proxy.
+template <class R,class Obj>
+struct ObjectSlot0_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(void * s)
+ {
+ typedef RType (Obj::*Method)();
+ ObjectSlotNode* os = (ObjectSlotNode*)s;
+ return ((Obj*)(os->object_)
+ ->*(reinterpret_cast<Method&>(os->method_)))();
+ }
+ };
+
+template <class R,class O1,class O2>
+Slot0<R>
+ slot(O1& obj,R (O2::*method)())
+ {
+ typedef ObjectSlot0_<R,O2> SType;
+ O2& obj_of_method = obj;
+ return new ObjectSlotNode((FuncPtr)(&SType::proxy),
+ &obj,
+ &obj_of_method,
+ method);
+ }
+
+template <class R,class O1,class O2>
+Slot0<R>
+ slot(O1& obj,R (O2::*method)() const)
+ {
+ typedef ObjectSlot0_<R,O2> SType;
+ O2& obj_of_method = obj;
+ return new ObjectSlotNode((FuncPtr)(&SType::proxy),
+ &obj,
+ &obj_of_method,
+ method);
+ }
+
+
+template <class R,class P1,class Obj>
+struct ObjectSlot1_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,void * s)
+ {
+ typedef RType (Obj::*Method)(P1);
+ ObjectSlotNode* os = (ObjectSlotNode*)s;
+ return ((Obj*)(os->object_)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1);
+ }
+ };
+
+template <class R,class P1,class O1,class O2>
+Slot1<R,P1>
+ slot(O1& obj,R (O2::*method)(P1))
+ {
+ typedef ObjectSlot1_<R,P1,O2> SType;
+ O2& obj_of_method = obj;
+ return new ObjectSlotNode((FuncPtr)(&SType::proxy),
+ &obj,
+ &obj_of_method,
+ method);
+ }
+
+template <class R,class P1,class O1,class O2>
+Slot1<R,P1>
+ slot(O1& obj,R (O2::*method)(P1) const)
+ {
+ typedef ObjectSlot1_<R,P1,O2> SType;
+ O2& obj_of_method = obj;
+ return new ObjectSlotNode((FuncPtr)(&SType::proxy),
+ &obj,
+ &obj_of_method,
+ method);
+ }
+
+
+template <class R,class P1,class P2,class Obj>
+struct ObjectSlot2_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void * s)
+ {
+ typedef RType (Obj::*Method)(P1,P2);
+ ObjectSlotNode* os = (ObjectSlotNode*)s;
+ return ((Obj*)(os->object_)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2);
+ }
+ };
+
+template <class R,class P1,class P2,class O1,class O2>
+Slot2<R,P1,P2>
+ slot(O1& obj,R (O2::*method)(P1,P2))
+ {
+ typedef ObjectSlot2_<R,P1,P2,O2> SType;
+ O2& obj_of_method = obj;
+ return new ObjectSlotNode((FuncPtr)(&SType::proxy),
+ &obj,
+ &obj_of_method,
+ method);
+ }
+
+template <class R,class P1,class P2,class O1,class O2>
+Slot2<R,P1,P2>
+ slot(O1& obj,R (O2::*method)(P1,P2) const)
+ {
+ typedef ObjectSlot2_<R,P1,P2,O2> SType;
+ O2& obj_of_method = obj;
+ return new ObjectSlotNode((FuncPtr)(&SType::proxy),
+ &obj,
+ &obj_of_method,
+ method);
+ }
+
+
+template <class R,class P1,class P2,class P3,class Obj>
+struct ObjectSlot3_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void * s)
+ {
+ typedef RType (Obj::*Method)(P1,P2,P3);
+ ObjectSlotNode* os = (ObjectSlotNode*)s;
+ return ((Obj*)(os->object_)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2,p3);
+ }
+ };
+
+template <class R,class P1,class P2,class P3,class O1,class O2>
+Slot3<R,P1,P2,P3>
+ slot(O1& obj,R (O2::*method)(P1,P2,P3))
+ {
+ typedef ObjectSlot3_<R,P1,P2,P3,O2> SType;
+ O2& obj_of_method = obj;
+ return new ObjectSlotNode((FuncPtr)(&SType::proxy),
+ &obj,
+ &obj_of_method,
+ method);
+ }
+
+template <class R,class P1,class P2,class P3,class O1,class O2>
+Slot3<R,P1,P2,P3>
+ slot(O1& obj,R (O2::*method)(P1,P2,P3) const)
+ {
+ typedef ObjectSlot3_<R,P1,P2,P3,O2> SType;
+ O2& obj_of_method = obj;
+ return new ObjectSlotNode((FuncPtr)(&SType::proxy),
+ &obj,
+ &obj_of_method,
+ method);
+ }
+
+
+template <class R,class P1,class P2,class P3,class P4,class Obj>
+struct ObjectSlot4_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,void * s)
+ {
+ typedef RType (Obj::*Method)(P1,P2,P3,P4);
+ ObjectSlotNode* os = (ObjectSlotNode*)s;
+ return ((Obj*)(os->object_)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2,p3,p4);
+ }
+ };
+
+template <class R,class P1,class P2,class P3,class P4,class O1,class O2>
+Slot4<R,P1,P2,P3,P4>
+ slot(O1& obj,R (O2::*method)(P1,P2,P3,P4))
+ {
+ typedef ObjectSlot4_<R,P1,P2,P3,P4,O2> SType;
+ O2& obj_of_method = obj;
+ return new ObjectSlotNode((FuncPtr)(&SType::proxy),
+ &obj,
+ &obj_of_method,
+ method);
+ }
+
+template <class R,class P1,class P2,class P3,class P4,class O1,class O2>
+Slot4<R,P1,P2,P3,P4>
+ slot(O1& obj,R (O2::*method)(P1,P2,P3,P4) const)
+ {
+ typedef ObjectSlot4_<R,P1,P2,P3,P4,O2> SType;
+ O2& obj_of_method = obj;
+ return new ObjectSlotNode((FuncPtr)(&SType::proxy),
+ &obj,
+ &obj_of_method,
+ method);
+ }
+
+
+template <class R,class P1,class P2,class P3,class P4,class P5,class Obj>
+struct ObjectSlot5_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,void * s)
+ {
+ typedef RType (Obj::*Method)(P1,P2,P3,P4,P5);
+ ObjectSlotNode* os = (ObjectSlotNode*)s;
+ return ((Obj*)(os->object_)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2,p3,p4,p5);
+ }
+ };
+
+template <class R,class P1,class P2,class P3,class P4,class P5,class O1,class O2>
+Slot5<R,P1,P2,P3,P4,P5>
+ slot(O1& obj,R (O2::*method)(P1,P2,P3,P4,P5))
+ {
+ typedef ObjectSlot5_<R,P1,P2,P3,P4,P5,O2> SType;
+ O2& obj_of_method = obj;
+ return new ObjectSlotNode((FuncPtr)(&SType::proxy),
+ &obj,
+ &obj_of_method,
+ method);
+ }
+
+template <class R,class P1,class P2,class P3,class P4,class P5,class O1,class O2>
+Slot5<R,P1,P2,P3,P4,P5>
+ slot(O1& obj,R (O2::*method)(P1,P2,P3,P4,P5) const)
+ {
+ typedef ObjectSlot5_<R,P1,P2,P3,P4,P5,O2> SType;
+ O2& obj_of_method = obj;
+ return new ObjectSlotNode((FuncPtr)(&SType::proxy),
+ &obj,
+ &obj_of_method,
+ method);
+ }
+
+
+template <class R,class P1,class P2,class P3,class P4,class P5,class P6,class Obj>
+struct ObjectSlot6_
+ {
+ typedef typename Trait<R>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,typename Trait<P6>::ref p6,void * s)
+ {
+ typedef RType (Obj::*Method)(P1,P2,P3,P4,P5,P6);
+ ObjectSlotNode* os = (ObjectSlotNode*)s;
+ return ((Obj*)(os->object_)
+ ->*(reinterpret_cast<Method&>(os->method_)))(p1,p2,p3,p4,p5,p6);
+ }
+ };
+
+template <class R,class P1,class P2,class P3,class P4,class P5,class P6,class O1,class O2>
+Slot6<R,P1,P2,P3,P4,P5,P6>
+ slot(O1& obj,R (O2::*method)(P1,P2,P3,P4,P5,P6))
+ {
+ typedef ObjectSlot6_<R,P1,P2,P3,P4,P5,P6,O2> SType;
+ O2& obj_of_method = obj;
+ return new ObjectSlotNode((FuncPtr)(&SType::proxy),
+ &obj,
+ &obj_of_method,
+ method);
+ }
+
+template <class R,class P1,class P2,class P3,class P4,class P5,class P6,class O1,class O2>
+Slot6<R,P1,P2,P3,P4,P5,P6>
+ slot(O1& obj,R (O2::*method)(P1,P2,P3,P4,P5,P6) const)
+ {
+ typedef ObjectSlot6_<R,P1,P2,P3,P4,P5,P6,O2> SType;
+ O2& obj_of_method = obj;
+ return new ObjectSlotNode((FuncPtr)(&SType::proxy),
+ &obj,
+ &obj_of_method,
+ method);
+ }
+
+
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+
+#endif /* SIGC_OBJECT_SLOT */
+
diff --git a/src/sigc++/retype.h b/src/sigc++/retype.h
new file mode 100644
index 0000000..660ce8d
--- /dev/null
+++ b/src/sigc++/retype.h
@@ -0,0 +1,381 @@
+// -*- c++ -*-
+// Copyright 2000, Karl Einar Nelson
+/* This is a generated file, do not edit. Generated from template.macros.m4 */
+
+#ifndef SIGC_RETYPE_H
+#define SIGC_RETYPE_H
+#include <sigc++/adaptor.h>
+
+/** @defgroup retype
+ * retype() alters a Slot to change arguments and return type.
+ *
+ * Only allowed conversions or conversions to void can properly
+ * be implemented. The types of the return and all arguments must always
+ * be specified as a template parameters.
+ *
+ * Simple sample usage:
+ *
+ * @code
+ * float f(float,float);
+ *
+ * SigC::Slot1<int, int, int> s1 = SigC::retype<int, int, int>(slot(&f));
+ * @endcode
+ *
+ *
+ * SigC::retype_return() alters a Slot by changing the return type.
+ *
+ * Only allowed conversions or conversions to void can properly
+ * be implemented. The type must always be specified as a
+ * template parameter.
+ *
+ * Simple sample usage:
+ *
+ * @code
+ * int f(int);
+ *
+ * SigC::Slot1<void, int> s1 = SigC::retype_return<void>(slot(&f));
+ * SigC::Slot1<float, int> s2 = SigC::retype_return<float>(slot(&f));
+ * @endcode
+ *
+ * SigC::hide_return() is an easy-to-use variant that converts the Slot by
+ * dropping its return value, thus converting it to a void slot.
+ *
+ * Simple Sample usage:
+ *
+ * @code
+ * int f(int);
+ * SigC::Slot1<void, int> s = SigC::hide_return( slot(&f) );
+ * @endcode
+ */
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+
+
+template <class R1,class R2>
+struct AdaptorRetypeSlot0_
+ {
+ typedef typename Slot0<R2>::Proxy Proxy;
+ typedef typename Trait<R1>::type RType;
+ static RType proxy(void *data)
+ {
+ AdaptorSlotNode& node = *static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return RType(((Proxy)(slot->proxy_))
+ (slot));
+ }
+ };
+
+/// @ingroup retype
+template <class R1,class R2>
+Slot0<R1>
+ retype(const Slot0<R2> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeSlot0_<R1,R2>::proxy),s);
+ }
+
+template <class R1,class R2>
+Slot0<R1>
+ retype0(const Slot0<R2> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeSlot0_<R1,R2>::proxy),s);
+ }
+
+
+
+template <class R1,class P1,class R2,class C1>
+struct AdaptorRetypeSlot1_
+ {
+ typedef typename Slot1<R2,C1>::Proxy Proxy;
+ typedef typename Trait<R1>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,void *data)
+ {
+ AdaptorSlotNode& node = *static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return RType(((Proxy)(slot->proxy_))
+ (p1,slot));
+ }
+ };
+
+/// @ingroup retype
+template <class R1,class P1,class R2,class C1>
+Slot1<R1,P1>
+ retype(const Slot1<R2,C1> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeSlot1_<R1,P1,R2,C1>::proxy),s);
+ }
+
+template <class R1,class P1,class R2,class C1>
+Slot1<R1,P1>
+ retype1(const Slot1<R2,C1> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeSlot1_<R1,P1,R2,C1>::proxy),s);
+ }
+
+
+
+template <class R1,class P1,class P2,class R2,class C1,class C2>
+struct AdaptorRetypeSlot2_
+ {
+ typedef typename Slot2<R2,C1,C2>::Proxy Proxy;
+ typedef typename Trait<R1>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void *data)
+ {
+ AdaptorSlotNode& node = *static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return RType(((Proxy)(slot->proxy_))
+ (p1,p2,slot));
+ }
+ };
+
+/// @ingroup retype
+template <class R1,class P1,class P2,class R2,class C1,class C2>
+Slot2<R1,P1,P2>
+ retype(const Slot2<R2,C1,C2> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeSlot2_<R1,P1,P2,R2,C1,C2>::proxy),s);
+ }
+
+template <class R1,class P1,class P2,class R2,class C1,class C2>
+Slot2<R1,P1,P2>
+ retype2(const Slot2<R2,C1,C2> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeSlot2_<R1,P1,P2,R2,C1,C2>::proxy),s);
+ }
+
+
+
+template <class R1,class P1,class P2,class P3,class R2,class C1,class C2,class C3>
+struct AdaptorRetypeSlot3_
+ {
+ typedef typename Slot3<R2,C1,C2,C3>::Proxy Proxy;
+ typedef typename Trait<R1>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void *data)
+ {
+ AdaptorSlotNode& node = *static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return RType(((Proxy)(slot->proxy_))
+ (p1,p2,p3,slot));
+ }
+ };
+
+/// @ingroup retype
+template <class R1,class P1,class P2,class P3,class R2,class C1,class C2,class C3>
+Slot3<R1,P1,P2,P3>
+ retype(const Slot3<R2,C1,C2,C3> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeSlot3_<R1,P1,P2,P3,R2,C1,C2,C3>::proxy),s);
+ }
+
+template <class R1,class P1,class P2,class P3,class R2,class C1,class C2,class C3>
+Slot3<R1,P1,P2,P3>
+ retype3(const Slot3<R2,C1,C2,C3> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeSlot3_<R1,P1,P2,P3,R2,C1,C2,C3>::proxy),s);
+ }
+
+
+
+template <class R1,class P1,class P2,class P3,class P4,class R2,class C1,class C2,class C3,class C4>
+struct AdaptorRetypeSlot4_
+ {
+ typedef typename Slot4<R2,C1,C2,C3,C4>::Proxy Proxy;
+ typedef typename Trait<R1>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,void *data)
+ {
+ AdaptorSlotNode& node = *static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return RType(((Proxy)(slot->proxy_))
+ (p1,p2,p3,p4,slot));
+ }
+ };
+
+/// @ingroup retype
+template <class R1,class P1,class P2,class P3,class P4,class R2,class C1,class C2,class C3,class C4>
+Slot4<R1,P1,P2,P3,P4>
+ retype(const Slot4<R2,C1,C2,C3,C4> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeSlot4_<R1,P1,P2,P3,P4,R2,C1,C2,C3,C4>::proxy),s);
+ }
+
+template <class R1,class P1,class P2,class P3,class P4,class R2,class C1,class C2,class C3,class C4>
+Slot4<R1,P1,P2,P3,P4>
+ retype4(const Slot4<R2,C1,C2,C3,C4> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeSlot4_<R1,P1,P2,P3,P4,R2,C1,C2,C3,C4>::proxy),s);
+ }
+
+
+
+template <class R1,class P1,class P2,class P3,class P4,class P5,class R2,class C1,class C2,class C3,class C4,class C5>
+struct AdaptorRetypeSlot5_
+ {
+ typedef typename Slot5<R2,C1,C2,C3,C4,C5>::Proxy Proxy;
+ typedef typename Trait<R1>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,void *data)
+ {
+ AdaptorSlotNode& node = *static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return RType(((Proxy)(slot->proxy_))
+ (p1,p2,p3,p4,p5,slot));
+ }
+ };
+
+/// @ingroup retype
+template <class R1,class P1,class P2,class P3,class P4,class P5,class R2,class C1,class C2,class C3,class C4,class C5>
+Slot5<R1,P1,P2,P3,P4,P5>
+ retype(const Slot5<R2,C1,C2,C3,C4,C5> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeSlot5_<R1,P1,P2,P3,P4,P5,R2,C1,C2,C3,C4,C5>::proxy),s);
+ }
+
+template <class R1,class P1,class P2,class P3,class P4,class P5,class R2,class C1,class C2,class C3,class C4,class C5>
+Slot5<R1,P1,P2,P3,P4,P5>
+ retype5(const Slot5<R2,C1,C2,C3,C4,C5> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeSlot5_<R1,P1,P2,P3,P4,P5,R2,C1,C2,C3,C4,C5>::proxy),s);
+ }
+
+
+
+template <class R1,class P1,class P2,class P3,class P4,class P5,class P6,class R2,class C1,class C2,class C3,class C4,class C5,class C6>
+struct AdaptorRetypeSlot6_
+ {
+ typedef typename Slot6<R2,C1,C2,C3,C4,C5,C6>::Proxy Proxy;
+ typedef typename Trait<R1>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,typename Trait<P6>::ref p6,void *data)
+ {
+ AdaptorSlotNode& node = *static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return RType(((Proxy)(slot->proxy_))
+ (p1,p2,p3,p4,p5,p6,slot));
+ }
+ };
+
+/// @ingroup retype
+template <class R1,class P1,class P2,class P3,class P4,class P5,class P6,class R2,class C1,class C2,class C3,class C4,class C5,class C6>
+Slot6<R1,P1,P2,P3,P4,P5,P6>
+ retype(const Slot6<R2,C1,C2,C3,C4,C5,C6> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeSlot6_<R1,P1,P2,P3,P4,P5,P6,R2,C1,C2,C3,C4,C5,C6>::proxy),s);
+ }
+
+template <class R1,class P1,class P2,class P3,class P4,class P5,class P6,class R2,class C1,class C2,class C3,class C4,class C5,class C6>
+Slot6<R1,P1,P2,P3,P4,P5,P6>
+ retype6(const Slot6<R2,C1,C2,C3,C4,C5,C6> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeSlot6_<R1,P1,P2,P3,P4,P5,P6,R2,C1,C2,C3,C4,C5,C6>::proxy),s);
+ }
+
+
+
+
+#if !defined(SIGC_CXX_VOID_CAST_RETURN) && defined(SIGC_CXX_PARTIAL_SPEC)
+template <class R2>
+struct AdaptorRetypeSlot0_ <void,R2>
+ {
+ typedef typename Slot0<R2>::Proxy Proxy;
+ static void proxy(void *data)
+ {
+ AdaptorSlotNode& node = *static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ ((Proxy)(slot->proxy_))(slot);
+ }
+ };
+
+
+
+template <class P1,class R2,class C1>
+struct AdaptorRetypeSlot1_ <void,P1,R2,C1>
+ {
+ typedef typename Slot1<R2,C1>::Proxy Proxy;
+ static void proxy(typename Trait<P1>::ref p1,void *data)
+ {
+ AdaptorSlotNode& node = *static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ ((Proxy)(slot->proxy_))(p1,slot);
+ }
+ };
+
+
+
+template <class P1,class P2,class R2,class C1,class C2>
+struct AdaptorRetypeSlot2_ <void,P1,P2,R2,C1,C2>
+ {
+ typedef typename Slot2<R2,C1,C2>::Proxy Proxy;
+ static void proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void *data)
+ {
+ AdaptorSlotNode& node = *static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ ((Proxy)(slot->proxy_))(p1,p2,slot);
+ }
+ };
+
+
+
+template <class P1,class P2,class P3,class R2,class C1,class C2,class C3>
+struct AdaptorRetypeSlot3_ <void,P1,P2,P3,R2,C1,C2,C3>
+ {
+ typedef typename Slot3<R2,C1,C2,C3>::Proxy Proxy;
+ static void proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void *data)
+ {
+ AdaptorSlotNode& node = *static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ ((Proxy)(slot->proxy_))(p1,p2,p3,slot);
+ }
+ };
+
+
+
+template <class P1,class P2,class P3,class P4,class R2,class C1,class C2,class C3,class C4>
+struct AdaptorRetypeSlot4_ <void,P1,P2,P3,P4,R2,C1,C2,C3,C4>
+ {
+ typedef typename Slot4<R2,C1,C2,C3,C4>::Proxy Proxy;
+ static void proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,void *data)
+ {
+ AdaptorSlotNode& node = *static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ ((Proxy)(slot->proxy_))(p1,p2,p3,p4,slot);
+ }
+ };
+
+
+
+template <class P1,class P2,class P3,class P4,class P5,class R2,class C1,class C2,class C3,class C4,class C5>
+struct AdaptorRetypeSlot5_ <void,P1,P2,P3,P4,P5,R2,C1,C2,C3,C4,C5>
+ {
+ typedef typename Slot5<R2,C1,C2,C3,C4,C5>::Proxy Proxy;
+ static void proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,void *data)
+ {
+ AdaptorSlotNode& node = *static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ ((Proxy)(slot->proxy_))(p1,p2,p3,p4,p5,slot);
+ }
+ };
+
+
+
+template <class P1,class P2,class P3,class P4,class P5,class P6,class R2,class C1,class C2,class C3,class C4,class C5,class C6>
+struct AdaptorRetypeSlot6_ <void,P1,P2,P3,P4,P5,P6,R2,C1,C2,C3,C4,C5,C6>
+ {
+ typedef typename Slot6<R2,C1,C2,C3,C4,C5,C6>::Proxy Proxy;
+ static void proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,typename Trait<P6>::ref p6,void *data)
+ {
+ AdaptorSlotNode& node = *static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ ((Proxy)(slot->proxy_))(p1,p2,p3,p4,p5,p6,slot);
+ }
+ };
+
+
+
+#endif
+
+#ifdef SIGC_CXX_NAMESPACES
+} // namespace
+#endif
+
+#endif // SIGC_RETYPE_H
diff --git a/src/sigc++/retype_return.h b/src/sigc++/retype_return.h
new file mode 100644
index 0000000..178a6c0
--- /dev/null
+++ b/src/sigc++/retype_return.h
@@ -0,0 +1,388 @@
+// -*- c++ -*-
+// Copyright 2000, Karl Einar Nelson
+/* This is a generated file, do not edit. Generated from template.macros.m4 */
+
+#ifndef SIGC_RETYPE_RETURN_H
+#define SIGC_RETYPE_RETURN_H
+#include <sigc++/adaptor.h>
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+
+
+/****************************************************************
+***** Adaptor Return Type Slot, 0 arguments
+****************************************************************/
+template <class R2,class R1>
+struct AdaptorRetypeReturnSlot0_
+ {
+ typedef typename Slot0<R1>::Proxy Proxy;
+ typedef typename Trait<R2>::type RType;
+ static RType proxy(void *data)
+ {
+ AdaptorSlotNode& node=*static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return RType(((Proxy)(slot->proxy_))
+ (slot));
+ }
+ };
+
+/// @ingroup retype
+template <class R2,class R>
+Slot0<R2>
+ retype_return(const Slot0<R> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeReturnSlot0_<R2,R>::proxy),s);
+ }
+
+/// @ingroup hide
+template <class R>
+Slot0<void>
+ hide_return(const Slot0<R> &s)
+ {
+ return retype_return<void>(s);
+ }
+
+
+/****************************************************************
+***** Adaptor Return Type Slot, 1 arguments
+****************************************************************/
+template <class R2,class R1,class P1>
+struct AdaptorRetypeReturnSlot1_
+ {
+ typedef typename Slot1<R1,P1>::Proxy Proxy;
+ typedef typename Trait<R2>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,void *data)
+ {
+ AdaptorSlotNode& node=*static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return RType(((Proxy)(slot->proxy_))
+ (p1,slot));
+ }
+ };
+
+/// @ingroup retype
+template <class R2,class R,class P1>
+Slot1<R2,P1>
+ retype_return(const Slot1<R,P1> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeReturnSlot1_<R2,R,P1>::proxy),s);
+ }
+
+/// @ingroup hide
+template <class R,class P1>
+Slot1<void,P1>
+ hide_return(const Slot1<R,P1> &s)
+ {
+ return retype_return<void>(s);
+ }
+
+
+/****************************************************************
+***** Adaptor Return Type Slot, 2 arguments
+****************************************************************/
+template <class R2,class R1,class P1,class P2>
+struct AdaptorRetypeReturnSlot2_
+ {
+ typedef typename Slot2<R1,P1,P2>::Proxy Proxy;
+ typedef typename Trait<R2>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void *data)
+ {
+ AdaptorSlotNode& node=*static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return RType(((Proxy)(slot->proxy_))
+ (p1,p2,slot));
+ }
+ };
+
+/// @ingroup retype
+template <class R2,class R,class P1,class P2>
+Slot2<R2,P1,P2>
+ retype_return(const Slot2<R,P1,P2> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeReturnSlot2_<R2,R,P1,P2>::proxy),s);
+ }
+
+/// @ingroup hide
+template <class R,class P1,class P2>
+Slot2<void,P1,P2>
+ hide_return(const Slot2<R,P1,P2> &s)
+ {
+ return retype_return<void>(s);
+ }
+
+
+/****************************************************************
+***** Adaptor Return Type Slot, 3 arguments
+****************************************************************/
+template <class R2,class R1,class P1,class P2,class P3>
+struct AdaptorRetypeReturnSlot3_
+ {
+ typedef typename Slot3<R1,P1,P2,P3>::Proxy Proxy;
+ typedef typename Trait<R2>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void *data)
+ {
+ AdaptorSlotNode& node=*static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return RType(((Proxy)(slot->proxy_))
+ (p1,p2,p3,slot));
+ }
+ };
+
+/// @ingroup retype
+template <class R2,class R,class P1,class P2,class P3>
+Slot3<R2,P1,P2,P3>
+ retype_return(const Slot3<R,P1,P2,P3> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeReturnSlot3_<R2,R,P1,P2,P3>::proxy),s);
+ }
+
+/// @ingroup hide
+template <class R,class P1,class P2,class P3>
+Slot3<void,P1,P2,P3>
+ hide_return(const Slot3<R,P1,P2,P3> &s)
+ {
+ return retype_return<void>(s);
+ }
+
+
+/****************************************************************
+***** Adaptor Return Type Slot, 4 arguments
+****************************************************************/
+template <class R2,class R1,class P1,class P2,class P3,class P4>
+struct AdaptorRetypeReturnSlot4_
+ {
+ typedef typename Slot4<R1,P1,P2,P3,P4>::Proxy Proxy;
+ typedef typename Trait<R2>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,void *data)
+ {
+ AdaptorSlotNode& node=*static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return RType(((Proxy)(slot->proxy_))
+ (p1,p2,p3,p4,slot));
+ }
+ };
+
+/// @ingroup retype
+template <class R2,class R,class P1,class P2,class P3,class P4>
+Slot4<R2,P1,P2,P3,P4>
+ retype_return(const Slot4<R,P1,P2,P3,P4> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeReturnSlot4_<R2,R,P1,P2,P3,P4>::proxy),s);
+ }
+
+/// @ingroup hide
+template <class R,class P1,class P2,class P3,class P4>
+Slot4<void,P1,P2,P3,P4>
+ hide_return(const Slot4<R,P1,P2,P3,P4> &s)
+ {
+ return retype_return<void>(s);
+ }
+
+
+/****************************************************************
+***** Adaptor Return Type Slot, 5 arguments
+****************************************************************/
+template <class R2,class R1,class P1,class P2,class P3,class P4,class P5>
+struct AdaptorRetypeReturnSlot5_
+ {
+ typedef typename Slot5<R1,P1,P2,P3,P4,P5>::Proxy Proxy;
+ typedef typename Trait<R2>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,void *data)
+ {
+ AdaptorSlotNode& node=*static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return RType(((Proxy)(slot->proxy_))
+ (p1,p2,p3,p4,p5,slot));
+ }
+ };
+
+/// @ingroup retype
+template <class R2,class R,class P1,class P2,class P3,class P4,class P5>
+Slot5<R2,P1,P2,P3,P4,P5>
+ retype_return(const Slot5<R,P1,P2,P3,P4,P5> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeReturnSlot5_<R2,R,P1,P2,P3,P4,P5>::proxy),s);
+ }
+
+/// @ingroup hide
+template <class R,class P1,class P2,class P3,class P4,class P5>
+Slot5<void,P1,P2,P3,P4,P5>
+ hide_return(const Slot5<R,P1,P2,P3,P4,P5> &s)
+ {
+ return retype_return<void>(s);
+ }
+
+
+/****************************************************************
+***** Adaptor Return Type Slot, 6 arguments
+****************************************************************/
+template <class R2,class R1,class P1,class P2,class P3,class P4,class P5,class P6>
+struct AdaptorRetypeReturnSlot6_
+ {
+ typedef typename Slot6<R1,P1,P2,P3,P4,P5,P6>::Proxy Proxy;
+ typedef typename Trait<R2>::type RType;
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,typename Trait<P6>::ref p6,void *data)
+ {
+ AdaptorSlotNode& node=*static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ return RType(((Proxy)(slot->proxy_))
+ (p1,p2,p3,p4,p5,p6,slot));
+ }
+ };
+
+/// @ingroup retype
+template <class R2,class R,class P1,class P2,class P3,class P4,class P5,class P6>
+Slot6<R2,P1,P2,P3,P4,P5,P6>
+ retype_return(const Slot6<R,P1,P2,P3,P4,P5,P6> &s)
+ {
+ return new AdaptorSlotNode((FuncPtr)(&AdaptorRetypeReturnSlot6_<R2,R,P1,P2,P3,P4,P5,P6>::proxy),s);
+ }
+
+/// @ingroup hide
+template <class R,class P1,class P2,class P3,class P4,class P5,class P6>
+Slot6<void,P1,P2,P3,P4,P5,P6>
+ hide_return(const Slot6<R,P1,P2,P3,P4,P5,P6> &s)
+ {
+ return retype_return<void>(s);
+ }
+
+
+
+#if !defined(SIGC_CXX_VOID_CAST_RETURN) && defined(SIGC_CXX_PARTIAL_SPEC)
+/****************************************************************
+***** Adaptor Return Type Slot, 0 arguments
+****************************************************************/
+template <class R1>
+struct AdaptorRetypeReturnSlot0_ <void,R1>
+ {
+ typedef typename Slot0<R1>::Proxy Proxy;
+ static void proxy(void *data)
+ {
+ AdaptorSlotNode& node=*static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ ((Proxy)(slot->proxy_))
+ (slot);
+ }
+ };
+
+
+
+/****************************************************************
+***** Adaptor Return Type Slot, 1 arguments
+****************************************************************/
+template <class R1,class P1>
+struct AdaptorRetypeReturnSlot1_ <void,R1,P1>
+ {
+ typedef typename Slot1<R1,P1>::Proxy Proxy;
+ static void proxy(typename Trait<P1>::ref p1,void *data)
+ {
+ AdaptorSlotNode& node=*static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ ((Proxy)(slot->proxy_))
+ (p1,slot);
+ }
+ };
+
+
+
+/****************************************************************
+***** Adaptor Return Type Slot, 2 arguments
+****************************************************************/
+template <class R1,class P1,class P2>
+struct AdaptorRetypeReturnSlot2_ <void,R1,P1,P2>
+ {
+ typedef typename Slot2<R1,P1,P2>::Proxy Proxy;
+ static void proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void *data)
+ {
+ AdaptorSlotNode& node=*static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ ((Proxy)(slot->proxy_))
+ (p1,p2,slot);
+ }
+ };
+
+
+
+/****************************************************************
+***** Adaptor Return Type Slot, 3 arguments
+****************************************************************/
+template <class R1,class P1,class P2,class P3>
+struct AdaptorRetypeReturnSlot3_ <void,R1,P1,P2,P3>
+ {
+ typedef typename Slot3<R1,P1,P2,P3>::Proxy Proxy;
+ static void proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void *data)
+ {
+ AdaptorSlotNode& node=*static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ ((Proxy)(slot->proxy_))
+ (p1,p2,p3,slot);
+ }
+ };
+
+
+
+/****************************************************************
+***** Adaptor Return Type Slot, 4 arguments
+****************************************************************/
+template <class R1,class P1,class P2,class P3,class P4>
+struct AdaptorRetypeReturnSlot4_ <void,R1,P1,P2,P3,P4>
+ {
+ typedef typename Slot4<R1,P1,P2,P3,P4>::Proxy Proxy;
+ static void proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,void *data)
+ {
+ AdaptorSlotNode& node=*static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ ((Proxy)(slot->proxy_))
+ (p1,p2,p3,p4,slot);
+ }
+ };
+
+
+
+/****************************************************************
+***** Adaptor Return Type Slot, 5 arguments
+****************************************************************/
+template <class R1,class P1,class P2,class P3,class P4,class P5>
+struct AdaptorRetypeReturnSlot5_ <void,R1,P1,P2,P3,P4,P5>
+ {
+ typedef typename Slot5<R1,P1,P2,P3,P4,P5>::Proxy Proxy;
+ static void proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,void *data)
+ {
+ AdaptorSlotNode& node=*static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ ((Proxy)(slot->proxy_))
+ (p1,p2,p3,p4,p5,slot);
+ }
+ };
+
+
+
+/****************************************************************
+***** Adaptor Return Type Slot, 6 arguments
+****************************************************************/
+template <class R1,class P1,class P2,class P3,class P4,class P5,class P6>
+struct AdaptorRetypeReturnSlot6_ <void,R1,P1,P2,P3,P4,P5,P6>
+ {
+ typedef typename Slot6<R1,P1,P2,P3,P4,P5,P6>::Proxy Proxy;
+ static void proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,typename Trait<P6>::ref p6,void *data)
+ {
+ AdaptorSlotNode& node=*static_cast<AdaptorSlotNode*>(data);
+ SlotNode* slot=static_cast<SlotNode*>(node.slot_.impl());
+ ((Proxy)(slot->proxy_))
+ (p1,p2,p3,p4,p5,p6,slot);
+ }
+ };
+
+
+
+#endif
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+#endif // SIGC_RETYPE_RETURN_H
diff --git a/src/sigc++/sigc++.h b/src/sigc++/sigc++.h
new file mode 100644
index 0000000..285eedc
--- /dev/null
+++ b/src/sigc++/sigc++.h
@@ -0,0 +1,36 @@
+/*************************************************************************
+***** A Signal Framework for C++
+**************************************************************************
+
+ Based on ideas from Gtk-- signal system by Tero Pulkkinen.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*************************************************************************/
+
+#ifndef SIGCXX_SIGCXX_H
+#define SIGCXX_SIGCXX_H
+
+#include <sigc++/slot.h>
+#include <sigc++/signal.h>
+#include <sigc++/bind.h>
+#include <sigc++/bind_return.h>
+#include <sigc++/hide.h>
+#include <sigc++/method_slot.h>
+#include <sigc++/object.h>
+#include <sigc++/object_slot.h>
+
+#endif /* SIGCXX_SIGCXX_H */
+
diff --git a/src/sigc++/sigcconfig.h b/src/sigc++/sigcconfig.h
new file mode 100644
index 0000000..1bfbc4b
--- /dev/null
+++ b/src/sigc++/sigcconfig.h
@@ -0,0 +1,67 @@
+/* sigc++/config/sigcconfig.h.in. */
+/*
+ This file controls all the configurablity of sigc++ with regards
+ to different compilers. If you are begining a new port of sigc++
+ to a compiler this is where to start.
+
+ Unix compilers are handled automatically by configure. Other
+ platforms require proper identification here. To add a new
+ port, first identify your compilers unique predefine and
+ create a LIBSIGC_{compiler} in the detection stage. Then
+ place a section which defines for the behavior of your compiler
+ in the platform section.
+*/
+#ifndef _SIGC_CONFIG_H_
+#define _SIGC_CONFIG_H_
+
+// autoconf likes to place a lot of stuff we don't want.
+#if 0
+
+/* Define if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* Version number of package */
+#undef VERSION
+
+#endif /* 0 */
+
+#define SIGC_MAJOR_VERSION 1
+#define SIGC_MINOR_VERSION 2
+#define SIGC_MICRO_VERSION 5
+
+// Detect common platforms
+
+#define LIBSIGC_MSVC
+#define LIBSIGC_DLL
+
+// Compiler specific definitions
+
+
+// I guess the configure checks can't be run on these plaforms,
+// so we specify these compiler features based on our experience.
+// These platforms are detected above based on compiler-defined macros.
+// murrayc:
+
+
+#ifdef LIBSIGC_MSVC
+#define SIGC_CXX_INT_CTOR 1
+#define SIGC_CXX_NAMESPACES 1
+//#define SIGC_CXX_MEMBER_FUNC_TEMPLATES 1
+//#define SIGC_CXX_MEMBER_CLASS_TEMPLATES 1
+//#define SIGC_CXX_TEMPLATE_CCTOR 1
+//#define SIGC_CXX_MUTABLE 1
+#define SIGC_CXX_EXPLICIT explicit
+#define SIGC_CXX_EXPLICIT_COPY explicit
+#endif /* LIBSIGC_MSVC */
+
+
+// Window DLL declarations
+
+#define LIBSIGC_API
+#define LIBSIGC_TMPL
+
+#endif /* _SIGC_CONFIG_H_ */
+
diff --git a/src/sigc++/signal.cpp b/src/sigc++/signal.cpp
new file mode 100644
index 0000000..9705fd7
--- /dev/null
+++ b/src/sigc++/signal.cpp
@@ -0,0 +1,241 @@
+// -*- c++ -*-
+/*
+ Copyright 2000, Karl Einar Nelson
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#include "sigc++/signal.h"
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+class SignalConnectionNode;
+class SignalIterator_;
+
+// Signal_ comes from Slot_, but it lacks a proxy until added by
+// the holding Signal<>, which does so on a request of the user.
+// Thus you must use the conversion operator on a Signal to get a Slot.
+
+
+SignalNode::SignalNode()
+ : SlotNode(0), exec_count_(0), begin_(0), end_(0)
+ {
+ reference();
+ }
+
+SignalNode::~SignalNode()
+ { clear(); }
+
+void SignalNode::clear()
+ {
+ if (!exec_count_)
+ {
+ SignalConnectionNode *i=begin_,*j;
+ begin_=end_=0;
+ while (i)
+ {
+ j=i->next_;
+ i->parent_ = 0;
+ i->unreference();
+ i=j;
+ }
+ }
+ else
+ {
+ SignalConnectionNode *i=begin_;
+ while (i)
+ {
+ i->defered_=true;
+ i->blocked_=true;
+ i=i->next_;
+ }
+ defered_=true;
+ }
+ }
+
+bool SignalNode::empty()
+ { return !begin_; }
+
+/*
+void Signal_::exec_reference()
+ {
+ reference();
+ exec_count_+=1;
+ }
+
+void Signal_::exec_unreference()
+ {
+ if (!--exec_count_)
+ cleanup();
+ unreference();
+ }
+*/
+
+void SignalNode::cleanup()
+ {
+ if(!defered_)
+ return;
+
+ defered_ = false;
+
+ SignalConnectionNode* i = begin_;
+
+ while(begin_ && begin_->defered_)
+ begin_ = begin_->next_;
+
+ while(end_ && end_->defered_)
+ end_ = end_->prev_;
+
+ // Hmm, this looks a bit tricky to me. The code above removes all
+ // elements from the front and the back that have defered_ = true set.
+ // But the following loop unreferences *all* defered elements, including
+ // those that are still in the list.
+ //
+ // I don't know whether this is a bug -- it's possible that defered nodes
+ // are always at the front or back. If not, a node could be unreferenced
+ // twice which is bad.
+ //
+ // --Daniel
+
+ while(i)
+ {
+ SignalConnectionNode* next = i->next_;
+
+ if(i->defered_)
+ {
+ i->parent_ = 0;
+ i->unreference();
+ }
+
+ i = next;
+ }
+ }
+
+SlotNode* SignalNode::create_slot(FuncPtr proxy) // nothrow
+{
+ proxy_=proxy;
+ return this;
+}
+
+ConnectionNode* SignalNode::push_front(const SlotBase& s)
+ {
+ SignalConnectionNode* c=new SignalConnectionNode((SlotNode*)(s.impl()));
+ c->reference();
+ c->parent_=this;
+ c->next_=begin_;
+ if (begin_)
+ begin_->prev_=c;
+ else
+ end_=c;
+ end_=c;
+ return c;
+ }
+
+ConnectionNode* SignalNode::push_back(const SlotBase& s)
+ {
+ SignalConnectionNode* c=new SignalConnectionNode((SlotNode*)(s.impl()));
+ c->reference();
+ c->parent_=this;
+ c->prev_=end_;
+ if (end_)
+ end_->next_=c;
+ else
+ begin_=c;
+ end_=c;
+ return c;
+ }
+
+void SignalNode::remove(SignalConnectionNode* c)
+ {
+ if (!exec_count_)
+ {
+ if (c->prev_)
+ c->prev_->next_=c->next_;
+ else
+ begin_=c->next_;
+
+ if (c->next_)
+ c->next_->prev_=c->prev_;
+ else
+ end_=c->prev_;
+
+ c->parent_ = 0;
+ c->unreference();
+ }
+ else
+ {
+ c->defered_=true;
+ c->blocked_=true;
+ defered_=true;
+ }
+ }
+
+
+
+/**********************************************************/
+
+SignalBase::SignalBase()
+ : impl_(0)
+ {}
+
+SignalBase::SignalBase(const SignalBase& s)
+ : impl_(s.impl())
+ {
+ impl_->reference();
+ }
+
+SignalBase::SignalBase(SignalNode* s)
+ : impl_(s)
+ {
+ if (s)
+ impl_->reference();
+ }
+
+SignalBase::~SignalBase()
+ {
+ if (impl_)
+ impl_->unreference();
+ }
+
+SignalNode* SignalBase::impl() const
+ {
+ if (!impl_)
+ impl_=new SignalNode();
+ return impl_;
+ }
+
+/**********************************************************/
+
+void SignalConnectionNode::notify(bool from_child)
+ {
+ Node n (this);
+ ConnectionNode::notify(from_child);
+
+ if(parent_) // this node might have been removed already
+ parent_->remove(this);
+ }
+
+SignalConnectionNode::~SignalConnectionNode()
+ { }
+SignalConnectionNode::SignalConnectionNode(SlotNode* s)
+ : ConnectionNode(s), parent_(0), next_(0), prev_(0)
+ { }
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
diff --git a/src/sigc++/signal.h b/src/sigc++/signal.h
new file mode 100644
index 0000000..701824e
--- /dev/null
+++ b/src/sigc++/signal.h
@@ -0,0 +1,978 @@
+// -*- c++ -*-
+// Copyright 2000, Karl Einar Nelson
+/* This is a generated file, do not edit. Generated from template.macros.m4 */
+
+#ifndef SIGC_SIGNAL_H
+#define SIGC_SIGNAL_H
+#include <sigc++/slot.h>
+#include <sigc++/connection.h>
+#include <sigc++/marshal.h>
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+/** @defgroup Signals
+ * Use connect() with SigC::slot to connect a method or function with a Signal.
+ *
+ * @code
+ * signal_clicked.connect( SigC::slot(*this, &MyWindow::on_clicked) );
+ * @endcode
+ *
+ * When the signal is emitted your method will be called.
+ *
+ * connect() returns a Connection, which you can later use to disconnect your method.
+ *
+ * When Signals are copied they share the underlying information,
+ * so you can have a protected/private SigC::Signal member and a public accessor method.
+ */
+
+class SignalConnectionNode;
+class SignalExec_;
+
+class LIBSIGC_API SignalNode : public SlotNode
+ {
+ public:
+ int exec_count_; // atomic
+ SignalConnectionNode *begin_,*end_;
+
+ SignalNode();
+ ~SignalNode();
+
+ // must be inline to avoid emission slowdowns.
+ void exec_reference()
+ {
+ reference();
+ exec_count_ += 1;
+ }
+
+ // must be inline to avoid emission slowdowns.
+ void exec_unreference()
+ {
+ exec_count_ -= 1;
+
+ if (defered_ && !exec_count_)
+ cleanup();
+
+ unreference();
+ }
+
+ SlotNode* create_slot(FuncPtr proxy); // nothrow
+ ConnectionNode* push_front(const SlotBase& s);
+ ConnectionNode* push_back(const SlotBase& s);
+
+ virtual void remove(SignalConnectionNode* c);
+ bool empty();
+ void clear();
+ void cleanup(); // nothrow
+ };
+
+class LIBSIGC_API SignalBase
+ {
+ friend class SignalConnectionNode;
+ private:
+ SignalBase& operator= (const SignalBase&); // no copy
+
+ protected:
+ typedef SignalExec_ Exec;
+
+ mutable SignalNode *impl_;
+
+ SlotNode* create_slot(FuncPtr c) const
+ { return impl()->create_slot(c); }
+
+ ConnectionNode* push_front(const SlotBase& s)
+ { return impl()->push_front(s); }
+
+ ConnectionNode* push_back(const SlotBase& s)
+ { return impl()->push_back(s); }
+
+ SignalBase();
+ SignalBase(const SignalBase& s);
+ SignalBase(SignalNode* s);
+ ~SignalBase();
+
+ public:
+ bool empty() const
+ { return !impl_ || impl()->empty(); }
+
+ void clear()
+ {
+ if(impl_)
+ impl()->clear();
+ }
+
+ SignalNode* impl() const;
+ };
+
+class LIBSIGC_API SignalConnectionNode : public ConnectionNode
+ {
+ public:
+ virtual void notify(bool from_child);
+
+ virtual ~SignalConnectionNode();
+ SignalConnectionNode(SlotNode*);
+
+ SignalNode *parent_;
+ SignalConnectionNode *next_,*prev_;
+
+ SlotNode* dest() { return (SlotNode*)(slot().impl()); }
+ };
+
+// Exeception-safe class for tracking signals.
+class LIBSIGC_API SignalExec_
+ {
+ public:
+ SignalNode* signal_;
+
+ SignalExec_(SignalNode* signal) :signal_(signal)
+ { signal_->exec_reference(); }
+
+ ~SignalExec_()
+ { signal_->exec_unreference(); }
+ };
+
+
+/********************************************************/
+
+
+
+
+/// @ingroup Signals
+template <class R,class Marsh=Marshal<R> >
+class Signal0 : public SignalBase
+ {
+ public:
+ typedef Slot0<R> InSlotType;
+ typedef Slot0<typename Marsh::OutType> OutSlotType;
+ typedef typename Trait<typename Marsh::OutType>::type OutType;
+
+ private:
+ // Used for both emit and proxy.
+ static OutType emit_(void* data);
+
+ public:
+ OutSlotType slot() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ operator OutSlotType() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ /// You can call Connection::disconnect() later.
+ Connection connect(const InSlotType& s)
+ { return Connection(push_back(s)); }
+
+ /// Call all the connected methods.
+ OutType emit()
+ { return emit_(impl_); }
+
+ /// See emit()
+ OutType operator()()
+ { return emit_(impl_); }
+
+ Signal0()
+ : SignalBase()
+ {}
+
+ Signal0(const InSlotType& s)
+ : SignalBase()
+ { connect(s); }
+
+ ~Signal0() {}
+ };
+
+
+// emit
+template <class R,class Marsh>
+typename Signal0<R,Marsh>::OutType
+Signal0<R,Marsh>::emit_(void* data)
+ {
+ SignalNode* impl = static_cast<SignalNode*>(data);
+
+ if (!impl || !impl->begin_)
+ return Marsh::default_value();
+
+ Exec exec(impl);
+ Marsh rc;
+ SlotNode* s = 0;
+
+ for (SignalConnectionNode* i = impl->begin_; i; i=i->next_)
+ {
+ if (i->blocked()) continue;
+ s = i->dest();
+ if (rc.marshal(((typename Slot0<R>::Proxy)(s->proxy_))(s)))
+ return rc.value();
+ }
+ return rc.value();
+ }
+
+
+
+/// @ingroup Signals
+template <class R,class P1,class Marsh=Marshal<R> >
+class Signal1 : public SignalBase
+ {
+ public:
+ typedef Slot1<R,P1> InSlotType;
+ typedef Slot1<typename Marsh::OutType,P1> OutSlotType;
+ typedef typename Trait<typename Marsh::OutType>::type OutType;
+
+ private:
+ // Used for both emit and proxy.
+ static OutType emit_(typename Trait<P1>::ref p1,void* data);
+
+ public:
+ OutSlotType slot() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ operator OutSlotType() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ /// You can call Connection::disconnect() later.
+ Connection connect(const InSlotType& s)
+ { return Connection(push_back(s)); }
+
+ /// Call all the connected methods.
+ OutType emit(typename Trait<P1>::ref p1)
+ { return emit_(p1,impl_); }
+
+ /// See emit()
+ OutType operator()(typename Trait<P1>::ref p1)
+ { return emit_(p1,impl_); }
+
+ Signal1()
+ : SignalBase()
+ {}
+
+ Signal1(const InSlotType& s)
+ : SignalBase()
+ { connect(s); }
+
+ ~Signal1() {}
+ };
+
+
+// emit
+template <class R,class P1,class Marsh>
+typename Signal1<R,P1,Marsh>::OutType
+Signal1<R,P1,Marsh>::emit_(typename Trait<P1>::ref p1,void* data)
+ {
+ SignalNode* impl = static_cast<SignalNode*>(data);
+
+ if (!impl || !impl->begin_)
+ return Marsh::default_value();
+
+ Exec exec(impl);
+ Marsh rc;
+ SlotNode* s = 0;
+
+ for (SignalConnectionNode* i = impl->begin_; i; i=i->next_)
+ {
+ if (i->blocked()) continue;
+ s = i->dest();
+ if (rc.marshal(((typename Slot1<R,P1>::Proxy)(s->proxy_))(p1,s)))
+ return rc.value();
+ }
+ return rc.value();
+ }
+
+
+
+/// @ingroup Signals
+template <class R,class P1,class P2,class Marsh=Marshal<R> >
+class Signal2 : public SignalBase
+ {
+ public:
+ typedef Slot2<R,P1,P2> InSlotType;
+ typedef Slot2<typename Marsh::OutType,P1,P2> OutSlotType;
+ typedef typename Trait<typename Marsh::OutType>::type OutType;
+
+ private:
+ // Used for both emit and proxy.
+ static OutType emit_(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void* data);
+
+ public:
+ OutSlotType slot() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ operator OutSlotType() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ /// You can call Connection::disconnect() later.
+ Connection connect(const InSlotType& s)
+ { return Connection(push_back(s)); }
+
+ /// Call all the connected methods.
+ OutType emit(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2)
+ { return emit_(p1,p2,impl_); }
+
+ /// See emit()
+ OutType operator()(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2)
+ { return emit_(p1,p2,impl_); }
+
+ Signal2()
+ : SignalBase()
+ {}
+
+ Signal2(const InSlotType& s)
+ : SignalBase()
+ { connect(s); }
+
+ ~Signal2() {}
+ };
+
+
+// emit
+template <class R,class P1,class P2,class Marsh>
+typename Signal2<R,P1,P2,Marsh>::OutType
+Signal2<R,P1,P2,Marsh>::emit_(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void* data)
+ {
+ SignalNode* impl = static_cast<SignalNode*>(data);
+
+ if (!impl || !impl->begin_)
+ return Marsh::default_value();
+
+ Exec exec(impl);
+ Marsh rc;
+ SlotNode* s = 0;
+
+ for (SignalConnectionNode* i = impl->begin_; i; i=i->next_)
+ {
+ if (i->blocked()) continue;
+ s = i->dest();
+ if (rc.marshal(((typename Slot2<R,P1,P2>::Proxy)(s->proxy_))(p1,p2,s)))
+ return rc.value();
+ }
+ return rc.value();
+ }
+
+
+
+/// @ingroup Signals
+template <class R,class P1,class P2,class P3,class Marsh=Marshal<R> >
+class Signal3 : public SignalBase
+ {
+ public:
+ typedef Slot3<R,P1,P2,P3> InSlotType;
+ typedef Slot3<typename Marsh::OutType,P1,P2,P3> OutSlotType;
+ typedef typename Trait<typename Marsh::OutType>::type OutType;
+
+ private:
+ // Used for both emit and proxy.
+ static OutType emit_(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void* data);
+
+ public:
+ OutSlotType slot() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ operator OutSlotType() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ /// You can call Connection::disconnect() later.
+ Connection connect(const InSlotType& s)
+ { return Connection(push_back(s)); }
+
+ /// Call all the connected methods.
+ OutType emit(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3)
+ { return emit_(p1,p2,p3,impl_); }
+
+ /// See emit()
+ OutType operator()(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3)
+ { return emit_(p1,p2,p3,impl_); }
+
+ Signal3()
+ : SignalBase()
+ {}
+
+ Signal3(const InSlotType& s)
+ : SignalBase()
+ { connect(s); }
+
+ ~Signal3() {}
+ };
+
+
+// emit
+template <class R,class P1,class P2,class P3,class Marsh>
+typename Signal3<R,P1,P2,P3,Marsh>::OutType
+Signal3<R,P1,P2,P3,Marsh>::emit_(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void* data)
+ {
+ SignalNode* impl = static_cast<SignalNode*>(data);
+
+ if (!impl || !impl->begin_)
+ return Marsh::default_value();
+
+ Exec exec(impl);
+ Marsh rc;
+ SlotNode* s = 0;
+
+ for (SignalConnectionNode* i = impl->begin_; i; i=i->next_)
+ {
+ if (i->blocked()) continue;
+ s = i->dest();
+ if (rc.marshal(((typename Slot3<R,P1,P2,P3>::Proxy)(s->proxy_))(p1,p2,p3,s)))
+ return rc.value();
+ }
+ return rc.value();
+ }
+
+
+
+/// @ingroup Signals
+template <class R,class P1,class P2,class P3,class P4,class Marsh=Marshal<R> >
+class Signal4 : public SignalBase
+ {
+ public:
+ typedef Slot4<R,P1,P2,P3,P4> InSlotType;
+ typedef Slot4<typename Marsh::OutType,P1,P2,P3,P4> OutSlotType;
+ typedef typename Trait<typename Marsh::OutType>::type OutType;
+
+ private:
+ // Used for both emit and proxy.
+ static OutType emit_(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,void* data);
+
+ public:
+ OutSlotType slot() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ operator OutSlotType() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ /// You can call Connection::disconnect() later.
+ Connection connect(const InSlotType& s)
+ { return Connection(push_back(s)); }
+
+ /// Call all the connected methods.
+ OutType emit(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4)
+ { return emit_(p1,p2,p3,p4,impl_); }
+
+ /// See emit()
+ OutType operator()(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4)
+ { return emit_(p1,p2,p3,p4,impl_); }
+
+ Signal4()
+ : SignalBase()
+ {}
+
+ Signal4(const InSlotType& s)
+ : SignalBase()
+ { connect(s); }
+
+ ~Signal4() {}
+ };
+
+
+// emit
+template <class R,class P1,class P2,class P3,class P4,class Marsh>
+typename Signal4<R,P1,P2,P3,P4,Marsh>::OutType
+Signal4<R,P1,P2,P3,P4,Marsh>::emit_(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,void* data)
+ {
+ SignalNode* impl = static_cast<SignalNode*>(data);
+
+ if (!impl || !impl->begin_)
+ return Marsh::default_value();
+
+ Exec exec(impl);
+ Marsh rc;
+ SlotNode* s = 0;
+
+ for (SignalConnectionNode* i = impl->begin_; i; i=i->next_)
+ {
+ if (i->blocked()) continue;
+ s = i->dest();
+ if (rc.marshal(((typename Slot4<R,P1,P2,P3,P4>::Proxy)(s->proxy_))(p1,p2,p3,p4,s)))
+ return rc.value();
+ }
+ return rc.value();
+ }
+
+
+
+/// @ingroup Signals
+template <class R,class P1,class P2,class P3,class P4,class P5,class Marsh=Marshal<R> >
+class Signal5 : public SignalBase
+ {
+ public:
+ typedef Slot5<R,P1,P2,P3,P4,P5> InSlotType;
+ typedef Slot5<typename Marsh::OutType,P1,P2,P3,P4,P5> OutSlotType;
+ typedef typename Trait<typename Marsh::OutType>::type OutType;
+
+ private:
+ // Used for both emit and proxy.
+ static OutType emit_(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,void* data);
+
+ public:
+ OutSlotType slot() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ operator OutSlotType() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ /// You can call Connection::disconnect() later.
+ Connection connect(const InSlotType& s)
+ { return Connection(push_back(s)); }
+
+ /// Call all the connected methods.
+ OutType emit(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5)
+ { return emit_(p1,p2,p3,p4,p5,impl_); }
+
+ /// See emit()
+ OutType operator()(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5)
+ { return emit_(p1,p2,p3,p4,p5,impl_); }
+
+ Signal5()
+ : SignalBase()
+ {}
+
+ Signal5(const InSlotType& s)
+ : SignalBase()
+ { connect(s); }
+
+ ~Signal5() {}
+ };
+
+
+// emit
+template <class R,class P1,class P2,class P3,class P4,class P5,class Marsh>
+typename Signal5<R,P1,P2,P3,P4,P5,Marsh>::OutType
+Signal5<R,P1,P2,P3,P4,P5,Marsh>::emit_(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,void* data)
+ {
+ SignalNode* impl = static_cast<SignalNode*>(data);
+
+ if (!impl || !impl->begin_)
+ return Marsh::default_value();
+
+ Exec exec(impl);
+ Marsh rc;
+ SlotNode* s = 0;
+
+ for (SignalConnectionNode* i = impl->begin_; i; i=i->next_)
+ {
+ if (i->blocked()) continue;
+ s = i->dest();
+ if (rc.marshal(((typename Slot5<R,P1,P2,P3,P4,P5>::Proxy)(s->proxy_))(p1,p2,p3,p4,p5,s)))
+ return rc.value();
+ }
+ return rc.value();
+ }
+
+
+
+#ifdef SIGC_CXX_PARTIAL_SPEC
+
+/// @ingroup Signals
+template <class Marsh>
+class Signal0<void,Marsh> : public SignalBase
+ {
+ public:
+ typedef Slot0<void> InSlotType;
+ typedef InSlotType OutSlotType;
+ typedef void OutType;
+
+ private:
+ // Used for both emit and proxy.
+ static OutType emit_(void* data);
+
+ public:
+ OutSlotType slot() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ operator OutSlotType() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ /// You can call Connection::disconnect() later.
+ Connection connect(const InSlotType& s)
+ { return Connection(push_back(s)); }
+
+ /// Call all the connected methods.
+ OutType emit()
+ { emit_(impl_); }
+
+ /// See emit()
+ OutType operator()()
+ { emit_(impl_); }
+
+ Signal0()
+ : SignalBase()
+ {}
+
+ Signal0(const InSlotType& s)
+ : SignalBase()
+ { connect(s); }
+
+ ~Signal0() {}
+ };
+
+
+// emit
+template <class Marsh>
+void Signal0<void,Marsh>::emit_(void* data)
+ {
+ SignalNode* impl = static_cast<SignalNode*>(data);
+
+ if (!impl||!impl->begin_)
+ return;
+
+ Exec exec(impl);
+ SlotNode* s = 0;
+ for (SignalConnectionNode* i = impl->begin_; i; i = i->next_)
+ {
+ if (i->blocked())
+ continue;
+
+ s = i->dest();
+ ((typename Slot0<void>::Proxy)(s->proxy_))(s);
+ }
+ return;
+ }
+
+
+
+/// @ingroup Signals
+template <class P1,class Marsh>
+class Signal1<void,P1,Marsh> : public SignalBase
+ {
+ public:
+ typedef Slot1<void,P1> InSlotType;
+ typedef InSlotType OutSlotType;
+ typedef void OutType;
+
+ private:
+ // Used for both emit and proxy.
+ static OutType emit_(typename Trait<P1>::ref p1,void* data);
+
+ public:
+ OutSlotType slot() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ operator OutSlotType() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ /// You can call Connection::disconnect() later.
+ Connection connect(const InSlotType& s)
+ { return Connection(push_back(s)); }
+
+ /// Call all the connected methods.
+ OutType emit(typename Trait<P1>::ref p1)
+ { emit_(p1,impl_); }
+
+ /// See emit()
+ OutType operator()(typename Trait<P1>::ref p1)
+ { emit_(p1,impl_); }
+
+ Signal1()
+ : SignalBase()
+ {}
+
+ Signal1(const InSlotType& s)
+ : SignalBase()
+ { connect(s); }
+
+ ~Signal1() {}
+ };
+
+
+// emit
+template <class P1,class Marsh>
+void Signal1<void,P1,Marsh>::emit_(typename Trait<P1>::ref p1,void* data)
+ {
+ SignalNode* impl = static_cast<SignalNode*>(data);
+
+ if (!impl||!impl->begin_)
+ return;
+
+ Exec exec(impl);
+ SlotNode* s = 0;
+ for (SignalConnectionNode* i = impl->begin_; i; i = i->next_)
+ {
+ if (i->blocked())
+ continue;
+
+ s = i->dest();
+ ((typename Slot1<void,P1>::Proxy)(s->proxy_))(p1,s);
+ }
+ return;
+ }
+
+
+
+/// @ingroup Signals
+template <class P1,class P2,class Marsh>
+class Signal2<void,P1,P2,Marsh> : public SignalBase
+ {
+ public:
+ typedef Slot2<void,P1,P2> InSlotType;
+ typedef InSlotType OutSlotType;
+ typedef void OutType;
+
+ private:
+ // Used for both emit and proxy.
+ static OutType emit_(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void* data);
+
+ public:
+ OutSlotType slot() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ operator OutSlotType() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ /// You can call Connection::disconnect() later.
+ Connection connect(const InSlotType& s)
+ { return Connection(push_back(s)); }
+
+ /// Call all the connected methods.
+ OutType emit(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2)
+ { emit_(p1,p2,impl_); }
+
+ /// See emit()
+ OutType operator()(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2)
+ { emit_(p1,p2,impl_); }
+
+ Signal2()
+ : SignalBase()
+ {}
+
+ Signal2(const InSlotType& s)
+ : SignalBase()
+ { connect(s); }
+
+ ~Signal2() {}
+ };
+
+
+// emit
+template <class P1,class P2,class Marsh>
+void Signal2<void,P1,P2,Marsh>::emit_(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void* data)
+ {
+ SignalNode* impl = static_cast<SignalNode*>(data);
+
+ if (!impl||!impl->begin_)
+ return;
+
+ Exec exec(impl);
+ SlotNode* s = 0;
+ for (SignalConnectionNode* i = impl->begin_; i; i = i->next_)
+ {
+ if (i->blocked())
+ continue;
+
+ s = i->dest();
+ ((typename Slot2<void,P1,P2>::Proxy)(s->proxy_))(p1,p2,s);
+ }
+ return;
+ }
+
+
+
+/// @ingroup Signals
+template <class P1,class P2,class P3,class Marsh>
+class Signal3<void,P1,P2,P3,Marsh> : public SignalBase
+ {
+ public:
+ typedef Slot3<void,P1,P2,P3> InSlotType;
+ typedef InSlotType OutSlotType;
+ typedef void OutType;
+
+ private:
+ // Used for both emit and proxy.
+ static OutType emit_(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void* data);
+
+ public:
+ OutSlotType slot() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ operator OutSlotType() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ /// You can call Connection::disconnect() later.
+ Connection connect(const InSlotType& s)
+ { return Connection(push_back(s)); }
+
+ /// Call all the connected methods.
+ OutType emit(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3)
+ { emit_(p1,p2,p3,impl_); }
+
+ /// See emit()
+ OutType operator()(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3)
+ { emit_(p1,p2,p3,impl_); }
+
+ Signal3()
+ : SignalBase()
+ {}
+
+ Signal3(const InSlotType& s)
+ : SignalBase()
+ { connect(s); }
+
+ ~Signal3() {}
+ };
+
+
+// emit
+template <class P1,class P2,class P3,class Marsh>
+void Signal3<void,P1,P2,P3,Marsh>::emit_(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void* data)
+ {
+ SignalNode* impl = static_cast<SignalNode*>(data);
+
+ if (!impl||!impl->begin_)
+ return;
+
+ Exec exec(impl);
+ SlotNode* s = 0;
+ for (SignalConnectionNode* i = impl->begin_; i; i = i->next_)
+ {
+ if (i->blocked())
+ continue;
+
+ s = i->dest();
+ ((typename Slot3<void,P1,P2,P3>::Proxy)(s->proxy_))(p1,p2,p3,s);
+ }
+ return;
+ }
+
+
+
+/// @ingroup Signals
+template <class P1,class P2,class P3,class P4,class Marsh>
+class Signal4<void,P1,P2,P3,P4,Marsh> : public SignalBase
+ {
+ public:
+ typedef Slot4<void,P1,P2,P3,P4> InSlotType;
+ typedef InSlotType OutSlotType;
+ typedef void OutType;
+
+ private:
+ // Used for both emit and proxy.
+ static OutType emit_(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,void* data);
+
+ public:
+ OutSlotType slot() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ operator OutSlotType() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ /// You can call Connection::disconnect() later.
+ Connection connect(const InSlotType& s)
+ { return Connection(push_back(s)); }
+
+ /// Call all the connected methods.
+ OutType emit(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4)
+ { emit_(p1,p2,p3,p4,impl_); }
+
+ /// See emit()
+ OutType operator()(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4)
+ { emit_(p1,p2,p3,p4,impl_); }
+
+ Signal4()
+ : SignalBase()
+ {}
+
+ Signal4(const InSlotType& s)
+ : SignalBase()
+ { connect(s); }
+
+ ~Signal4() {}
+ };
+
+
+// emit
+template <class P1,class P2,class P3,class P4,class Marsh>
+void Signal4<void,P1,P2,P3,P4,Marsh>::emit_(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,void* data)
+ {
+ SignalNode* impl = static_cast<SignalNode*>(data);
+
+ if (!impl||!impl->begin_)
+ return;
+
+ Exec exec(impl);
+ SlotNode* s = 0;
+ for (SignalConnectionNode* i = impl->begin_; i; i = i->next_)
+ {
+ if (i->blocked())
+ continue;
+
+ s = i->dest();
+ ((typename Slot4<void,P1,P2,P3,P4>::Proxy)(s->proxy_))(p1,p2,p3,p4,s);
+ }
+ return;
+ }
+
+
+
+/// @ingroup Signals
+template <class P1,class P2,class P3,class P4,class P5,class Marsh>
+class Signal5<void,P1,P2,P3,P4,P5,Marsh> : public SignalBase
+ {
+ public:
+ typedef Slot5<void,P1,P2,P3,P4,P5> InSlotType;
+ typedef InSlotType OutSlotType;
+ typedef void OutType;
+
+ private:
+ // Used for both emit and proxy.
+ static OutType emit_(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,void* data);
+
+ public:
+ OutSlotType slot() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ operator OutSlotType() const
+ { return create_slot((FuncPtr)(&emit_)); }
+
+ /// You can call Connection::disconnect() later.
+ Connection connect(const InSlotType& s)
+ { return Connection(push_back(s)); }
+
+ /// Call all the connected methods.
+ OutType emit(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5)
+ { emit_(p1,p2,p3,p4,p5,impl_); }
+
+ /// See emit()
+ OutType operator()(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5)
+ { emit_(p1,p2,p3,p4,p5,impl_); }
+
+ Signal5()
+ : SignalBase()
+ {}
+
+ Signal5(const InSlotType& s)
+ : SignalBase()
+ { connect(s); }
+
+ ~Signal5() {}
+ };
+
+
+// emit
+template <class P1,class P2,class P3,class P4,class P5,class Marsh>
+void Signal5<void,P1,P2,P3,P4,P5,Marsh>::emit_(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,void* data)
+ {
+ SignalNode* impl = static_cast<SignalNode*>(data);
+
+ if (!impl||!impl->begin_)
+ return;
+
+ Exec exec(impl);
+ SlotNode* s = 0;
+ for (SignalConnectionNode* i = impl->begin_; i; i = i->next_)
+ {
+ if (i->blocked())
+ continue;
+
+ s = i->dest();
+ ((typename Slot5<void,P1,P2,P3,P4,P5>::Proxy)(s->proxy_))(p1,p2,p3,p4,p5,s);
+ }
+ return;
+ }
+
+
+#endif
+
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+#endif // SIGC_SIGNAL_H
diff --git a/src/sigc++/slot.cpp b/src/sigc++/slot.cpp
new file mode 100644
index 0000000..718872a
--- /dev/null
+++ b/src/sigc++/slot.cpp
@@ -0,0 +1,93 @@
+// -*- c++ -*-
+/*
+ Copyright 2000, Karl Einar Nelson
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#include "sigc++/slot.h"
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+SlotNode::SlotNode(FuncPtr proxy)
+ : NodeBase(), proxy_(proxy), dep_(0)
+ {}
+
+SlotNode::~SlotNode(void)
+ {}
+
+/*********************************************************/
+
+void SlotNode::add_dependency(NodeBase* node)
+ {
+ if (!node) return;
+ Link* link=node->link();
+ if (!link) return;
+ link->next_=dep_;
+ link->prev_=0;
+ if (dep_)
+ dep_->link()->prev_=node;
+ dep_=node;
+ }
+
+void SlotNode::remove_dependency(NodeBase* node)
+ {
+ if (!node) return;
+ Link *link=node->link();
+ Link *nlink,*plink;
+ if (dep_==node)
+ dep_=link->next_;
+ if (link->next_)
+ {
+ nlink=link->next_->link();
+ nlink->prev_=link->prev_;
+ }
+ if (link->prev_)
+ {
+ plink=link->prev_->link();
+ plink->next_=link->next_;
+ }
+ }
+
+void SlotNode::notify(bool from_child)
+ {
+ Node hold(this);
+ NodeBase::notify(from_child);
+ NodeBase *n=dep_;
+ while (n)
+ {
+ NodeBase* next = n->link()->next_;
+ n->notify(true);
+ n = next;
+ }
+ dep_=0;
+ }
+
+/*********************************************************/
+
+FuncSlotNode::FuncSlotNode(FuncPtr proxy,FuncPtr func)
+ : SlotNode(proxy), func_(func)
+ {}
+
+FuncSlotNode::~FuncSlotNode()
+ {}
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+
diff --git a/src/sigc++/slot.h b/src/sigc++/slot.h
new file mode 100644
index 0000000..2c1b30e
--- /dev/null
+++ b/src/sigc++/slot.h
@@ -0,0 +1,495 @@
+// -*- c++ -*-
+// Copyright 2000, Karl Einar Nelson
+/* This is a generated file, do not edit. Generated from template.macros.m4 */
+
+#ifndef SIGC_SLOT_H
+#define SIGC_SLOT_H
+
+/* FIXME where is the docs buddy! */
+
+/** @defgroup Slots
+ * Slots are type-safe representations of callback methods and functions.
+ * A Slot can be constructed from any function, regardless of whether it is
+ * a global function, a member method, static, or virtual.
+ *
+ * Use the SigC::slot() template function to get a SigC::Slot, like so:
+ * @code
+ * SigC::Slot1<void, int> slot = SigC::slot(someobj, &SomeClass::somemethod);
+ * @endcode
+ * or
+ * @code
+ * m_Button.signal_clicked().connect( SigC::slot(*this, &MyWindow::on_button_clicked) );
+ * @endcode
+ * The compiler will complain if SomeClass::somemethod has the wrong signature.
+ *
+ * You can also pass slots as method parameters where you might normally pass a function pointer.
+ */
+
+#include <sigc++/node.h>
+#include <sigc++/trait.h>
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+// this is a dummy type which we will cast to any static function
+typedef void (*FuncPtr)(void*);
+
+// (internal) All Slot types derive from this.
+class LIBSIGC_API SlotNode: public NodeBase
+ {
+ public:
+ virtual ~SlotNode()=0;
+
+ // node must be dynamic
+ virtual void add_dependency(NodeBase*);
+ virtual void remove_dependency(NodeBase*);
+
+ // message from child that it has died and we should start
+ // our shut down. If from_child is true, we do not need
+ // to clean up the child links.
+ virtual void notify(bool from_child);
+
+ SlotNode(FuncPtr proxy);
+
+ FuncPtr proxy_;
+ NodeBase *dep_;
+ };
+
+/**************************************************************/
+// These are internal classes used to represent function varients of slots
+
+// (internal)
+struct LIBSIGC_API FuncSlotNode : public SlotNode
+ {
+ FuncPtr func_;
+ FuncSlotNode(FuncPtr proxy,FuncPtr func);
+ virtual ~FuncSlotNode();
+ };
+
+
+
+// These do not derive from FuncSlot, they merely hold typedefs and
+// static functions on how to deal with the proxy.
+template <class R>
+struct FuncSlot0_
+ {
+ typedef typename Trait<R>::type RType;
+ typedef RType (*Callback)();
+ static RType proxy(void *s)
+ {
+ return ((Callback)(((FuncSlotNode*)s)->func_))();
+ }
+ };
+
+template <class R,class P1>
+struct FuncSlot1_
+ {
+ typedef typename Trait<R>::type RType;
+ typedef RType (*Callback)(P1);
+ static RType proxy(typename Trait<P1>::ref p1,void *s)
+ {
+ return ((Callback)(((FuncSlotNode*)s)->func_))(p1);
+ }
+ };
+
+template <class R,class P1,class P2>
+struct FuncSlot2_
+ {
+ typedef typename Trait<R>::type RType;
+ typedef RType (*Callback)(P1,P2);
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void *s)
+ {
+ return ((Callback)(((FuncSlotNode*)s)->func_))(p1,p2);
+ }
+ };
+
+template <class R,class P1,class P2,class P3>
+struct FuncSlot3_
+ {
+ typedef typename Trait<R>::type RType;
+ typedef RType (*Callback)(P1,P2,P3);
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void *s)
+ {
+ return ((Callback)(((FuncSlotNode*)s)->func_))(p1,p2,p3);
+ }
+ };
+
+template <class R,class P1,class P2,class P3,class P4>
+struct FuncSlot4_
+ {
+ typedef typename Trait<R>::type RType;
+ typedef RType (*Callback)(P1,P2,P3,P4);
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,void *s)
+ {
+ return ((Callback)(((FuncSlotNode*)s)->func_))(p1,p2,p3,p4);
+ }
+ };
+
+template <class R,class P1,class P2,class P3,class P4,class P5>
+struct FuncSlot5_
+ {
+ typedef typename Trait<R>::type RType;
+ typedef RType (*Callback)(P1,P2,P3,P4,P5);
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,void *s)
+ {
+ return ((Callback)(((FuncSlotNode*)s)->func_))(p1,p2,p3,p4,p5);
+ }
+ };
+
+template <class R,class P1,class P2,class P3,class P4,class P5,class P6>
+struct FuncSlot6_
+ {
+ typedef typename Trait<R>::type RType;
+ typedef RType (*Callback)(P1,P2,P3,P4,P5,P6);
+ static RType proxy(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,typename Trait<P6>::ref p6,void *s)
+ {
+ return ((Callback)(((FuncSlotNode*)s)->func_))(p1,p2,p3,p4,p5,p6);
+ }
+ };
+
+
+/**************************************************************/
+// Slot# is a holder to a SlotNode, its type is held by type of the
+// pointer and not the SlotNode itself. This reduces the
+// number and size of type objects.
+
+/// (internal) Typeless Slot base class.
+class LIBSIGC_API SlotBase : public Node
+ {
+ public:
+ // For backwards compatiblity
+ bool connected() const { return valid(); }
+
+ // (internal)
+ SlotNode* operator->() { return static_cast<SlotNode*>(node_); }
+ protected:
+ // users don't use slots so we will protect the methods
+ SlotBase() : Node() {}
+ SlotBase(const SlotBase& s) : Node(s) {}
+ ~SlotBase() {}
+
+ SlotBase& operator =(const SlotBase& s)
+ { Node::operator=(s); return *this; }
+ };
+
+
+
+// these represent the callable structure of a slot with various types.
+// they are fundimentally just wrappers. They have no differences other
+// that the types they cast data to.
+/// @ingroup Slots
+template <class R>
+class Slot0 : public SlotBase
+ {
+ public:
+ typedef typename Trait<R>::type RType;
+ typedef R (*Callback)();
+ typedef RType (*Proxy)(void*);
+ RType operator ()()
+ {
+ if (!node_) return RType();
+ if (node_->notified_)
+ { clear(); return RType(); }
+ return ((Proxy)(static_cast<SlotNode*>(node_)->proxy_))
+ (node_);
+ }
+
+ Slot0& operator= (const Slot0 &s)
+ {
+ SlotBase::operator=(s);
+ return *this;
+ }
+
+ Slot0()
+ : SlotBase() {}
+ Slot0(const Slot0& s)
+ : SlotBase(s)
+ {}
+ Slot0(SlotNode* node)
+ : SlotBase()
+ { assign(node); }
+ Slot0(Callback callback)
+ : SlotBase()
+ {
+ typedef FuncSlot0_<R> Proxy_;
+ assign(new FuncSlotNode((FuncPtr)&Proxy_::proxy,(FuncPtr)callback));
+ }
+ ~Slot0() {}
+ };
+
+template <class R>
+Slot0<R> slot(R (*func)())
+ { return func; }
+
+/// @ingroup Slots
+template <class R,class P1>
+class Slot1 : public SlotBase
+ {
+ public:
+ typedef typename Trait<R>::type RType;
+ typedef R (*Callback)(P1);
+ typedef RType (*Proxy)(typename Trait<P1>::ref p1,void*);
+ RType operator ()(typename Trait<P1>::ref p1)
+ {
+ if (!node_) return RType();
+ if (node_->notified_)
+ { clear(); return RType(); }
+ return ((Proxy)(static_cast<SlotNode*>(node_)->proxy_))
+ (p1,node_);
+ }
+
+ Slot1& operator= (const Slot1 &s)
+ {
+ SlotBase::operator=(s);
+ return *this;
+ }
+
+ Slot1()
+ : SlotBase() {}
+ Slot1(const Slot1& s)
+ : SlotBase(s)
+ {}
+ Slot1(SlotNode* node)
+ : SlotBase()
+ { assign(node); }
+ Slot1(Callback callback)
+ : SlotBase()
+ {
+ typedef FuncSlot1_<R,P1> Proxy_;
+ assign(new FuncSlotNode((FuncPtr)&Proxy_::proxy,(FuncPtr)callback));
+ }
+ ~Slot1() {}
+ };
+
+template <class R,class P1>
+Slot1<R,P1> slot(R (*func)(P1))
+ { return func; }
+
+/// @ingroup Slots
+template <class R,class P1,class P2>
+class Slot2 : public SlotBase
+ {
+ public:
+ typedef typename Trait<R>::type RType;
+ typedef R (*Callback)(P1,P2);
+ typedef RType (*Proxy)(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,void*);
+ RType operator ()(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2)
+ {
+ if (!node_) return RType();
+ if (node_->notified_)
+ { clear(); return RType(); }
+ return ((Proxy)(static_cast<SlotNode*>(node_)->proxy_))
+ (p1,p2,node_);
+ }
+
+ Slot2& operator= (const Slot2 &s)
+ {
+ SlotBase::operator=(s);
+ return *this;
+ }
+
+ Slot2()
+ : SlotBase() {}
+ Slot2(const Slot2& s)
+ : SlotBase(s)
+ {}
+ Slot2(SlotNode* node)
+ : SlotBase()
+ { assign(node); }
+ Slot2(Callback callback)
+ : SlotBase()
+ {
+ typedef FuncSlot2_<R,P1,P2> Proxy_;
+ assign(new FuncSlotNode((FuncPtr)&Proxy_::proxy,(FuncPtr)callback));
+ }
+ ~Slot2() {}
+ };
+
+template <class R,class P1,class P2>
+Slot2<R,P1,P2> slot(R (*func)(P1,P2))
+ { return func; }
+
+/// @ingroup Slots
+template <class R,class P1,class P2,class P3>
+class Slot3 : public SlotBase
+ {
+ public:
+ typedef typename Trait<R>::type RType;
+ typedef R (*Callback)(P1,P2,P3);
+ typedef RType (*Proxy)(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,void*);
+ RType operator ()(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3)
+ {
+ if (!node_) return RType();
+ if (node_->notified_)
+ { clear(); return RType(); }
+ return ((Proxy)(static_cast<SlotNode*>(node_)->proxy_))
+ (p1,p2,p3,node_);
+ }
+
+ Slot3& operator= (const Slot3 &s)
+ {
+ SlotBase::operator=(s);
+ return *this;
+ }
+
+ Slot3()
+ : SlotBase() {}
+ Slot3(const Slot3& s)
+ : SlotBase(s)
+ {}
+ Slot3(SlotNode* node)
+ : SlotBase()
+ { assign(node); }
+ Slot3(Callback callback)
+ : SlotBase()
+ {
+ typedef FuncSlot3_<R,P1,P2,P3> Proxy_;
+ assign(new FuncSlotNode((FuncPtr)&Proxy_::proxy,(FuncPtr)callback));
+ }
+ ~Slot3() {}
+ };
+
+template <class R,class P1,class P2,class P3>
+Slot3<R,P1,P2,P3> slot(R (*func)(P1,P2,P3))
+ { return func; }
+
+/// @ingroup Slots
+template <class R,class P1,class P2,class P3,class P4>
+class Slot4 : public SlotBase
+ {
+ public:
+ typedef typename Trait<R>::type RType;
+ typedef R (*Callback)(P1,P2,P3,P4);
+ typedef RType (*Proxy)(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,void*);
+ RType operator ()(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4)
+ {
+ if (!node_) return RType();
+ if (node_->notified_)
+ { clear(); return RType(); }
+ return ((Proxy)(static_cast<SlotNode*>(node_)->proxy_))
+ (p1,p2,p3,p4,node_);
+ }
+
+ Slot4& operator= (const Slot4 &s)
+ {
+ SlotBase::operator=(s);
+ return *this;
+ }
+
+ Slot4()
+ : SlotBase() {}
+ Slot4(const Slot4& s)
+ : SlotBase(s)
+ {}
+ Slot4(SlotNode* node)
+ : SlotBase()
+ { assign(node); }
+ Slot4(Callback callback)
+ : SlotBase()
+ {
+ typedef FuncSlot4_<R,P1,P2,P3,P4> Proxy_;
+ assign(new FuncSlotNode((FuncPtr)&Proxy_::proxy,(FuncPtr)callback));
+ }
+ ~Slot4() {}
+ };
+
+template <class R,class P1,class P2,class P3,class P4>
+Slot4<R,P1,P2,P3,P4> slot(R (*func)(P1,P2,P3,P4))
+ { return func; }
+
+/// @ingroup Slots
+template <class R,class P1,class P2,class P3,class P4,class P5>
+class Slot5 : public SlotBase
+ {
+ public:
+ typedef typename Trait<R>::type RType;
+ typedef R (*Callback)(P1,P2,P3,P4,P5);
+ typedef RType (*Proxy)(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,void*);
+ RType operator ()(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5)
+ {
+ if (!node_) return RType();
+ if (node_->notified_)
+ { clear(); return RType(); }
+ return ((Proxy)(static_cast<SlotNode*>(node_)->proxy_))
+ (p1,p2,p3,p4,p5,node_);
+ }
+
+ Slot5& operator= (const Slot5 &s)
+ {
+ SlotBase::operator=(s);
+ return *this;
+ }
+
+ Slot5()
+ : SlotBase() {}
+ Slot5(const Slot5& s)
+ : SlotBase(s)
+ {}
+ Slot5(SlotNode* node)
+ : SlotBase()
+ { assign(node); }
+ Slot5(Callback callback)
+ : SlotBase()
+ {
+ typedef FuncSlot5_<R,P1,P2,P3,P4,P5> Proxy_;
+ assign(new FuncSlotNode((FuncPtr)&Proxy_::proxy,(FuncPtr)callback));
+ }
+ ~Slot5() {}
+ };
+
+template <class R,class P1,class P2,class P3,class P4,class P5>
+Slot5<R,P1,P2,P3,P4,P5> slot(R (*func)(P1,P2,P3,P4,P5))
+ { return func; }
+
+/// @ingroup Slots
+template <class R,class P1,class P2,class P3,class P4,class P5,class P6>
+class Slot6 : public SlotBase
+ {
+ public:
+ typedef typename Trait<R>::type RType;
+ typedef R (*Callback)(P1,P2,P3,P4,P5,P6);
+ typedef RType (*Proxy)(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,typename Trait<P6>::ref p6,void*);
+ RType operator ()(typename Trait<P1>::ref p1,typename Trait<P2>::ref p2,typename Trait<P3>::ref p3,typename Trait<P4>::ref p4,typename Trait<P5>::ref p5,typename Trait<P6>::ref p6)
+ {
+ if (!node_) return RType();
+ if (node_->notified_)
+ { clear(); return RType(); }
+ return ((Proxy)(static_cast<SlotNode*>(node_)->proxy_))
+ (p1,p2,p3,p4,p5,p6,node_);
+ }
+
+ Slot6& operator= (const Slot6 &s)
+ {
+ SlotBase::operator=(s);
+ return *this;
+ }
+
+ Slot6()
+ : SlotBase() {}
+ Slot6(const Slot6& s)
+ : SlotBase(s)
+ {}
+ Slot6(SlotNode* node)
+ : SlotBase()
+ { assign(node); }
+ Slot6(Callback callback)
+ : SlotBase()
+ {
+ typedef FuncSlot6_<R,P1,P2,P3,P4,P5,P6> Proxy_;
+ assign(new FuncSlotNode((FuncPtr)&Proxy_::proxy,(FuncPtr)callback));
+ }
+ ~Slot6() {}
+ };
+
+template <class R,class P1,class P2,class P3,class P4,class P5,class P6>
+Slot6<R,P1,P2,P3,P4,P5,P6> slot(R (*func)(P1,P2,P3,P4,P5,P6))
+ { return func; }
+
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+#endif // SIGC_SLOT
diff --git a/src/sigc++/trait.h b/src/sigc++/trait.h
new file mode 100644
index 0000000..013e29c
--- /dev/null
+++ b/src/sigc++/trait.h
@@ -0,0 +1,72 @@
+// -*- c++ -*-
+/*
+ Copyright 2000, Karl Einar Nelson
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#ifndef SIGC_TRAIT
+#define SIGC_TRAIT
+
+#include <sigc++/sigcconfig.h>
+
+#ifdef SIGC_CXX_NAMESPACES
+namespace SigC
+{
+#endif
+
+#ifdef SIGC_CXX_SPECIALIZE_REFERENCES
+template <class T>
+struct Trait
+ {
+ typedef T type;
+ typedef const T& ref;
+ };
+
+template <class T>
+struct Trait<T&>
+ {
+ typedef T& type;
+ typedef T& ref;
+ };
+#else
+// for really dumb compilers, we have to copy rather than reference
+template <class T>
+struct Trait
+ {
+ typedef T type;
+ typedef T ref;
+ };
+#endif
+
+#ifdef SIGC_CXX_VOID_RETURN
+template <>
+struct Trait<void>
+ {
+ typedef void type;
+ };
+#else
+template <>
+struct Trait<void>
+ {
+ typedef int type;
+ };
+#endif
+
+#ifdef SIGC_CXX_NAMESPACES
+}
+#endif
+
+
+#endif // SIGC_TRAIT

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 16, 1:12 AM (2 w, 20 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
72380
Default Alt Text
(839 KB)

Event Timeline