544 lines
13 KiB
C++
544 lines
13 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 "UserInterfaceManager.h"
|
||
|
#include "UILayout.h"
|
||
|
#include "UserInterfaceLocal.h"
|
||
|
|
||
|
using namespace sdProperties;
|
||
|
|
||
|
SD_UI_IMPLEMENT_CLASS( sdUILayout_Static, sdUIObject_Drawable )
|
||
|
|
||
|
idCVar gui_debugLayout( "gui_debugLayout", "0", CVAR_GAME | CVAR_BOOL, "Debug UI layout classes" );
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_Static::sdUILayout_Static
|
||
|
============
|
||
|
*/
|
||
|
sdUILayout_Static::sdUILayout_Static() {
|
||
|
GetScope().GetProperties().RegisterProperty( "rect", rect );
|
||
|
GetScope().GetProperties().RegisterProperty( "absoluteRect", absoluteRect );
|
||
|
GetScope().GetProperties().RegisterProperty( "visible", visible );
|
||
|
|
||
|
rect = idVec4( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT );
|
||
|
|
||
|
absoluteRect = rect;
|
||
|
absoluteRect.SetReadOnly( true );
|
||
|
visible = 1.0f;
|
||
|
|
||
|
recalculateLayout = true;
|
||
|
|
||
|
UI_ADD_VEC4_CALLBACK( rect, sdUILayout_StaticBase, OnRectChanged )
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_Static::~sdUILayout_Static
|
||
|
============
|
||
|
*/
|
||
|
sdUILayout_Static::~sdUILayout_Static() {
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_Static::ApplyLayout
|
||
|
============
|
||
|
*/
|
||
|
void sdUILayout_Static::ApplyLayout() {
|
||
|
if( recalculateLayout ) {
|
||
|
sdUIObject* object = GetNode().GetParent();
|
||
|
idVec4 cachedOffset( rect );
|
||
|
|
||
|
while( object != NULL ) {
|
||
|
if( sdProperty* rect = object->GetScope().GetProperty( "rect", sdProperties::PT_VEC4 ) ) {
|
||
|
cachedOffset.ToVec2() += rect->value.vec4Value->GetValue().ToVec2();
|
||
|
}
|
||
|
object = object->GetNode().GetParent();
|
||
|
}
|
||
|
|
||
|
absoluteRect.SetReadOnly( false );
|
||
|
absoluteRect = cachedOffset;
|
||
|
absoluteRect.SetReadOnly( true );
|
||
|
|
||
|
DoApplyLayout();
|
||
|
recalculateLayout = false;
|
||
|
}
|
||
|
sdUIObject::ApplyLayout();
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_Static::UpdateToolTip
|
||
|
============
|
||
|
*/
|
||
|
sdUIObject* sdUILayout_Static::UpdateToolTip( const idVec2& cursor ) {
|
||
|
if( !visible ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
sdUIObject* prev = NULL;
|
||
|
sdUIObject* child = GetNode().GetChild();
|
||
|
while( child != NULL ) {
|
||
|
prev = child;
|
||
|
child = child->GetNode().GetSibling();
|
||
|
}
|
||
|
|
||
|
child = prev;
|
||
|
while( child != NULL ) {
|
||
|
if( sdUIObject* result = child->UpdateToolTip( cursor ) ) {
|
||
|
return result;
|
||
|
}
|
||
|
child = child->GetNode().GetPriorSibling();
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_Static::OnRectChanged
|
||
|
============
|
||
|
*/
|
||
|
void sdUILayout_Static::OnRectChanged( const idVec4& oldValue, const idVec4& newValue ) {
|
||
|
MakeLayoutDirty();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_StaticBase::OnChildRectChanged
|
||
|
============
|
||
|
*/
|
||
|
void sdUILayout_StaticBase::OnChildRectChanged( const idVec4& oldValue, const idVec4& newValue ) {
|
||
|
for( int i = 0; i < childRects.Num(); i++ ) {
|
||
|
rectInfo_t& info = childRects[ i ];
|
||
|
info.rect.z = info.property->value.vec4Value->GetValue().z;
|
||
|
info.rect.w = info.property->value.vec4Value->GetValue().w;
|
||
|
}
|
||
|
|
||
|
MakeLayoutDirty();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_Static::Draw
|
||
|
============
|
||
|
*/
|
||
|
void sdUILayout_Static::Draw() {
|
||
|
if( !visible ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
sdUIObject* child = GetNode().GetChild();
|
||
|
while( child != NULL ) {
|
||
|
if( sdUIObject_Drawable* window = child->Cast< sdUIObject_Drawable >() ) {
|
||
|
window->Draw();
|
||
|
}
|
||
|
child = child->GetNode().GetSibling();
|
||
|
}
|
||
|
if( gui_debugLayout.GetBool() ) {
|
||
|
deviceContext->DrawClippedBox( absoluteRect.GetValue().x, absoluteRect.GetValue().y, absoluteRect.GetValue().z, absoluteRect.GetValue().w, 1.0f, colorGreen );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_Static::FinalDraw
|
||
|
============
|
||
|
*/
|
||
|
void sdUILayout_Static::FinalDraw() {
|
||
|
if( !visible ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
sdUIObject* child = GetNode().GetChild();
|
||
|
while( child != NULL ) {
|
||
|
if( sdUIObject_Drawable* window = child->Cast< sdUIObject_Drawable >() ) {
|
||
|
window->FinalDraw();
|
||
|
}
|
||
|
child = child->GetNode().GetSibling();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_Static::PostEvent
|
||
|
============
|
||
|
*/
|
||
|
bool sdUILayout_Static::PostEvent( const sdSysEvent* event ) {
|
||
|
if( !visible ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
sdUIObject* child = GetNode().GetChild();
|
||
|
while( child != NULL ) {
|
||
|
if( child->PostEvent( event ) ) {
|
||
|
return true;
|
||
|
}
|
||
|
child = child->GetNode().GetSibling();
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_Static::HandleFocus
|
||
|
============
|
||
|
*/
|
||
|
bool sdUILayout_Static::HandleFocus( const sdSysEvent* event ) {
|
||
|
if( !visible ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
sdUIObject* prev = NULL;
|
||
|
sdUIObject* child = GetNode().GetChild();
|
||
|
while( child != NULL ) {
|
||
|
prev = child;
|
||
|
child = child->GetNode().GetSibling();
|
||
|
}
|
||
|
|
||
|
child = prev;
|
||
|
|
||
|
while( child != NULL ) {
|
||
|
if( child->HandleFocus( event ) ) {
|
||
|
return true;
|
||
|
}
|
||
|
child = child->GetNode().GetPriorSibling();
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
SD_UI_IMPLEMENT_CLASS( sdUILayout_StaticBase, sdUILayout_Static )
|
||
|
|
||
|
extern const char sdUITemplateFunctionInstance_IdentifierLayout_Table[] = "Layout_Table";
|
||
|
idHashMap< sdUILayout_StaticBase::sdUILayoutFunction* > sdUILayout_StaticBase::layoutFunctions;
|
||
|
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_StaticBase::sdUILayout_StaticBase
|
||
|
============
|
||
|
*/
|
||
|
sdUILayout_StaticBase::sdUILayout_StaticBase() {
|
||
|
GetScope().GetProperties().RegisterProperty( "margins", margins );
|
||
|
GetScope().GetProperties().RegisterProperty( "spacing", spacing );
|
||
|
|
||
|
margins = idVec4( 4.0f, 4.0f, 4.0f, 4.0f );
|
||
|
rect = idVec4( 0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT );
|
||
|
spacing = idVec2( 2.0f, 2.0f );
|
||
|
|
||
|
UI_ADD_VEC4_CALLBACK( margins, sdUILayout_StaticBase, OnMarginsChanged )
|
||
|
UI_ADD_VEC2_CALLBACK( spacing, sdUILayout_StaticBase, OnSpacingChanged )
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_StaticBase::~sdUILayout_StaticBase
|
||
|
============
|
||
|
*/
|
||
|
sdUILayout_StaticBase::~sdUILayout_StaticBase() {
|
||
|
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_StaticBase::GetFunction
|
||
|
============
|
||
|
*/
|
||
|
sdUIFunctionInstance* sdUILayout_StaticBase::GetFunction( const char* name ) {
|
||
|
const sdUILayoutFunction* function = sdUILayout_StaticBase::FindFunction( name );
|
||
|
if( !function ) {
|
||
|
return sdUIObject::GetFunction( name );
|
||
|
}
|
||
|
|
||
|
return new sdUITemplateFunctionInstance< sdUILayout_StaticBase, sdUITemplateFunctionInstance_IdentifierLayout_Table >( this, function );
|
||
|
}
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_StaticBase::FindFunction
|
||
|
============
|
||
|
*/
|
||
|
const sdUILayout_StaticBase::sdUILayoutFunction* sdUILayout_StaticBase::FindFunction( const char* name ) {
|
||
|
sdUILayoutFunction** ptr;
|
||
|
return layoutFunctions.Get( name, &ptr ) ? *ptr : NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_StaticBase::InitFunctions
|
||
|
============
|
||
|
*/
|
||
|
SD_UI_PUSH_CLASS_TAG( sdUILayout_StaticBase )
|
||
|
void sdUILayout_StaticBase::InitFunctions( void ) {
|
||
|
SD_UI_ENUM_TAG( VLF_DRAW_REVERSED, "Draw children in reverse order." )
|
||
|
sdDeclGUI::AddDefine( va( "VLF_DRAW_REVERSED %i", VLF_DRAW_REVERSED ) );
|
||
|
SD_UI_ENUM_TAG( VLF_NOSIZE, "Do not extend the child window widths to the right edge of the layout edge." )
|
||
|
sdDeclGUI::AddDefine( va( "VLF_NOSIZE %i", VLF_NOSIZE ) );
|
||
|
sdDeclGUI::AddDefine( va( "VLF_DYNAMIC_CHILDREN %i", VLF_DYNAMIC_CHILDREN ) );
|
||
|
}
|
||
|
SD_UI_POP_CLASS_TAG
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_StaticBase::OnMarginsChanged
|
||
|
============
|
||
|
*/
|
||
|
void sdUILayout_StaticBase::OnMarginsChanged( const idVec4& oldValue, const idVec4& newValue ) {
|
||
|
MakeLayoutDirty();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_StaticBase::OnSpacingChanged
|
||
|
============
|
||
|
*/
|
||
|
void sdUILayout_StaticBase::OnSpacingChanged( const idVec2& oldValue, const idVec2& newValue ) {
|
||
|
MakeLayoutDirty();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_StaticBase::OnCreate
|
||
|
============
|
||
|
*/
|
||
|
void sdUILayout_StaticBase::OnCreate() {
|
||
|
sdUIObject* child = GetNode().GetChild();
|
||
|
while( child != NULL ) {
|
||
|
sdProperty* property = child->GetScope().GetProperty( "rect", sdProperties::PT_VEC4 );
|
||
|
if( property != NULL ) {
|
||
|
rectInfo_t info;
|
||
|
info.property = property;
|
||
|
info.rect = *property->value.vec4Value;
|
||
|
info.source = child;
|
||
|
childRects.Append( info );
|
||
|
if( TestFlag( VLF_DYNAMIC_CHILDREN ) ) {
|
||
|
UI_ADD_VEC4_CALLBACK( ( *property->value.vec4Value ), sdUILayout_StaticBase, OnChildRectChanged )
|
||
|
}
|
||
|
}
|
||
|
child = child->GetNode().GetSibling();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_StaticBase::Draw
|
||
|
============
|
||
|
*/
|
||
|
void sdUILayout_StaticBase::Draw() {
|
||
|
if( !visible ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if( !TestFlag( VLF_DRAW_REVERSED ) ) {
|
||
|
sdUILayout_Static::Draw();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
sdUIObject* prev = NULL;
|
||
|
sdUIObject* child = GetNode().GetChild();
|
||
|
while( child != NULL ) {
|
||
|
prev = child;
|
||
|
child = child->GetNode().GetSibling();
|
||
|
}
|
||
|
|
||
|
child = prev;
|
||
|
|
||
|
while( child != NULL ) {
|
||
|
if( sdUIObject_Drawable* window = child->Cast< sdUIObject_Drawable >() ) {
|
||
|
window->Draw();
|
||
|
}
|
||
|
child = child->GetNode().GetPriorSibling();
|
||
|
}
|
||
|
if( gui_debugLayout.GetBool() ) {
|
||
|
deviceContext->DrawClippedBox( absoluteRect.GetValue().x, absoluteRect.GetValue().y, absoluteRect.GetValue().z, absoluteRect.GetValue().w, 1.0f, colorGreen );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_StaticBase::FinalDraw
|
||
|
============
|
||
|
*/
|
||
|
void sdUILayout_StaticBase::FinalDraw() {
|
||
|
if( !TestFlag( VLF_DRAW_REVERSED ) ) {
|
||
|
sdUILayout_Static::FinalDraw();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
sdUIObject* prev = NULL;
|
||
|
sdUIObject* child = GetNode().GetChild();
|
||
|
while( child != NULL ) {
|
||
|
prev = child;
|
||
|
child = child->GetNode().GetSibling();
|
||
|
}
|
||
|
|
||
|
child = prev;
|
||
|
|
||
|
while( child != NULL ) {
|
||
|
if( sdUIObject_Drawable* window = child->Cast< sdUIObject_Drawable >() ) {
|
||
|
window->FinalDraw();
|
||
|
}
|
||
|
child = child->GetNode().GetPriorSibling();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_StaticBase::PostEvent
|
||
|
============
|
||
|
*/
|
||
|
bool sdUILayout_StaticBase::PostEvent( const sdSysEvent* event ) {
|
||
|
if( !visible ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if( !TestFlag( VLF_DRAW_REVERSED ) ) {
|
||
|
return sdUILayout_Static::PostEvent( event );
|
||
|
}
|
||
|
|
||
|
sdUIObject* prev = NULL;
|
||
|
sdUIObject* child = GetNode().GetChild();
|
||
|
while( child != NULL ) {
|
||
|
prev = child;
|
||
|
child = child->GetNode().GetSibling();
|
||
|
}
|
||
|
|
||
|
child = prev;
|
||
|
|
||
|
while( child != NULL ) {
|
||
|
if( child->PostEvent( event ) ) {
|
||
|
return true;
|
||
|
}
|
||
|
child = child->GetNode().GetPriorSibling();
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_StaticBase::HandleFocus
|
||
|
============
|
||
|
*/
|
||
|
bool sdUILayout_StaticBase::HandleFocus( const sdSysEvent* event ) {
|
||
|
if( !visible ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if( !TestFlag( VLF_DRAW_REVERSED ) ) {
|
||
|
return sdUILayout_Static::HandleFocus( event );
|
||
|
}
|
||
|
|
||
|
sdUIObject* prev = NULL;
|
||
|
sdUIObject* child = GetNode().GetChild();
|
||
|
while( child != NULL ) {
|
||
|
prev = child;
|
||
|
child = child->GetNode().GetSibling();
|
||
|
}
|
||
|
|
||
|
child = prev;
|
||
|
|
||
|
while( child != NULL ) {
|
||
|
if( child->HandleFocus( event ) ) {
|
||
|
return true;
|
||
|
}
|
||
|
child = child->GetNode().GetPriorSibling();
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_Static::MakeLayoutDirty
|
||
|
============
|
||
|
*/
|
||
|
void sdUILayout_Static::MakeLayoutDirty() {
|
||
|
recalculateLayout = true;
|
||
|
MakeLayoutDirty_r( this );
|
||
|
}
|
||
|
|
||
|
SD_UI_IMPLEMENT_CLASS( sdUILayout_Vertical, sdUILayout_StaticBase )
|
||
|
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_Vertical::sdUILayout_Vertical
|
||
|
============
|
||
|
*/
|
||
|
sdUILayout_Vertical::sdUILayout_Vertical() {
|
||
|
GetScope().GetProperties().RegisterProperty( "verticalSize", verticalSize );
|
||
|
verticalSize = 0.0f;
|
||
|
verticalSize.SetReadOnly( true );
|
||
|
}
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_Vertical::DoApplyLayout
|
||
|
============
|
||
|
*/
|
||
|
void sdUILayout_Vertical::DoApplyLayout() {
|
||
|
idVec2 offset( margins.GetValue().x, margins.GetValue().y );
|
||
|
|
||
|
for( int i = 0; i < childRects.Num(); i++ ) {
|
||
|
rectInfo_t& rectInfo = childRects[ i ];
|
||
|
|
||
|
idVec4 childRect = rectInfo.rect;
|
||
|
if( TestFlag( VLF_NOSIZE ) == false && rectInfo.source->TestFlag( OF_FIXED_LAYOUT ) == false ) {
|
||
|
childRect.z = rect.GetValue().z - ( margins.GetValue().x + margins.GetValue().z ) - childRect.x;
|
||
|
}
|
||
|
|
||
|
childRect.x = rectInfo.rect.x + offset.x;
|
||
|
childRect.y = rectInfo.rect.y + offset.y;
|
||
|
|
||
|
*rectInfo.property->value.vec4Value = childRect;
|
||
|
offset.y += rectInfo.rect.y + childRect.w + spacing.GetValue().y;
|
||
|
}
|
||
|
verticalSize.SetReadOnly( false );
|
||
|
verticalSize = offset.y;
|
||
|
verticalSize.SetReadOnly( true );
|
||
|
}
|
||
|
|
||
|
SD_UI_IMPLEMENT_CLASS( sdUILayout_Horizontal, sdUILayout_StaticBase )
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
sdUILayout_Horizontal::DoApplyLayout
|
||
|
============
|
||
|
*/
|
||
|
void sdUILayout_Horizontal::DoApplyLayout() {
|
||
|
idVec2 offset( margins.GetValue().x, margins.GetValue().y );
|
||
|
|
||
|
for( int i = 0; i < childRects.Num(); i++ ) {
|
||
|
rectInfo_t& rectInfo = childRects[ i ];
|
||
|
|
||
|
idVec4 childRect = rectInfo.rect;
|
||
|
if( TestFlag( VLF_NOSIZE ) == false && rectInfo.source->TestFlag( OF_FIXED_LAYOUT ) == false ) {
|
||
|
childRect.w = rect.GetValue().w - ( margins.GetValue().y + margins.GetValue().w ) - childRect.y;
|
||
|
}
|
||
|
|
||
|
childRect.x += offset.x;
|
||
|
childRect.y += offset.y;
|
||
|
|
||
|
*rectInfo.property->value.vec4Value = childRect;
|
||
|
offset.x += rectInfo.rect.x + childRect.z + spacing.GetValue().x;
|
||
|
}
|
||
|
}
|
||
|
|