Files
2026-06-01 12:46:52 +02:00

1483 lines
37 KiB
C++

#include "stdafx.h"
#include "KResourceManager.h"
#include "KUITextureManager.h"
#include "KViewport.h"
#include "KUIParser.h"
#include "KUIGenWnd.h"
#include "KUIDefine.h"
#include "KUIWndManager.h"
#include "KUIDragAndDrop.h"
#include "Controls/KUIControl.h"
#include "Controls/KUIControlEdit.h"
#include "Controls/KUIControlStatic.h"
#include "Controls/KUIControlButton.h"
#include "Controls/KUIControlGauge.h"
#include "Controls/KUIControlStatusBar.h"
#include "Controls/KUIControlTitleBar.h"
#include "Controls/KUITipControl.h"
// { [sonador]
#ifdef _KUI_INVALIDATION
#include "KResource.h"
#include <toolkit/XStringUtil.h>
#endif
// }
#include "SGameOption.h"
bool KUIGenWnd::m_bWinMove;
using namespace KUI_MESSAGE;
namespace
{
const int FRAME_GAP = 2;
//AniName 임. spr에 존재 해야함.
const char * DEFAULT_GENWND_ANINAME[TOTAL_GENWND_ANINAME] =
{
"window_titlebar01", //타이틀 바
"window_off", //닫기?
"window_reduction", //MINIMIZE
"button_common_down", //리사이즈 임시 버튼? windows_button01_right
"window_statusbar", //상태 바
"outframe", //테두리
"window_topframe", //상단
"window_tile", //타이틀
"window_button01", //버튼?
};
}
namespace
{
KUIWnd* GenWndCreator()
{
return new KUIGenWnd;
}
bool bRegister = KUIFactory::GetInstance()->RegisterCreator( GenWndCreator, "genwnd");
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KUIGenWnd Implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
KUIGenWnd::KUIGenWnd()
// { [sonador]
#ifdef _KUI_INVALIDATION
: m_spImageCache ( 0 )
, m_pImageCachePrimitive ( 0 )
, m_bNeedToCheckCached ( true )
, m_bActivateImageCache ( true )
#endif
// }
{
m_pMinimize = NULL;
m_pClose = NULL;
m_pTitleBar = NULL;
m_pTopFrame = NULL;
m_pStatusBar = NULL;
m_pResize = NULL;
m_nPieceCount = 0;
m_pSpriteList = NULL;
m_pBackgroundArea = NULL;
m_nBackgroundCount = 0;
m_pBackgroundList = NULL;
m_bResizing = false;
m_bMoving = false;
m_pDragAndDropIcon = new KUIDragAndDropNormalIconRenderer;
m_pDragAndDropIcon->SetMaxState( TOTAL_STATE );
m_nResizeXUnit = 1;
m_nResizeYUnit = 1;
#ifdef _RAC
SetShow( false );
#else
SetShow( true );
#endif
for(int i = 0; i < TOTAL_GENWND_ANINAME; ++i)
m_sTotalAniName[i] = DEFAULT_GENWND_ANINAME[i];
m_bRightDown = false;
//gmpbigsun( 20130104, #23793 ) : 잠금기능 설정하더라도 초기화코드때문에 풀림현상 수정
// m_bWinMove = true; //old
const _OPT_DATA& opt_data = GetGameOption().GetOptData();
KUIGenWnd::AbleMoveWin( !opt_data.nWinLock );
}
KUIGenWnd::~KUIGenWnd()
{
SAFE_DELETE_ARRAY( m_pBackgroundList );
SAFE_DELETE_ARRAY( m_pBackgroundArea );
SAFE_DELETE_ARRAY( m_pSpriteList );
SAFE_DELETE( m_pTopFrame );
SAFE_DELETE( m_pDragAndDropIcon );
// { [sonador]
#ifdef _KUI_INVALIDATION
SAFE_DELETE( m_pImageCachePrimitive );
RemoveAllPopupControl();
#endif
// }
}
// MJ 2004/09/15
void KUIGenWnd::Create(KStream& stream, KUIWndManager* pManager)
{
KUIParser parser;
if( false == parser.DoParsing( stream) )
return;
if( parser.GetParseObjCount() < 1)
return;
// For now, the initial Parser Object is set to a single GenWNd
KUIWndParseObject* pParseObj = parser.GetParseObject( 0);
KUIWND_CREATE_ARG genArg = pParseObj->GetCreateArg();
m_pManager = pManager;
genArg.pWndManager = pManager;
Create( genArg );
for(DWORD i = 0; i < pParseObj->GetChildCount(); ++i)
{
KUIWndParseObject* pChildParseObj = pParseObj->GetChildParseObj( i );
KUIWND_CREATE_ARG childArg = pChildParseObj->GetCreateArg();
if(childArg.lpszSprName.empty())
childArg.lpszSprName = this->m_sSprName;
childArg.pParent = this;
childArg.pWndManager = m_pManager;
// It goes up into actual memory
KUITextureManager::GetManager()->GetSprAni( childArg.lpszSprName.c_str(), childArg.lpszAniName.c_str() );
m_pManager->CreateControl( childArg );
}
// pManager->AddWnd( this );
}
void KUIGenWnd::Create(KUIWND_CREATE_ARG& CREATE_ARG)
{
KUIWnd::Create( CREATE_ARG);
m_rcClipArea = m_rcRegion;
if( NULL == _getSpriteSet() )
{
OutputDebugString( "Sprite not found" );
return;
}
m_maxSize = KUIWndManager::GetResolution();
m_minSize = KSize(100,100);
KUIWND_CREATE_ARG CHILD_ARG;
CHILD_ARG.pParent = this;
CHILD_ARG.pWndManager = m_pManager;
CHILD_ARG.lpszSprName = m_sSprName.c_str();
if ( m_dwStyle & KSTYLE_NORESIZE )
{
m_pResize = NULL;
}
else
{
std::string sAniName;
KResSprite* pFrame = _getSpriteSet()->GetSpriteRes( m_sTotalAniName[GENWND_RESIZE].c_str(), 0 );
if( pFrame )
{
if( m_dwStyle & KSTYLE_RESIZE_LEFT)
{
CHILD_ARG.dwAnchor = KANCHOR_LEFT;
m_rcResize.left = m_rcRegion.left + FRAME_GAP;
}
else
{
CHILD_ARG.dwAnchor = KANCHOR_RIGHT;
m_rcResize.left = m_rcRegion.right - pFrame->GetSizeX() - FRAME_GAP;
}
if( m_dwStyle & KSTYLE_RESIZE_TOP)
{
CHILD_ARG.dwAnchor |= KANCHOR_TOP;
m_rcResize.top = m_rcRegion.top + FRAME_GAP;
}
else
{
CHILD_ARG.dwAnchor |= KANCHOR_BOTTOM;
m_rcResize.top = m_rcRegion.bottom - pFrame->GetSizeY() - FRAME_GAP;
}
}
}
if(! (m_dwStyle & KSTYLE_NOFRAME) )
{
_reArrangeFrame();
_makeSpriteFrame();
}
if( !(m_dwStyle & KSTYLE_NOTOPFRAME) )
_makeTopFrame();
if( !(m_dwStyle & KSTYLE_NOBACKGROUND) )
{
_reArrangeBackground();
_makeBackgroundFrame();
}
}
void KUIGenWnd::Render( KViewportObject *pViewport, bool isFront )
{
if( m_bShowFlag )
{
#ifdef _KUI_INVALIDATION
if( _initImageCache() )
{
_prepareImageCache( isFront );
pViewport->Register( m_pImageCachePrimitive, isFront );
}
else
{
_render( pViewport, isFront );
}
_renderPopupControl( pViewport, isFront );
_renderToolTip( pViewport, true );
#else
// Background을 먼저 깔고
for(int i = 0; i < m_nBackgroundCount; ++i)
pViewport->Register( &m_pBackgroundList[i] );
// 나머지 콘트롤들을 렌더
KUIWnd::Render( pViewport, isFront );
if(NULL != m_pTopFrame)
pViewport->Register(m_pTopFrame);
for(int i = 0; i < m_vtGenWndControls.size(); ++i)
m_vtGenWndControls.at(i)->Render( pViewport, isFront );
// 한 후에 다시 Frame Render
for(int i = 0; i < m_nPieceCount; ++i)
pViewport->Register(&m_pSpriteList[i]);
#endif
}
}
DWORD KUIGenWnd::OnMouseMessage(DWORD dwMessage, int x, int y)
{
/// 2011.10.18 test - prodongi
if (stricmp(GetID(), "window_raid_siege_status") == 0)
{
int a = 0;
}
DWORD dwRet = KUIWnd::OnMouseMessage( dwMessage, x, y );
if( ::_stricmp( GetID(), "chat" ) == 0 && (dwMessage == KWHEEL_UP || dwMessage == KWHEEL_DOWN) )
dwRet = KMR_NORMAL | dwRet;
if(KMR_NO_GET & dwRet)
return dwRet;
switch(dwMessage)
{
case KMOUSE_MOVE:
if(m_bResizing)
{
//
KResSprite* pFrame = _getSpriteSet()->GetSpriteRes( m_sTotalAniName[GENWND_RESIZE].c_str(), 0 );
if( !pFrame )
return dwRet;
KRect newrect = m_rcRegion;
if( m_dwStyle & KSTYLE_RESIZE_LEFT)
newrect.left = x + pFrame->GetSizeX()/3;
else
newrect.right = x + pFrame->GetSizeX()/3;
if( m_dwStyle & KSTYLE_RESIZE_TOP)
newrect.top = y + pFrame->GetSizeY()/3;
else
newrect.bottom = y + pFrame->GetSizeY()/3;
KRect oldRect = m_rcRegion;
Resize( newrect );
if( oldRect != m_rcRegion)
{
PumpUpMessage( GetID(), KUI_MESSAGE::KGENWND_RESIZE, oldRect.GetWidth(), oldRect.GetHeight() );
}
}
else if(m_bMoving)
{
if( IsAbleMoveWin() )
{
int XOffset = x - m_ptMovingOffset.x;
int YOffset = y - m_ptMovingOffset.y;
if(XOffset != 0 || YOffset != 0)
{
KPoint ptOld( m_rcRegion.left, m_rcRegion.top);
MovePos( XOffset, YOffset);
PumpUpMessage( GetID(), KUI_MESSAGE::KGENWND_MOVE, ptOld.x, ptOld.y);
}
}
}
break;
case KLBUTTON_UP:
if(m_bResizing)
{
m_bResizing = false;
m_pManager->ReleaseCapture(this);
}
else if(m_bMoving)
{
m_bMoving = false;
m_pManager->ReleaseCapture(this);
}
break;
case KLBUTTON_DBLCLK:
{
PumpUpMessage(GetID(), KICON_DBLCLK, x, y );
}
break;
case KLBUTTON_DOWN:
{
// MJ 2004/10/21
// 별개의 윈도우끼리 포커스 처리 같이 해줄때, skill 창 focus 되면 sysmenu 도 함께 focus 되어야 한다..등..
// 메인 프레임 아무곳이나 선택해도 컨트롤과 상관없이 메시지 처리해야 할때
PumpUpMessage(GetID(), KFOCUS_ACTIVATED, x, y );
if(true == m_bResizing || true == m_bMoving)
break;
// Child가 메시지를 받지 않거나, NO_GET인 경우
if( (m_dwStyle & KSTYLE_MOVE_BY_ALL) && m_rcRegion.IsInRect( x, y) &&
( !(dwRet & KMR_CHILD_GET_MSG) ) )
m_bMoving = true;
if( (m_dwStyle & KSTYLE_MOVE_BY_TITLEBAR) &&
NULL != m_pTitleBar && m_pTitleBar->IsInRect( x, y) )
m_bMoving = true;
if( (m_dwStyle & KSTYLE_MOVE_BY_TOPFRAME) && m_rcTopFrame.IsInRect( x , y ) )
m_bMoving = true;
if (!(dwRet & KMR_CHILD_GET_MSG) )
{
if( (m_dwStyle & KSTYLE_MOVE_BY_ALL) && m_rcRegion.IsInRect( x, y) )
m_bMoving = true;
if( (m_dwStyle & KSTYLE_MOVE_BY_CUSTOM) )
{
for(int i = 0; i < m_vtCustomRect.size(); ++i)
{
if( m_vtCustomRect.at( i ).IsInRect( x, y ) )
{
m_bMoving = true;
break;
}
}
}
}
if( true == m_bMoving )
{
m_ptMovingOffset = KPoint( x - m_rcRegion.left, y - m_rcRegion.top);
m_pManager->SetCapture( this);
}
}
break;
case KRBUTTON_UP:
{
if( IsInRect( x, y ) && m_bRightDown )
{
m_bRightDown = false;
//Right Click 발생
PumpUpMessage(GetID(), KGENWND_RIGHT_CLICK, x, y );
// _oprint( "KGENWND_RIGHT_CLICK 발생\n" );
}
}
break;
case KRBUTTON_DOWN:
{
if( IsInRect( x, y ) )
m_bRightDown = true;
else
m_bRightDown = false;
}
break;
default:
break;
}
return dwRet;
}
DWORD KUIGenWnd::OnKeyMessage(DWORD dwMessage, DWORD dwKeyCode)
{
DWORD dwRet = KUIWnd::OnKeyMessage( dwMessage, dwKeyCode);
if(KMR_NO_GET & dwRet)
return dwRet;
if ( dwMessage == KKEY_DOWN && dwKeyCode == VK_RETURN )
PumpUpMessage( "IDOK", KBUTTON_CLICK, 0, 0 );
if ( dwMessage == KKEY_DOWN && dwKeyCode == VK_ESCAPE )
PumpUpMessage( "IDCANCEL", KBUTTON_CLICK, 0, 0 );
return dwRet;
}
void* KUIGenWnd::Perform( KID id, KArg& msg )
{
_CID( UI_BEGIN_DRAG );
_CID( UI_RECV_DROP );
_CID( UI_SEND_DROP );
_CID( UI_CANDROP );
_CID( UI_ON_CHECK_DROP );
// 요건 상속받은 놈들에서 처리하자.
if ( id == id_UI_BEGIN_DRAG )
{
KUIBeginDragMessage* pBeginMsg = static_cast<KUIBeginDragMessage*>( &msg );
// Drag Object의 Icon의 Renderer 설정.
// ( 상속받은 놈에서 이걸 맘대로 고쳐줄수 있음)
KUIWnd* pWnd = GetChild( pBeginMsg->sDragControlID.c_str() );
if( NULL != pWnd)
{
m_pDragAndDropIcon->SetStateIcon( pWnd->GetSprName(), pWnd->GetAniName(), pWnd->GetFrameIndex(),
STATE_NORMAL);
// Drag And Drop을 하지 못할때의 Icon 설정
// m_pDragAndDropIcon->SetStateIcon( m_sSprName.c_str(), "", 0, STATE_CANNOT_DROP);
// 가능 할때 Icon 설정
// m_pDragAndDropIcon->SetStateIcon( m_sSprName.c_str(), "", 0, STATE_CAN_DROP);
}
pBeginMsg->pDragAndDropRenderer = m_pDragAndDropIcon;
}
else if ( id == id_UI_RECV_DROP )
{
KUISendRecvDropMessage* pRecvMsg = static_cast<KUISendRecvDropMessage*>( &msg );
}
else if ( id == id_UI_SEND_DROP )
{
KUISendRecvDropMessage* pSendMsg = static_cast<KUISendRecvDropMessage*>( &msg );
}
else if ( id == id_UI_CANDROP )
{
KUIDragAndDropMessage* pDropMsg = static_cast<KUIDragAndDropMessage*>( &msg );
pDropMsg->sRecvDropParentID = GetID();
static KUIOnCheckDropMessage checkMsg;
checkMsg.sSendDropControlID = pDropMsg->pObject->GetControlID();
checkMsg.sRecvDropParentID = GetID();
checkMsg.ptDropPos = pDropMsg->ptDropPos;
bool bFind = false;
KUIWnd* pParent = pDropMsg->pObject->GetParent();
// List를 돌면서 check (뒤에서부터 이므로 주의)
for(std::list<KUIWnd*>::reverse_iterator it = m_listChild.rbegin(); it != m_listChild.rend(); ++it)
{
KUIWnd *pWnd = (*it);
// 맨처음으로 Rect에 걸린 녀석만 체크해 준다.
if( pWnd->IsInRect( pDropMsg->ptDropPos.x, pDropMsg->ptDropPos.y) &&
!(pWnd->GetFlag() & KFLAG_NO_GET_MESSAGE ) )
{
// Control에 대해서 체크
pDropMsg->sRecvDropControlID = pWnd->GetID();
checkMsg.sRecvDropControlID = pWnd->GetID();
if( NULL != pParent)
pParent->Perform( id_UI_ON_CHECK_DROP, checkMsg);
pWnd->Perform(id_UI_CANDROP, *pDropMsg);
bFind = true;
break;
}
}
// GenWnd 대해서 체크
if( false == bFind)
{
// 받은놈이 없지?
checkMsg.sRecvDropControlID = "";
if( NULL != pParent)
pParent->Perform( id_UI_ON_CHECK_DROP, checkMsg);
}
}
else if ( id == id_UI_ON_CHECK_DROP )
{
// Drag를 쏜 Parent GenWnd 로 이 메세지가 날라온다.
// ( 현재 Icon의 위치와 연관되는 Receiver Control, Parent GenWnd ID, ptPos를 담고 있다.)
KUIOnCheckDropMessage* pCheckMsg = static_cast<KUIOnCheckDropMessage*> ( &msg );
for( DWORD i = 0; i < 3; ++i)
m_pDragAndDropIcon->EnableState( i , false);
m_pDragAndDropIcon->EnableState( STATE_NORMAL, true);
if(pCheckMsg->sRecvDropControlID.empty() == false &&
pCheckMsg->sSendDropControlID != pCheckMsg->sRecvDropControlID)
{
m_pDragAndDropIcon->EnableState( STATE_CAN_DROP, true);
}
}
return NULL;
}
void KUIGenWnd::PumpUpMessage( LPCSTR lpszControlID, DWORD nMessage, DWORD lparam, DWORD wparam )
{
switch ( nMessage )
{
case KEDIT_SYSKEY:
if ( lparam == VK_RETURN )
PumpUpMessage( "IDOK", KBUTTON_CLICK, 0, 0 );
if ( lparam == VK_ESCAPE )
PumpUpMessage( "IDCANCEL", KBUTTON_CLICK, 0, 0 );
if ( lparam == VK_TAB )
{
if ( m_listChild.size() > 1 )
{
for( std::list<KUIWnd*>::iterator it = m_listChild.begin(); it != m_listChild.end(); it++ )
{
// 포커스를 가진 차일드가 있는 경우
if( (*it)->HasFocus() )
{
std::list<KUIWnd*>::iterator itNext = it;
// 나머지 차일드 중 포커스를 받을 수 있는 것을 찾아서 포커스를 준다.
for( size_t n( 0 ); n < (m_listChild.size() - 1); ++n )
{
itNext++;
if( itNext == m_listChild.end() ) itNext = m_listChild.begin();
// tab stop플래그가 없으므로 edit컨트롤에만 포커스를 주도록 한다.
if( (*itNext)->GetClassName() == "edit" )
{
(*it)->SetFocus( false );
(*itNext)->SetFocus( true );
break;
}
}
break;
}
}
}
}
break;
case KBUTTON_PRESSING:
//TODO : 하드코딩
if ( _stricmp( "_Resize", lpszControlID ) == 0 )
{
m_bResizing = true;
m_pManager->SetCapture( this );
}
break;
case KBUTTON_CLICK:
if ( _stricmp( "_Resize", lpszControlID ) == 0 )
{
m_bResizing = false;
m_pManager->ReleaseCapture( this );
}
// 이건 있으면 문제의 소지가 있음 .. "_Close" 자체로 해결 가능.
//else if(_stricmp( "_Close", lpszControlID) == 0)
//{
// PumpUpMessage("ID_CLOSE", KBUTTON_CLICK, 0,0);
//}
break;
}
}
void KUIGenWnd::OnSizeChangeNofity(const KRect& rcRect)
{
// Unit 만큼 보정한 값을 가져온다.
KRect rcNewResize = _calculateCorrectionRect(rcRect);
// 같으면 안되네.
if(rcNewResize == m_rcRegion)
return;
int nXMove = 0; int nYMove = 0;
if( m_dwStyle & KSTYLE_RESIZE_LEFT)
nXMove = rcNewResize.left - m_rcRegion.left;
else
nXMove = rcNewResize.right - m_rcRegion.right;
if( m_dwStyle & KSTYLE_RESIZE_TOP)
nYMove = rcNewResize.top - m_rcRegion.top;
else
nYMove = rcNewResize.bottom - m_rcRegion.bottom;
// 보정값 만큼 설정
m_rcRegion = rcNewResize;
m_rcClipArea = rcNewResize;
m_rcCaptionArea = rcNewResize;
const KRect & rcChildRect = _calculateChildRect( rcNewResize );
// Child Control들은 Child Control Area로 setting
for ( std::list< KUIWnd* >::iterator it = m_listChild.begin();it != m_listChild.end() ; ++it )
{
(*it)->OnParentSizeChangeNotify(rcChildRect , nXMove, nYMove, m_dwStyle);
(*it)->OnParentClipChangeNotify(rcChildRect);
}
// GenWnd에 등록된 Control의 Clip Area는 다시 셋팅
for ( std::vector<KUIControl*>::iterator it = m_vtGenWndControls.begin();
it != m_vtGenWndControls.end(); ++it )
(*it)->OnParentClipChangeNotify(m_rcRegion);
// frame size setting
if( NULL != m_pTopFrame)
{
BuildPrimitive( m_pTopFrame, m_sTotalAniName[GENWND_TOPFRAME].c_str(), 1, K3DVertex(m_rcRegion.left, m_rcRegion.top, m_fZPos),
1.0f, KSize(m_rcRegion.GetWidth(), -1), false );
}
if( !(m_dwStyle & KSTYLE_NOBACKGROUND) )
{
_reArrangeBackground();
_makeBackgroundFrame();
_reArrangeFrame();
for(int i = 0; i <m_nPieceCount; ++i)
{
if( m_pSpriteList ) m_pSpriteList[i].SetTargetSize( (float)m_rcPieceArea[i].GetWidth(), (float)m_rcPieceArea[i].GetHeight() );
if( m_pSpriteList ) m_pSpriteList[i].SetPosition( K3DVector((K3DVALUE)m_rcPieceArea[i].left ,(K3DVALUE)m_rcPieceArea[i].top, m_fZPos ) );
}
// StatusBar 늘리기
if(NULL != m_pStatusBar)
_refreshStatusBar();
}
#ifdef _KUI_INVALIDATION
// { [sonador]
_releaseImageCache();
// }
#endif
}
void KUIGenWnd::OnParentSizeChangeNotify(const KRect& rcNewRect,int nXMove, int nYMove,int nResizeStyle)
{
int nXMoveOffset = 0; int nYMoveOffset = 0;
if( nResizeStyle & KSTYLE_RESIZE_LEFT) // 왼쪽으로 이동
nXMoveOffset = (m_dwAnchor & KANCHOR_LEFT ) ? nXMove : 0;
else
nXMoveOffset = (m_dwAnchor & KANCHOR_RIGHT ) ? nXMove : 0;
if( nResizeStyle & KSTYLE_RESIZE_TOP)
nYMoveOffset = (m_dwAnchor & KANCHOR_TOP ) ? nYMove : 0;
else
nYMoveOffset = (m_dwAnchor & KANCHOR_BOTTOM ) ? nYMove : 0;
MovePosOffset( nXMoveOffset, nYMoveOffset);
}
void KUIGenWnd::OnPosChangeNofity(int x,int y)
{
KUIWnd::OnPosChangeNofity(x, y);
for(int i = 0; i < m_nPieceCount; ++i)
m_pSpriteList[i].SetAddPosition(x,y);
for(int i = 0; i < m_nBackgroundCount; ++i)
m_pBackgroundList[i].SetAddPosition(x, y);
if(m_pTopFrame)
m_pTopFrame->SetAddPosition(x,y);
_updateTopFrameRect();
m_rcClipArea.left += x; m_rcClipArea.top += y;
m_rcClipArea.right += x; m_rcClipArea.bottom += y;
const KRect & rcChildRect = _calculateChildRect( m_rcClipArea );
// Child Control들은 Child Control Area로 setting
for ( std::list< KUIWnd* >::iterator it = m_listChild.begin();it != m_listChild.end() ; ++it )
(*it)->OnParentClipChangeNotify(rcChildRect);
// GenWND에 등록된 Control의 Clip Area는 다시 셋팅
for ( std::vector<KUIControl*>::iterator it = m_vtGenWndControls.begin();
it != m_vtGenWndControls.end() ;++it )
(*it)->OnParentClipChangeNotify(m_rcClipArea);
// Custom Moving Rect 이동
for(int i = 0; i < m_vtCustomRect.size(); ++i)
{
KRect& rcCustom = m_vtCustomRect.at( i );
rcCustom.left += x; rcCustom.top += y;
rcCustom.right += x;rcCustom.bottom += y;
}
}
void KUIGenWnd::OnParentPosChangeNotify(int XOffset, int YOffset)
{
MovePos( m_rcRegion.left + XOffset, m_rcRegion.top + YOffset );
}
void KUIGenWnd::OnClipChangeNotify( const KRect& rcClipRect)
{
KUIWnd::OnClipChangeNotify( rcClipRect );
for(int i = 0; i < m_nPieceCount; ++i)
m_pSpriteList[i].SetClipRect( &m_rcClipArea );
for(int i = 0; i < m_nBackgroundCount; ++i)
m_pBackgroundList[i].SetClipRect( &m_rcClipArea );
if( m_pTopFrame )
m_pTopFrame->SetClipRect( &m_rcClipArea);
}
void KUIGenWnd::OnParentClipChangeNotify(const KRect& rcClipRect)
{
if( !(m_dwStyle & KSTYLE_NO_CLIPPING) )
ClipRect( rcClipRect );
}
void KUIGenWnd::OnAlphaChangeNotify(float fAlpha)
{
KUIWnd::OnAlphaChangeNotify( fAlpha );
for(int i = 0; i < m_nPieceCount; ++i)
m_pSpriteList[i].SetVisibility( fAlpha );
for(int i = 0; i < m_nBackgroundCount; ++i)
m_pBackgroundList[i].SetVisibility( fAlpha );
if(m_pTopFrame)
m_pTopFrame->SetVisibility( fAlpha );
}
void KUIGenWnd::OnChangeCaptionNotify()
{
if( NULL != m_pTitleBar )
m_pTitleBar->SetCaption( m_sCaption.c_str() );
KUIWnd::OnChangeCaptionNotify();
}
#ifdef _KUI_INVALIDATION
void KUIGenWnd::OnShowNotify( bool bShowFlag )
{
if( GetParent() == 0 )
{
if( bShowFlag == false )
{
_releaseImageCache();
m_bNeedToCheckCached = true;
}
}
}
void KUIGenWnd::ActivateImageCache( bool bActive )
{
m_bActivateImageCache = bActive;
if( !m_bActivateImageCache )
{
_releaseImageCache();
}
}
void KUIGenWnd::OnDeviceLost()
{
_releaseImageCache();
InvalidateWnd();
}
#endif
void KUIGenWnd::AddButton( const char *_id, const char *_caption, const char* _toolTip )
{
if ( m_pStatusBar )
{
DWORD capwidth = m_rcRegion.GetWidth();
capwidth = KTextPhrase::GetStringSize( _caption, capwidth).width;
KResSprite* pFrame = _getSpriteSet()->GetSpriteRes( m_sTotalAniName[GENWND_STATUSBAR_BTN].c_str(), 0 );
KRect rc;
int style = 0;
if ( m_VtButtons.size() == 0 )
{
rc.left = m_rcRegion.left;
rc.top = m_rcRegion.bottom - pFrame->GetSizeY();
style = KSTYLE_BUTTON_LEFTSIDE;
rc.right = rc.left + pFrame->GetSizeX() * 3 + capwidth;
rc.bottom = m_rcRegion.bottom;
}
else
{
KRect lastrc = m_VtButtons[m_VtButtons.size()-1]->GetRect();
rc.left = lastrc.right - pFrame->GetSizeX();
rc.top = m_rcRegion.bottom - pFrame->GetSizeY();
rc.right = rc.left + pFrame->GetSizeX() * 3 + capwidth;
rc.bottom = m_rcRegion.bottom;
}
rc.top -= FRAME_GAP;
rc.bottom -=FRAME_GAP;
KUIWND_CREATE_ARG arg;
arg.lpszClassName = "button";
arg.lpszID = _id;
arg.lpszCaption = _caption;
arg.lpszToolTip = _toolTip;
arg.lpszAniName = m_sTotalAniName[GENWND_STATUSBAR_BTN].c_str();
arg.lpszSprName = m_sSprName.c_str();
arg.rcRect = rc;
arg.pParent = this;
arg.dwStyle = style;
arg.dwAnchor = KANCHOR_BOTTOM | KANCHOR_LEFT;
KUIControlButton *button = reinterpret_cast<KUIControlButton*>(m_pManager->CreateControl(arg));
m_VtButtons.push_back( button );
_refreshStatusBar();
m_vtGenWndControls.push_back( button);
}
}
void KUIGenWnd::SetStatusText( const char *text )
{
m_sStatusBarCaption = text;
m_pStatusBar->SetCaption( m_sStatusBarCaption.c_str());
}
void KUIGenWnd::SetResizeUnit(int nXUnit, int nYUnit, KSize minSize, KSize maxSize)
{
m_nResizeXUnit = nXUnit;
m_nResizeYUnit = nYUnit;
m_minSize = minSize;
m_maxSize = maxSize;
}
void KUIGenWnd::SetGenWndAniName(LPCSTR lpszAniName, int nType)
{
if( nType < 0 || nType >= TOTAL_GENWND_ANINAME)
return;
if( lpszAniName == NULL)
m_sTotalAniName[nType] = "";
else
m_sTotalAniName[nType] = lpszAniName;
}
void KUIGenWnd::SetCustomMovingRect(const KRect& rcMovingRect)
{
if(m_vtCustomRect.empty() )
{
AddCustomRect( rcMovingRect );
}
else
{
ChangeCustomRect(rcMovingRect, 0);
}
}
void KUIGenWnd::AddCustomRect(const KRect& rcCustom)
{
m_vtCustomRect.push_back( rcCustom );
}
void KUIGenWnd::ChangeCustomRect(const KRect& rcMovingRect, int nIndex)
{
if( nIndex < 0 || nIndex >= m_vtCustomRect.size() )
{
assert(false && "Invalid Index");
return;
}
m_vtCustomRect.at( nIndex ) = rcMovingRect;
}
KRect& KUIGenWnd::GetCustomRect(int nIndex)
{
return m_vtCustomRect.at( nIndex );
}
int KUIGenWnd::GetCustomRectSize()const
{
return int( m_vtCustomRect.size() );
}
void KUIGenWnd::RemoveCustomRectAll()
{
m_vtCustomRect.clear();
}
bool KUIGenWnd::RemoveCustomRect(DWORD dwIndex)
{
if( dwIndex >= m_vtCustomRect.size() )
return false;
m_vtCustomRect.erase( m_vtCustomRect.begin() + dwIndex );
return true;
}
KRect KUIGenWnd::_calculateCorrectionRect(const KRect& rcRect)
{
KRect rcNewResize = rcRect;
// Min, Max Check
if(m_dwStyle & KSTYLE_RESIZE_LEFT)
{
rcNewResize.left = min( m_rcRegion.right - m_minSize.cx, rcNewResize.left );
rcNewResize.left = max( m_rcRegion.right - m_maxSize.cx, rcNewResize.left );
}
else
{
rcNewResize.right = max( rcNewResize.right, m_rcRegion.left + m_minSize.cx);
rcNewResize.right = min( rcNewResize.right, m_rcRegion.left + m_maxSize.cx);
}
if( m_dwStyle & KSTYLE_RESIZE_TOP)
{
rcNewResize.top = min( m_rcRegion.bottom - m_minSize.cy, rcNewResize.top );
rcNewResize.top = max( m_rcRegion.bottom - m_maxSize.cy, rcNewResize.top );
}
else
{
rcNewResize.bottom = max( rcNewResize.bottom, m_rcRegion.top + m_minSize.cy);
rcNewResize.bottom = min( rcNewResize.bottom, m_rcRegion.top + m_maxSize.cy);
}
// 바뀐값 (offset)
int nXMove = 0; int nYMove = 0;
if(m_dwStyle & KSTYLE_RESIZE_LEFT)
nXMove = rcNewResize.left - m_rcRegion.left;
else
nXMove = rcNewResize.right - m_rcRegion.right;
if(m_dwStyle & KSTYLE_RESIZE_TOP)
nYMove = rcNewResize.top - m_rcRegion.top;
else
nYMove = rcNewResize.bottom - m_rcRegion.bottom;
// Unit로 나눈 나머지
int nXMoveMod = m_nResizeXUnit ? nXMove % m_nResizeXUnit : nXMove;
int nYMoveMod = m_nResizeYUnit ? nYMove % m_nResizeYUnit : nYMove;
// Unit 만큼 Resize값 보정
if (m_nResizeXUnit < (int)abs( nXMoveMod ) * 2)
{
int nXCorrection = nXMoveMod > 0 ? m_nResizeXUnit : -m_nResizeXUnit;
if(m_dwStyle & KSTYLE_RESIZE_LEFT)
rcNewResize.left = rcNewResize.left - nXMoveMod + nXCorrection;
else
rcNewResize.right = rcNewResize.right - nXMoveMod + nXCorrection;
}
else
{
if(m_dwStyle & KSTYLE_RESIZE_LEFT)
rcNewResize.left = rcNewResize.left - nXMoveMod;
else
rcNewResize.right = rcNewResize.right - nXMoveMod;
}
if (m_nResizeYUnit < (int)abs( nYMoveMod ) * 2)
{
int nYCorrection = nYMoveMod > 0 ? m_nResizeYUnit : -m_nResizeYUnit;
if(m_dwStyle & KSTYLE_RESIZE_TOP)
rcNewResize.top = rcNewResize.top - nYMoveMod + nYCorrection;
else
rcNewResize.bottom = rcNewResize.bottom - nYMoveMod + nYCorrection;
}
else
{
if(m_dwStyle & KSTYLE_RESIZE_TOP)
rcNewResize.top = rcNewResize.top - nYMoveMod;
else
rcNewResize.bottom = rcNewResize.bottom - nYMoveMod;
}
return rcNewResize;
}
const KRect& KUIGenWnd::_calculateChildRect(const KRect& rcWindowRect)
{
m_rcChildRect = rcWindowRect;
// Frame ( -1씩 빼줌)
if( !(KSTYLE_NOFRAME & m_dwStyle) )
{
m_rcChildRect.left += 1; m_rcChildRect.top += 1;
m_rcChildRect.right -= 1; m_rcChildRect.bottom -= 1;
}
// Status Bar or Button
if( !(KSTYLE_NOSTATUSBAR & m_dwStyle) || m_VtButtons.size() > 0 )
{
int nStatusBarHeight = m_pStatusBar ? m_pStatusBar->GetRect().GetHeight() : 0;
m_rcChildRect.bottom -= nStatusBarHeight + FRAME_GAP;
}
return m_rcChildRect;
}
void KUIGenWnd::_refreshStatusBar()
{
if ( m_pStatusBar )
{
KResSprite* pFrame = _getSpriteSet()->GetSpriteRes( m_sTotalAniName[GENWND_STATUSBAR_BTN].c_str(), 0 );
int style = 0;
if ( m_VtButtons.size() > 0 )
{
KRect lastrc = m_VtButtons[m_VtButtons.size() - 1]->GetRect();
m_rcStatusBar.left = lastrc.right - pFrame->GetSizeX();
m_rcStatusBar.top = m_rcRegion.bottom - pFrame->GetSizeY();
m_rcStatusBar.bottom = m_rcRegion.bottom;
m_rcStatusBar.right = m_rcRegion.right;
}
else
{
style = KSTYLE_SB_NOLEFTSIDE;
m_rcStatusBar.left = m_rcRegion.left;
m_rcStatusBar.top = m_rcRegion.bottom - pFrame->GetSizeY();
m_rcStatusBar.bottom = m_rcRegion.bottom;
m_rcStatusBar.right = m_rcRegion.right;
}
m_rcStatusBar.top -= FRAME_GAP;
m_rcStatusBar.bottom -= FRAME_GAP;
m_rcStatusBar.right -= FRAME_GAP;
if ( m_dwStyle & KSTYLE_NORESIZE || m_dwStyle & KSTYLE_RESIZE_LEFT ||
m_dwStyle & KSTYLE_RESIZE_TOP )
style |= KSTYLE_SB_NORIGHTSIDE;
m_pStatusBar->SetStyle( style );
m_pStatusBar->Resize( m_rcStatusBar );
}
}
void KUIGenWnd::_reArrangeFrame()
{
if( _getSpriteSet() )
{
m_nPieceCount = _getSpriteSet()->GetSpriteResAniCount( m_sTotalAniName[GENWND_FRAME].c_str() );
if(m_nPieceCount < 1)
return;
int nLeft = m_rcRegion.left;
int nTop = m_rcRegion.top;
KResSprite * pFrame = _getSpriteSet()->GetSpriteRes( m_sTotalAniName[GENWND_FRAME].c_str(), 0 );
int nSizeX = (int)pFrame->GetSizeX(); int nSizeY = (int)pFrame->GetSizeY();
int nMidSizeX = m_rcRegion.right - m_rcRegion.left - nSizeX * 2;
int nMidSizeY = m_rcRegion.bottom - m_rcRegion.top - nSizeY * 2;
switch(m_nPieceCount)
{
case 9: // 9조각으로 찢어질 경우
{
int nCount = 0;
// 찍는 부분 설정
for(int i = 0; i < 3; ++ i)
{
nLeft = m_rcRegion.left;
for(int j = 0; j < 3; ++j)
{
m_rcPieceArea[nCount].left = nLeft;
m_rcPieceArea[nCount].top = nTop;
m_rcPieceArea[nCount].right = m_rcPieceArea[nCount].left + nSizeX;
m_rcPieceArea[nCount].bottom = m_rcPieceArea[nCount].top + nSizeY;
// 중간 열
if( j == 1)
{
nLeft += nMidSizeX;
m_rcPieceArea[nCount].right = m_rcPieceArea[nCount].left + nMidSizeX;
}
else
nLeft += nSizeX;
// 중간 행
if(i == 1)
m_rcPieceArea[nCount].bottom = m_rcPieceArea[nCount].top + nMidSizeY ;
nCount++;
}
// Mid
if( i == 1)
nTop += nMidSizeY;
else
nTop += nSizeY;
}
}
break;
default:
{ assert(false && "Piece Number is Invalid"); }
}
}
}
void KUIGenWnd::_reArrangeBackground()
{
SAFE_DELETE_ARRAY( m_pBackgroundArea );
KResSprite * pFrame = NULL;
if(_getSpriteSet())
pFrame = _getSpriteSet()->GetSpriteRes( m_sTotalAniName[GENWND_BACKGROUND].c_str(), 0 );
if( NULL == pFrame)
return;
int nSizeX = pFrame->GetSizeX(); int nSizeY = pFrame->GetSizeY();
int nVerticalCount = 1;
int nHorizontalCount = 1;
// 우선은 기본적으로 Genwnd 크기
int nBackWidth = m_rcRegion.GetWidth();
int nBackHeight = m_rcRegion.GetHeight();
// 세로 반복
if( KSTYLE_VERTICAL_REPEAT & m_dwStyle)
{
nBackHeight = nSizeY;
// 모자라면 + 1 해줌
nVerticalCount = ( m_rcRegion.GetHeight() - 1 ) / nSizeY + 1;
}
// 가로 반복
if( KSTYLE_HORIZONTAL_REPEAT & m_dwStyle)
{
nBackWidth = nSizeX;
// 모자라면 + 1 해줌
nHorizontalCount = ( m_rcRegion.GetWidth() - 1 ) / nSizeX + 1;
}
m_nBackgroundCount = nVerticalCount * nHorizontalCount;
m_pBackgroundArea = new KRect[m_nBackgroundCount];
// 우선 세로 먼저
int nPosX = m_rcRegion.left; int nPosY = m_rcRegion.top;
for(int i = 0; i < nVerticalCount; ++i)
{
nPosX = m_rcRegion.left;
for(int k = 0; k < nHorizontalCount; ++k)
{
m_pBackgroundArea[i * nHorizontalCount + k] = KRect( nPosX, nPosY, nPosX + nBackWidth, nPosY + nBackHeight);
nPosX += nSizeX;
}
nPosY += nSizeY;
}
}
void KUIGenWnd::_makeSpriteFrame()
{
SAFE_DELETE_ARRAY( m_pSpriteList );
m_pSpriteList = new KSpritePrimitive[m_nPieceCount];
for(int i = 0; i <m_nPieceCount; ++i)
{
KResSprite * pFrame = NULL;
if(_getSpriteSet())
pFrame = _getSpriteSet()->GetSpriteRes( m_sTotalAniName[GENWND_FRAME].c_str(), i );
if(!pFrame)
continue;
m_pSpriteList[i].SetRes(pFrame);
m_pSpriteList[i].SetTargetSize( (float)m_rcPieceArea[i].GetWidth(), (float)m_rcPieceArea[i].GetHeight() );
m_pSpriteList[i].SetPosition( K3DVector((K3DVALUE)m_rcPieceArea[i].left ,(K3DVALUE)m_rcPieceArea[i].top, m_fZPos ) );
}
}
void KUIGenWnd::_makeBackgroundFrame()
{
SAFE_DELETE_ARRAY( m_pBackgroundList );
m_pBackgroundList = new KSpritePrimitive[m_nBackgroundCount];
KResSprite * pFrame = NULL;
if(_getSpriteSet())
pFrame = _getSpriteSet()->GetSpriteRes( m_sTotalAniName[GENWND_BACKGROUND].c_str(), 0 );
if(!pFrame)
return;
for(int i = 0; i <m_nBackgroundCount; ++i)
{
m_pBackgroundList[i].SetRes(pFrame);
m_pBackgroundList[i].SetTargetSize( (float)m_pBackgroundArea[i].GetWidth(), (float)m_pBackgroundArea[i].GetHeight() );
m_pBackgroundList[i].SetPosition( K3DVector((K3DVALUE)m_pBackgroundArea[i].left ,
(K3DVALUE)m_pBackgroundArea[i].top, m_fZPos ) );
m_pBackgroundList[i].SetClipRect( &m_rcClipArea);
}
}
void KUIGenWnd::_makeTopFrame()
{
SAFE_DELETE( m_pTopFrame );
m_pTopFrame = new KSpritePrimitive;
BuildPrimitive( m_pTopFrame, m_sTotalAniName[GENWND_TOPFRAME].c_str(), 1,
K3DVertex(m_rcRegion.left, m_rcRegion.top + FRAME_GAP, m_fZPos),
1.0f, KSize(m_rcRegion.GetWidth(), -1), false );
}
void KUIGenWnd::_updateTopFrameRect()
{
m_rcTopFrame = m_rcRegion;
if( NULL == m_pTopFrame)
return;
if( m_pTopFrame->GetRes() != NULL )
m_rcTopFrame.bottom = m_rcTopFrame.top + m_pTopFrame->GetRes()->GetSizeY();
else
m_rcTopFrame.bottom = m_rcTopFrame.top;
}
// { [sonador]
#ifdef _KUI_INVALIDATION
bool KUIGenWnd::_initImageCache()
{
if( !m_bActivateImageCache || !_isTopWindow() ) return false;
if( m_bNeedToCheckCached )
{
if( m_spImageCache == 0 )
m_spImageCache = _getRenderTarget();
if( m_spImageCache )
{
if( m_pImageCachePrimitive == 0 )
{
m_pImageCachePrimitive = new KSpritePrimitive();
m_pImageCachePrimitive->SetRes( new KResSprite() );
}
m_pImageCachePrimitive->GetRes()->SetTexture( m_spImageCache, 0 );
}
else
{
SAFE_DELETE( m_pImageCachePrimitive );
}
m_bNeedToCheckCached = false;
}
return m_spImageCache;
}
void KUIGenWnd::_releaseImageCache()
{
m_bNeedToCheckCached = true; // [sonador] =_=;;; 어쩔수 없나...
if( m_spImageCache )
m_spImageCache = 0;
if( m_pImageCachePrimitive &&
m_pImageCachePrimitive->GetRes() &&
m_pImageCachePrimitive->GetRes()->GetTexture() )
m_pImageCachePrimitive->GetRes()->SetTexture( 0, 0 );
}
bool KUIGenWnd::_prepareImageCache( bool isFront )
{
if( !m_pManager || !m_pManager->GetViewportObject() ) return false;
if( !IsValidWnd() )
{
KViewportObject* pGuiViewport = m_pManager->GetViewportObject();
_render( pGuiViewport, isFront );
K3DVector vRegion( m_rcRegion.left, m_rcRegion.top, 0.0f );
pGuiViewport->RearrangeSpriteOffset( vRegion );
pGuiViewport->Render( m_spImageCache );
m_pImageCachePrimitive->SetRes( m_pImageCachePrimitive->GetRes() );
ValidateWnd();
}
// KUIGenWnd의 위치에 맞게 렌더타겟용 sprite primitive를 움직이자.
K3DMatrix mSprite;
K3DMatrixIdentity( mSprite );
K3DVector vRegion( m_rcRegion.left, m_rcRegion.top, m_fZPos );
mSprite.SetPosVector( vRegion );
m_pImageCachePrimitive->SetTransform( mSprite );
return true;
}
#endif
// }
void KUIGenWnd::SwapControl( const char* szID, const char* szSwapID )
{
if( m_listChild.size() == 0 ) return;
std::list<KUIWnd*> BackList;
KUIWnd* pOriginalWnd;
KUIWnd* pNewWnd;
bool bNewUpdate = false, bOriginalUpdate = false;
std::list<KUIWnd*>::iterator it = m_listChild.begin();
while( it != m_listChild.end() )
{
KUIWnd* pWnd = (*it);
if( ::_stricmp(pWnd->GetID(), szID) == 0 && !bOriginalUpdate )
{
pOriginalWnd = KUIFactory::GetInstance()->CreateObject( pWnd->GetClassName().c_str() );
*pOriginalWnd = *pWnd;
bOriginalUpdate = true;
}
else if( ::_stricmp(pWnd->GetID(), szSwapID) == 0 && !bNewUpdate )
{
pNewWnd = KUIFactory::GetInstance()->CreateObject( pWnd->GetClassName().c_str() );
*pNewWnd = *pWnd;
bNewUpdate = true;
}
BackList.push_back(pWnd);
it++;
}
bNewUpdate = false, bOriginalUpdate = false;
it = BackList.begin();
while( it != BackList.end() )
{
KUIWnd* pWnd =(*it);
if( ::_stricmp(pWnd->GetID(), szID) == 0 && !bNewUpdate )
{
*(*it) = *pNewWnd;
bNewUpdate = true;
}
else if( ::_stricmp(pWnd->GetID(), szSwapID) == 0 && !bOriginalUpdate )
{
*(*it) = *pOriginalWnd;
bOriginalUpdate = true;
}
it++;
}
m_listChild.swap( BackList );
}
#ifdef _KUI_INVALIDATION
void KUIGenWnd::AddPopupControl( KUIControl* pControl )
{
if( pControl == NULL ) return;
for( int i(0); i<m_vtPopupControl.size(); ++i )
{
if( m_vtPopupControl[i] == pControl )
return;
}
m_vtPopupControl.push_back( pControl );
pControl->SetPopupWnd(true);
}
void KUIGenWnd::RemovePopupControl( KUIControl* pControl )
{
if( pControl == NULL ) return;
std::vector<KUIControl*>::iterator it = m_vtPopupControl.begin();
KUIControl* pCmpControl(NULL);
while( it != m_vtPopupControl.end() )
{
pCmpControl = *it;
if( pCmpControl == pControl )
{
if( pCmpControl )
pCmpControl->SetPopupWnd(false);
m_vtPopupControl.erase( it );
return;
}
it++;
}
}
void KUIGenWnd::RemoveAllPopupControl()
{
for( int i(0); i<m_vtPopupControl.size(); ++i )
{
if( m_vtPopupControl[i] )
m_vtPopupControl[i]->SetPopupWnd(false);
}
m_vtPopupControl.clear();
}
void KUIGenWnd::_render( KViewportObject* pViewport, bool isFront )
{
// Background을 먼저 깔고
for(int i = 0; i < m_nBackgroundCount; ++i)
pViewport->Register( &m_pBackgroundList[i] );
// 나머지 콘트롤들을 렌더
KUIWnd::Render( pViewport, isFront );
if(NULL != m_pTopFrame)
pViewport->Register(m_pTopFrame);
for(int i = 0; i < m_vtGenWndControls.size(); ++i)
m_vtGenWndControls.at(i)->Render( pViewport, isFront );
// 한 후에 다시 Frame Render
for(int i = 0; i < m_nPieceCount; ++i)
pViewport->Register(&m_pSpriteList[i]);
}
void KUIGenWnd::_renderPopupControl( KViewportObject *pViewport, bool isFront )
{
for( int i(0); i<m_vtPopupControl.size(); ++i )
{
if( m_vtPopupControl[i] && m_vtPopupControl[i]->IsShow() )
m_vtPopupControl[i]->Render( pViewport, isFront );
}
}
void KUIGenWnd::_renderToolTip( KViewportObject *pViewport, bool isFront )
{
if( m_pOnToolTipWnd )
((KUIControl*)m_pOnToolTipWnd)->RenderToolTip( pViewport, isFront );
}
#endif