mirror of
https://github.com/thug1src/thug.git
synced 2025-01-22 05:43:47 +00:00
1411 lines
37 KiB
C++
1411 lines
37 KiB
C++
#include <core/defines.h>
|
|
#include <core/HashTable.h>
|
|
#include <gfx/NxFontMan.h>
|
|
#include <gfx/NxViewMan.h>
|
|
#include <gfx/2D/ScreenElement2.h>
|
|
#include <gfx/2D/ScreenElemMan.h>
|
|
#include <gfx/2D/Window.h>
|
|
#include <gel/Event.h>
|
|
#include <gel/objtrack.h>
|
|
#include <gel/Scripting/array.h>
|
|
#include <gel/Scripting/scriptdefs.h>
|
|
#include <gel/Scripting/script.h>
|
|
#include <gel/scripting/struct.h>
|
|
#include <gel/scripting/checksum.h>
|
|
#include <gel/scripting/vecpair.h>
|
|
#include <gel/scripting/array.h>
|
|
#include <gel/scripting/utils.h>
|
|
#ifdef __PLAT_NGPS__
|
|
#include <gfx/ngps/nx/line.h>
|
|
#endif
|
|
|
|
/*
|
|
=========================================================
|
|
RTFM!!!!
|
|
|
|
Be sure to check out the user's guide for the menu system
|
|
to get an idea of what all this code's for. Heurghh!!
|
|
=========================================================
|
|
*/
|
|
|
|
namespace Front
|
|
{
|
|
|
|
|
|
const float CScreenElement::vJUST_LEFT = -1.0f;
|
|
const float CScreenElement::vJUST_TOP = -1.0f;
|
|
const float CScreenElement::vJUST_CENTER = 0.0f;
|
|
const float CScreenElement::vJUST_RIGHT = 1.0f;
|
|
const float CScreenElement::vJUST_BOTTOM = 1.0f;
|
|
|
|
const float CScreenElement::AUTO_Z_SPACE = 1.0f;
|
|
|
|
CScreenElement::CScreenElement()
|
|
: CObject()
|
|
{
|
|
m_key_time = 0;
|
|
mp_parent = NULL;
|
|
mp_child_list = NULL;
|
|
mp_prev_sibling = NULL;
|
|
mp_next_sibling = NULL;
|
|
|
|
m_local_props.SetScale(1.0f, 1.0f);
|
|
m_local_props.SetAbsoluteScale(1.0f, 1.0f);
|
|
m_local_props.SetScreenPos(0.0f, 0.0f);
|
|
m_local_props.SetRotate( 0.0f );
|
|
m_local_props.SetWorldPos( Mth::Vector(0.0f, 0.0f, 0.0f) );
|
|
|
|
Image::RGBA default_rgba;
|
|
default_rgba.r = 128;
|
|
default_rgba.g = 128;
|
|
default_rgba.b = 128;
|
|
default_rgba.a = 128;
|
|
m_local_props.SetRGBA( default_rgba );
|
|
|
|
m_local_props.alpha = 1.0f;
|
|
m_target_local_props = m_local_props;
|
|
m_summed_props = m_local_props;
|
|
|
|
m_base_w = 0.0f;
|
|
m_base_h = 0.0f;
|
|
|
|
m_rgba.r = 128;
|
|
m_rgba.g = 128;
|
|
m_rgba.b = 128;
|
|
m_rgba.a = 128;
|
|
|
|
m_z_priority = 0.0f;
|
|
|
|
m_originalAlpha = 1.0f;
|
|
|
|
m_object_flags |= vNEEDS_LOCAL_POS_CALC;
|
|
m_object_flags |= vIS_SCREEN_ELEMENT;
|
|
}
|
|
|
|
|
|
|
|
|
|
CScreenElement::~CScreenElement()
|
|
{
|
|
set_parent(NULL, vDONT_RECALC_POS);
|
|
m_id = 0xDEADBEEF;
|
|
}
|
|
|
|
|
|
|
|
|
|
// absolute upper-left, last frame's
|
|
float CScreenElement::GetAbsX()
|
|
{
|
|
return m_summed_props.GetScreenUpperLeftX();
|
|
}
|
|
|
|
|
|
|
|
|
|
// absolute upper-left, last frame's
|
|
float CScreenElement::GetAbsY()
|
|
{
|
|
return m_summed_props.GetScreenUpperLeftY();
|
|
}
|
|
|
|
|
|
|
|
|
|
// absolute width, includes scale, last frame's
|
|
float CScreenElement::GetAbsW()
|
|
{
|
|
return m_base_w * m_summed_props.GetAbsoluteScaleX();
|
|
}
|
|
|
|
|
|
|
|
|
|
// absolute height, includes scale, last frame's
|
|
float CScreenElement::GetAbsH()
|
|
{
|
|
return m_base_h * m_summed_props.GetAbsoluteScaleY();
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Position of anchor point, in parent's space. 'Target' means where it's going,
|
|
not necessarily where it is.
|
|
*/
|
|
void CScreenElement::GetLocalPos(float *pX, float *pY)
|
|
{
|
|
Dbg_Assert(pX);
|
|
Dbg_Assert(pY);
|
|
|
|
*pX = m_target_local_props.GetScreenPosX();
|
|
*pY = m_target_local_props.GetScreenPosY();
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Position of upper left corner of element, in parent's space. 'Target' means where
|
|
it's going, not necessarily where it is.
|
|
*/
|
|
void CScreenElement::GetLocalULPos(float *pX, float *pY)
|
|
{
|
|
Dbg_Assert(pX);
|
|
Dbg_Assert(pY);
|
|
|
|
*pX = m_target_local_props.GetScreenUpperLeftX();
|
|
*pY = m_target_local_props.GetScreenUpperLeftY();
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Justification is a fixed attribute (doesn't morph)
|
|
*/
|
|
void CScreenElement::GetJust(float *pJustX, float *pJustY)
|
|
{
|
|
Dbg_Assert(pJustX);
|
|
Dbg_Assert(pJustY);
|
|
|
|
*pJustX = m_just_x;
|
|
*pJustY = m_just_y;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Sets desired local position, element will morph from current position to
|
|
that position over set morph time (unless force_instant set).
|
|
*/
|
|
void CScreenElement::SetPos(float x, float y, EForceInstant forceInstant)
|
|
{
|
|
Dbg_MsgAssert(!(m_object_flags & CScreenElement::v3D_POS), ("Illegal to set the 2D position of a 3D screen element"));
|
|
|
|
if (m_target_local_props.GetScreenPosX() != x || m_target_local_props.GetScreenPosY() != y)
|
|
{
|
|
m_target_local_props.SetScreenPos(x, y);
|
|
m_object_flags |= vNEEDS_LOCAL_POS_CALC;
|
|
compute_ul_pos(m_target_local_props);
|
|
}
|
|
if (forceInstant)
|
|
{
|
|
if (m_local_props.GetScreenPosX() != x || m_local_props.GetScreenPosY() != y)
|
|
{
|
|
// on the next update, this element will arrive at the target position
|
|
m_local_props.SetScreenPos(x, y);
|
|
m_object_flags |= vNEEDS_LOCAL_POS_CALC;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Sets desired world position, element will morph from current position to
|
|
that position over set morph time (unless force_instant set).
|
|
*/
|
|
void CScreenElement::SetPos3D(const Mth::Vector & pos3D, EForceInstant forceInstant)
|
|
{
|
|
if (m_target_local_props.GetWorldPos() != pos3D )
|
|
{
|
|
m_target_local_props.SetWorldPos(pos3D);
|
|
m_object_flags |= vNEEDS_LOCAL_POS_CALC;
|
|
compute_ul_pos(m_target_local_props);
|
|
}
|
|
if (forceInstant)
|
|
{
|
|
if (m_local_props.GetWorldPos() != pos3D )
|
|
{
|
|
// on the next update, this element will arrive at the target position
|
|
m_local_props.SetWorldPos(pos3D);
|
|
m_object_flags |= vNEEDS_LOCAL_POS_CALC;
|
|
}
|
|
}
|
|
|
|
m_object_flags |= CScreenElement::v3D_POS;
|
|
}
|
|
|
|
|
|
/*
|
|
Set 'force' if dims being set from outside element. When that happens, element cannot
|
|
change own dims.
|
|
|
|
Well, actually it can (VMenu), but 'force' is taken is a suggestion.
|
|
*/
|
|
void CScreenElement::SetDims(float w, float h, EForceDims force)
|
|
{
|
|
if (m_base_w != w || m_base_h != h)
|
|
{
|
|
m_object_flags |= vNEEDS_LOCAL_POS_CALC;
|
|
m_base_w = w;
|
|
m_base_h = h;
|
|
compute_ul_pos(m_target_local_props);
|
|
}
|
|
|
|
if (force)
|
|
m_object_flags |= vFORCED_DIMS;
|
|
else
|
|
m_object_flags &= ~vFORCED_DIMS;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Justification effects where the upper-left corner of an element is relative to
|
|
the element's assigned position (anchor point).
|
|
|
|
(-1.0, -1.0): anchor is at upper-left of element
|
|
(0.0, 0.0): anchor is in center of element
|
|
(1.0, 1.0): anchor is at lower-right of element
|
|
|
|
You can figure out the meaning of other numbers.
|
|
*/
|
|
void CScreenElement::SetJust(float justX, float justY)
|
|
{
|
|
if (m_just_x != justX || m_just_y != justY)
|
|
{
|
|
// calculate justification differences and adjust new position so the item still appears to
|
|
// have the same location as before
|
|
float x_diff = m_local_props.GetScaleX() * m_base_w * (justX - m_just_x) / 2.0f;
|
|
float y_diff = m_local_props.GetScaleY() * m_base_h * (justY - m_just_y) / 2.0f;
|
|
m_local_props.SetScreenPos(m_local_props.GetScreenPosX() + x_diff, m_local_props.GetScreenPosY() + y_diff);
|
|
m_target_local_props.SetScreenPos(m_target_local_props.GetScreenPosX() + x_diff, m_target_local_props.GetScreenPosY() + y_diff);
|
|
//m_local_props.ulx += x_diff;
|
|
//m_local_props.uly += y_diff;
|
|
|
|
m_just_x = justX;
|
|
m_just_y = justY;
|
|
m_object_flags |= vNEEDS_LOCAL_POS_CALC;
|
|
|
|
compute_ul_pos(m_target_local_props);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Sets desired local scale, element will morph from current scale to
|
|
that scale over set morph time (unless force_instant set).
|
|
*/
|
|
void CScreenElement::SetScale(float scaleX, float scaleY, bool relative, EForceInstant forceInstant )
|
|
{
|
|
if (m_target_local_props.GetScaleX() != scaleX || m_target_local_props.GetScaleY() != scaleY || relative)
|
|
{
|
|
if ( !relative )
|
|
{
|
|
m_target_local_props.SetAbsoluteScale(scaleX, scaleY);
|
|
}
|
|
else
|
|
{
|
|
scaleX *= m_target_local_props.GetAbsoluteScaleX();
|
|
scaleY *= m_target_local_props.GetAbsoluteScaleY();
|
|
}
|
|
m_target_local_props.SetScale(scaleX, scaleY);
|
|
compute_ul_pos(m_target_local_props);
|
|
m_object_flags |= vNEEDS_LOCAL_POS_CALC;
|
|
}
|
|
if (forceInstant)
|
|
{
|
|
if (m_local_props.GetScaleX() != scaleX || m_local_props.GetScaleY() != scaleY)
|
|
{
|
|
// on the next update, this element will arrive at the target scale
|
|
m_local_props.SetScale(scaleX, scaleY);
|
|
m_object_flags |= vNEEDS_LOCAL_POS_CALC;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Sets desired local alpha, element will morph from current alpha to
|
|
that alpha over set morph time (unless force_instant set).
|
|
*/
|
|
void CScreenElement::SetAlpha(float alpha, EForceInstant forceInstant)
|
|
{
|
|
if (m_target_local_props.alpha != alpha)
|
|
{
|
|
m_target_local_props.alpha = alpha;
|
|
m_object_flags |= vNEEDS_LOCAL_POS_CALC;
|
|
}
|
|
if (forceInstant)
|
|
{
|
|
if (m_local_props.alpha != alpha)
|
|
{
|
|
// on the next update, this element will arrive at the target alpha
|
|
m_local_props.alpha = alpha;
|
|
m_object_flags |= vNEEDS_LOCAL_POS_CALC;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Specifies the amount of time over which this element will changes from its
|
|
current morphable properties (pos, scale, alpha) to the target ones. If
|
|
an animation already in progress, override previously set time.
|
|
*/
|
|
void CScreenElement::SetAnimTime(Tmr::Time animTime)
|
|
{
|
|
m_base_time = Tmr::GetTime();
|
|
m_key_time = animTime;
|
|
m_last_motion_grad = 0.0f;
|
|
m_last_pct_changed = 0.0f;
|
|
|
|
if (!animTime)
|
|
{
|
|
m_local_props = m_target_local_props;
|
|
}
|
|
m_object_flags |= vNEEDS_LOCAL_POS_CALC;
|
|
m_object_flags &= ~vMORPHING_PAUSED;
|
|
m_object_flags &= ~vMORPHING_PAUSED2;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Note: The alpha component here is multiplied by the alpha from SetAlpha() to
|
|
determine final alpha.
|
|
*/
|
|
void CScreenElement::SetRGBA( Image::RGBA rgba, EForceInstant forceInstant )
|
|
{
|
|
Image::RGBA target_rgba = m_target_local_props.GetRGBA();
|
|
if ( target_rgba.r != rgba.r || target_rgba.g != rgba.g || target_rgba.b != rgba.b || target_rgba.a != rgba.a )
|
|
{
|
|
m_target_local_props.SetRGBA( rgba );
|
|
m_object_flags |= vNEEDS_LOCAL_POS_CALC;
|
|
}
|
|
if ( forceInstant )
|
|
{
|
|
m_local_props.SetRGBA( rgba );
|
|
m_object_flags |= vNEEDS_LOCAL_POS_CALC;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Used to force drawing order entry (instead of it being automatically assigned). Client code should be
|
|
written using knowledge of how these values work.
|
|
*/
|
|
void CScreenElement::SetZPriority(float zPriority)
|
|
{
|
|
m_z_priority = zPriority;
|
|
m_object_flags |= vCHANGED_STATIC_PROPS;
|
|
m_object_flags |= vCUSTOM_Z_PRIORITY;
|
|
}
|
|
|
|
|
|
|
|
|
|
void CScreenElement::SetMorphPausedState(bool pause)
|
|
{
|
|
if (pause)
|
|
m_object_flags |= vMORPHING_PAUSED;
|
|
else
|
|
{
|
|
m_object_flags &= ~vMORPHING_PAUSED;
|
|
m_object_flags &= ~vMORPHING_PAUSED2;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
When element is unlocked, children can be added or removed, otherwise they can't. Really just an
|
|
optimization so that lots of children can be added en masse without slowdown.
|
|
|
|
Note: The children you add to an element don't officially exist until you lock the element again,
|
|
so don't forget to do this.
|
|
*/
|
|
void CScreenElement::SetChildLockState(CScreenElement::ELockState lockState)
|
|
{
|
|
ELockState current_lock_state = UNLOCK;
|
|
if (m_object_flags & CScreenElement::vCHILD_LOCK) current_lock_state = LOCK;
|
|
if (lockState == current_lock_state)
|
|
return;
|
|
|
|
if (lockState == LOCK)
|
|
m_object_flags |= CScreenElement::vCHILD_LOCK;
|
|
else
|
|
m_object_flags &= ~CScreenElement::vCHILD_LOCK;
|
|
|
|
Obj::CTracker* p_tracker = Obj::CTracker::Instance();
|
|
|
|
if (lockState == LOCK)
|
|
{
|
|
//Ryan("Setting child lock on, item %s\n", Script::FindChecksumName(m_id));
|
|
|
|
// send out notice that child lock has been turned on
|
|
p_tracker->LaunchEvent(Obj::CEvent::TYPE_NOTIFY_CHILD_LOCK, m_id);
|
|
}
|
|
else
|
|
{
|
|
//Ryan("Setting child lock off, item %s\n", Script::FindChecksumName(m_id));
|
|
|
|
// send out notice that child lock has been turned off
|
|
p_tracker->LaunchEvent(Obj::CEvent::TYPE_NOTIFY_CHILD_UNLOCK, m_id);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
CScreenElement* CScreenElement::GetLastChild()
|
|
{
|
|
CScreenElement* pChild = mp_child_list;
|
|
while(pChild)
|
|
{
|
|
if (!pChild->GetNextSibling())
|
|
break;
|
|
|
|
pChild = pChild->GetNextSibling();
|
|
}
|
|
|
|
return pChild;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Returns a pointer to the child with that ID.
|
|
*/
|
|
CScreenElement* CScreenElement::GetChildById(uint32 id, int *pIndex)
|
|
{
|
|
return get_child_by_id_or_index(id, pIndex);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Returns a pointer to the Nth child, where N = index.
|
|
|
|
The children are indexed in the order they are added. If one is removed,
|
|
then the indices of all subsequent children are shifted down a notch.
|
|
*/
|
|
CScreenElement* CScreenElement::GetChildByIndex(int index)
|
|
{
|
|
return get_child_by_id_or_index(0, &index);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Returns number of children.
|
|
*/
|
|
int CScreenElement::CountChildren()
|
|
{
|
|
CScreenElementPtr p_child = mp_child_list;
|
|
int count = 0;
|
|
while(p_child)
|
|
{
|
|
p_child = p_child->GetNextSibling();
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
An important entry point to CScreenElement from script. Sets the elements static
|
|
(as opposed to morphable) properties.
|
|
|
|
Note: a virtual function, so can be extended by subclasses
|
|
Note: SetProperties() in a subclass should call this function before doing its own logic
|
|
*/
|
|
void CScreenElement::SetProperties(Script::CStruct *pProps)
|
|
{
|
|
CScreenElementManager *pManager = static_cast<CScreenElementManager *>(mp_manager);
|
|
Dbg_Assert(pManager);
|
|
|
|
Script::CPair pos;
|
|
if (pProps->GetPair(CRCD(0x7f261953,"pos"), &pos))
|
|
{
|
|
// in this case, position will be forced instantly to the specified position
|
|
SetPos(pos.mX, pos.mY, FORCE_INSTANT);
|
|
}
|
|
|
|
Mth::Vector pos3D;
|
|
if (pProps->GetVector(CRCD(0x4b491900,"pos3D"), &pos3D))
|
|
{
|
|
pos3D[W] = 1.0f; // force to be a point
|
|
//Dbg_Message("************ position (%f, %f, %f)", pos3D[X], pos3D[Y], pos3D[Z]);
|
|
SetPos3D(pos3D, FORCE_INSTANT);
|
|
}
|
|
|
|
Script::CPair dims;
|
|
if (pProps->GetPair(CRCD(0x34a68574,"dims"), &dims))
|
|
{
|
|
SetDims(dims.mX, dims.mY, FORCE_DIMS);
|
|
}
|
|
|
|
uint32 parent_id = pManager->ResolveComplexID(pProps, CRCD(0xc2719fb0,"parent"));
|
|
if (parent_id)
|
|
{
|
|
CScreenElementPtr pParent = pManager->GetElement(parent_id);
|
|
#ifdef __NOPT_ASSERT__
|
|
|
|
if (pParent->GetType() == CScreenElement::TYPE_TEXT_BLOCK_ELEMENT)
|
|
{
|
|
if (GetType() != CScreenElement::TYPE_TEXT_ELEMENT)
|
|
{
|
|
Script::PrintContents(pProps);
|
|
Dbg_MsgAssert(0,("TextBlockElement %s parenting child %s that is NOT a CTextElement (it's %s)\nIn CScreenElement::SetProperties\n^^^ SEE STRUCTURE ABOVE MEM DUMP & TELL BRAD^^^\n",
|
|
Script::FindChecksumName(pParent->GetID()), Script::FindChecksumName(GetID()), Script::FindChecksumName(GetType())));
|
|
}
|
|
}
|
|
|
|
if (!pParent)
|
|
{
|
|
Script::PrintContents(pProps, 2);
|
|
Dbg_MsgAssert(0, ("could not resolve parent, see struct above"));
|
|
}
|
|
#endif
|
|
pManager->SetParent(pParent, this);
|
|
}
|
|
|
|
float just[2] = { 0.0f, 0.0f };
|
|
if (resolve_just(pProps, CRCD(0x8b60022f,"just"), just, just+1))
|
|
SetJust(just[0], just[1]);
|
|
|
|
|
|
Image::RGBA rgba;
|
|
if (resolve_rgba(pProps, CRCD(0x3f6bcdba,"rgba"), &rgba))
|
|
{
|
|
SetRGBA(rgba);
|
|
}
|
|
|
|
float z_priority;
|
|
if (pProps->GetFloat(CRCD(0x57710f31,"z_priority"), &z_priority))
|
|
{
|
|
SetZPriority(z_priority);
|
|
}
|
|
|
|
if (pProps->ContainsFlag(CRCD(0x1d944426,"not_focusable")))
|
|
{
|
|
// sets a flag
|
|
SetChecksumTag(NONAME, CRCD(0xf33a3321,"tag_not_focusable"));
|
|
}
|
|
else if (pProps->ContainsFlag(CRCD(0x5cdecf29,"focusable")))
|
|
{
|
|
RemoveFlagTag(CRCD(0xf33a3321,"tag_not_focusable"));
|
|
}
|
|
|
|
uint32 local_id;
|
|
if (pProps->GetChecksum(CRCD(0xa2a5defe,"local_id"), &local_id))
|
|
{
|
|
SetChecksumTag(CRCD(0x9494a525,"tag_local_id"), local_id);
|
|
}
|
|
|
|
if (pProps->ContainsFlag(CRCD(0xff85d4d7,"unpause")))
|
|
{
|
|
SetMorphPausedState(false);
|
|
}
|
|
|
|
if ( pProps->ContainsFlag( CRCD(0xe5d6fe3e,"block_events") ) )
|
|
{
|
|
m_object_flags |= vEVENTS_BLOCKED;
|
|
}
|
|
else if ( pProps->ContainsFlag( CRCD(0xd5614a50,"unblock_events") ) )
|
|
{
|
|
m_object_flags &= ~vEVENTS_BLOCKED;
|
|
}
|
|
|
|
if ( pProps->ContainsFlag( CRCD(0x5b6634d4,"hide") ) )
|
|
{
|
|
m_object_flags |= vHIDDEN;
|
|
}
|
|
else if ( pProps->ContainsFlag( CRCD(0xb60d1f35,"unhide") ) )
|
|
{
|
|
m_object_flags &= ~vHIDDEN;
|
|
m_object_flags |= vCHANGED_STATIC_PROPS;
|
|
}
|
|
|
|
CObject::SetProperties(pProps);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void CScreenElement::WritePropertiesToStruct( Script::CStruct *pStruct )
|
|
{
|
|
// alpha value
|
|
pStruct->AddFloat( CRCD(0x2f1fc695,"alpha"), m_local_props.alpha );
|
|
|
|
// rgba array
|
|
Image::RGBA current_rgba = m_local_props.GetRGBA();
|
|
Script::CArray* p_rgba = new Script::CArray();
|
|
p_rgba->SetSizeAndType( 4, ESYMBOLTYPE_INTEGER );
|
|
p_rgba->SetInteger( 0, current_rgba.r );
|
|
p_rgba->SetInteger( 1, current_rgba.g );
|
|
p_rgba->SetInteger( 2, current_rgba.b );
|
|
p_rgba->SetInteger( 3, current_rgba.a );
|
|
pStruct->AddArray( CRCD(0x3f6bcdba,"rgba"), p_rgba );
|
|
Script::CleanUpArray( p_rgba );
|
|
delete p_rgba;
|
|
|
|
// scale value
|
|
float scaleX = m_local_props.GetScaleX();
|
|
float scaleY = m_local_props.GetScaleY();
|
|
// only add a pair if they're different
|
|
if ( scaleX == scaleY )
|
|
pStruct->AddFloat( CRCD(0x13b9da7b,"scale"), scaleX );
|
|
else
|
|
pStruct->AddPair( CRCD(0x13b9da7b,"scale"), scaleX, scaleY );
|
|
|
|
// position
|
|
pStruct->AddPair( CRCD(0x7f261953,"pos"), m_local_props.GetScreenPosX(), m_local_props.GetScreenPosY() );
|
|
|
|
// are the events blocked?
|
|
if ( EventsBlocked() )
|
|
pStruct->AddInteger( CRCD(0x73cb6d65,"events_blocked"), 1 );
|
|
else
|
|
pStruct->AddInteger( CRCD(0x73cb6d65,"events_blocked"), 0 );
|
|
}
|
|
|
|
|
|
/*
|
|
Another important entry point to CScreenElement from script. Sets the elements morphable
|
|
(as opposed to static) properties.
|
|
|
|
Note: a virtual function, so can be extended by subclasses.
|
|
Note: SetMorph() in a subclass should call this function before doing its own logic
|
|
*/
|
|
void CScreenElement::SetMorph(Script::CStruct *pProps)
|
|
{
|
|
float pos_x, pos_y;
|
|
if (resolve_pos(pProps, &pos_x, &pos_y))
|
|
{
|
|
SetPos(pos_x, pos_y);
|
|
}
|
|
|
|
// TODO: temp hack for restoring alpha values
|
|
if ( pProps->ContainsFlag( CRCD(0x5d8bb535,"restore_alpha") ) )
|
|
SetAlpha( m_originalAlpha );
|
|
|
|
float alpha;
|
|
if ( pProps->GetFloat(CRCD(0x2f1fc695,"alpha"), &alpha) )
|
|
{
|
|
// TODO: temp hack for remembering alpha values
|
|
if ( pProps->ContainsFlag( CRCD(0xff8df26b,"remember_alpha") ) )
|
|
m_originalAlpha = m_local_props.alpha;
|
|
|
|
SetAlpha( alpha );
|
|
}
|
|
|
|
float scale;
|
|
int relative_scale = 0;
|
|
if ( pProps->ContainsFlag( CRCD(0xe1f4711f,"relative_scale") ) )
|
|
relative_scale = 1;
|
|
if (pProps->GetFloat(CRCD(0x13b9da7b,"scale"), &scale))
|
|
{
|
|
SetScale(scale, scale, relative_scale );
|
|
}
|
|
Script::CPair scale_pair;
|
|
if (pProps->GetPair(CRCD(0x13b9da7b,"scale"), &scale_pair))
|
|
{
|
|
SetScale(scale_pair.mX, scale_pair.mY, relative_scale);
|
|
}
|
|
|
|
float desired_time;
|
|
Tmr::Time anim_time;
|
|
if (pProps->GetFloat(CRCD(0x906b67ba,"time"), &desired_time))
|
|
{
|
|
anim_time = (Tmr::Time) (desired_time * (float) Tmr::vRESOLUTION);
|
|
}
|
|
else
|
|
anim_time = 0;
|
|
SetAnimTime(anim_time);
|
|
|
|
uint32 anim_type = 0;
|
|
// clear affected bits
|
|
m_object_flags &= ~(vANIM_BIT_MASK << vANIM_FIRST_BIT);
|
|
if (pProps->GetChecksum(CRCD(0x98549ba4,"anim"), &anim_type))
|
|
{
|
|
if (anim_type == CRCD(0xf5b95ce4, "fast_out"))
|
|
m_object_flags |= vANIM_FAST_OUT << vANIM_FIRST_BIT;
|
|
else if (anim_type == CRCD(0x6aa7dd49, "fast_in"))
|
|
m_object_flags |= vANIM_FAST_IN << vANIM_FIRST_BIT;
|
|
else if (anim_type == CRCD(0x768f6843, "gentle"))
|
|
m_object_flags |= vANIM_SLOW_INOUT << vANIM_FIRST_BIT;
|
|
}
|
|
if (!anim_type)
|
|
{
|
|
m_object_flags |= (vANIM_LINEAR << vANIM_FIRST_BIT);
|
|
}
|
|
|
|
// rgba values
|
|
Image::RGBA rgba;
|
|
if ( resolve_rgba( pProps, CRCD(0x3f6bcdba,"rgba"), &rgba ) )
|
|
{
|
|
SetRGBA( rgba, DONT_FORCE_INSTANT );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
This function must be implemented for access to member commands from script.
|
|
*/
|
|
bool CScreenElement::CallMemberFunction( uint32 Checksum, Script::CStruct *pParams, Script::CScript *pScript )
|
|
{
|
|
if (Checksum == CRCD(0x6c63c7c5, "SetProps"))
|
|
{
|
|
SetProperties(pParams);
|
|
}
|
|
else if (Checksum == CRCD(0xdd0c8df3, "DoMorph"))
|
|
{
|
|
float time;
|
|
if (pParams->GetFloat(CRCD(0x906b67ba,"time"), &time))
|
|
{
|
|
Tmr::Time anim_time = (Tmr::Time) (time * (float) Tmr::vRESOLUTION);
|
|
pScript->WaitTime(anim_time);
|
|
}
|
|
|
|
SetMorph(pParams);
|
|
}
|
|
else if (Checksum == CRCD(0xc6870028, "Die"))
|
|
{
|
|
CScreenElementManager* p_manager = CScreenElementManager::Instance();
|
|
|
|
CScreenElementPtr p_parent = mp_parent;
|
|
p_parent->SetChildLockState(UNLOCK);
|
|
|
|
// will kill this screen element and all its children
|
|
// THIS IS POTENTIALLY DANGEROUS, LEAVE THIS FUNCTION ASAP
|
|
p_manager->DestroyElement(m_id, CScreenElementManager::RECURSE, CScreenElementManager::DONT_PRESERVE_PARENT, pScript);
|
|
|
|
p_parent->SetChildLockState(LOCK);
|
|
return true;
|
|
}
|
|
else if ( Checksum == CRCD(0x9492f814, "GetProps" ) )
|
|
{
|
|
WritePropertiesToStruct( pScript->GetParams() );
|
|
}
|
|
else
|
|
{
|
|
return CObject::CallMemberFunction(Checksum, pParams, pScript);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Update Procedure:
|
|
|
|
(Recurse through all elements in tree, starting at root)
|
|
|
|
For each element:
|
|
1. Update local position, scale, alpha
|
|
2. Update summed position, scale, alpha
|
|
3. Update: (optional)
|
|
-properties of children
|
|
-underlying CSprite or CText object(s)
|
|
-underlying 3D object(s)
|
|
-own base_w, base_h dimensions
|
|
4. Run these steps on all children
|
|
|
|
Events may be launched at various points.
|
|
*/
|
|
void CScreenElement::UpdateProperties()
|
|
{
|
|
#ifdef __NOPT_ASSERT__
|
|
debug_verify_integrity();
|
|
#endif
|
|
//Dbg_MsgAssert(m_id && m_id != 0xDEADBEEF, ("this screen element seems to have been deleted"));
|
|
|
|
Tmr::Time current_time = Tmr::GetTime();
|
|
|
|
AddReference();
|
|
|
|
// for convenience -- once element is being used, we can assume it's locked
|
|
SetChildLockState(LOCK);
|
|
|
|
// only do expensive calculation when change occurs
|
|
bool needs_summed_pos_calc = false;
|
|
|
|
// Update 3D position, if any
|
|
if (m_object_flags & CScreenElement::v3D_POS)
|
|
{
|
|
Nx::CViewport *p_viewport = Nx::CViewportManager::sGetActiveViewport();
|
|
Dbg_MsgAssert(p_viewport, ("Can't find an active viewport"));
|
|
|
|
float screen_pos_x, screen_pos_y;
|
|
Nx::ZBufferValue screen_pos_z;
|
|
float scale_3d;
|
|
scale_3d = p_viewport->TransformToScreenCoord(m_target_local_props.GetWorldPos(), screen_pos_x, screen_pos_y, screen_pos_z);
|
|
if (scale_3d >= 0.0f)
|
|
{
|
|
m_target_local_props.SetScreenPos(screen_pos_x, screen_pos_y, screen_pos_z);
|
|
SetScale(scale_3d, scale_3d, true); // set to relative scale
|
|
m_object_flags &= ~CScreenElement::v3D_CULLED;
|
|
} else {
|
|
m_target_local_props.SetScreenPos(-320.0f, -224.0f);
|
|
m_object_flags |= CScreenElement::v3D_CULLED;
|
|
}
|
|
compute_ul_pos(m_target_local_props);
|
|
|
|
if (mp_parent)
|
|
{
|
|
Dbg_MsgAssert(!(mp_parent->m_object_flags & CScreenElement::v3D_POS), ("Can't handle having 3D parent"));
|
|
}
|
|
|
|
m_object_flags |= vNEEDS_LOCAL_POS_CALC;
|
|
}
|
|
|
|
// continue animation of this element
|
|
if ((m_object_flags & vNEEDS_LOCAL_POS_CALC) && !(m_object_flags & vMORPHING_PAUSED2))
|
|
{
|
|
if (m_key_time)
|
|
{
|
|
float pct_changed = (float) (current_time - m_base_time) / (float) m_key_time;
|
|
// if element has reached its new destination, end animation
|
|
if (current_time - m_base_time >= m_key_time)
|
|
{
|
|
pct_changed = 1.0f;
|
|
m_key_time = 0;
|
|
}
|
|
|
|
float motion_grad;
|
|
int anim_type = ((m_object_flags >> vANIM_FIRST_BIT) & vANIM_BIT_MASK);
|
|
switch (anim_type)
|
|
{
|
|
case vANIM_FAST_OUT:
|
|
motion_grad = 2.0f * pct_changed - pct_changed * pct_changed;
|
|
break;
|
|
case vANIM_FAST_IN:
|
|
motion_grad = pct_changed * pct_changed;
|
|
break;
|
|
case vANIM_SLOW_INOUT:
|
|
motion_grad = (3.0f - 2.0f * pct_changed) * pct_changed * pct_changed;
|
|
break;
|
|
default:
|
|
motion_grad = pct_changed;
|
|
break;
|
|
}
|
|
|
|
float motion_inc = (motion_grad - m_last_motion_grad) / (1.0f - m_last_motion_grad);
|
|
float pct_changed_inc = (pct_changed - m_last_pct_changed) / (1.0f - m_last_pct_changed);
|
|
m_local_props.SetScreenPos(m_local_props.GetScreenPosX() + (m_target_local_props.GetScreenPosX() - m_local_props.GetScreenPosX()) * motion_inc,
|
|
m_local_props.GetScreenPosY() + (m_target_local_props.GetScreenPosY() - m_local_props.GetScreenPosY()) * motion_inc);
|
|
m_local_props.SetScale(m_local_props.GetScaleX() + (m_target_local_props.GetScaleX() - m_local_props.GetScaleX()) * pct_changed_inc,
|
|
m_local_props.GetScaleY() + (m_target_local_props.GetScaleY() - m_local_props.GetScaleY()) * pct_changed_inc);
|
|
|
|
m_local_props.SetRotate( m_local_props.GetRotate() + ( m_target_local_props.GetRotate() - m_local_props.GetRotate() ) * pct_changed_inc);
|
|
|
|
m_local_props.alpha = m_local_props.alpha + (m_target_local_props.alpha - m_local_props.alpha) * pct_changed_inc;
|
|
compute_ul_pos(m_local_props);
|
|
|
|
// figure any new rgba values
|
|
Image::RGBA current_rgba = m_local_props.GetRGBA();
|
|
Image::RGBA target_rgba = m_target_local_props.GetRGBA();
|
|
Image::RGBA new_rgba;
|
|
new_rgba.r = (int)( current_rgba.r + ( target_rgba.r - current_rgba.r ) * pct_changed_inc );
|
|
new_rgba.g = (int)( current_rgba.g + ( target_rgba.g - current_rgba.g ) * pct_changed_inc );
|
|
new_rgba.b = (int)( current_rgba.b + ( target_rgba.b - current_rgba.b ) * pct_changed_inc );
|
|
new_rgba.a = (int)( current_rgba.a + ( target_rgba.a - current_rgba.a ) * pct_changed_inc );
|
|
m_local_props.SetRGBA( new_rgba );
|
|
|
|
m_last_motion_grad = motion_grad;
|
|
m_last_pct_changed = pct_changed;
|
|
|
|
/*
|
|
if (m_key_time == 0)
|
|
{
|
|
//m_local_props = m_target_local_props;
|
|
m_local_props.ulx = m_local_props.x - m_local_props.scalex * m_base_w * (m_just_x + 1.0f) / 2.0f;
|
|
m_local_props.uly = m_local_props.y - m_local_props.scaley * m_base_h * (m_just_y + 1.0f) / 2.0f;
|
|
printf("Hurk!! target UL=(%.2f,%.2f) local UL=(%.2f,%.2f)\n",
|
|
m_target_local_props.ulx, m_target_local_props.uly,
|
|
m_local_props.ulx, m_local_props.uly);
|
|
}
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
m_local_props = m_target_local_props;
|
|
m_object_flags &= ~vNEEDS_LOCAL_POS_CALC;
|
|
}
|
|
needs_summed_pos_calc = true;
|
|
|
|
/*
|
|
if (GetID() == Script::GenerateCRC("test_h_menu"))
|
|
printf("local_pos=(%.2f,%.2f), ul=(%.2f,%.2f), dims=(%.2f,%.2f)\n",
|
|
m_local_props.x, m_local_props.y,
|
|
m_local_props.ulx, m_local_props.uly,
|
|
m_base_w, m_base_h);
|
|
*/
|
|
} // end if
|
|
|
|
if (mp_parent && (mp_parent->m_object_flags & vDID_SUMMED_POS_CALC))
|
|
needs_summed_pos_calc = true;
|
|
m_object_flags &= ~vDID_SUMMED_POS_CALC;
|
|
|
|
if (needs_summed_pos_calc)
|
|
{
|
|
if (mp_parent && !(m_object_flags & CScreenElement::v3D_POS))
|
|
{
|
|
m_summed_props.SetScale(m_local_props.GetScaleX() * mp_parent->m_summed_props.GetScaleX(),
|
|
m_local_props.GetScaleY() * mp_parent->m_summed_props.GetScaleY());
|
|
m_summed_props.SetScreenPos(mp_parent->m_summed_props.GetScreenUpperLeftX() + m_local_props.GetScreenPosX() * mp_parent->m_summed_props.GetScaleX(),
|
|
mp_parent->m_summed_props.GetScreenUpperLeftY() + m_local_props.GetScreenPosY() * mp_parent->m_summed_props.GetScaleY());
|
|
m_summed_props.alpha = m_local_props.alpha * mp_parent->m_summed_props.alpha;
|
|
m_summed_props.SetScreenUpperLeft(mp_parent->m_summed_props.GetScreenUpperLeftX() + m_local_props.GetScreenUpperLeftX() * mp_parent->m_summed_props.GetScaleX(),
|
|
mp_parent->m_summed_props.GetScreenUpperLeftY() + m_local_props.GetScreenUpperLeftY() * mp_parent->m_summed_props.GetScaleY());
|
|
}
|
|
else
|
|
m_summed_props = m_local_props;
|
|
m_object_flags |= vDID_SUMMED_POS_CALC;
|
|
} // end if
|
|
|
|
update();
|
|
|
|
m_object_flags &= ~vCHANGED_STATIC_PROPS;
|
|
if (m_object_flags & vMORPHING_PAUSED)
|
|
m_object_flags |= vMORPHING_PAUSED2;
|
|
|
|
// update all children
|
|
//CScreenElementPtr pChild = mp_child_list;
|
|
CScreenElement * pChild = mp_child_list;
|
|
while(pChild)
|
|
{
|
|
pChild->UpdateProperties();
|
|
pChild = pChild->GetNextSibling();
|
|
}
|
|
|
|
RemoveReference();
|
|
}
|
|
|
|
|
|
|
|
|
|
CScreenElementPtr CScreenElement::get_child_by_id_or_index(uint32 id, int *pIndex)
|
|
{
|
|
int count = 0;
|
|
CScreenElementPtr pChild = mp_child_list;
|
|
while(pChild)
|
|
{
|
|
// if we are getting by index
|
|
if (id == 0)
|
|
{
|
|
if (*pIndex == count)
|
|
break;
|
|
}
|
|
// if we are getting by ID
|
|
else if (pChild->GetID() == id)
|
|
{
|
|
// save index
|
|
if (pIndex)
|
|
*pIndex = count;
|
|
break;
|
|
}
|
|
|
|
pChild = pChild->GetNextSibling();
|
|
count++;
|
|
}
|
|
|
|
return pChild;
|
|
}
|
|
|
|
|
|
CScreenElementPtr CScreenElement::get_parent()
|
|
{
|
|
return mp_parent;
|
|
}
|
|
|
|
|
|
CWindowElement * CScreenElement::get_window()
|
|
{
|
|
CScreenElement * p_parent = get_parent();
|
|
while (p_parent)
|
|
{
|
|
if (p_parent->GetType() == (sint) TYPE_WINDOW_ELEMENT)
|
|
{
|
|
return static_cast<CWindowElement *>(p_parent);
|
|
}
|
|
|
|
p_parent = p_parent->get_parent();
|
|
}
|
|
|
|
Dbg_MsgAssert(0, ("Could not find window for CScreenElement."));
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
Private function, should not be called by anything except
|
|
CScreenElementManager.
|
|
*/
|
|
void CScreenElement::set_parent(const CScreenElementPtr &pParent, EPosRecalc recalculatePosition)
|
|
{
|
|
if (pParent)
|
|
{
|
|
Dbg_MsgAssert(!(pParent->m_object_flags & CScreenElement::vCHILD_LOCK), ("can't add child %s -- locked parent - %s", Script::FindChecksumName(m_id), Script::FindChecksumName( pParent->GetID())));
|
|
//Ryan("parent of screen element %s is now %s\n", Script::FindChecksumName(GetID()), Script::FindChecksumName(pParent->GetID()));
|
|
#ifdef __NOPT_ASSERT__
|
|
if (pParent->GetType() == CScreenElement::TYPE_TEXT_BLOCK_ELEMENT)
|
|
{
|
|
Dbg_MsgAssert(GetType() == CScreenElement::TYPE_TEXT_ELEMENT,("TextBlockElement %s parenting child %s that is NOT a CTextElement (it's %s)\n",
|
|
Script::FindChecksumName(pParent->GetID()), Script::FindChecksumName(GetID()), Script::FindChecksumName(GetType())));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
if (mp_parent)
|
|
{
|
|
// remove from existing parent's child list before setting new
|
|
// (there are max. 5 references to remove)
|
|
|
|
|
|
CScreenElementPtr p_elem = mp_parent->mp_child_list;
|
|
while(p_elem)
|
|
{
|
|
if (p_elem == this)
|
|
{
|
|
if (GetPrevSibling())
|
|
{
|
|
GetPrevSibling()->mp_next_sibling = GetNextSibling();
|
|
}
|
|
else
|
|
{
|
|
// ref count won't change for next sibling, since was ref'd by this
|
|
mp_parent->mp_child_list = GetNextSibling();
|
|
}
|
|
|
|
if (GetNextSibling())
|
|
{
|
|
// Either original parent or original prev sibling is now pointing to original next sibling
|
|
// Would both add and remove a reference on next, but they cancel each other, so do nothing
|
|
|
|
GetNextSibling()->mp_prev_sibling = GetPrevSibling();
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
p_elem = p_elem->GetNextSibling();
|
|
}
|
|
}
|
|
|
|
// add to new parent's child list
|
|
// (at end of list)
|
|
mp_parent = pParent;
|
|
if (mp_parent)
|
|
{
|
|
CScreenElementPtr p_prev_sib = mp_parent->GetFirstChild();
|
|
if (p_prev_sib)
|
|
{
|
|
while(p_prev_sib->GetNextSibling())
|
|
p_prev_sib = p_prev_sib->GetNextSibling();
|
|
p_prev_sib->mp_next_sibling = this;
|
|
}
|
|
else
|
|
mp_parent->mp_child_list = this;
|
|
mp_prev_sibling = p_prev_sib;
|
|
}
|
|
else
|
|
// no parent, therefore no siblings
|
|
mp_prev_sibling = NULL;
|
|
mp_next_sibling = NULL;
|
|
|
|
if (pParent)
|
|
auto_set_z_priorities_recursive(pParent->m_z_priority + AUTO_Z_SPACE);
|
|
else
|
|
auto_set_z_priorities_recursive(0.0f);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
...given element's dimensions, justification, scale, and target position.
|
|
*/
|
|
void CScreenElement::compute_ul_pos(ConcatProps &props)
|
|
{
|
|
props.SetScreenUpperLeft(props.GetScreenPosX() - props.GetScaleX() * m_base_w * (m_just_x + 1.0f) / 2.0f,
|
|
props.GetScreenPosY() - props.GetScaleY() * m_base_h * (m_just_y + 1.0f) / 2.0f);
|
|
}
|
|
|
|
|
|
|
|
|
|
// called by set_parent()
|
|
void CScreenElement::auto_set_z_priorities_recursive(float topPriority)
|
|
{
|
|
if (!(m_object_flags & vCUSTOM_Z_PRIORITY))
|
|
{
|
|
m_object_flags |= vCHANGED_STATIC_PROPS;
|
|
m_z_priority = topPriority;
|
|
}
|
|
|
|
CScreenElementPtr pChild = mp_child_list;
|
|
while(pChild)
|
|
{
|
|
pChild->auto_set_z_priorities_recursive(topPriority + AUTO_Z_SPACE);
|
|
pChild = pChild->GetNextSibling();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Resolves position info stored in a script structure:
|
|
|
|
pos=(x y)
|
|
pos={relative (x y)}
|
|
pos={proportional (x y)}
|
|
|
|
Returns false if no position info found.
|
|
*/
|
|
bool CScreenElement::resolve_pos(Script::CStruct *pProps, float *pX, float *pY)
|
|
{
|
|
Script::CPair pos_pair;
|
|
Script::CStruct *p_pos_struct;
|
|
if (pProps->GetStructure(CRCD(0x7f261953,"pos"), &p_pos_struct))
|
|
{
|
|
p_pos_struct->GetPair(NONAME, &pos_pair, true);
|
|
if (p_pos_struct->ContainsFlag(0x91a4c826)) // "relative"
|
|
{
|
|
*pX = m_target_local_props.GetScreenPosX() + pos_pair.mX;
|
|
*pY = m_target_local_props.GetScreenPosY() + pos_pair.mY;
|
|
}
|
|
else if (p_pos_struct->ContainsFlag(0xb922906a)) // "proportional"
|
|
{
|
|
Dbg_Assert(mp_parent);
|
|
*pX = pos_pair.mX * mp_parent->GetBaseW();
|
|
*pY = pos_pair.mY * mp_parent->GetBaseH();
|
|
}
|
|
else
|
|
Dbg_MsgAssert(0, ("position needs 'relative' or 'proportional' flag"));
|
|
return true;
|
|
}
|
|
else if (pProps->GetPair(CRCD(0x7f261953,"pos"), &pos_pair))
|
|
{
|
|
*pX = pos_pair.mX;
|
|
*pY = pos_pair.mY;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Resolves justification info stored in a script structure, e.g.:
|
|
|
|
just=[left top]
|
|
just=[center center]
|
|
just=[right bottom]
|
|
just=(-1.0 1.0)
|
|
just=(.65 3.75)
|
|
|
|
Returns false if no justification info found.
|
|
*/
|
|
bool CScreenElement::resolve_just(Script::CStruct *pProps, const uint32 RefName, float *pHJust, float *pVJust)
|
|
{
|
|
Script::CArray *p_just;
|
|
if (pProps->GetArray(RefName, &p_just))
|
|
{
|
|
Script::ESymbolType type = (Script::ESymbolType) p_just->GetType();
|
|
switch(type)
|
|
{
|
|
case ESYMBOLTYPE_FLOAT:
|
|
*pHJust = p_just->GetFloat(0);
|
|
*pVJust = p_just->GetFloat(1);
|
|
break;
|
|
case ESYMBOLTYPE_NAME:
|
|
{
|
|
float just[2];
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
uint32 crc = p_just->GetNameChecksum(i);
|
|
if (crc == CRCD(0x85981897, "left") || crc == CRCD(0xe126e035, "top"))
|
|
just[i] = -1.0f;
|
|
else if (crc == CRCD(0x4b358aeb, "right") || crc == CRCD(0x76a08d5b, "bottom"))
|
|
just[i] = 1.0f;
|
|
else
|
|
just[i] = 0;
|
|
}
|
|
*pHJust = just[0];
|
|
*pVJust = just[1];
|
|
break;
|
|
}
|
|
default:
|
|
Dbg_MsgAssert(0, ("wrong type for justification"));
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Retrieves RGBA information from a script struct.
|
|
*/
|
|
bool CScreenElement::resolve_rgba(Script::CStruct *pProps, const uint32 RefName, Image::RGBA *pRGBA)
|
|
{
|
|
Script::CArray *p_color;
|
|
if (pProps->GetArray(RefName, &p_color))
|
|
{
|
|
uint32 rgba = 0;
|
|
int size = p_color->GetSize();
|
|
Dbg_MsgAssert(size >= 3 && size <= 4, ("wrong size %d for color array", size));
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
rgba |= (p_color->GetInteger(i) & 255) << (i*8);
|
|
}
|
|
#ifdef __PLAT_NGC__
|
|
rgba = ( ( rgba & 0xff000000 ) >> 24 ) | ( ( rgba & 0xff0000 ) >> 8 ) | ( ( rgba & 0xff00 ) << 8 ) | ( ( rgba & 0xff ) << 24 );
|
|
#endif // __PLAT_NGC__
|
|
*pRGBA = *((Image::RGBA *) &rgba);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef __NOPT_ASSERT__
|
|
/*
|
|
Used to verify that screen element has not been corrupted.
|
|
*/
|
|
void CScreenElement::debug_verify_integrity()
|
|
{
|
|
|
|
// Mick - Removed for now, as it's taking up rather a lot of time....
|
|
return;
|
|
|
|
Dbg_MsgAssert(Mem::Valid(this), ("not a valid block!"));
|
|
Dbg_MsgAssert(m_id, ("screen element has id of 0, that shouldn't happen"));
|
|
Dbg_MsgAssert(m_id != 0xDEADBEEF, ("screen element has been deleted"));
|
|
|
|
CScreenElementManager* p_manager = CScreenElementManager::Instance();
|
|
CScreenElementPtr p_in_tracker = p_manager->GetElement(m_id);
|
|
Dbg_MsgAssert(p_in_tracker == this, ("this element seems to have been lost from tracking"));
|
|
|
|
if (mp_parent)
|
|
{
|
|
Dbg_MsgAssert(!((uint) mp_parent.Convert() & 3), ("parent has goofy address"));
|
|
Dbg_MsgAssert(Mem::Valid(mp_parent), ("parent not a valid block!"));
|
|
CScreenElementPtr p_sib = mp_parent->mp_child_list;
|
|
while(p_sib)
|
|
{
|
|
if (p_sib == this)
|
|
break;
|
|
p_sib = p_sib->GetNextSibling();
|
|
}
|
|
Dbg_MsgAssert(p_sib, ("this element not in its parent's child list"));
|
|
}
|
|
|
|
CScreenElementPtr p_child = mp_child_list;
|
|
while(p_child)
|
|
{
|
|
Dbg_MsgAssert(!((uint) (p_child.Convert()) & 3), ("child has goofy address"));
|
|
Dbg_MsgAssert(Mem::Valid(p_child), ("child not a valid block!"));
|
|
Dbg_MsgAssert(p_child->mp_parent == this, ("this element not parent of child"));
|
|
p_child = p_child->GetNextSibling();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
CContainerElement::CContainerElement()
|
|
{
|
|
//Ryan("I am a new CContainerElement\n");
|
|
m_focusable_child = 0;
|
|
|
|
SetType(CScreenElement::TYPE_CONTAINER_ELEMENT);
|
|
}
|
|
|
|
|
|
|
|
|
|
CContainerElement::~CContainerElement()
|
|
{
|
|
//Ryan("Destroying CContainerElement\n");
|
|
}
|
|
|
|
|
|
|
|
|
|
void CContainerElement::SetProperties(Script::CStruct *pProps)
|
|
{
|
|
pProps->GetChecksum("focusable_child", &m_focusable_child);
|
|
|
|
CScreenElement::SetProperties(pProps);
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CContainerElement::PassTargetedEvent(Obj::CEvent *pEvent, bool broadcast)
|
|
{
|
|
if (!Obj::CObject::PassTargetedEvent(pEvent))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (pEvent->GetType() == Obj::CEvent::TYPE_FOCUS || pEvent->GetType() == Obj::CEvent::TYPE_UNFOCUS)
|
|
{
|
|
// forward events of these types to specified focusable child
|
|
if (m_focusable_child)
|
|
{
|
|
int controller = Obj::CEvent::sExtractControllerIndex(pEvent);
|
|
Script::CStruct data;
|
|
data.AddInteger(CRCD(0xb30d9965,"controller"), controller);
|
|
|
|
Obj::CTracker* p_tracker = Obj::CTracker::Instance();
|
|
p_tracker->LaunchEvent(pEvent->GetType(), m_focusable_child, Obj::CEvent::vSYSTEM_EVENT, &data);
|
|
}
|
|
pEvent->MarkHandled(m_id);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CScreenElement::EventsBlocked()
|
|
{
|
|
// recurse back up through the parents to find any parent that is hidden
|
|
if ( ( m_object_flags & vEVENTS_BLOCKED) || ( mp_parent && mp_parent->EventsBlocked() ) )
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool CScreenElement::IsHidden()
|
|
{
|
|
// recurse back up through the parents to find any parent that is hidden
|
|
if ( ( m_object_flags & vHIDDEN ) || ( mp_parent && mp_parent->IsHidden() ) )
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
} // end namespace
|