313 lines
7.9 KiB
C++
313 lines
7.9 KiB
C++
|
// Copyright (C) 2007 Id Software, Inc.
|
||
|
//
|
||
|
|
||
|
|
||
|
#include "../precompiled.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#if defined( _DEBUG ) && !defined( ID_REDIRECT_NEWDELETE )
|
||
|
#define new DEBUG_NEW
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
#include "UIWindow.h"
|
||
|
#include "UserInterfaceLocal.h"
|
||
|
#include "UICreditScroll.h"
|
||
|
|
||
|
#include "../../sys/sys_local.h"
|
||
|
|
||
|
SD_UI_IMPLEMENT_CLASS( sdUICreditScroll, sdUIWindow )
|
||
|
|
||
|
idHashMap< sdUITemplateFunction< sdUICreditScroll >* > sdUICreditScroll::creditFunctions;
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUICreditScroll::sdUICreditScroll
|
||
|
============
|
||
|
*/
|
||
|
sdUICreditScroll::sdUICreditScroll( void ) :
|
||
|
items( NULL ),
|
||
|
totalHeight( 0.0f ),
|
||
|
scrollStartTime( 0 ),
|
||
|
scrollTargetTime( 0 ) {
|
||
|
scriptState.GetProperties().RegisterProperty( "speed", speed );
|
||
|
|
||
|
speed = 5.0f;
|
||
|
scrollOffset = 0.0f;
|
||
|
|
||
|
SetWindowFlag( WF_CLIP_TO_RECT );
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUICreditScroll::~sdUICreditScroll
|
||
|
============
|
||
|
*/
|
||
|
sdUICreditScroll::~sdUICreditScroll( void ) {
|
||
|
DisconnectGlobalCallbacks();
|
||
|
ClearItems();
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUICreditScroll::ClearItems
|
||
|
============
|
||
|
*/
|
||
|
void sdUICreditScroll::ClearItems() {
|
||
|
while( items != NULL ) {
|
||
|
sdCreditItem* next = items->next;
|
||
|
delete items;
|
||
|
items = next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUICreditScroll::GetFunction
|
||
|
============
|
||
|
*/
|
||
|
sdUIFunctionInstance* sdUICreditScroll::GetFunction( const char* name ) {
|
||
|
const sdUITemplateFunction< sdUICreditScroll >* function = sdUICreditScroll::FindFunction( name );
|
||
|
if( !function ) {
|
||
|
return sdUIWindow::GetFunction( name );
|
||
|
}
|
||
|
|
||
|
return new sdUITemplateFunctionInstance< sdUICreditScroll, sdUITemplateFunctionInstance_IdentifierTimeline >( this, function );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUICreditScroll::FindFunction
|
||
|
============
|
||
|
*/
|
||
|
const sdUITemplateFunction< sdUICreditScroll >* sdUICreditScroll::FindFunction( const char* name ) {
|
||
|
sdUITemplateFunction< sdUICreditScroll >** ptr;
|
||
|
return creditFunctions.Get( name, &ptr ) ? *ptr : NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUICreditScroll::InitFunctions
|
||
|
============
|
||
|
*/
|
||
|
SD_UI_PUSH_CLASS_TAG( sdUICreditScroll )
|
||
|
void sdUICreditScroll::InitFunctions() {
|
||
|
SD_UI_FUNC_TAG( resetScroll, "Reset scroll amount." )
|
||
|
SD_UI_END_FUNC_TAG
|
||
|
creditFunctions.Set( "resetScroll", new sdUITemplateFunction< sdUICreditScroll >( 'v', "", &sdUICreditScroll::Script_ResetScroll ) );
|
||
|
|
||
|
SD_UI_FUNC_TAG( loadFromFile, "Load the text to scroll from a file. Supports UTF8." )
|
||
|
SD_UI_FUNC_PARM( string, "filePath", "File to load data from." )
|
||
|
SD_UI_END_FUNC_TAG
|
||
|
creditFunctions.Set( "loadFromFile",new sdUITemplateFunction< sdUICreditScroll >( 'v', "s", &sdUICreditScroll::Script_LoadFromFile ) );
|
||
|
}
|
||
|
SD_UI_POP_CLASS_TAG
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUICreditScroll::Script_ResetScroll
|
||
|
============
|
||
|
*/
|
||
|
void sdUICreditScroll::Script_ResetScroll( sdUIFunctionStack& stack ) {
|
||
|
scrollOffset = 0.0f;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUICreditScroll::DrawLocal
|
||
|
============
|
||
|
*/
|
||
|
void sdUICreditScroll::DrawLocal() {
|
||
|
const sdCreditItem* item = items;
|
||
|
|
||
|
sdBounds2D bounds( cachedClientRect );
|
||
|
while( item != NULL ) {
|
||
|
sdBounds2D b( item->rect );
|
||
|
b.TranslateSelf( 0.0f, scrollOffset );
|
||
|
|
||
|
if( b.IntersectsBounds( bounds ) ) {
|
||
|
if( item->material.material != NULL ) {
|
||
|
deviceContext->DrawMaterial( item->rect.x, item->rect.y + scrollOffset, item->rect.z, item->rect.w, item->material.material, item->color, item->material.st0, item->material.st1 );
|
||
|
} else {
|
||
|
deviceContext->SetColor( item->color );
|
||
|
|
||
|
deviceContext->SetFontSize( fontSize + item->fontSize );
|
||
|
deviceContext->DrawText( item->text.c_str(), b, DTF_TOP | DTF_SINGLELINE | DTF_CENTER );
|
||
|
}
|
||
|
}
|
||
|
item = item->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUICreditScroll::Script_LoadFromFile
|
||
|
============
|
||
|
*/
|
||
|
void sdUICreditScroll::Script_LoadFromFile( sdUIFunctionStack& stack ) {
|
||
|
ClearItems();
|
||
|
|
||
|
idStr fileName;
|
||
|
stack.Pop( fileName );
|
||
|
|
||
|
sdFilePtr file( fileSystem->OpenFileRead( fileName.c_str() ) );
|
||
|
if( !file.IsValid() ) {
|
||
|
gameLocal.Warning( "%s: Script_LoadFromFile: could not find '%s'", name.GetValue().c_str(), fileName.c_str() );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
sdUTF8 utf8( file.Get() );
|
||
|
file.Release();
|
||
|
|
||
|
int numChars = utf8.DecodeLength();
|
||
|
wchar_t* ucs2 = static_cast< wchar_t* >( Mem_Alloc( ( numChars + 1 ) * sizeof( wchar_t ) ) );
|
||
|
|
||
|
utf8.Decode( ucs2 );
|
||
|
|
||
|
idWLexer src( ucs2, idWStr::Length( ucs2 ), fileName );
|
||
|
if ( !src.IsLoaded() ) {
|
||
|
Mem_Free( ucs2 );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
declManager->AddDependency( GetUI()->GetDecl(), fileName.c_str() );
|
||
|
|
||
|
lastItem = NULL;
|
||
|
|
||
|
idWToken token;
|
||
|
while( src.ReadToken( &token ) ) {
|
||
|
|
||
|
int i = token.linesCrossed;
|
||
|
while( i > 1 ) {
|
||
|
sdCreditItem* item = new sdCreditItem;
|
||
|
item->rect.w = 8.0f;
|
||
|
Append( item );
|
||
|
i--;
|
||
|
}
|
||
|
sdCreditItem* item = new sdCreditItem;
|
||
|
|
||
|
bool needText = false;
|
||
|
bool useText = true;
|
||
|
if( token.Cmp( L"material" ) == 0 ) {
|
||
|
idWToken w;
|
||
|
idWToken h;
|
||
|
src.ReadToken( &w );
|
||
|
src.ReadToken( &h );
|
||
|
|
||
|
src.ReadToken( &token );
|
||
|
|
||
|
GetUI()->LookupMaterial( va( "%ls", token.c_str() ), item->material );
|
||
|
|
||
|
assert( w.type == TT_NUMBER );
|
||
|
assert( h.type == TT_NUMBER );
|
||
|
item->rect.z = w.GetFloatValue();
|
||
|
item->rect.w = h.GetFloatValue();
|
||
|
useText = false;
|
||
|
item->color = colorWhite;
|
||
|
} else if( token.Icmp( L"small" ) == 0 ) {
|
||
|
item->fontSize = -2;
|
||
|
needText = true;
|
||
|
item->color = colorWhite;
|
||
|
} else if( token.Icmp( L"big" ) == 0 ) {
|
||
|
item->fontSize = 2;
|
||
|
item->color = colorWhite;
|
||
|
needText = true;
|
||
|
} else if( token.Icmp( L"huge" ) == 0 ) {
|
||
|
item->fontSize = 4;
|
||
|
item->color = colorWhite;
|
||
|
needText = true;
|
||
|
}
|
||
|
|
||
|
if( needText ) {
|
||
|
src.ReadToken( &token );
|
||
|
}
|
||
|
|
||
|
if( useText ) {
|
||
|
assert( token.type == TT_STRING );
|
||
|
item->text = token.c_str();
|
||
|
}
|
||
|
|
||
|
Append( item );
|
||
|
}
|
||
|
MakeLayoutDirty();
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUICreditScroll::Append
|
||
|
============
|
||
|
*/
|
||
|
void sdUICreditScroll::Append( sdCreditItem* item ) {
|
||
|
if( items == NULL ) {
|
||
|
items = item;
|
||
|
} else if( lastItem != NULL ) {
|
||
|
lastItem->next = item;
|
||
|
}
|
||
|
lastItem = item;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUICreditScroll::ApplyLayout
|
||
|
============
|
||
|
*/
|
||
|
void sdUICreditScroll::ApplyLayout() {
|
||
|
bool apply = windowState.recalculateLayout;
|
||
|
sdUIWindow::ApplyLayout();
|
||
|
|
||
|
if( apply ) {
|
||
|
float yOffset = 0.0f;
|
||
|
sdBounds2D measureRect( 0.0f, 0.0f, cachedClientRect.z * 0.33f, SCREEN_HEIGHT );
|
||
|
int w;
|
||
|
int h;
|
||
|
|
||
|
ActivateFont( true );
|
||
|
|
||
|
sdCreditItem* item = items;
|
||
|
while( item != NULL ) {
|
||
|
if( item->material.material != NULL ) {
|
||
|
item->rect.x = cachedClientRect.x + ( cachedClientRect.z * 0.5f ) - ( item->rect.z * 0.5f );
|
||
|
item->rect.y = cachedClientRect.y + yOffset;
|
||
|
} else if( !item->text.IsEmpty() ) {
|
||
|
deviceContext->SetFontSize( fontSize + item->fontSize );
|
||
|
deviceContext->GetTextDimensions( item->text.c_str(), measureRect, DTF_SINGLELINE | DTF_CENTER | DTF_TOP, cachedFontHandle, fontSize + item->fontSize, w, h );
|
||
|
item->rect.x = cachedClientRect.x + ( cachedClientRect.z * 0.5f ) - ( w * 0.5f );
|
||
|
item->rect.y = cachedClientRect.y + yOffset;
|
||
|
item->rect.z = w;
|
||
|
item->rect.w = h;
|
||
|
}
|
||
|
yOffset += item->rect.w;
|
||
|
item = item->next;
|
||
|
}
|
||
|
totalHeight = yOffset;
|
||
|
scrollOffset = cachedClientRect.w;
|
||
|
scrollStartTime = 0;
|
||
|
scrollTargetTime = 0;
|
||
|
}
|
||
|
|
||
|
const int now = GetUI()->GetCurrentTime();
|
||
|
|
||
|
float ratio = totalHeight / cachedClientRect.w;
|
||
|
if ( ratio < 1.0f ) {
|
||
|
ratio = 1.0f;
|
||
|
}
|
||
|
|
||
|
if ( now >= scrollTargetTime || scrollStartTime == scrollTargetTime || now < scrollStartTime ) {
|
||
|
scrollStartTime = now;
|
||
|
}
|
||
|
scrollTargetTime = scrollStartTime + SEC2MS( speed * ratio );
|
||
|
|
||
|
float totalTime = static_cast< float >( scrollTargetTime - scrollStartTime );
|
||
|
float percent = static_cast< float >( now - scrollStartTime ) / totalTime;
|
||
|
|
||
|
scrollOffset = cachedClientRect.w - percent * ( cachedClientRect.w + totalHeight );
|
||
|
|
||
|
if( idMath::Fabs( scrollOffset ) >= totalHeight ) {
|
||
|
scrollOffset = cachedClientRect.w;
|
||
|
}
|
||
|
}
|