Added Bullet SAP/MultiSAP support by Erwin Coumans (BulletSAPCompleteBoxPruningTest.*) AABB tree broadphase by Nathanael Presson (btDbvt.*, DbvtTest.*)
3266 lines
93 KiB
C++
3266 lines
93 KiB
C++
// ---------------------------------------------------------------------------
|
|
//
|
|
// @file TwMgr.cpp
|
|
// @author Philippe Decaudin - http://www.antisphere.com
|
|
// @license This file is part of the AntTweakBar library.
|
|
// Copyright © 2005, 2006 Philippe Decaudin.
|
|
// For conditions of distribution and use, see License.txt
|
|
//
|
|
// note: TAB=4
|
|
//
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
#include "TwPrecomp.h"
|
|
|
|
#include <AntTweakBar.h>
|
|
#include "TwMgr.h"
|
|
#include "TwBar.h"
|
|
#include "TwFonts.h"
|
|
#include "TwOpenGL.h"
|
|
#ifdef ANT_WINDOWS
|
|
# include "TwDirect3D9.h"
|
|
# include "resource.h"
|
|
# ifdef _DEBUG
|
|
# include <crtdbg.h>
|
|
# endif // _DEBUG
|
|
#endif // ANT_WINDOWS
|
|
|
|
using namespace std;
|
|
|
|
|
|
CTwMgr *g_TwMgr = NULL;
|
|
bool g_BreakOnError = false;
|
|
TwErrorHandler g_ErrorHandler = NULL;
|
|
int g_TabLength = 4;
|
|
CTwBar * const TW_GLOBAL_BAR = (CTwBar *)(-1);
|
|
int g_InitWndWidth = -1;
|
|
int g_InitWndHeight = -1;
|
|
|
|
extern const char *g_ErrUnknownAttrib;
|
|
extern const char *g_ErrNoValue;
|
|
extern const char *g_ErrBadValue;
|
|
const char *g_ErrInit = "Already initialized";
|
|
const char *g_ErrShut = "Already shutdown";
|
|
const char *g_ErrNotInit = "Not initialized";
|
|
const char *g_ErrUnknownAPI = "Unsupported graph API";
|
|
const char *g_ErrBadDevice = "Invalid graph device";
|
|
const char *g_ErrBadParam = "Invalid parameter";
|
|
const char *g_ErrExist = "Exists already";
|
|
const char *g_ErrNotFound = "Not found";
|
|
const char *g_ErrNthToDo = "Nothing to do";
|
|
const char *g_ErrBadWndSize = "Bad window size";
|
|
const char *g_ErrOffset = "Offset larger than StructSize";
|
|
const char *g_ErrDelStruct = "Cannot delete a struct member";
|
|
const char *g_ErrNoBackQuote= "Name cannot include back-quote";
|
|
char g_ErrParse[512];
|
|
|
|
void ANT_CALL TwGlobalError(const char *_ErrorMessage);
|
|
|
|
#if defined(_UNIX)
|
|
#define _stricmp strcasecmp
|
|
#define _strdup strdup
|
|
#endif
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// a static global object to verify that Tweakbar module has been properly terminated (in debug mode only)
|
|
#ifdef _DEBUG
|
|
static struct CTwVerif
|
|
{
|
|
~CTwVerif()
|
|
{
|
|
if( g_TwMgr!=NULL )
|
|
g_TwMgr->SetLastError("Tweak bar module has not been terminated properly: call TwTerminate()\n");
|
|
}
|
|
} s_Verif;
|
|
#endif // _DEBUG
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void CColorExt::RGB2HLS()
|
|
{
|
|
float fH = 0, fL = 0, fS = 0;
|
|
ColorRGBToHLSf((float)R/255.0f, (float)G/255.0f, (float)B/255.0f, &fH, &fL, &fS);
|
|
H = (int)fH;
|
|
if( H>=360 )
|
|
H -= 360;
|
|
else if( H<0 )
|
|
H += 360;
|
|
L = (int)(255.0f*fL + 0.5f);
|
|
if( L<0 )
|
|
L = 0;
|
|
else if( L>255 )
|
|
L = 255;
|
|
S = (int)(255.0f*fS + 0.5f);
|
|
if( S<0 )
|
|
S = 0;
|
|
else if( S>255 )
|
|
S = 255;
|
|
}
|
|
|
|
void CColorExt::HLS2RGB()
|
|
{
|
|
float fR = 0, fG = 0, fB = 0;
|
|
ColorHLSToRGBf((float)H, (float)L/255.0f, (float)S/255.0f, &fR, &fG, &fB);
|
|
R = (int)(255.0f*fR + 0.5f);
|
|
if( R<0 )
|
|
R = 0;
|
|
else if( R>255 )
|
|
R = 255;
|
|
G = (int)(255.0f*fG + 0.5f);
|
|
if( G<0 )
|
|
G = 0;
|
|
else if( G>255 )
|
|
G = 255;
|
|
B = (int)(255.0f*fB + 0.5f);
|
|
if( B<0 )
|
|
B = 0;
|
|
else if( B>255 )
|
|
B = 255;
|
|
}
|
|
|
|
void ANT_CALL CColorExt::InitColor32CB(void *_ExtValue, void *_ClientData)
|
|
{
|
|
CColorExt *ext = static_cast<CColorExt *>(_ExtValue);
|
|
if( ext )
|
|
{
|
|
ext->m_IsColorF = false;
|
|
ext->R = 0;
|
|
ext->G = 0;
|
|
ext->B = 0;
|
|
ext->H = 0;
|
|
ext->L = 0;
|
|
ext->S = 0;
|
|
ext->A = 255;
|
|
ext->m_HLS = false;
|
|
ext->m_HasAlpha = false;
|
|
ext->m_CanHaveAlpha = true;
|
|
if( g_TwMgr && g_TwMgr->m_GraphAPI!=TW_OPENGL )
|
|
ext->m_OGL = false;
|
|
else
|
|
ext->m_OGL = true;
|
|
ext->m_PrevConvertedColor = Color32FromARGBi(ext->A, ext->R, ext->G, ext->B);
|
|
ext->m_StructProxy = (CTwMgr::CStructProxy *)_ClientData;
|
|
}
|
|
}
|
|
|
|
void ANT_CALL CColorExt::InitColor3FCB(void *_ExtValue, void *_ClientData)
|
|
{
|
|
InitColor32CB(_ExtValue, _ClientData);
|
|
CColorExt *ext = static_cast<CColorExt *>(_ExtValue);
|
|
if( ext )
|
|
{
|
|
ext->m_IsColorF = true;
|
|
ext->m_HasAlpha = false;
|
|
ext->m_CanHaveAlpha = false;
|
|
}
|
|
}
|
|
|
|
void ANT_CALL CColorExt::InitColor4FCB(void *_ExtValue, void *_ClientData)
|
|
{
|
|
InitColor32CB(_ExtValue, _ClientData);
|
|
CColorExt *ext = static_cast<CColorExt *>(_ExtValue);
|
|
if( ext )
|
|
{
|
|
ext->m_IsColorF = true;
|
|
ext->m_HasAlpha = true;
|
|
ext->m_CanHaveAlpha = true;
|
|
}
|
|
}
|
|
|
|
void ANT_CALL CColorExt::CopyVarFromExtCB(void *_VarValue, const void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData)
|
|
{
|
|
unsigned int *var32 = static_cast<unsigned int *>(_VarValue);
|
|
float *varF = static_cast<float *>(_VarValue);
|
|
CColorExt *ext = (CColorExt *)(_ExtValue);
|
|
CTwMgr::CMemberProxy *mProxy = static_cast<CTwMgr::CMemberProxy *>(_ClientData);
|
|
if( _VarValue && ext )
|
|
{
|
|
if( ext->m_HasAlpha && mProxy && mProxy->m_StructProxy && mProxy->m_StructProxy->m_Type==g_TwMgr->m_TypeColor3F )
|
|
ext->m_HasAlpha = false;
|
|
|
|
// Synchronize HLS and RGB
|
|
if( _ExtMemberIndex>=0 && _ExtMemberIndex<=2 )
|
|
ext->RGB2HLS();
|
|
else if( _ExtMemberIndex>=3 && _ExtMemberIndex<=5 )
|
|
ext->HLS2RGB();
|
|
else if( mProxy && _ExtMemberIndex==7 && mProxy->m_VarParent )
|
|
{
|
|
assert( mProxy->m_VarParent->m_Vars.size()==8 );
|
|
if( mProxy->m_VarParent->m_Vars[0]->m_Visible != !ext->m_HLS
|
|
|| mProxy->m_VarParent->m_Vars[1]->m_Visible != !ext->m_HLS
|
|
|| mProxy->m_VarParent->m_Vars[2]->m_Visible != !ext->m_HLS
|
|
|| mProxy->m_VarParent->m_Vars[3]->m_Visible != ext->m_HLS
|
|
|| mProxy->m_VarParent->m_Vars[4]->m_Visible != ext->m_HLS
|
|
|| mProxy->m_VarParent->m_Vars[5]->m_Visible != ext->m_HLS )
|
|
{
|
|
mProxy->m_VarParent->m_Vars[0]->m_Visible = !ext->m_HLS;
|
|
mProxy->m_VarParent->m_Vars[1]->m_Visible = !ext->m_HLS;
|
|
mProxy->m_VarParent->m_Vars[2]->m_Visible = !ext->m_HLS;
|
|
mProxy->m_VarParent->m_Vars[3]->m_Visible = ext->m_HLS;
|
|
mProxy->m_VarParent->m_Vars[4]->m_Visible = ext->m_HLS;
|
|
mProxy->m_VarParent->m_Vars[5]->m_Visible = ext->m_HLS;
|
|
mProxy->m_Bar->NotUpToDate();
|
|
}
|
|
if( mProxy->m_VarParent->m_Vars[6]->m_Visible != ext->m_HasAlpha )
|
|
{
|
|
mProxy->m_VarParent->m_Vars[6]->m_Visible = ext->m_HasAlpha;
|
|
mProxy->m_Bar->NotUpToDate();
|
|
}
|
|
if( static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[7])->m_ReadOnly )
|
|
{
|
|
static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[7])->m_ReadOnly = false;
|
|
mProxy->m_Bar->NotUpToDate();
|
|
}
|
|
}
|
|
// Convert to color32
|
|
color32 col = Color32FromARGBi((ext->m_HasAlpha ? ext->A : 255), ext->R, ext->G, ext->B);
|
|
if( ext->m_OGL && !ext->m_IsColorF )
|
|
col = (col&0xff00ff00) | (unsigned char)(col>>16) | (((unsigned char)(col))<<16);
|
|
if( ext->m_IsColorF )
|
|
Color32ToARGBf(col, (ext->m_HasAlpha ? varF+3 : NULL), varF+0, varF+1, varF+2);
|
|
else
|
|
{
|
|
if( ext->m_HasAlpha )
|
|
*var32 = col;
|
|
else
|
|
*var32 = ((*var32)&0xff000000) | (col&0x00ffffff);
|
|
}
|
|
ext->m_PrevConvertedColor = col;
|
|
}
|
|
}
|
|
|
|
void ANT_CALL CColorExt::CopyVarToExtCB(const void *_VarValue, void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData)
|
|
{
|
|
const unsigned int *var32 = static_cast<const unsigned int *>(_VarValue);
|
|
const float *varF = static_cast<const float *>(_VarValue);
|
|
CColorExt *ext = static_cast<CColorExt *>(_ExtValue);
|
|
CTwMgr::CMemberProxy *mProxy = static_cast<CTwMgr::CMemberProxy *>(_ClientData);
|
|
if( _VarValue && ext )
|
|
{
|
|
if( ext->m_HasAlpha && mProxy && mProxy->m_StructProxy && mProxy->m_StructProxy->m_Type==g_TwMgr->m_TypeColor3F )
|
|
ext->m_HasAlpha = false;
|
|
|
|
if( mProxy && _ExtMemberIndex==7 && mProxy->m_VarParent )
|
|
{
|
|
assert( mProxy->m_VarParent->m_Vars.size()==8 );
|
|
if( mProxy->m_VarParent->m_Vars[0]->m_Visible != !ext->m_HLS
|
|
|| mProxy->m_VarParent->m_Vars[1]->m_Visible != !ext->m_HLS
|
|
|| mProxy->m_VarParent->m_Vars[2]->m_Visible != !ext->m_HLS
|
|
|| mProxy->m_VarParent->m_Vars[3]->m_Visible != ext->m_HLS
|
|
|| mProxy->m_VarParent->m_Vars[4]->m_Visible != ext->m_HLS
|
|
|| mProxy->m_VarParent->m_Vars[5]->m_Visible != ext->m_HLS )
|
|
{
|
|
mProxy->m_VarParent->m_Vars[0]->m_Visible = !ext->m_HLS;
|
|
mProxy->m_VarParent->m_Vars[1]->m_Visible = !ext->m_HLS;
|
|
mProxy->m_VarParent->m_Vars[2]->m_Visible = !ext->m_HLS;
|
|
mProxy->m_VarParent->m_Vars[3]->m_Visible = ext->m_HLS;
|
|
mProxy->m_VarParent->m_Vars[4]->m_Visible = ext->m_HLS;
|
|
mProxy->m_VarParent->m_Vars[5]->m_Visible = ext->m_HLS;
|
|
mProxy->m_Bar->NotUpToDate();
|
|
}
|
|
if( mProxy->m_VarParent->m_Vars[6]->m_Visible != ext->m_HasAlpha )
|
|
{
|
|
mProxy->m_VarParent->m_Vars[6]->m_Visible = ext->m_HasAlpha;
|
|
mProxy->m_Bar->NotUpToDate();
|
|
}
|
|
if( static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[7])->m_ReadOnly )
|
|
{
|
|
static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[7])->m_ReadOnly = false;
|
|
mProxy->m_Bar->NotUpToDate();
|
|
}
|
|
}
|
|
color32 col;
|
|
if( ext->m_IsColorF )
|
|
col = Color32FromARGBf((ext->m_HasAlpha ? varF[3] : 1), varF[0], varF[1], varF[2]);
|
|
else
|
|
col = *var32;
|
|
if( ext->m_OGL && !ext->m_IsColorF )
|
|
col = (col&0xff00ff00) | (unsigned char)(col>>16) | (((unsigned char)(col))<<16);
|
|
Color32ToARGBi(col, (ext->m_HasAlpha ? &ext->A : NULL), &ext->R, &ext->G, &ext->B);
|
|
if( (col & 0x00ffffff)!=(ext->m_PrevConvertedColor & 0x00ffffff) )
|
|
ext->RGB2HLS();
|
|
ext->m_PrevConvertedColor = col;
|
|
}
|
|
}
|
|
|
|
void ANT_CALL CColorExt::SummaryCB(char *_SummaryString, size_t /*_SummaryMaxLength*/, const void *_ExtValue, void * /*_ClientData*/)
|
|
{
|
|
// copy var
|
|
CColorExt *ext = (CColorExt *)(_ExtValue);
|
|
if( ext && ext->m_StructProxy && ext->m_StructProxy->m_StructData )
|
|
{
|
|
if( ext->m_StructProxy->m_StructGetCallback )
|
|
ext->m_StructProxy->m_StructGetCallback(ext->m_StructProxy->m_StructData, ext->m_StructProxy->m_StructClientData);
|
|
//if( *(unsigned int *)(ext->m_StructProxy->m_StructData)!=ext->m_PrevConvertedColor )
|
|
CopyVarToExtCB(ext->m_StructProxy->m_StructData, ext, 99, NULL);
|
|
}
|
|
|
|
//unsigned int col = 0;
|
|
//CopyVar32FromExtCB(&col, _ExtValue, 99, _ClientData);
|
|
//_snprintf(_SummaryString, _SummaryMaxLength, "0x%.8X", col);
|
|
//(void) _SummaryMaxLength, _ExtValue, _ClientData;
|
|
_SummaryString[0] = ' '; // required to force background color for this value
|
|
_SummaryString[1] = '\0';
|
|
}
|
|
|
|
void CColorExt::CreateTypes()
|
|
{
|
|
if( g_TwMgr==NULL )
|
|
return;
|
|
TwStructMember ColorExtMembers[] = { { "Red", TW_TYPE_INT32, offsetof(CColorExt, R), "min=0 max=255" },
|
|
{ "Green", TW_TYPE_INT32, offsetof(CColorExt, G), "min=0 max=255" },
|
|
{ "Blue", TW_TYPE_INT32, offsetof(CColorExt, B), "min=0 max=255" },
|
|
{ "Hue", TW_TYPE_INT32, offsetof(CColorExt, H), "hide min=0 max=359" },
|
|
{ "Lightness", TW_TYPE_INT32, offsetof(CColorExt, L), "hide min=0 max=255" },
|
|
{ "Saturation", TW_TYPE_INT32, offsetof(CColorExt, S), "hide min=0 max=255" },
|
|
{ "Alpha", TW_TYPE_INT32, offsetof(CColorExt, A), "hide min=0 max=255" },
|
|
{ "Mode", TW_TYPE_BOOLCPP, offsetof(CColorExt, m_HLS), "true='HLS' false='RGB' readwrite" } };
|
|
g_TwMgr->m_TypeColor32 = TwDefineStructExt("COLOR32", ColorExtMembers, 8, sizeof(unsigned int), sizeof(CColorExt), CColorExt::InitColor32CB, CColorExt::CopyVarFromExtCB, CColorExt::CopyVarToExtCB, CColorExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData);
|
|
g_TwMgr->m_TypeColor3F = TwDefineStructExt("COLOR3F", ColorExtMembers, 8, 3*sizeof(float), sizeof(CColorExt), CColorExt::InitColor3FCB, CColorExt::CopyVarFromExtCB, CColorExt::CopyVarToExtCB, CColorExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData);
|
|
g_TwMgr->m_TypeColor4F = TwDefineStructExt("COLOR4F", ColorExtMembers, 8, 4*sizeof(float), sizeof(CColorExt), CColorExt::InitColor4FCB, CColorExt::CopyVarFromExtCB, CColorExt::CopyVarToExtCB, CColorExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData);
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
static int TwCreateGraph(ETwGraphAPI _GraphAPI)
|
|
{
|
|
assert( g_TwMgr!=NULL && g_TwMgr->m_Graph==NULL );
|
|
|
|
switch( _GraphAPI )
|
|
{
|
|
case TW_OPENGL:
|
|
g_TwMgr->m_Graph = new CTwGraphOpenGL;
|
|
break;
|
|
case TW_DIRECT3D9:
|
|
#ifdef ANT_WINDOWS
|
|
if( g_TwMgr->m_Device!=NULL )
|
|
g_TwMgr->m_Graph = new CTwGraphDirect3D9;
|
|
else
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrBadDevice);
|
|
return 0;
|
|
}
|
|
#endif // ANT_WINDOWS
|
|
break;
|
|
}
|
|
|
|
if( g_TwMgr->m_Graph==NULL )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrUnknownAPI);
|
|
return 0;
|
|
}
|
|
else
|
|
return g_TwMgr->m_Graph->Init();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL TwInit(ETwGraphAPI _GraphAPI, void *_Device)
|
|
{
|
|
#if defined(_DEBUG) && defined(ANT_WINDOWS)
|
|
_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF));
|
|
#endif
|
|
|
|
if( g_TwMgr!=NULL )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrInit);
|
|
return 0;
|
|
}
|
|
|
|
g_TwMgr = new CTwMgr(_GraphAPI, _Device);
|
|
|
|
TwGenerateDefaultFonts();
|
|
g_TwMgr->m_CurrentFont = g_DefaultNormalFont;
|
|
|
|
int Res = TwCreateGraph(_GraphAPI);
|
|
|
|
if( Res )
|
|
{
|
|
g_TwMgr->m_KeyPressedTextObj = g_TwMgr->m_Graph->NewTextObj();
|
|
g_TwMgr->m_InfoTextObj = g_TwMgr->m_Graph->NewTextObj();
|
|
|
|
g_TwMgr->m_HelpBar = TwNewBar("TW_HELP");
|
|
if( g_TwMgr->m_HelpBar )
|
|
{
|
|
g_TwMgr->m_HelpBar->m_Label = "~ Help & Shortcuts ~";
|
|
g_TwMgr->m_HelpBar->m_PosX = 32;
|
|
g_TwMgr->m_HelpBar->m_PosY = 32;
|
|
g_TwMgr->m_HelpBar->m_Width = 400;
|
|
g_TwMgr->m_HelpBar->m_Height = 200;
|
|
g_TwMgr->m_HelpBar->m_ValuesWidth = 12*(g_TwMgr->m_HelpBar->m_Font->m_CharHeight/2);
|
|
g_TwMgr->m_HelpBar->m_Color = 0xd7ffffff;
|
|
g_TwMgr->m_HelpBar->m_IsHelpBar = true;
|
|
g_TwMgr->Minimize(g_TwMgr->m_HelpBar);
|
|
}
|
|
else
|
|
{
|
|
TwTerminate();
|
|
Res = 0;
|
|
}
|
|
}
|
|
|
|
if( Res )
|
|
CColorExt::CreateTypes();
|
|
|
|
return Res;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL TwTerminate()
|
|
{
|
|
if( g_TwMgr==NULL )
|
|
{
|
|
//TwGlobalError(g_ErrShut); -> not an error
|
|
return 0; // already shutdown
|
|
}
|
|
|
|
TwDeleteAllBars();
|
|
if( g_TwMgr->m_CursorsCreated )
|
|
g_TwMgr->FreeCursors();
|
|
|
|
int Res = 1;
|
|
if( g_TwMgr->m_Graph )
|
|
{
|
|
if( g_TwMgr->m_KeyPressedTextObj )
|
|
{
|
|
g_TwMgr->m_Graph->DeleteTextObj(g_TwMgr->m_KeyPressedTextObj);
|
|
g_TwMgr->m_KeyPressedTextObj = NULL;
|
|
}
|
|
if( g_TwMgr->m_InfoTextObj )
|
|
{
|
|
g_TwMgr->m_Graph->DeleteTextObj(g_TwMgr->m_InfoTextObj);
|
|
g_TwMgr->m_InfoTextObj = NULL;
|
|
}
|
|
Res = g_TwMgr->m_Graph->Shut();
|
|
delete g_TwMgr->m_Graph;
|
|
g_TwMgr->m_Graph = NULL;
|
|
}
|
|
|
|
TwDeleteDefaultFonts();
|
|
|
|
delete g_TwMgr;
|
|
g_TwMgr = NULL;
|
|
|
|
return Res;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL TwDraw()
|
|
{
|
|
PERF( PerfTimer Timer; double DT; )
|
|
//CTwFPU fpu; // fpu precision only forced in update (do not modif dx draw calls)
|
|
|
|
if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return 0; // not initialized
|
|
}
|
|
|
|
assert(g_TwMgr->m_Bars.size()==g_TwMgr->m_Order.size());
|
|
|
|
// Create cursors
|
|
#if defined(ANT_WINDOWS)
|
|
if( !g_TwMgr->m_CursorsCreated )
|
|
g_TwMgr->CreateCursors();
|
|
#elif defined(ANT_UNIX)
|
|
if( !g_TwMgr->m_CurrentXDisplay )
|
|
g_TwMgr->m_CurrentXDisplay = glXGetCurrentDisplay();
|
|
if( !g_TwMgr->m_CurrentXWindow )
|
|
g_TwMgr->m_CurrentXWindow = glXGetCurrentDrawable();
|
|
if( g_TwMgr->m_CurrentXDisplay && !g_TwMgr->m_CursorsCreated )
|
|
g_TwMgr->CreateCursors();
|
|
#endif // defined(ANT_UNIX)
|
|
|
|
// Autorepeat TW_MOUSE_PRESSED
|
|
double RepeatDT = g_TwMgr->m_Timer.GetTime() - g_TwMgr->m_LastMousePressedTime;
|
|
if( fabs(RepeatDT)>2.0*g_TwMgr->m_RepeatMousePressedDelay
|
|
|| abs(g_TwMgr->m_LastMousePressedPosition[0]-g_TwMgr->m_LastMouseX)>4
|
|
|| abs(g_TwMgr->m_LastMousePressedPosition[1]-g_TwMgr->m_LastMouseY)>4 )
|
|
{
|
|
g_TwMgr->m_CanRepeatMousePressed = false;
|
|
g_TwMgr->m_IsRepeatingMousePressed = false;
|
|
}
|
|
if( g_TwMgr->m_CanRepeatMousePressed )
|
|
{
|
|
if( (!g_TwMgr->m_IsRepeatingMousePressed && RepeatDT>g_TwMgr->m_RepeatMousePressedDelay)
|
|
|| (g_TwMgr->m_IsRepeatingMousePressed && RepeatDT>g_TwMgr->m_RepeatMousePressedPeriod) )
|
|
{
|
|
g_TwMgr->m_IsRepeatingMousePressed = true;
|
|
g_TwMgr->m_LastMousePressedTime = g_TwMgr->m_Timer.GetTime();
|
|
TwMouseButton(TW_MOUSE_PRESSED, g_TwMgr->m_LastMousePressedButtonID);
|
|
}
|
|
}
|
|
|
|
|
|
if( g_TwMgr->m_WndWidth<0 || g_TwMgr->m_WndHeight<0 )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrBadWndSize);
|
|
return 0;
|
|
}
|
|
else if( g_TwMgr->m_WndWidth==0 || g_TwMgr->m_WndHeight==0 ) // probably iconified
|
|
return 1; // nothing to do
|
|
|
|
// count number of bars to draw
|
|
size_t i, idx;
|
|
int Nb = 0;
|
|
for( i=0; i<g_TwMgr->m_Bars.size(); ++i )
|
|
if( g_TwMgr->m_Bars[i]!=NULL && g_TwMgr->m_Bars[i]->m_Visible )
|
|
++Nb;
|
|
|
|
if( Nb>0 )
|
|
{
|
|
PERF( Timer.Reset(); )
|
|
g_TwMgr->m_Graph->BeginDraw(g_TwMgr->m_WndWidth, g_TwMgr->m_WndHeight);
|
|
PERF( DT = Timer.GetTime(); printf("\nBegin=%.4fms ", 1000.0*DT); )
|
|
|
|
PERF( Timer.Reset(); )
|
|
for( i=0; i<g_TwMgr->m_Bars.size(); ++i )
|
|
{
|
|
idx = g_TwMgr->m_Order[i];
|
|
if( g_TwMgr->m_Bars[idx]->m_Visible )
|
|
{
|
|
g_TwMgr->m_Bars[idx]->Draw();
|
|
}
|
|
}
|
|
PERF( DT = Timer.GetTime(); printf("Draw=%.4fms ", 1000.0*DT); )
|
|
|
|
PERF( Timer.Reset(); )
|
|
g_TwMgr->m_Graph->EndDraw();
|
|
PERF( DT = Timer.GetTime(); printf("End=%.4fms\n", 1000.0*DT); )
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL TwWindowSize(int _Width, int _Height)
|
|
{
|
|
g_InitWndWidth = _Width;
|
|
g_InitWndHeight = _Height;
|
|
|
|
if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
|
|
{
|
|
//TwGlobalError(g_ErrNotInit); -> not an error here
|
|
return 0; // not initialized
|
|
}
|
|
|
|
if( _Width<0 || _Height<0 )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrBadWndSize);
|
|
return 0;
|
|
}
|
|
|
|
g_TwMgr->m_WndWidth = _Width;
|
|
g_TwMgr->m_WndHeight = _Height;
|
|
g_TwMgr->m_Graph->Restore();
|
|
for( std::vector<TwBar*>::iterator it=g_TwMgr->m_Bars.begin(); it!=g_TwMgr->m_Bars.end(); ++it )
|
|
(*it)->NotUpToDate();
|
|
return 1;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
CTwMgr::CTwMgr(ETwGraphAPI _GraphAPI, void *_Device)
|
|
{
|
|
m_GraphAPI = _GraphAPI;
|
|
m_Device = _Device;
|
|
m_LastError = NULL;
|
|
m_CurrentDbgFile = "";
|
|
m_CurrentDbgLine = 0;
|
|
m_Graph = NULL;
|
|
m_WndWidth = g_InitWndWidth;
|
|
m_WndHeight = g_InitWndHeight;
|
|
m_CurrentFont = NULL; // set after by TwIntialize
|
|
m_NbMinimizedBars = 0;
|
|
m_HelpBar = NULL;
|
|
m_HelpBarNotUpToDate = true;
|
|
m_HelpBarUpdateNow = false;
|
|
m_LastHelpUpdateTime = 0;
|
|
m_LastMouseX = -1;
|
|
m_LastMouseY = -1;
|
|
m_LastMouseWheelPos = 0;
|
|
m_KeyPressedTextObj = NULL;
|
|
m_KeyPressedBuildText = false;
|
|
m_KeyPressedTime = 0;
|
|
m_InfoTextObj = NULL;
|
|
m_InfoBuildText = true;
|
|
m_BarInitColorHue = 155;
|
|
m_PopupBar = NULL;
|
|
m_TypeColor32 = TW_TYPE_UNDEF;
|
|
m_TypeColor3F = TW_TYPE_UNDEF;
|
|
m_TypeColor4F = TW_TYPE_UNDEF;
|
|
m_LastMousePressedTime = 0;
|
|
m_LastMousePressedButtonID = TW_MOUSE_MIDDLE;
|
|
m_LastMousePressedPosition[0] = -1000;
|
|
m_LastMousePressedPosition[1] = -1000;
|
|
m_RepeatMousePressedDelay = 0.5;
|
|
m_RepeatMousePressedPeriod = 0.1;
|
|
m_CanRepeatMousePressed = false;
|
|
m_IsRepeatingMousePressed = false;
|
|
|
|
m_CursorsCreated = false;
|
|
#if defined(ANT_UNIX)
|
|
m_CurrentXDisplay = NULL;
|
|
m_CurrentXWindow = 0;
|
|
#endif // defined(ANT_UNIX)
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
CTwMgr::~CTwMgr()
|
|
{
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int CTwMgr::FindBar(const char *_Name) const
|
|
{
|
|
if( _Name==NULL || strlen(_Name)<=0 )
|
|
return -1;
|
|
int i;
|
|
for( i=0; i<(int)m_Bars.size(); ++i )
|
|
if( m_Bars[i]!=NULL && strcmp(_Name, m_Bars[i]->m_Name.c_str())==0 )
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
enum EMgrAttribs
|
|
{
|
|
MGR_HELP = 1,
|
|
};
|
|
|
|
int CTwMgr::HasAttrib(const char *_Attrib, bool *_HasValue) const
|
|
{
|
|
*_HasValue = true;
|
|
if( _stricmp(_Attrib, "help")==0 )
|
|
return MGR_HELP;
|
|
|
|
*_HasValue = false;
|
|
return 0; // not found
|
|
}
|
|
|
|
int CTwMgr::SetAttrib(int _AttribID, const char *_Value)
|
|
{
|
|
switch( _AttribID )
|
|
{
|
|
case MGR_HELP:
|
|
if( _Value && strlen(_Value)>0 )
|
|
{
|
|
m_Help = _Value;
|
|
m_HelpBarNotUpToDate = true;
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrNoValue);
|
|
return 0;
|
|
}
|
|
default:
|
|
g_TwMgr->SetLastError(g_ErrUnknownAttrib);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void CTwMgr::Minimize(TwBar *_Bar)
|
|
{
|
|
assert(m_Graph!=NULL && _Bar!=NULL);
|
|
assert(m_Bars.size()==m_MinOccupied.size());
|
|
if( _Bar->m_IsMinimized )
|
|
return;
|
|
size_t i = m_NbMinimizedBars;
|
|
m_NbMinimizedBars++;
|
|
for( i=0; i<m_MinOccupied.size(); ++i )
|
|
if( !m_MinOccupied[i] )
|
|
break;
|
|
if( i<m_MinOccupied.size() )
|
|
m_MinOccupied[i] = true;
|
|
_Bar->m_MinNumber = (int)i;
|
|
_Bar->m_IsMinimized = true;
|
|
_Bar->NotUpToDate();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void CTwMgr::Maximize(TwBar *_Bar)
|
|
{
|
|
assert(m_Graph!=NULL && _Bar!=NULL);
|
|
assert(m_Bars.size()==m_MinOccupied.size());
|
|
if( !_Bar->m_IsMinimized )
|
|
return;
|
|
--m_NbMinimizedBars;
|
|
if( m_NbMinimizedBars<0 )
|
|
m_NbMinimizedBars = 0;
|
|
if( _Bar->m_MinNumber>=0 && _Bar->m_MinNumber<(int)m_MinOccupied.size() )
|
|
m_MinOccupied[_Bar->m_MinNumber] = false;
|
|
_Bar->m_IsMinimized = false;
|
|
_Bar->NotUpToDate();
|
|
if( _Bar->m_IsHelpBar )
|
|
m_HelpBarNotUpToDate = true;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void CTwMgr::Hide(TwBar *_Bar)
|
|
{
|
|
assert(m_Graph!=NULL && _Bar!=NULL);
|
|
if( !_Bar->m_Visible )
|
|
return;
|
|
_Bar->m_Visible = false;
|
|
if( !_Bar->m_IsHelpBar )
|
|
m_HelpBarNotUpToDate = true;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void CTwMgr::Unhide(TwBar *_Bar)
|
|
{
|
|
assert(m_Graph!=NULL && _Bar!=NULL);
|
|
if( _Bar->m_Visible )
|
|
return;
|
|
_Bar->m_Visible = true;
|
|
_Bar->NotUpToDate();
|
|
if( !_Bar->m_IsHelpBar )
|
|
m_HelpBarNotUpToDate = true;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void CTwMgr::SetFont(const CTexFont *_Font, bool _ResizeBars)
|
|
{
|
|
assert(m_Graph!=NULL);
|
|
assert(_Font!=NULL);
|
|
|
|
m_CurrentFont = _Font;
|
|
|
|
for( int i=0; i<(int)m_Bars.size(); ++i )
|
|
if( m_Bars[i]!=NULL )
|
|
{
|
|
int fh = m_Bars[i]->m_Font->m_CharHeight;
|
|
m_Bars[i]->m_Font = _Font;
|
|
if( _ResizeBars )
|
|
{
|
|
m_Bars[i]->m_PosX += (3*(fh-_Font->m_CharHeight))/2;
|
|
m_Bars[i]->m_PosY += (fh-_Font->m_CharHeight)/2;
|
|
m_Bars[i]->m_Width = (m_Bars[i]->m_Width*_Font->m_CharHeight)/fh;
|
|
m_Bars[i]->m_Height = (m_Bars[i]->m_Height*_Font->m_CharHeight)/fh;
|
|
m_Bars[i]->m_ValuesWidth = (m_Bars[i]->m_ValuesWidth*_Font->m_CharHeight)/fh;
|
|
}
|
|
m_Bars[i]->NotUpToDate();
|
|
}
|
|
|
|
if( g_TwMgr->m_HelpBar!=NULL )
|
|
g_TwMgr->m_HelpBar->Update();
|
|
g_TwMgr->m_InfoBuildText = true;
|
|
g_TwMgr->m_KeyPressedBuildText = true;
|
|
m_HelpBarNotUpToDate = true;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void ANT_CALL TwGlobalError(const char *_ErrorMessage) // to be called when g_TwMgr is not created
|
|
{
|
|
if( g_ErrorHandler==NULL )
|
|
{
|
|
fprintf(stderr, "ERROR(AntTweakBar) >> %s\n", _ErrorMessage);
|
|
#ifdef ANT_WINDOWS
|
|
OutputDebugString("ERROR(AntTweakBar) >> ");
|
|
OutputDebugString(_ErrorMessage);
|
|
OutputDebugString("\n");
|
|
#endif // ANT_WINDOWS
|
|
}
|
|
else
|
|
g_ErrorHandler(_ErrorMessage);
|
|
|
|
if( g_BreakOnError )
|
|
abort();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void CTwMgr::SetLastError(const char *_ErrorMessage) // _ErrorMessage must be a static string
|
|
{
|
|
m_LastError = _ErrorMessage;
|
|
|
|
if( g_ErrorHandler==NULL )
|
|
{
|
|
if( m_CurrentDbgFile!=NULL && strlen(m_CurrentDbgFile)>0 && m_CurrentDbgLine>0 )
|
|
fprintf(stderr, "%s(%d): ", m_CurrentDbgFile, m_CurrentDbgLine);
|
|
fprintf(stderr, "ERROR(AntTweakBar) >> %s\n", m_LastError);
|
|
#ifdef ANT_WINDOWS
|
|
if( m_CurrentDbgFile!=NULL && strlen(m_CurrentDbgFile)>0 && m_CurrentDbgLine>0 )
|
|
{
|
|
OutputDebugString(m_CurrentDbgFile);
|
|
char sl[32];
|
|
sprintf(sl, "(%d): ", m_CurrentDbgLine);
|
|
OutputDebugString(sl);
|
|
}
|
|
OutputDebugString("ERROR(AntTweakBar) >> ");
|
|
OutputDebugString(m_LastError);
|
|
OutputDebugString("\n");
|
|
#endif // ANT_WINDOWS
|
|
}
|
|
else
|
|
g_ErrorHandler(_ErrorMessage);
|
|
|
|
if( g_BreakOnError )
|
|
abort();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const char *CTwMgr::GetLastError()
|
|
{
|
|
const char *Err = m_LastError;
|
|
m_LastError = NULL;
|
|
return Err;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const char *CTwMgr::CheckLastError() const
|
|
{
|
|
return m_LastError;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void CTwMgr::SetCurrentDbgParams(const char *dbgFile, int dbgLine)
|
|
{
|
|
m_CurrentDbgFile = dbgFile;
|
|
m_CurrentDbgLine = dbgLine;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL __TwDbg(const char *dbgFile, int dbgLine)
|
|
{
|
|
if( g_TwMgr!=NULL )
|
|
g_TwMgr->SetCurrentDbgParams(dbgFile, dbgLine);
|
|
return 0; // always returns zero
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void ANT_CALL TwHandleErrors(TwErrorHandler _ErrorHandler, int _BreakOnError)
|
|
{
|
|
g_ErrorHandler = _ErrorHandler;
|
|
g_BreakOnError = (_BreakOnError) ? true : false;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const char *ANT_CALL TwGetLastError()
|
|
{
|
|
if( g_TwMgr==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return g_ErrNotInit;
|
|
}
|
|
else
|
|
return g_TwMgr->GetLastError();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
TwBar *ANT_CALL TwNewBar(const char *_Name)
|
|
{
|
|
if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return NULL; // not initialized
|
|
}
|
|
|
|
if( _Name==NULL || strlen(_Name)<=0 )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrBadParam);
|
|
return NULL;
|
|
}
|
|
if( g_TwMgr->FindBar(_Name)>=0 )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrExist);
|
|
return NULL;
|
|
}
|
|
|
|
if( strstr(_Name, "`")!=NULL )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrNoBackQuote);
|
|
return NULL;
|
|
}
|
|
|
|
if( g_TwMgr->m_PopupBar!=NULL ) // delete popup bar if it exists
|
|
{
|
|
TwDeleteBar(g_TwMgr->m_PopupBar);
|
|
g_TwMgr->m_PopupBar = NULL;
|
|
}
|
|
|
|
TwBar *Bar = new CTwBar(_Name);
|
|
g_TwMgr->m_Bars.push_back(Bar);
|
|
g_TwMgr->m_Order.push_back((int)g_TwMgr->m_Bars.size()-1);
|
|
g_TwMgr->m_MinOccupied.push_back(false);
|
|
g_TwMgr->m_HelpBarNotUpToDate = true;
|
|
|
|
return Bar;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL TwDeleteBar(TwBar *_Bar)
|
|
{
|
|
if( g_TwMgr==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return 0; // not initialized
|
|
}
|
|
if( _Bar==NULL )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrBadParam);
|
|
return 0;
|
|
}
|
|
vector<TwBar*>::iterator BarIt;
|
|
int i = 0;
|
|
for( BarIt=g_TwMgr->m_Bars.begin(); BarIt!=g_TwMgr->m_Bars.end(); ++BarIt, ++i )
|
|
if( (*BarIt)==_Bar )
|
|
break;
|
|
if( BarIt==g_TwMgr->m_Bars.end() )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrNotFound);
|
|
return 0;
|
|
}
|
|
|
|
if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar ) // delete popup bar first if it exists
|
|
{
|
|
TwDeleteBar(g_TwMgr->m_PopupBar);
|
|
g_TwMgr->m_PopupBar = NULL;
|
|
}
|
|
|
|
// force bar to un-minimize
|
|
g_TwMgr->Maximize(_Bar);
|
|
// find an empty MinOccupied
|
|
vector<bool>::iterator itm;
|
|
int j = 0;
|
|
for( itm=g_TwMgr->m_MinOccupied.begin(); itm!=g_TwMgr->m_MinOccupied.end(); ++itm, ++j)
|
|
if( (*itm)==false )
|
|
break;
|
|
assert( itm!=g_TwMgr->m_MinOccupied.end() );
|
|
// shift MinNumbers and erase the empty MinOccupied
|
|
for( size_t k=0; k<g_TwMgr->m_Bars.size(); ++k )
|
|
if( g_TwMgr->m_Bars[k]!=NULL && g_TwMgr->m_Bars[k]->m_MinNumber>j )
|
|
g_TwMgr->m_Bars[k]->m_MinNumber -= 1;
|
|
g_TwMgr->m_MinOccupied.erase(itm);
|
|
// erase _Bar order
|
|
vector<int>::iterator BarOrderIt = g_TwMgr->m_Order.end();
|
|
for(vector<int>::iterator it=g_TwMgr->m_Order.begin(); it!=g_TwMgr->m_Order.end(); ++it )
|
|
if( (*it)==i )
|
|
BarOrderIt = it;
|
|
else if( (*it)>i )
|
|
(*it) -= 1;
|
|
assert( BarOrderIt!=g_TwMgr->m_Order.end() );
|
|
g_TwMgr->m_Order.erase(BarOrderIt);
|
|
|
|
// erase & delete _Bar
|
|
g_TwMgr->m_Bars.erase(BarIt);
|
|
delete _Bar;
|
|
|
|
g_TwMgr->m_HelpBarNotUpToDate = true;
|
|
return 1;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL TwDeleteAllBars()
|
|
{
|
|
if( g_TwMgr==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return 0; // not initialized
|
|
}
|
|
|
|
int n = 0;
|
|
for( size_t i=0; i<g_TwMgr->m_Bars.size(); ++i )
|
|
if( g_TwMgr->m_Bars[i]!=NULL )
|
|
{
|
|
++n;
|
|
delete g_TwMgr->m_Bars[i];
|
|
g_TwMgr->m_Bars[i] = NULL;
|
|
}
|
|
g_TwMgr->m_Bars.clear();
|
|
g_TwMgr->m_Order.clear();
|
|
g_TwMgr->m_MinOccupied.clear();
|
|
g_TwMgr->m_HelpBarNotUpToDate = true;
|
|
|
|
if( n==0 )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrNthToDo);
|
|
return 0;
|
|
}
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL TwSetTopBar(const TwBar *_Bar)
|
|
{
|
|
if( g_TwMgr==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return 0; // not initialized
|
|
}
|
|
if( _Bar==NULL )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrBadParam);
|
|
return 0;
|
|
}
|
|
|
|
int i = -1, iOrder;
|
|
for( iOrder=0; iOrder<(int)g_TwMgr->m_Bars.size(); ++iOrder )
|
|
{
|
|
i = g_TwMgr->m_Order[iOrder];
|
|
assert( i>=0 && i<(int)g_TwMgr->m_Bars.size() );
|
|
if( g_TwMgr->m_Bars[i]==_Bar )
|
|
break;
|
|
}
|
|
if( i<0 || iOrder>=(int)g_TwMgr->m_Bars.size() ) // bar not found
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrNotFound);
|
|
return 0;
|
|
}
|
|
|
|
for( int j=iOrder; j<(int)g_TwMgr->m_Bars.size()-1; ++j )
|
|
g_TwMgr->m_Order[j] = g_TwMgr->m_Order[j+1];
|
|
g_TwMgr->m_Order[(int)g_TwMgr->m_Bars.size()-1] = i;
|
|
|
|
if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar )
|
|
TwSetTopBar(g_TwMgr->m_PopupBar);
|
|
|
|
return 1;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
TwBar * ANT_CALL TwGetTopBar()
|
|
{
|
|
if( g_TwMgr==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return NULL; // not initialized
|
|
}
|
|
|
|
if( g_TwMgr->m_Bars.size()>0 && g_TwMgr->m_PopupBar==NULL )
|
|
return g_TwMgr->m_Bars[g_TwMgr->m_Order[ g_TwMgr->m_Bars.size()-1 ]];
|
|
else if( g_TwMgr->m_Bars.size()>1 && g_TwMgr->m_PopupBar!=NULL )
|
|
return g_TwMgr->m_Bars[g_TwMgr->m_Order[ g_TwMgr->m_Bars.size()-2 ]];
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL TwSetBarState(TwBar *_Bar, TwState _State)
|
|
{
|
|
if( g_TwMgr==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return 0; // not initialized
|
|
}
|
|
if( _Bar==NULL )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrBadParam);
|
|
return 0;
|
|
}
|
|
|
|
switch( _State )
|
|
{
|
|
case TW_STATE_SHOWN:
|
|
g_TwMgr->Unhide(_Bar);
|
|
return 1;
|
|
case TW_STATE_ICONIFIED:
|
|
g_TwMgr->Unhide(_Bar);
|
|
g_TwMgr->Minimize(_Bar);
|
|
return 1;
|
|
case TW_STATE_HIDDEN:
|
|
g_TwMgr->Maximize(_Bar);
|
|
g_TwMgr->Hide(_Bar);
|
|
return 1;
|
|
default:
|
|
g_TwMgr->SetLastError(g_ErrBadParam);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
TwState ANT_CALL TwGetBarState(const TwBar *_Bar)
|
|
{
|
|
if( g_TwMgr==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return TW_STATE_ERROR; // not initialized
|
|
}
|
|
if( _Bar==NULL )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrBadParam);
|
|
return TW_STATE_ERROR;
|
|
}
|
|
|
|
if( !_Bar->m_Visible )
|
|
return TW_STATE_HIDDEN;
|
|
else if( _Bar->IsMinimized() )
|
|
return TW_STATE_ICONIFIED;
|
|
else
|
|
return TW_STATE_SHOWN;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const char * ANT_CALL TwGetBarName(TwBar *_Bar)
|
|
{
|
|
if( g_TwMgr==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return NULL; // not initialized
|
|
}
|
|
if( _Bar==NULL )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrBadParam);
|
|
return NULL;
|
|
}
|
|
|
|
return _Bar->m_Name.c_str();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
static int s_PassProxy = 0;
|
|
void *CTwMgr::CStruct::s_PassProxyAsClientData = &s_PassProxy; // special tag
|
|
|
|
CTwMgr::CStructProxy::CStructProxy()
|
|
{
|
|
memset(this, 0, sizeof(*this));
|
|
}
|
|
|
|
CTwMgr::CStructProxy::~CStructProxy()
|
|
{
|
|
if( m_StructData!=NULL && m_DeleteStructData )
|
|
delete[] (char*)m_StructData;
|
|
if( m_StructExtData!=NULL )
|
|
delete[] (char*)m_StructExtData;
|
|
memset(this, 0, sizeof(*this));
|
|
}
|
|
|
|
CTwMgr::CMemberProxy::CMemberProxy()
|
|
{
|
|
memset(this, 0, sizeof(*this));
|
|
}
|
|
|
|
CTwMgr::CMemberProxy::~CMemberProxy()
|
|
{
|
|
memset(this, 0, sizeof(*this));
|
|
}
|
|
|
|
void ANT_CALL CTwMgr::CMemberProxy::SetCB(const void *_Value, void *_ClientData)
|
|
{
|
|
if( _ClientData && _Value )
|
|
{
|
|
const CMemberProxy *mProxy = static_cast<const CMemberProxy *>(_ClientData);
|
|
if( g_TwMgr && mProxy )
|
|
{
|
|
const CStructProxy *sProxy = mProxy->m_StructProxy;
|
|
if( sProxy && sProxy->m_StructData && sProxy->m_Type>=TW_TYPE_STRUCT_BASE && sProxy->m_Type<TW_TYPE_STRUCT_BASE+(int)g_TwMgr->m_Structs.size() )
|
|
{
|
|
CTwMgr::CStruct& s = g_TwMgr->m_Structs[sProxy->m_Type-TW_TYPE_STRUCT_BASE];
|
|
if( mProxy->m_MemberIndex>=0 && mProxy->m_MemberIndex<(int)s.m_Members.size() )
|
|
{
|
|
CTwMgr::CStructMember& m = s.m_Members[mProxy->m_MemberIndex];
|
|
if( m.m_Size>0 && m.m_Type!=TW_TYPE_BUTTON )
|
|
{
|
|
if( s.m_IsExt )
|
|
{
|
|
memcpy((char *)sProxy->m_StructExtData + m.m_Offset, _Value, m.m_Size);
|
|
if( s.m_CopyVarFromExtCallback && sProxy->m_StructExtData )
|
|
s.m_CopyVarFromExtCallback(sProxy->m_StructData, sProxy->m_StructExtData, mProxy->m_MemberIndex, (s.m_ExtClientData==s.s_PassProxyAsClientData) ? _ClientData : s.m_ExtClientData);
|
|
}
|
|
else
|
|
memcpy((char *)sProxy->m_StructData + m.m_Offset, _Value, m.m_Size);
|
|
if( sProxy->m_StructSetCallback )
|
|
sProxy->m_StructSetCallback(sProxy->m_StructData, sProxy->m_StructClientData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ANT_CALL CTwMgr::CMemberProxy::GetCB(void *_Value, void *_ClientData)
|
|
{
|
|
if( _ClientData && _Value )
|
|
{
|
|
const CMemberProxy *mProxy = static_cast<const CMemberProxy *>(_ClientData);
|
|
if( g_TwMgr && mProxy )
|
|
{
|
|
const CStructProxy *sProxy = mProxy->m_StructProxy;
|
|
if( sProxy && sProxy->m_StructData && sProxy->m_Type>=TW_TYPE_STRUCT_BASE && sProxy->m_Type<TW_TYPE_STRUCT_BASE+(int)g_TwMgr->m_Structs.size() )
|
|
{
|
|
CTwMgr::CStruct& s = g_TwMgr->m_Structs[sProxy->m_Type-TW_TYPE_STRUCT_BASE];
|
|
if( mProxy->m_MemberIndex>=0 && mProxy->m_MemberIndex<(int)s.m_Members.size() )
|
|
{
|
|
CTwMgr::CStructMember& m = s.m_Members[mProxy->m_MemberIndex];
|
|
if( m.m_Size>0 && m.m_Type!=TW_TYPE_BUTTON )
|
|
{
|
|
if( sProxy->m_StructGetCallback )
|
|
sProxy->m_StructGetCallback(sProxy->m_StructData, sProxy->m_StructClientData);
|
|
if( s.m_IsExt )
|
|
{
|
|
if( s.m_CopyVarToExtCallback && sProxy->m_StructExtData )
|
|
s.m_CopyVarToExtCallback(sProxy->m_StructData, sProxy->m_StructExtData, mProxy->m_MemberIndex, (s.m_ExtClientData==s.s_PassProxyAsClientData) ? _ClientData : s.m_ExtClientData);
|
|
memcpy(_Value, (char *)sProxy->m_StructExtData + m.m_Offset, m.m_Size);
|
|
}
|
|
else
|
|
memcpy(_Value, (char *)sProxy->m_StructData + m.m_Offset, m.m_Size);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
static int AddVar(TwBar *_Bar, const char *_Name, ETwType _Type, void *_VarPtr, bool _ReadOnly, TwSetVarCallback _SetCallback, TwGetVarCallback _GetCallback, TwButtonCallback _ButtonCallback, void *_ClientData, const char *_Def)
|
|
{
|
|
CTwFPU fpu; // force fpu precision
|
|
|
|
if( g_TwMgr==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return 0; // not initialized
|
|
}
|
|
if( _Bar==NULL || _Name==NULL || strlen(_Name)==0 || (_VarPtr==NULL && _GetCallback==NULL && _Type!=TW_TYPE_BUTTON) )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrBadParam);
|
|
return 0;
|
|
}
|
|
if( _Bar->Find(_Name)!=NULL )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrExist);
|
|
return 0;
|
|
}
|
|
|
|
if( strstr(_Name, "`")!=NULL )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrNoBackQuote);
|
|
return 0;
|
|
}
|
|
|
|
if( _VarPtr==NULL && _Type!=TW_TYPE_BUTTON && _GetCallback!=NULL && _SetCallback==NULL )
|
|
_ReadOnly = true; // force readonly in this case
|
|
|
|
// Convert color types
|
|
if( _Type==TW_TYPE_COLOR32 )
|
|
_Type = g_TwMgr->m_TypeColor32;
|
|
else if( _Type==TW_TYPE_COLOR3F )
|
|
_Type = g_TwMgr->m_TypeColor3F;
|
|
else if( _Type==TW_TYPE_COLOR4F )
|
|
_Type = g_TwMgr->m_TypeColor4F;
|
|
|
|
if( _Type<TW_TYPE_STRUCT_BASE || (_Type>=TW_TYPE_ENUM_BASE && _Type<TW_TYPE_ENUM_BASE+(int)g_TwMgr->m_Enums.size()) )
|
|
{
|
|
CTwVarAtom *Var = new CTwVarAtom;
|
|
Var->m_Name = _Name;
|
|
Var->m_Ptr = _VarPtr;
|
|
Var->m_Type = _Type;
|
|
if( _VarPtr!=NULL )
|
|
{
|
|
assert( _GetCallback==NULL && _SetCallback==NULL && _ButtonCallback==NULL );
|
|
|
|
Var->m_ReadOnly = _ReadOnly;
|
|
Var->m_GetCallback = NULL;
|
|
Var->m_SetCallback = NULL;
|
|
Var->m_ButtonCallback = NULL;
|
|
Var->m_ClientData = NULL;
|
|
}
|
|
else
|
|
{
|
|
assert( _GetCallback!=NULL || _Type==TW_TYPE_BUTTON );
|
|
|
|
Var->m_GetCallback = _GetCallback;
|
|
Var->m_SetCallback = _SetCallback;
|
|
Var->m_ButtonCallback = _ButtonCallback;
|
|
Var->m_ClientData = _ClientData;
|
|
if( _Type!=TW_TYPE_BUTTON )
|
|
Var->m_ReadOnly = (_SetCallback==NULL || _ReadOnly);
|
|
else
|
|
Var->m_ReadOnly = (_ButtonCallback==NULL);
|
|
}
|
|
Var->m_Color = _Bar->m_ColLabelText;
|
|
Var->SetDefaults();
|
|
|
|
_Bar->m_VarRoot.m_Vars.push_back(Var);
|
|
_Bar->NotUpToDate();
|
|
g_TwMgr->m_HelpBarNotUpToDate = true;
|
|
|
|
if( _Def!=NULL && strlen(_Def)>0 )
|
|
{
|
|
string d = '`' + _Bar->m_Name + "`/`" + _Name + "` " + _Def;
|
|
return TwDefine(d.c_str());
|
|
}
|
|
else
|
|
return 1;
|
|
}
|
|
else if(_Type>=TW_TYPE_STRUCT_BASE && _Type<TW_TYPE_STRUCT_BASE+(TwType)g_TwMgr->m_Structs.size())
|
|
{
|
|
CTwMgr::CStruct& s = g_TwMgr->m_Structs[_Type-TW_TYPE_STRUCT_BASE];
|
|
CTwMgr::CStructProxy *sProxy = NULL;
|
|
void *vPtr;
|
|
if( !s.m_IsExt )
|
|
{
|
|
if( _VarPtr!=NULL )
|
|
vPtr = _VarPtr;
|
|
else
|
|
{
|
|
assert( _GetCallback!=NULL || _SetCallback!=NULL );
|
|
assert( s.m_Size>0 );
|
|
vPtr = new char[s.m_Size];
|
|
memset(vPtr, 0, s.m_Size);
|
|
// create a new StructProxy
|
|
g_TwMgr->m_StructProxies.push_back(CTwMgr::CStructProxy());
|
|
sProxy = &(g_TwMgr->m_StructProxies.back());
|
|
sProxy->m_Type = _Type;
|
|
sProxy->m_StructData = vPtr;
|
|
sProxy->m_DeleteStructData = true;
|
|
sProxy->m_StructSetCallback = _SetCallback;
|
|
sProxy->m_StructGetCallback = _GetCallback;
|
|
sProxy->m_StructClientData = _ClientData;
|
|
}
|
|
}
|
|
else // s.m_IsExt
|
|
{
|
|
assert( s.m_Size>0 && s.m_ClientStructSize>0 );
|
|
vPtr = new char[s.m_Size]; // will be m_StructExtData
|
|
memset(vPtr, 0, s.m_Size);
|
|
// create a new StructProxy
|
|
g_TwMgr->m_StructProxies.push_back(CTwMgr::CStructProxy());
|
|
sProxy = &(g_TwMgr->m_StructProxies.back());
|
|
sProxy->m_Type = _Type;
|
|
sProxy->m_StructExtData = vPtr;
|
|
sProxy->m_StructSetCallback = _SetCallback;
|
|
sProxy->m_StructGetCallback = _GetCallback;
|
|
sProxy->m_StructClientData = _ClientData;
|
|
if( _VarPtr!=NULL )
|
|
{
|
|
sProxy->m_StructData = _VarPtr;
|
|
sProxy->m_DeleteStructData = false;
|
|
}
|
|
else
|
|
{
|
|
sProxy->m_StructData = new char[s.m_ClientStructSize];
|
|
memset(sProxy->m_StructData, 0, s.m_ClientStructSize);
|
|
sProxy->m_DeleteStructData = true;
|
|
}
|
|
_VarPtr = NULL; // force use of TwAddVarCB for members
|
|
|
|
// init m_StructExtdata
|
|
if( s.m_ExtClientData==CTwMgr::CStruct::s_PassProxyAsClientData )
|
|
s.m_StructExtInitCallback(sProxy->m_StructExtData, sProxy);
|
|
else
|
|
s.m_StructExtInitCallback(sProxy->m_StructExtData, s.m_ExtClientData);
|
|
}
|
|
for( int i=0; i<(int)s.m_Members.size(); ++i )
|
|
{
|
|
CTwMgr::CStructMember& m = s.m_Members[i];
|
|
string name = string(_Name) + '.' + m.m_Name;
|
|
const char *access = "";
|
|
if( _ReadOnly )
|
|
access = "readonly ";
|
|
string def = "label=`" + m.m_Name + "` group=`" + _Name + "` " + access; // + m.m_DefString; // member def must be done after group def
|
|
if( _VarPtr!=NULL )
|
|
{
|
|
if( TwAddVarRW(_Bar, name.c_str(), m.m_Type, (char*)vPtr+m.m_Offset, def.c_str())==0 )
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
assert( sProxy!=NULL );
|
|
// create a new MemberProxy
|
|
g_TwMgr->m_MemberProxies.push_back(CTwMgr::CMemberProxy());
|
|
CTwMgr::CMemberProxy& mProxy = g_TwMgr->m_MemberProxies.back();
|
|
mProxy.m_StructProxy = sProxy;
|
|
mProxy.m_MemberIndex = i;
|
|
if( TwAddVarCB(_Bar, name.c_str(), m.m_Type, CTwMgr::CMemberProxy::SetCB, CTwMgr::CMemberProxy::GetCB, &mProxy, def.c_str())==0 )
|
|
return 0;
|
|
mProxy.m_Var = _Bar->Find(name.c_str(), &mProxy.m_VarParent, NULL);
|
|
mProxy.m_Bar = _Bar;
|
|
}
|
|
}
|
|
char structInfo[64];
|
|
sprintf(structInfo, "typeid=%d valptr=%p close ", _Type, vPtr);
|
|
string grpDef = '`' + _Bar->m_Name + "`/`" + _Name + "` " + structInfo;
|
|
if( _Def!=NULL && strlen(_Def)>0 )
|
|
grpDef += _Def;
|
|
if( TwDefine(grpDef.c_str()) )
|
|
{
|
|
for( int i=0; i<(int)s.m_Members.size(); ++i )
|
|
{
|
|
CTwMgr::CStructMember& m = s.m_Members[i];
|
|
if( m.m_DefString.length()>0 )
|
|
{
|
|
string memberDef = '`' + _Bar->m_Name + "`/`" + _Name + '.' + m.m_Name + "` " + m.m_DefString;
|
|
if( !TwDefine(memberDef.c_str()) )
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrNotFound);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL TwAddVarRW(TwBar *_Bar, const char *_Name, ETwType _Type, void *_Var, const char *_Def)
|
|
{
|
|
return AddVar(_Bar, _Name, _Type, _Var, false, NULL, NULL, NULL, NULL, _Def);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL TwAddVarRO(TwBar *_Bar, const char *_Name, ETwType _Type, const void *_Var, const char *_Def)
|
|
{
|
|
return AddVar(_Bar, _Name, _Type, const_cast<void *>(_Var), true, NULL, NULL, NULL, NULL, _Def);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL TwAddVarCB(TwBar *_Bar, const char *_Name, ETwType _Type, TwSetVarCallback _SetCallback, TwGetVarCallback _GetCallback, void *_ClientData, const char *_Def)
|
|
{
|
|
return AddVar(_Bar, _Name, _Type, NULL, false, _SetCallback, _GetCallback, NULL, _ClientData, _Def);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL TwAddButton(TwBar *_Bar, const char *_Name, TwButtonCallback _Callback, void *_ClientData, const char *_Def)
|
|
{
|
|
return AddVar(_Bar, _Name, TW_TYPE_BUTTON, NULL, false, NULL, NULL, _Callback, _ClientData, _Def);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL TwRemoveVar(TwBar *_Bar, const char *_Name)
|
|
{
|
|
if( g_TwMgr==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return 0; // not initialized
|
|
}
|
|
if( _Bar==NULL || _Name==NULL || strlen(_Name)==0 )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrBadParam);
|
|
return 0;
|
|
}
|
|
|
|
if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar ) // delete popup bar first if it exists
|
|
{
|
|
TwDeleteBar(g_TwMgr->m_PopupBar);
|
|
g_TwMgr->m_PopupBar = NULL;
|
|
}
|
|
|
|
CTwVarGroup *Parent = NULL;
|
|
int Index = -1;
|
|
CTwVar *Var = _Bar->Find(_Name, &Parent, &Index);
|
|
if( Var!=NULL && Parent!=NULL && Index>=0 )
|
|
{
|
|
if( Parent->m_StructValuePtr!=NULL )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrDelStruct);
|
|
return 0;
|
|
}
|
|
|
|
delete Var;
|
|
Parent->m_Vars.erase(Parent->m_Vars.begin()+Index);
|
|
if( Parent!=&(_Bar->m_VarRoot) && Parent->m_Vars.size()<=0 )
|
|
TwRemoveVar(_Bar, Parent->m_Name.c_str());
|
|
_Bar->NotUpToDate();
|
|
if( _Bar!=g_TwMgr->m_HelpBar )
|
|
g_TwMgr->m_HelpBarNotUpToDate = true;
|
|
return 1;
|
|
}
|
|
|
|
g_TwMgr->SetLastError(g_ErrNotFound);
|
|
return 0;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL TwRemoveAllVars(TwBar *_Bar)
|
|
{
|
|
if( g_TwMgr==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return 0; // not initialized
|
|
}
|
|
if( _Bar==NULL )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrBadParam);
|
|
return 0;
|
|
}
|
|
|
|
if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar ) // delete popup bar first if it exists
|
|
{
|
|
TwDeleteBar(g_TwMgr->m_PopupBar);
|
|
g_TwMgr->m_PopupBar = NULL;
|
|
}
|
|
|
|
for( vector<CTwVar*>::iterator it=_Bar->m_VarRoot.m_Vars.begin(); it!=_Bar->m_VarRoot.m_Vars.end(); ++it )
|
|
if( *it != NULL )
|
|
{
|
|
delete *it;
|
|
*it = NULL;
|
|
}
|
|
_Bar->m_VarRoot.m_Vars.resize(0);
|
|
_Bar->NotUpToDate();
|
|
g_TwMgr->m_HelpBarNotUpToDate = true;
|
|
return 1;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ParseToken(string& _Token, const char *_Def, int& Line, int& Column, bool _KeepQuotes, bool _EndCR, char _Sep1='\0', char _Sep2='\0')
|
|
{
|
|
const char *Cur = _Def;
|
|
_Token = "";
|
|
// skip spaces
|
|
while( *Cur==' ' || *Cur=='\t' || *Cur=='\r' || *Cur=='\n' )
|
|
{
|
|
if( *Cur=='\n' && _EndCR )
|
|
return (int)(Cur-_Def); // a CR has been found
|
|
++Cur;
|
|
if( *Cur=='\n' )
|
|
{
|
|
++Line;
|
|
Column = 1;
|
|
}
|
|
else if( *Cur=='\t' )
|
|
Column += g_TabLength;
|
|
else if( *Cur!='\r' )
|
|
++Column;
|
|
}
|
|
// read token
|
|
int QuoteLine=0, QuoteColumn=0;
|
|
const char *QuoteCur;
|
|
char Quote = 0;
|
|
bool AddChar;
|
|
while( (Quote==0 && (*Cur!='\0' && *Cur!=' ' && *Cur!='\t' && *Cur!='\r' && *Cur!='\n' && *Cur!=_Sep1 && *Cur!=_Sep2))
|
|
|| (Quote!=0 && (*Cur!='\0' /* && *Cur!='\r' && *Cur!='\n' */)) ) // allow multi-line strings
|
|
{
|
|
AddChar = true;
|
|
if( Quote==0 && (*Cur=='\'' || *Cur=='\"' || *Cur=='`') )
|
|
{
|
|
Quote = *Cur;
|
|
QuoteLine = Line;
|
|
QuoteColumn = Column;
|
|
QuoteCur = Cur;
|
|
AddChar = _KeepQuotes;
|
|
}
|
|
else if ( Quote!=0 && *Cur==Quote )
|
|
{
|
|
Quote = 0;
|
|
AddChar = _KeepQuotes;
|
|
}
|
|
|
|
if( AddChar )
|
|
_Token += *Cur;
|
|
++Cur;
|
|
if( *Cur=='\t' )
|
|
Column += g_TabLength;
|
|
else if( *Cur=='\n' )
|
|
{
|
|
++Line;
|
|
Column = 1;
|
|
}
|
|
else
|
|
++Column;
|
|
}
|
|
|
|
if( Quote!=0 )
|
|
{
|
|
Line = QuoteLine;
|
|
Column = QuoteColumn;
|
|
return -(int)(Cur-_Def); // unclosed quote
|
|
}
|
|
else
|
|
{
|
|
if( *Cur=='\n' )
|
|
{
|
|
++Line;
|
|
Column = 1;
|
|
}
|
|
else if( *Cur=='\t' )
|
|
Column += g_TabLength;
|
|
else if( *Cur!='\r' && *Cur!='\0' )
|
|
++Column;
|
|
return (int)(Cur-_Def);
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int GetBarVarFromString(CTwBar **_Bar, CTwVar **_Var, CTwVarGroup **_VarParent, int *_VarIndex, const char *_Str)
|
|
{
|
|
*_Bar = NULL;
|
|
*_Var = NULL;
|
|
*_VarParent = NULL;
|
|
*_VarIndex = -1;
|
|
vector<string> Names;
|
|
string Token;
|
|
const char *Cur =_Str;
|
|
int l=1, c=1, p=1;
|
|
while( *Cur!='\0' && p>0 && Names.size()<=3 )
|
|
{
|
|
p = ParseToken(Token, Cur, l, c, false, true, '/', '\\');
|
|
if( p>0 && Token.size()>0 )
|
|
{
|
|
Names.push_back(Token);
|
|
Cur += p + ((Cur[p]!='\0')?1:0);
|
|
}
|
|
}
|
|
if( p<=0 || (Names.size()!=1 && Names.size()!=2) )
|
|
return 0; // parse error
|
|
int BarIdx = g_TwMgr->FindBar(Names[0].c_str());
|
|
if( BarIdx<0 )
|
|
{
|
|
if( Names.size()==1 && _stricmp(Names[0].c_str(), "global")==0 )
|
|
{
|
|
*_Bar = TW_GLOBAL_BAR;
|
|
return +3; // 'GLOBAL' found
|
|
}
|
|
else
|
|
return -1; // bar not found
|
|
}
|
|
*_Bar = g_TwMgr->m_Bars[BarIdx];
|
|
if( Names.size()==1 )
|
|
return 1; // bar found, no var name parsed
|
|
*_Var = (*_Bar)->Find(Names[1].c_str(), _VarParent, _VarIndex);
|
|
if( *_Var==NULL )
|
|
return -2; // var not found
|
|
return 2; // bar and var found
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int BarVarHasAttrib(CTwBar *_Bar, CTwVar *_Var, const char *_Attrib, bool *_HasValue)
|
|
{
|
|
assert(_Bar!=NULL && _HasValue!=NULL && _Attrib!=NULL && strlen(_Attrib)>0);
|
|
*_HasValue = false;
|
|
if( _Bar==TW_GLOBAL_BAR )
|
|
{
|
|
assert( _Var==NULL );
|
|
return g_TwMgr->HasAttrib(_Attrib, _HasValue);
|
|
}
|
|
else if( _Var==NULL )
|
|
return _Bar->HasAttrib(_Attrib, _HasValue);
|
|
else
|
|
return _Var->HasAttrib(_Attrib, _HasValue);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int BarVarSetAttrib(CTwBar *_Bar, CTwVar *_Var, CTwVarGroup *_VarParent, int _VarIndex, int _AttribID, const char *_Value)
|
|
{
|
|
assert(_Bar!=NULL && _AttribID>0);
|
|
|
|
/* don't delete popupbar here: if any attrib is changed every frame by the app, popup will not work anymore.
|
|
if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_PopupBar->m_BarLinkedToPopupList==_Bar ) // delete popup bar first if it exists
|
|
{
|
|
TwDeleteBar(g_TwMgr->m_PopupBar);
|
|
g_TwMgr->m_PopupBar = NULL;
|
|
}
|
|
*/
|
|
|
|
if( _Bar==TW_GLOBAL_BAR )
|
|
{
|
|
assert( _Var==NULL );
|
|
return g_TwMgr->SetAttrib(_AttribID, _Value);
|
|
}
|
|
else if( _Var==NULL )
|
|
return _Bar->SetAttrib(_AttribID, _Value);
|
|
else
|
|
return _Var->SetAttrib(_AttribID, _Value, _Bar, _VarParent, _VarIndex);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL TwDefine(const char *_Def)
|
|
{
|
|
CTwFPU fpu; // force fpu precision
|
|
|
|
if( g_TwMgr==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return 0; // not initialized
|
|
}
|
|
if( _Def==NULL )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrBadParam);
|
|
return 0;
|
|
}
|
|
|
|
int Line = 1;
|
|
int Column = 1;
|
|
const char *Cur = _Def;
|
|
enum EState { PARSE_NAME, PARSE_ATTRIB };
|
|
EState State = PARSE_NAME;
|
|
string Token;
|
|
string Value;
|
|
CTwBar *Bar = NULL;
|
|
CTwVar *Var = NULL;
|
|
CTwVarGroup *VarParent = NULL;
|
|
int VarIndex = -1;
|
|
int p;
|
|
while( *Cur!='\0' )
|
|
{
|
|
const char *PrevCur = Cur;
|
|
p = ParseToken(Token, Cur, Line, Column, (State==PARSE_NAME), (State==PARSE_ATTRIB), (State==PARSE_ATTRIB)?'=':'\0');
|
|
if( p<=0 || Token.size()<=0 )
|
|
{
|
|
if( p>0 && Cur[p]=='\0' )
|
|
{
|
|
Cur += p;
|
|
continue;
|
|
}
|
|
sprintf(g_ErrParse, "Parsing error in def string, line %d column %d [%-16s...]", Line, Column, (p<0)?(Cur-p):PrevCur);
|
|
g_TwMgr->SetLastError(g_ErrParse);
|
|
return 0;
|
|
}
|
|
char CurSep = Cur[p];
|
|
Cur += p + ((CurSep!='\0')?1:0);
|
|
|
|
if( State==PARSE_NAME )
|
|
{
|
|
int Err = GetBarVarFromString(&Bar, &Var, &VarParent, &VarIndex, Token.c_str());
|
|
if( Err<=0 )
|
|
{
|
|
if( Err==-1 )
|
|
sprintf(g_ErrParse, "Parsing error in def string: Bar not found line %d column %d [%-16s...]", Line, Column, Token.c_str());
|
|
else if( Err==-2 )
|
|
sprintf(g_ErrParse, "Parsing error in def string: Variable not found line %d column %d [%-16s...]", Line, Column, Token.c_str());
|
|
else
|
|
sprintf(g_ErrParse, "Parsing error in def string, line %d column %d [%-16s...]", Line, Column, Token.c_str());
|
|
g_TwMgr->SetLastError(g_ErrParse);
|
|
return 0;
|
|
}
|
|
State = PARSE_ATTRIB;
|
|
}
|
|
else // State==PARSE_ATTRIB
|
|
{
|
|
assert(State==PARSE_ATTRIB);
|
|
assert(Bar!=NULL);
|
|
|
|
bool HasValue = false;
|
|
Value = "";
|
|
int AttribID = BarVarHasAttrib(Bar, Var, Token.c_str(), &HasValue);
|
|
if( AttribID<=0 )
|
|
{
|
|
sprintf(g_ErrParse, "Parsing error in def string: Unknown attribute line %d column %d [%-16s...]", Line, Column, Token.c_str());
|
|
g_TwMgr->SetLastError(g_ErrParse);
|
|
return 0;
|
|
}
|
|
if( HasValue )
|
|
{
|
|
if( CurSep!='=' )
|
|
{
|
|
string EqualStr;
|
|
p = ParseToken(EqualStr, Cur, Line, Column, true, true, '=');
|
|
CurSep = Cur[p];
|
|
if( p<0 || EqualStr.size()>0 || CurSep!='=' )
|
|
{
|
|
sprintf(g_ErrParse, "Parsing error in def string: '=' not found while reading attribute value line %d column %d [%-16s...]", Line, Column, Token.c_str());
|
|
g_TwMgr->SetLastError(g_ErrParse);
|
|
return 0;
|
|
}
|
|
Cur += p + 1;
|
|
}
|
|
p = ParseToken(Value, Cur, Line, Column, false, true);
|
|
if( p<=0 )
|
|
{
|
|
sprintf(g_ErrParse, "Parsing error in def string: can't read attribute value line %d column %d [%-16s...]", Line, Column, Token.c_str());
|
|
g_TwMgr->SetLastError(g_ErrParse);
|
|
return 0;
|
|
}
|
|
CurSep = Cur[p];
|
|
Cur += p + ((CurSep!='\0')?1:0);
|
|
}
|
|
if( BarVarSetAttrib(Bar, Var, VarParent, VarIndex, AttribID, HasValue?Value.c_str():NULL)==0 )
|
|
{
|
|
if( g_TwMgr->CheckLastError()==NULL || strlen(g_TwMgr->CheckLastError())<=0 )
|
|
sprintf(g_ErrParse, "Parsing error in def string: wrong attribute value line %d column %d [%-16s...]", Line, Column, Token.c_str());
|
|
else
|
|
sprintf(g_ErrParse, "%s line %d column %d [%-16s...]", g_TwMgr->CheckLastError(), Line, Column, Token.c_str());
|
|
g_TwMgr->SetLastError(g_ErrParse);
|
|
return 0;
|
|
}
|
|
// sweep spaces to detect next attrib
|
|
while( *Cur==' ' || *Cur=='\t' || *Cur=='\r' )
|
|
{
|
|
++Cur;
|
|
if( *Cur=='\t' )
|
|
Column += g_TabLength;
|
|
else if( *Cur!='\r' )
|
|
++Column;
|
|
}
|
|
if( *Cur=='\n' ) // new line detected
|
|
{
|
|
++Line;
|
|
Column = 1;
|
|
State = PARSE_NAME;
|
|
}
|
|
}
|
|
}
|
|
|
|
g_TwMgr->m_HelpBarNotUpToDate = true;
|
|
return 1;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
TwType ANT_CALL TwDefineEnum(const char *_Name, const TwEnumVal *_EnumValues, unsigned int _NbValues)
|
|
{
|
|
CTwFPU fpu; // force fpu precision
|
|
|
|
if( g_TwMgr==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return TW_TYPE_UNDEF; // not initialized
|
|
}
|
|
if( _EnumValues==NULL && _NbValues!=0 )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrBadParam);
|
|
return TW_TYPE_UNDEF;
|
|
}
|
|
|
|
if( g_TwMgr->m_PopupBar!=NULL ) // delete popup bar first if it exists
|
|
{
|
|
TwDeleteBar(g_TwMgr->m_PopupBar);
|
|
g_TwMgr->m_PopupBar = NULL;
|
|
}
|
|
|
|
size_t enumIndex = g_TwMgr->m_Enums.size();
|
|
if( _Name!=NULL && strlen(_Name)>0 )
|
|
for( size_t j=0; j<g_TwMgr->m_Enums.size(); ++j )
|
|
if( strcmp(_Name, g_TwMgr->m_Enums[j].m_Name.c_str())==0 )
|
|
{
|
|
enumIndex = j;
|
|
break;
|
|
}
|
|
if( enumIndex==g_TwMgr->m_Enums.size() )
|
|
g_TwMgr->m_Enums.push_back(CTwMgr::CEnum());
|
|
assert( enumIndex>=0 && enumIndex<g_TwMgr->m_Enums.size() );
|
|
CTwMgr::CEnum& e = g_TwMgr->m_Enums[enumIndex];
|
|
if( _Name!=NULL && strlen(_Name)>0 )
|
|
e.m_Name = _Name;
|
|
else
|
|
e.m_Name = "";
|
|
e.m_Entries.clear();
|
|
for(unsigned int i=0; i<_NbValues; ++i)
|
|
{
|
|
CTwMgr::CEnum::CEntries::value_type Entry(_EnumValues[i].Value, (_EnumValues[i].Label!=NULL)?_EnumValues[i].Label:"");
|
|
pair<CTwMgr::CEnum::CEntries::iterator, bool> Result = e.m_Entries.insert(Entry);
|
|
if( !Result.second )
|
|
(Result.first)->second = Entry.second;
|
|
}
|
|
|
|
return TwType( TW_TYPE_ENUM_BASE + enumIndex );
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void ANT_CALL CTwMgr::CStruct::DefaultSummary(char *_SummaryString, size_t _SummaryMaxLength, const void *_Value, void *_ClientData)
|
|
{
|
|
const CTwVarGroup *varGroup = static_cast<const CTwVarGroup *>(_Value); // special case
|
|
if( _SummaryString && _SummaryMaxLength>0 )
|
|
_SummaryString[0] = '\0';
|
|
size_t structIndex = (size_t)(_ClientData);
|
|
if( g_TwMgr && _SummaryString && _SummaryMaxLength>2
|
|
&& varGroup && static_cast<const CTwVar *>(varGroup)->IsGroup()
|
|
&& structIndex>=0 && structIndex<=g_TwMgr->m_Structs.size() )
|
|
{
|
|
// return g_TwMgr->m_Structs[structIndex].m_Name.c_str();
|
|
CTwMgr::CStruct& s = g_TwMgr->m_Structs[structIndex];
|
|
_SummaryString[0] = '{';
|
|
_SummaryString[1] = '\0';
|
|
bool separator = false;
|
|
for( size_t i=0; i<s.m_Members.size(); ++i )
|
|
{
|
|
string varName = varGroup->m_Name + '.' + s.m_Members[i].m_Name;
|
|
const CTwVar *var = varGroup->Find(varName.c_str(), NULL, NULL);
|
|
if( var )
|
|
{
|
|
if( var->IsGroup() )
|
|
{
|
|
const CTwVarGroup *grp = static_cast<const CTwVarGroup *>(var);
|
|
if( grp->m_SummaryCallback!=NULL )
|
|
{
|
|
size_t l = strlen(_SummaryString);
|
|
if( separator )
|
|
{
|
|
_SummaryString[l++] = ',';
|
|
_SummaryString[l++] = '\0';
|
|
}
|
|
if( grp->m_SummaryCallback==CTwMgr::CStruct::DefaultSummary )
|
|
grp->m_SummaryCallback(_SummaryString+l, _SummaryMaxLength-l, grp, grp->m_SummaryClientData);
|
|
else
|
|
grp->m_SummaryCallback(_SummaryString+l, _SummaryMaxLength-l, grp->m_StructValuePtr, grp->m_SummaryClientData);
|
|
separator = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
size_t l = strlen(_SummaryString);
|
|
if( separator )
|
|
{
|
|
_SummaryString[l++] = ',';
|
|
_SummaryString[l++] = '\0';
|
|
}
|
|
string valString;
|
|
const CTwVarAtom *atom = static_cast<const CTwVarAtom *>(var);
|
|
atom->ValueToString(&valString);
|
|
strncat(_SummaryString, valString.c_str(), _SummaryMaxLength-l);
|
|
separator = true;
|
|
}
|
|
if( strlen(_SummaryString)>_SummaryMaxLength-2 )
|
|
break;
|
|
}
|
|
}
|
|
size_t l = strlen(_SummaryString);
|
|
if( l>_SummaryMaxLength-2 )
|
|
{
|
|
_SummaryString[_SummaryMaxLength-2] = '.';
|
|
_SummaryString[_SummaryMaxLength-1] = '.';
|
|
_SummaryString[_SummaryMaxLength+0] = '\0';
|
|
}
|
|
else
|
|
{
|
|
_SummaryString[l+0] = '}';
|
|
_SummaryString[l+1] = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
TwType ANT_CALL TwDefineStruct(const char *_StructName, const TwStructMember *_StructMembers, unsigned int _NbMembers, size_t _StructSize, TwSummaryCallback _SummaryCallback, void *_SummaryClientData)
|
|
{
|
|
CTwFPU fpu; // force fpu precision
|
|
|
|
if( g_TwMgr==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return TW_TYPE_UNDEF; // not initialized
|
|
}
|
|
if( _StructMembers==NULL || _NbMembers==0 || _StructSize==0 )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrBadParam);
|
|
return TW_TYPE_UNDEF;
|
|
}
|
|
|
|
if( _StructName!=NULL && strlen(_StructName)>0 )
|
|
for( size_t j=0; j<g_TwMgr->m_Structs.size(); ++j )
|
|
if( strcmp(_StructName, g_TwMgr->m_Structs[j].m_Name.c_str())==0 )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrExist);
|
|
return TW_TYPE_UNDEF;
|
|
}
|
|
|
|
size_t structIndex = g_TwMgr->m_Structs.size();
|
|
CTwMgr::CStruct s;
|
|
s.m_Size = _StructSize;
|
|
if( _StructName!=NULL && strlen(_StructName)>0 )
|
|
s.m_Name = _StructName;
|
|
else
|
|
s.m_Name = "";
|
|
s.m_Members.resize(_NbMembers);
|
|
if( _SummaryCallback!=NULL )
|
|
{
|
|
s.m_SummaryCallback = _SummaryCallback;
|
|
s.m_SummaryClientData = _SummaryClientData;
|
|
}
|
|
else
|
|
{
|
|
s.m_SummaryCallback = CTwMgr::CStruct::DefaultSummary;
|
|
s.m_SummaryClientData = (void *)(structIndex);
|
|
}
|
|
for( unsigned int i=0; i<_NbMembers; ++i )
|
|
{
|
|
CTwMgr::CStructMember& m = s.m_Members[i];
|
|
if( _StructMembers[i].Name!=NULL )
|
|
m.m_Name = _StructMembers[i].Name;
|
|
else
|
|
{
|
|
char name[16];
|
|
sprintf(name, "%u", i);
|
|
m.m_Name = name;
|
|
}
|
|
m.m_Type = _StructMembers[i].Type;
|
|
m.m_Size = 0; // to avoid endless recursivity in GetDataSize
|
|
m.m_Size = CTwVar::GetDataSize(m.m_Type);
|
|
if( _StructMembers[i].Offset<_StructSize )
|
|
m.m_Offset = _StructMembers[i].Offset;
|
|
else
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrOffset);
|
|
return TW_TYPE_UNDEF;
|
|
}
|
|
if( _StructMembers[i].DefString!=NULL && strlen(_StructMembers[i].DefString)>0 )
|
|
m.m_DefString = _StructMembers[i].DefString;
|
|
else
|
|
m.m_DefString = "";
|
|
}
|
|
|
|
g_TwMgr->m_Structs.push_back(s);
|
|
assert( g_TwMgr->m_Structs.size()==structIndex+1 );
|
|
return TwType( TW_TYPE_STRUCT_BASE + structIndex );
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
TwType ANT_CALL TwDefineStructExt(const char *_StructName, const TwStructMember *_StructExtMembers, unsigned int _NbExtMembers, size_t _StructSize, size_t _StructExtSize, TwStructExtInitCallback _StructExtInitCallback, TwCopyVarFromExtCallback _CopyVarFromExtCallback, TwCopyVarToExtCallback _CopyVarToExtCallback, TwSummaryCallback _SummaryCallback, void *_ClientData)
|
|
{
|
|
CTwFPU fpu; // force fpu precision
|
|
|
|
if( g_TwMgr==NULL )
|
|
{
|
|
TwGlobalError(g_ErrNotInit);
|
|
return TW_TYPE_UNDEF; // not initialized
|
|
}
|
|
if( _StructSize==0 || _StructExtInitCallback==NULL || _CopyVarFromExtCallback==NULL || _CopyVarToExtCallback==NULL )
|
|
{
|
|
g_TwMgr->SetLastError(g_ErrBadParam);
|
|
return TW_TYPE_UNDEF;
|
|
}
|
|
TwType type = TwDefineStruct(_StructName, _StructExtMembers, _NbExtMembers, _StructExtSize, _SummaryCallback, _ClientData);
|
|
if( type>=TW_TYPE_STRUCT_BASE && type<TW_TYPE_STRUCT_BASE+(int)g_TwMgr->m_Structs.size() )
|
|
{
|
|
CTwMgr::CStruct& s = g_TwMgr->m_Structs[type-TW_TYPE_STRUCT_BASE];
|
|
s.m_IsExt = true;
|
|
s.m_ClientStructSize = _StructSize;
|
|
s.m_StructExtInitCallback = _StructExtInitCallback;
|
|
s.m_CopyVarFromExtCallback = _CopyVarFromExtCallback;
|
|
s.m_CopyVarToExtCallback = _CopyVarToExtCallback;
|
|
s.m_ExtClientData = _ClientData;
|
|
}
|
|
return type;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
bool TwGetKeyCode(int *_Code, int *_Modif, const char *_String)
|
|
{
|
|
assert(_Code!=NULL && _Modif!=NULL);
|
|
bool Ok = true;
|
|
*_Modif = TW_KMOD_NONE;
|
|
*_Code = 0;
|
|
size_t Start = strlen(_String)-1;
|
|
if( Start<0 )
|
|
return false;
|
|
while( Start>0 && _String[Start-1]!='+' )
|
|
--Start;
|
|
while( _String[Start]==' ' || _String[Start]=='\t' )
|
|
++Start;
|
|
char *CodeStr = _strdup(_String+Start);
|
|
for( size_t i=strlen(CodeStr)-1; i>=0; ++i )
|
|
if( CodeStr[i]==' ' || CodeStr[i]=='\t' )
|
|
CodeStr[i] = '\0';
|
|
else
|
|
break;
|
|
|
|
/*
|
|
if( strstr(_String, "SHIFT")!=NULL || strstr(_String, "shift")!=NULL )
|
|
*_Modif |= TW_KMOD_SHIFT;
|
|
if( strstr(_String, "CTRL")!=NULL || strstr(_String, "ctrl")!=NULL )
|
|
*_Modif |= TW_KMOD_CTRL;
|
|
if( strstr(_String, "META")!=NULL || strstr(_String, "meta")!=NULL )
|
|
*_Modif |= TW_KMOD_META;
|
|
|
|
if( strstr(_String, "ALTGR")!=NULL || strstr(_String, "altgr")!=NULL )
|
|
((void)(0)); // *_Modif |= TW_KMOD_ALTGR;
|
|
else // ALT and ALTGR are exclusive
|
|
if( strstr(_String, "ALT")!=NULL || strstr(_String, "alt")!=NULL )
|
|
*_Modif |= TW_KMOD_ALT;
|
|
*/
|
|
char *up = _strdup(_String);
|
|
// _strupr(up);
|
|
for( char *upch=up; *upch!='\0'; ++upch )
|
|
*upch = (char)toupper(*upch);
|
|
if( strstr(up, "SHIFT")!=NULL )
|
|
*_Modif |= TW_KMOD_SHIFT;
|
|
if( strstr(up, "CTRL")!=NULL )
|
|
*_Modif |= TW_KMOD_CTRL;
|
|
if( strstr(up, "META")!=NULL )
|
|
*_Modif |= TW_KMOD_META;
|
|
|
|
if( strstr(up, "ALTGR")!=NULL )
|
|
((void)(0)); // *_Modif |= TW_KMOD_ALTGR;
|
|
else // ALT and ALTGR are exclusive
|
|
if( strstr(up, "ALT")!=NULL )
|
|
*_Modif |= TW_KMOD_ALT;
|
|
free(up);
|
|
|
|
if( strlen(CodeStr)==1 )
|
|
*_Code = (unsigned char)(CodeStr[0]);
|
|
else if( _stricmp(CodeStr, "backspace")==0 || _stricmp(CodeStr, "bs")==0 )
|
|
*_Code = TW_KEY_BACKSPACE;
|
|
else if( _stricmp(CodeStr, "tab")==0 )
|
|
*_Code = TW_KEY_TAB;
|
|
else if( _stricmp(CodeStr, "clear")==0 || _stricmp(CodeStr, "clr")==0 )
|
|
*_Code = TW_KEY_CLEAR;
|
|
else if( _stricmp(CodeStr, "return")==0 || _stricmp(CodeStr, "ret")==0 )
|
|
*_Code = TW_KEY_RETURN;
|
|
else if( _stricmp(CodeStr, "pause")==0 )
|
|
*_Code = TW_KEY_PAUSE;
|
|
else if( _stricmp(CodeStr, "escape")==0 || _stricmp(CodeStr, "esc")==0 )
|
|
*_Code = TW_KEY_ESCAPE;
|
|
else if( _stricmp(CodeStr, "space")==0 )
|
|
*_Code = TW_KEY_SPACE;
|
|
else if( _stricmp(CodeStr, "delete")==0 || _stricmp(CodeStr, "del")==0 )
|
|
*_Code = TW_KEY_DELETE;
|
|
/*
|
|
else if( strlen(CodeStr)==4 && CodeStr[3]>='0' && CodeStr[3]<='9' && (strstr(CodeStr, "pad")==CodeStr || strstr(CodeStr, "PAD")==CodeStr) )
|
|
*_Code = TW_KEY_PAD_0 + CodeStr[3]-'0';
|
|
else if( _stricmp(CodeStr, "pad.")==0 )
|
|
*_Code = TW_KEY_PAD_PERIOD;
|
|
else if( _stricmp(CodeStr, "pad/")==0 )
|
|
*_Code = TW_KEY_PAD_DIVIDE;
|
|
else if( _stricmp(CodeStr, "pad*")==0 )
|
|
*_Code = TW_KEY_PAD_MULTIPLY;
|
|
else if( _stricmp(CodeStr, "pad+")==0 )
|
|
*_Code = TW_KEY_PAD_PLUS;
|
|
else if( _stricmp(CodeStr, "pad-")==0 )
|
|
*_Code = TW_KEY_PAD_MINUS;
|
|
else if( _stricmp(CodeStr, "padenter")==0 )
|
|
*_Code = TW_KEY_PAD_ENTER;
|
|
else if( _stricmp(CodeStr, "pad=")==0 )
|
|
*_Code = TW_KEY_PAD_EQUALS;
|
|
*/
|
|
else if( _stricmp(CodeStr, "up")==0 )
|
|
*_Code = TW_KEY_UP;
|
|
else if( _stricmp(CodeStr, "down")==0 )
|
|
*_Code = TW_KEY_DOWN;
|
|
else if( _stricmp(CodeStr, "right")==0 )
|
|
*_Code = TW_KEY_RIGHT;
|
|
else if( _stricmp(CodeStr, "left")==0 )
|
|
*_Code = TW_KEY_LEFT;
|
|
else if( _stricmp(CodeStr, "insert")==0 || _stricmp(CodeStr, "ins")==0 )
|
|
*_Code = TW_KEY_INSERT;
|
|
else if( _stricmp(CodeStr, "home")==0 )
|
|
*_Code = TW_KEY_HOME;
|
|
else if( _stricmp(CodeStr, "end")==0 )
|
|
*_Code = TW_KEY_END;
|
|
else if( _stricmp(CodeStr, "pgup")==0 )
|
|
*_Code = TW_KEY_PAGE_UP;
|
|
else if( _stricmp(CodeStr, "pgdown")==0 )
|
|
*_Code = TW_KEY_PAGE_DOWN;
|
|
else if( (strlen(CodeStr)==2 || strlen(CodeStr)==3) && (CodeStr[0]=='f' || CodeStr[0]=='F') )
|
|
{
|
|
int n = 0;
|
|
if( sscanf(CodeStr+1, "%d", &n)==1 && n>0 && n<16 )
|
|
*_Code = TW_KEY_F1 + n-1;
|
|
else
|
|
Ok = false;
|
|
}
|
|
|
|
free(CodeStr);
|
|
return Ok;
|
|
}
|
|
|
|
bool TwGetKeyString(std::string *_String, int _Code, int _Modif)
|
|
{
|
|
assert(_String!=NULL);
|
|
bool Ok = true;
|
|
if( _Modif & TW_KMOD_SHIFT )
|
|
*_String += "SHIFT+";
|
|
if( _Modif & TW_KMOD_CTRL )
|
|
*_String += "CTRL+";
|
|
if ( _Modif & TW_KMOD_ALT )
|
|
*_String += "ALT+";
|
|
if ( _Modif & TW_KMOD_META )
|
|
*_String += "META+";
|
|
// if ( _Modif & TW_KMOD_ALTGR )
|
|
// *_String += "ALTGR+";
|
|
switch( _Code )
|
|
{
|
|
case TW_KEY_BACKSPACE:
|
|
*_String += "BackSpace";
|
|
break;
|
|
case TW_KEY_TAB:
|
|
*_String += "Tab";
|
|
break;
|
|
case TW_KEY_CLEAR:
|
|
*_String += "Clear";
|
|
break;
|
|
case TW_KEY_RETURN:
|
|
*_String += "Return";
|
|
break;
|
|
case TW_KEY_PAUSE:
|
|
*_String += "Pause";
|
|
break;
|
|
case TW_KEY_ESCAPE:
|
|
*_String += "Esc";
|
|
break;
|
|
case TW_KEY_SPACE:
|
|
*_String += "Space";
|
|
break;
|
|
case TW_KEY_DELETE:
|
|
*_String += "Delete";
|
|
break;
|
|
/*
|
|
case TW_KEY_PAD_0:
|
|
*_String += "PAD0";
|
|
break;
|
|
case TW_KEY_PAD_1:
|
|
*_String += "PAD1";
|
|
break;
|
|
case TW_KEY_PAD_2:
|
|
*_String += "PAD2";
|
|
break;
|
|
case TW_KEY_PAD_3:
|
|
*_String += "PAD3";
|
|
break;
|
|
case TW_KEY_PAD_4:
|
|
*_String += "PAD4";
|
|
break;
|
|
case TW_KEY_PAD_5:
|
|
*_String += "PAD5";
|
|
break;
|
|
case TW_KEY_PAD_6:
|
|
*_String += "PAD6";
|
|
break;
|
|
case TW_KEY_PAD_7:
|
|
*_String += "PAD7";
|
|
break;
|
|
case TW_KEY_PAD_8:
|
|
*_String += "PAD8";
|
|
break;
|
|
case TW_KEY_PAD_9:
|
|
*_String += "PAD9";
|
|
break;
|
|
case TW_KEY_PAD_PERIOD:
|
|
*_String += "PAD.";
|
|
break;
|
|
case TW_KEY_PAD_DIVIDE:
|
|
*_String += "PAD/";
|
|
break;
|
|
case TW_KEY_PAD_MULTIPLY:
|
|
*_String += "PAD*";
|
|
break;
|
|
case TW_KEY_PAD_MINUS:
|
|
*_String += "PAD-";
|
|
break;
|
|
case TW_KEY_PAD_PLUS:
|
|
*_String += "PAD+";
|
|
break;
|
|
case TW_KEY_PAD_ENTER:
|
|
*_String += "PADEnter";
|
|
break;
|
|
case TW_KEY_PAD_EQUALS:
|
|
*_String += "PAD=";
|
|
break;
|
|
*/
|
|
case TW_KEY_UP:
|
|
*_String += "Up";
|
|
break;
|
|
case TW_KEY_DOWN:
|
|
*_String += "Down";
|
|
break;
|
|
case TW_KEY_RIGHT:
|
|
*_String += "Right";
|
|
break;
|
|
case TW_KEY_LEFT:
|
|
*_String += "Left";
|
|
break;
|
|
case TW_KEY_INSERT:
|
|
*_String += "Insert";
|
|
break;
|
|
case TW_KEY_HOME:
|
|
*_String += "Home";
|
|
break;
|
|
case TW_KEY_END:
|
|
*_String += "End";
|
|
break;
|
|
case TW_KEY_PAGE_UP:
|
|
*_String += "PgUp";
|
|
break;
|
|
case TW_KEY_PAGE_DOWN:
|
|
*_String += "PgDown";
|
|
break;
|
|
case TW_KEY_F1:
|
|
*_String += "F1";
|
|
break;
|
|
case TW_KEY_F2:
|
|
*_String += "F2";
|
|
break;
|
|
case TW_KEY_F3:
|
|
*_String += "F3";
|
|
break;
|
|
case TW_KEY_F4:
|
|
*_String += "F4";
|
|
break;
|
|
case TW_KEY_F5:
|
|
*_String += "F5";
|
|
break;
|
|
case TW_KEY_F6:
|
|
*_String += "F6";
|
|
break;
|
|
case TW_KEY_F7:
|
|
*_String += "F7";
|
|
break;
|
|
case TW_KEY_F8:
|
|
*_String += "F8";
|
|
break;
|
|
case TW_KEY_F9:
|
|
*_String += "F9";
|
|
break;
|
|
case TW_KEY_F10:
|
|
*_String += "F10";
|
|
break;
|
|
case TW_KEY_F11:
|
|
*_String += "F11";
|
|
break;
|
|
case TW_KEY_F12:
|
|
*_String += "F12";
|
|
break;
|
|
case TW_KEY_F13:
|
|
*_String += "F13";
|
|
break;
|
|
case TW_KEY_F14:
|
|
*_String += "F14";
|
|
break;
|
|
case TW_KEY_F15:
|
|
*_String += "F15";
|
|
break;
|
|
default:
|
|
if( _Code>0 && _Code<256 )
|
|
*_String += char(_Code);
|
|
else
|
|
{
|
|
*_String += "Unknown";
|
|
Ok = false;
|
|
}
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const int TW_MOUSE_NOMOTION = -1;
|
|
ETwMouseAction TW_MOUSE_MOTION = (ETwMouseAction)(-2);
|
|
ETwMouseAction TW_MOUSE_WHEEL = (ETwMouseAction)(-3);
|
|
ETwMouseButtonID TW_MOUSE_NA = (ETwMouseButtonID)(-1);
|
|
|
|
static int TwMouseEvent(ETwMouseAction _EventType, TwMouseButtonID _Button, int _MouseX, int _MouseY, int _WheelPos)
|
|
{
|
|
CTwFPU fpu; // force fpu precision
|
|
|
|
if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
|
|
{
|
|
// TwGlobalError(g_ErrNotInit); -> not an error here
|
|
return 0; // not initialized
|
|
}
|
|
if( g_TwMgr->m_WndHeight<=0 || g_TwMgr->m_WndWidth<=0 )
|
|
{
|
|
//g_TwMgr->SetLastError(g_ErrBadWndSize); // not an error, windows not yet ready.
|
|
return 0;
|
|
}
|
|
|
|
if( _MouseX==TW_MOUSE_NOMOTION )
|
|
_MouseX = g_TwMgr->m_LastMouseX;
|
|
else
|
|
g_TwMgr->m_LastMouseX = _MouseX;
|
|
if( _MouseY==TW_MOUSE_NOMOTION )
|
|
_MouseY = g_TwMgr->m_LastMouseY;
|
|
else
|
|
g_TwMgr->m_LastMouseY = _MouseY;
|
|
|
|
// for autorepeat
|
|
if( (!g_TwMgr->m_IsRepeatingMousePressed || !g_TwMgr->m_CanRepeatMousePressed) && _EventType==TW_MOUSE_PRESSED )
|
|
{
|
|
g_TwMgr->m_LastMousePressedTime = g_TwMgr->m_Timer.GetTime();
|
|
g_TwMgr->m_LastMousePressedButtonID = _Button;
|
|
g_TwMgr->m_LastMousePressedPosition[0] = _MouseX;
|
|
g_TwMgr->m_LastMousePressedPosition[1] = _MouseY;
|
|
g_TwMgr->m_CanRepeatMousePressed = true;
|
|
g_TwMgr->m_IsRepeatingMousePressed = false;
|
|
}
|
|
else if( _EventType==TW_MOUSE_RELEASED || _EventType==TW_MOUSE_WHEEL )
|
|
{
|
|
g_TwMgr->m_CanRepeatMousePressed = false;
|
|
g_TwMgr->m_IsRepeatingMousePressed = false;
|
|
}
|
|
|
|
bool Handled = false;
|
|
bool wasPopup = (g_TwMgr->m_PopupBar!=NULL);
|
|
CTwBar *Bar = NULL;
|
|
int i;
|
|
for( i=((int)g_TwMgr->m_Bars.size())-1; i>=0; --i )
|
|
{
|
|
Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]];
|
|
if( Bar!=NULL && Bar->m_Visible )
|
|
{
|
|
if( _EventType==TW_MOUSE_MOTION )
|
|
Handled = Bar->MouseMotion(_MouseX, _MouseY);
|
|
else if( _EventType==TW_MOUSE_PRESSED || _EventType==TW_MOUSE_RELEASED )
|
|
Handled = Bar->MouseButton(_Button, (_EventType==TW_MOUSE_PRESSED), _MouseX, _MouseY);
|
|
else if( _EventType==TW_MOUSE_WHEEL )
|
|
{
|
|
if( abs(_WheelPos-g_TwMgr->m_LastMouseWheelPos)<4 ) // avoid crazy wheel positions
|
|
Handled = Bar->MouseWheel(_WheelPos, g_TwMgr->m_LastMouseWheelPos, _MouseX, _MouseY);
|
|
}
|
|
if( Handled )
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
if( i>=0 && Bar!=NULL && Handled && (_EventType==TW_MOUSE_PRESSED || Bar->IsMinimized()) && i!=((int)g_TwMgr->m_Bars.size())-1 )
|
|
{
|
|
int iOrder = g_TwMgr->m_Order[i];
|
|
for( int j=i; j<(int)g_TwMgr->m_Bars.size()-1; ++j )
|
|
g_TwMgr->m_Order[j] = g_TwMgr->m_Order[j+1];
|
|
g_TwMgr->m_Order[(int)g_TwMgr->m_Bars.size()-1] = iOrder;
|
|
}
|
|
*/
|
|
if( _EventType==TW_MOUSE_PRESSED || (Bar!=NULL && Bar->IsMinimized() && Handled) )
|
|
{
|
|
if( wasPopup && Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_PopupBar!=NULL ) // delete popup
|
|
{
|
|
TwDeleteBar(g_TwMgr->m_PopupBar);
|
|
g_TwMgr->m_PopupBar = NULL;
|
|
}
|
|
|
|
if( i>=0 && Bar!=NULL && Handled && !wasPopup )
|
|
TwSetTopBar(Bar);
|
|
}
|
|
|
|
if( _EventType==TW_MOUSE_WHEEL )
|
|
g_TwMgr->m_LastMouseWheelPos = _WheelPos;
|
|
|
|
return Handled ? 1 : 0;
|
|
}
|
|
|
|
int ANT_CALL TwMouseButton(ETwMouseAction _EventType, TwMouseButtonID _Button)
|
|
{
|
|
return TwMouseEvent(_EventType, _Button, TW_MOUSE_NOMOTION, TW_MOUSE_NOMOTION, 0);
|
|
}
|
|
|
|
int ANT_CALL TwMouseMotion(int _MouseX, int _MouseY)
|
|
{
|
|
return TwMouseEvent(TW_MOUSE_MOTION, TW_MOUSE_NA, _MouseX, _MouseY, 0);
|
|
}
|
|
|
|
int ANT_CALL TwMouseWheel(int _Pos)
|
|
{
|
|
return TwMouseEvent(TW_MOUSE_WHEEL, TW_MOUSE_NA, TW_MOUSE_NOMOTION, TW_MOUSE_NOMOTION, _Pos);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
static int TranslateKey(int _Key, int _Modifiers)
|
|
{
|
|
// CTRL special cases
|
|
// if( (_Modifiers&TW_KMOD_CTRL) && !(_Modifiers&TW_KMOD_ALT || _Modifiers&TW_KMOD_META) && _Key>0 && _Key<32 )
|
|
// _Key += 'a'-1;
|
|
if( (_Modifiers&TW_KMOD_CTRL) )
|
|
{
|
|
if( _Key>='a' && _Key<='z' && ( ((_Modifiers&0x2000) && !(_Modifiers&TW_KMOD_SHIFT)) || (!(_Modifiers&0x2000) && (_Modifiers&TW_KMOD_SHIFT)) )) // 0x2000 is SDL's KMOD_CAPS
|
|
_Key += 'A'-'a';
|
|
else if ( _Key>='A' && _Key<='Z' && ( ((_Modifiers&0x2000) && (_Modifiers&TW_KMOD_SHIFT)) || (!(_Modifiers&0x2000) && !(_Modifiers&TW_KMOD_SHIFT)) )) // 0x2000 is SDL's KMOD_CAPS
|
|
_Key += 'a'-'A';
|
|
}
|
|
|
|
// PAD translation (for SDL keysym)
|
|
if( _Key>=256 && _Key<=272 ) // 256=SDLK_KP0 ... 272=SDLK_KP_EQUALS
|
|
{
|
|
//bool Num = ((_Modifiers&TW_KMOD_SHIFT) && !(_Modifiers&0x1000)) || (!(_Modifiers&TW_KMOD_SHIFT) && (_Modifiers&0x1000)); // 0x1000 is SDL's KMOD_NUM
|
|
//_Modifiers &= ~TW_KMOD_SHIFT; // remove shift modifier
|
|
bool Num = (!(_Modifiers&TW_KMOD_SHIFT) && (_Modifiers&0x1000)); // 0x1000 is SDL's KMOD_NUM
|
|
if( _Key==266 ) // SDLK_KP_PERIOD
|
|
_Key = Num ? '.' : TW_KEY_DELETE;
|
|
else if( _Key==267 ) // SDLK_KP_DIVIDE
|
|
_Key = '/';
|
|
else if( _Key==268 ) // SDLK_KP_MULTIPLY
|
|
_Key = '*';
|
|
else if( _Key==269 ) // SDLK_KP_MINUS
|
|
_Key = '-';
|
|
else if( _Key==270 ) // SDLK_KP_PLUS
|
|
_Key = '+';
|
|
else if( _Key==271 ) // SDLK_KP_ENTER
|
|
_Key = TW_KEY_RETURN;
|
|
else if( _Key==272 ) // SDLK_KP_EQUALS
|
|
_Key = '=';
|
|
else if( Num ) // num SDLK_KP0..9
|
|
_Key += '0' - 256;
|
|
else if( _Key==256 ) // non-num SDLK_KP01
|
|
_Key = TW_KEY_INSERT;
|
|
else if( _Key==257 ) // non-num SDLK_KP1
|
|
_Key = TW_KEY_END;
|
|
else if( _Key==258 ) // non-num SDLK_KP2
|
|
_Key = TW_KEY_DOWN;
|
|
else if( _Key==259 ) // non-num SDLK_KP3
|
|
_Key = TW_KEY_PAGE_DOWN;
|
|
else if( _Key==260 ) // non-num SDLK_KP4
|
|
_Key = TW_KEY_LEFT;
|
|
else if( _Key==262 ) // non-num SDLK_KP6
|
|
_Key = TW_KEY_RIGHT;
|
|
else if( _Key==263 ) // non-num SDLK_KP7
|
|
_Key = TW_KEY_HOME;
|
|
else if( _Key==264 ) // non-num SDLK_KP8
|
|
_Key = TW_KEY_UP;
|
|
else if( _Key==265 ) // non-num SDLK_KP9
|
|
_Key = TW_KEY_PAGE_UP;
|
|
}
|
|
return _Key;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int ANT_CALL TwKeyPressed(int _Key, int _Modifiers)
|
|
{
|
|
CTwFPU fpu; // force fpu precision
|
|
|
|
if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
|
|
{
|
|
// TwGlobalError(g_ErrNotInit); -> not an error here
|
|
return 0; // not initialized
|
|
}
|
|
if( g_TwMgr->m_WndHeight<=0 || g_TwMgr->m_WndWidth<=0 )
|
|
{
|
|
//g_TwMgr->SetLastError(g_ErrBadWndSize); // not an error, windows not yet ready.
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
// Test for TwDeleteBar
|
|
if( _Key>='0' && _Key<='9' )
|
|
{
|
|
int n = _Key-'0';
|
|
if( (int)g_TwMgr->m_Bars.size()>n && g_TwMgr->m_Bars[n]!=NULL )
|
|
{
|
|
printf("Delete %s\n", g_TwMgr->m_Bars[n]->m_Name.c_str());
|
|
TwDeleteBar(g_TwMgr->m_Bars[n]);
|
|
}
|
|
else
|
|
printf("can't delete %d\n", n);
|
|
return 1;
|
|
}
|
|
*/
|
|
|
|
//char s[256];
|
|
//sprintf(s, "twkeypressed k=%d m=%x\n", _Key, _Modifiers);
|
|
//OutputDebugString(s);
|
|
|
|
_Key = TranslateKey(_Key, _Modifiers);
|
|
if( _Key>' ' && _Key<256 ) // don't test SHIFT if _Key is a common key
|
|
_Modifiers &= ~TW_KMOD_SHIFT;
|
|
// complete partial modifiers comming from SDL
|
|
if( _Modifiers & TW_KMOD_SHIFT )
|
|
_Modifiers |= TW_KMOD_SHIFT;
|
|
if( _Modifiers & TW_KMOD_CTRL )
|
|
_Modifiers |= TW_KMOD_CTRL;
|
|
if( _Modifiers & TW_KMOD_ALT )
|
|
_Modifiers |= TW_KMOD_ALT;
|
|
if( _Modifiers & TW_KMOD_META )
|
|
_Modifiers |= TW_KMOD_META;
|
|
|
|
bool Handled = false;
|
|
CTwBar *Bar = NULL;
|
|
//int Order = 0;
|
|
int i;
|
|
if( _Key>0 && _Key<TW_KEY_LAST )
|
|
{
|
|
// First send it to bar which includes the mouse pointer
|
|
int MouseX = g_TwMgr->m_LastMouseX;
|
|
int MouseY = g_TwMgr->m_LastMouseY;
|
|
for( i=((int)g_TwMgr->m_Bars.size())-1; i>=0 && !Handled; --i )
|
|
{
|
|
Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]];
|
|
if( Bar!=NULL && Bar->m_Visible && !Bar->IsMinimized() && MouseX>=Bar->m_PosX && MouseX<Bar->m_PosX+Bar->m_Width && MouseY>=Bar->m_PosY && MouseY<Bar->m_PosY+Bar->m_Height )
|
|
Handled = Bar->KeyPressed(_Key, _Modifiers);
|
|
}
|
|
|
|
// If not handled, send it to non-iconified bars in the right order
|
|
for( i=((int)g_TwMgr->m_Bars.size())-1; i>=0 && !Handled; --i )
|
|
{
|
|
Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]];
|
|
/*
|
|
for( size_t j=0; j<g_TwMgr->m_Bars.size(); ++j )
|
|
if( g_TwMgr->m_Order[j]==i )
|
|
{
|
|
Bar = g_TwMgr->m_Bars[j];
|
|
break;
|
|
}
|
|
Order = i;
|
|
*/
|
|
|
|
if( Bar!=NULL && Bar->m_Visible && !Bar->IsMinimized() )
|
|
Handled = Bar->KeyPressed(_Key, _Modifiers);
|
|
}
|
|
|
|
// If not handled, send it to iconified bars in the right order
|
|
for( i=((int)g_TwMgr->m_Bars.size())-1; i>=0 && !Handled; --i )
|
|
{
|
|
Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]];
|
|
if( Bar!=NULL && Bar->m_Visible && Bar->IsMinimized() )
|
|
Handled = Bar->KeyPressed(_Key, _Modifiers);
|
|
}
|
|
|
|
if( g_TwMgr->m_HelpBar!=NULL && g_TwMgr->m_Graph )
|
|
{
|
|
string Str;
|
|
TwGetKeyString(&Str, _Key, _Modifiers);
|
|
char Msg[256];
|
|
sprintf(Msg, "Key pressed: %s", Str.c_str());
|
|
g_TwMgr->m_KeyPressedStr = Msg;
|
|
g_TwMgr->m_KeyPressedBuildText = true;
|
|
// OutputDebugString(Msg);
|
|
}
|
|
}
|
|
|
|
if( Handled && Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_PopupBar!=NULL ) // delete popup
|
|
{
|
|
TwDeleteBar(g_TwMgr->m_PopupBar);
|
|
g_TwMgr->m_PopupBar = NULL;
|
|
}
|
|
|
|
if( Handled && Bar!=NULL && Bar!=g_TwMgr->m_PopupBar )
|
|
TwSetTopBar(Bar);
|
|
|
|
return Handled ? 1 : 0;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
struct StructCompare : public binary_function<TwType, TwType, bool>
|
|
{
|
|
bool operator()(const TwType& _Left, const TwType& _Right) const
|
|
{
|
|
assert( g_TwMgr!=NULL );
|
|
int i0 = _Left-TW_TYPE_STRUCT_BASE;
|
|
int i1 = _Right-TW_TYPE_STRUCT_BASE;
|
|
if( i0>=0 && i0<(int)g_TwMgr->m_Structs.size() && i1>=0 && i1<(int)g_TwMgr->m_Structs.size() )
|
|
return g_TwMgr->m_Structs[i0].m_Name < g_TwMgr->m_Structs[i1].m_Name;
|
|
else
|
|
return false;
|
|
}
|
|
};
|
|
|
|
typedef set<TwType, StructCompare> StructSet;
|
|
|
|
static void InsertUsedStructs(StructSet& _Set, const CTwVarGroup *_Grp)
|
|
{
|
|
assert( g_TwMgr!=NULL && _Grp!=NULL );
|
|
|
|
for( size_t i=0; i<_Grp->m_Vars.size(); ++i )
|
|
if( _Grp->m_Vars[i]!=NULL && _Grp->m_Vars[i]->m_Visible && _Grp->m_Vars[i]->IsGroup() )
|
|
{
|
|
const CTwVarGroup *SubGrp = static_cast<const CTwVarGroup *>(_Grp->m_Vars[i]);
|
|
if( SubGrp->m_StructValuePtr!=NULL && SubGrp->m_StructType>=TW_TYPE_STRUCT_BASE && SubGrp->m_StructType<TW_TYPE_STRUCT_BASE+(int)g_TwMgr->m_Structs.size() && g_TwMgr->m_Structs[SubGrp->m_StructType-TW_TYPE_STRUCT_BASE].m_Name.length()>0 )
|
|
_Set.insert(SubGrp->m_StructType);
|
|
InsertUsedStructs(_Set, SubGrp);
|
|
}
|
|
}
|
|
|
|
static void SplitString(vector<string>& _OutSplits, const char *_String, int _Width, const CTexFont *_Font)
|
|
{
|
|
assert( _Font!=NULL && _String!=NULL );
|
|
_OutSplits.resize(0);
|
|
int l = (int)strlen(_String);
|
|
if( l==0 )
|
|
{
|
|
_String = " ";
|
|
l = 1;
|
|
}
|
|
|
|
if( _String!=NULL && l>0 && _Width>0 )
|
|
{
|
|
int w = 0;
|
|
int i = 0;
|
|
int First = 0;
|
|
int Last = 0;
|
|
bool PrevNotBlank = true;
|
|
unsigned char c;
|
|
bool Tab = false, CR = false;
|
|
string Split;
|
|
const string TabString(g_TabLength, ' ');
|
|
|
|
while( i<l )
|
|
{
|
|
c = _String[i];
|
|
if( c=='\t' )
|
|
{
|
|
w += g_TabLength * _Font->m_CharWidth[(int)' '];
|
|
Tab = true;
|
|
}
|
|
else if( c=='\n' )
|
|
{
|
|
w += _Width+1; // force split
|
|
Last = i;
|
|
CR = true;
|
|
}
|
|
else
|
|
w += _Font->m_CharWidth[(int)c];
|
|
if( w>_Width || i==l-1 )
|
|
{
|
|
if( Last<=First || i==l-1 )
|
|
Last = i;
|
|
if( Tab )
|
|
{
|
|
Split.resize(0);
|
|
for(int k=0; k<Last-First+(CR?0:1); ++k)
|
|
if( _String[First+k]=='\t' )
|
|
Split += TabString;
|
|
else
|
|
Split += _String[First+k];
|
|
Tab = false;
|
|
}
|
|
else
|
|
Split.assign(_String+First, Last-First+(CR?0:1));
|
|
_OutSplits.push_back(Split);
|
|
First = Last+1;
|
|
if( !CR )
|
|
while( First<l && (_String[First]==' ' || _String[First]=='\t') ) // skip blanks
|
|
++First;
|
|
Last = First;
|
|
w = 0;
|
|
PrevNotBlank = true;
|
|
i = First;
|
|
CR = false;
|
|
}
|
|
else if( c==' ' || c=='\t' )
|
|
{
|
|
if( PrevNotBlank )
|
|
Last = i-1;
|
|
PrevNotBlank = false;
|
|
++i;
|
|
}
|
|
else
|
|
{
|
|
PrevNotBlank = true;
|
|
++i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int AppendHelpString(CTwVarGroup *_Grp, const char *_String, int _Level, int _Width, ETwType _Type)
|
|
{
|
|
assert( _Grp!=NULL && g_TwMgr!=NULL && g_TwMgr->m_HelpBar!=NULL);
|
|
assert( _String!=NULL );
|
|
int n = 0;
|
|
const CTexFont *Font = g_TwMgr->m_HelpBar->m_Font;
|
|
assert(Font!=NULL);
|
|
string Decal;
|
|
for( int s=0; s<_Level; ++s )
|
|
Decal += ' ';
|
|
int DecalWidth = (_Level+2)*Font->m_CharWidth[(int)' '];
|
|
|
|
if( _Width>DecalWidth )
|
|
{
|
|
vector<string> Split;
|
|
SplitString(Split, _String, _Width-DecalWidth, Font);
|
|
for( int i=0; i<(int)Split.size(); ++i )
|
|
{
|
|
CTwVarAtom *Var = new CTwVarAtom;
|
|
Var->m_Name = Decal + Split[i];
|
|
Var->m_Ptr = NULL;
|
|
if( _Type==TW_TYPE_HELP_HEADER )
|
|
Var->m_ReadOnly = false;
|
|
else
|
|
Var->m_ReadOnly = true;
|
|
Var->m_NoSlider = true;
|
|
Var->m_DontClip = true;
|
|
Var->m_Type = _Type;
|
|
Var->m_LeftMargin = (signed short)(_Level*Font->m_CharWidth[(int)' ']);
|
|
Var->m_TopMargin = (signed short)(-g_TwMgr->m_HelpBar->m_Sep);
|
|
//Var->m_TopMargin = 1;
|
|
Var->m_Color = g_TwMgr->m_HelpBar->m_ColHelpText;
|
|
Var->SetDefaults();
|
|
_Grp->m_Vars.push_back(Var);
|
|
++n;
|
|
}
|
|
}
|
|
return n;
|
|
}
|
|
|
|
static int AppendHelp(CTwVarGroup *_Grp, const CTwVarGroup *_ToAppend, int _Level, int _Width)
|
|
{
|
|
assert( _Grp!=NULL );
|
|
assert( _ToAppend!=NULL );
|
|
int n = 0;
|
|
string Decal;
|
|
for( int s=0; s<_Level; ++s )
|
|
Decal += ' ';
|
|
|
|
if( _ToAppend->m_Help.size()>0 )
|
|
n += AppendHelpString(_Grp, _ToAppend->m_Help.c_str(), _Level, _Width, TW_TYPE_HELP_GRP);
|
|
|
|
for( size_t i=0; i<_ToAppend->m_Vars.size(); ++i )
|
|
if( _ToAppend->m_Vars[i]!=NULL && _ToAppend->m_Vars[i]->m_Visible )
|
|
{
|
|
CTwVarAtom *Var = new CTwVarAtom;
|
|
Var->m_Name = Decal;
|
|
if( _ToAppend->m_Vars[i]->m_Label.size()>0 )
|
|
Var->m_Name += _ToAppend->m_Vars[i]->m_Label;
|
|
else
|
|
Var->m_Name += _ToAppend->m_Vars[i]->m_Name;
|
|
Var->m_Ptr = NULL;
|
|
if( _ToAppend->m_Vars[i]->IsGroup() && static_cast<const CTwVarGroup *>(_ToAppend->m_Vars[i])->m_StructValuePtr!=NULL )
|
|
{ // That's a struct var
|
|
Var->m_Type = TW_TYPE_HELP_STRUCT;
|
|
Var->m_Val.m_HelpStruct.m_StructType = static_cast<const CTwVarGroup *>(_ToAppend->m_Vars[i])->m_StructType;
|
|
Var->m_ReadOnly = true;
|
|
Var->m_NoSlider = true;
|
|
}
|
|
else if( !_ToAppend->m_Vars[i]->IsGroup() )
|
|
{
|
|
Var->m_Type = TW_TYPE_SHORTCUT;
|
|
Var->m_Val.m_Shortcut.m_Incr[0] = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i])->m_KeyIncr[0];
|
|
Var->m_Val.m_Shortcut.m_Incr[1] = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i])->m_KeyIncr[1];
|
|
Var->m_Val.m_Shortcut.m_Decr[0] = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i])->m_KeyDecr[0];
|
|
Var->m_Val.m_Shortcut.m_Decr[1] = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i])->m_KeyDecr[1];
|
|
Var->m_ReadOnly = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i])->m_ReadOnly;
|
|
Var->m_NoSlider = true;
|
|
}
|
|
else
|
|
{
|
|
Var->m_Type = TW_TYPE_HELP_GRP;
|
|
Var->m_DontClip = true;
|
|
Var->m_LeftMargin = (signed short)((_Level+1)*g_TwMgr->m_HelpBar->m_Font->m_CharWidth[(int)' ']);
|
|
//Var->m_TopMargin = (signed short)(g_TwMgr->m_HelpBar->m_Font->m_CharHeight/2-2+2*(_Level-1));
|
|
Var->m_TopMargin = 2;
|
|
if( Var->m_TopMargin>g_TwMgr->m_HelpBar->m_Font->m_CharHeight-3 )
|
|
Var->m_TopMargin = (signed short)(g_TwMgr->m_HelpBar->m_Font->m_CharHeight-3);
|
|
Var->m_ReadOnly = true;
|
|
}
|
|
Var->SetDefaults();
|
|
_Grp->m_Vars.push_back(Var);
|
|
++n;
|
|
if( _ToAppend->m_Vars[i]->IsGroup() && static_cast<const CTwVarGroup *>(_ToAppend->m_Vars[i])->m_StructValuePtr==NULL )
|
|
n += AppendHelp(_Grp, static_cast<const CTwVarGroup *>(_ToAppend->m_Vars[i]), _Level+1, _Width);
|
|
else if( _ToAppend->m_Vars[i]->m_Help.length()>0 )
|
|
n += AppendHelpString(_Grp, _ToAppend->m_Vars[i]->m_Help.c_str(), _Level+1, _Width, TW_TYPE_HELP_ATOM);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
|
|
static void CopyHierarchy(CTwVarGroup *dst, const CTwVarGroup *src)
|
|
{
|
|
if( dst==NULL || src==NULL )
|
|
return;
|
|
|
|
dst->m_Name = src->m_Name;
|
|
dst->m_Open = src->m_Open;
|
|
dst->m_Visible = src->m_Visible;
|
|
dst->m_Color = src->m_Color;
|
|
dst->m_DontClip = src->m_DontClip;
|
|
dst->m_IsRoot = src->m_IsRoot;
|
|
dst->m_LeftMargin = src->m_LeftMargin;
|
|
dst->m_TopMargin = src->m_TopMargin;
|
|
|
|
dst->m_Vars.resize(src->m_Vars.size());
|
|
for(size_t i=0; i<src->m_Vars.size(); ++i)
|
|
if( src->m_Vars[i]!=NULL && src->m_Vars[i]->IsGroup() )
|
|
{
|
|
CTwVarGroup *grp = new CTwVarGroup;
|
|
CopyHierarchy(grp, static_cast<const CTwVarGroup *>(src->m_Vars[i]));
|
|
dst->m_Vars[i] = grp;
|
|
}
|
|
else
|
|
dst->m_Vars[i] = NULL;
|
|
}
|
|
|
|
// copy the 'open' flag from original hierarchy to current hierarchy
|
|
static void SynchroHierarchy(CTwVarGroup *cur, const CTwVarGroup *orig)
|
|
{
|
|
if( cur==NULL || orig==NULL )
|
|
return;
|
|
|
|
if( strcmp(cur->m_Name.c_str(), orig->m_Name.c_str())==0 )
|
|
cur->m_Open = orig->m_Open;
|
|
|
|
size_t j = 0;
|
|
while( j<orig->m_Vars.size() && (orig->m_Vars[j]==NULL || !orig->m_Vars[j]->IsGroup()) )
|
|
++j;
|
|
|
|
for(size_t i=0; i<cur->m_Vars.size(); ++i)
|
|
if( cur->m_Vars[i]!=NULL && cur->m_Vars[i]->IsGroup() && j<orig->m_Vars.size() && orig->m_Vars[j]!=NULL && orig->m_Vars[j]->IsGroup() )
|
|
{
|
|
CTwVarGroup *curGrp = static_cast<CTwVarGroup *>(cur->m_Vars[i]);
|
|
const CTwVarGroup *origGrp = static_cast<const CTwVarGroup *>(orig->m_Vars[j]);
|
|
if( strcmp(curGrp->m_Name.c_str(), origGrp->m_Name.c_str())==0 )
|
|
{
|
|
curGrp->m_Open = origGrp->m_Open;
|
|
|
|
SynchroHierarchy(curGrp, origGrp);
|
|
|
|
++j;
|
|
while( j<orig->m_Vars.size() && (orig->m_Vars[j]==NULL || !orig->m_Vars[j]->IsGroup()) )
|
|
++j;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CTwMgr::UpdateHelpBar()
|
|
{
|
|
if( m_HelpBar==NULL || m_HelpBar->IsMinimized() )
|
|
return;
|
|
if( !m_HelpBarUpdateNow && (float)m_Timer.GetTime()<m_LastHelpUpdateTime+2 ) // update at most every 2 seconds
|
|
return;
|
|
m_HelpBarUpdateNow = false;
|
|
m_LastHelpUpdateTime = (float)m_Timer.GetTime();
|
|
#ifdef _DEBUG
|
|
//printf("UPDATE HELPBAR\n");
|
|
#endif // _DEBUG
|
|
|
|
CTwVarGroup prevHierarchy;
|
|
CopyHierarchy(&prevHierarchy, &m_HelpBar->m_VarRoot);
|
|
|
|
TwRemoveAllVars(m_HelpBar);
|
|
|
|
if( m_HelpBar->m_UpToDate )
|
|
m_HelpBar->Update();
|
|
|
|
if( m_Help.size()>0 )
|
|
AppendHelpString(&(m_HelpBar->m_VarRoot), m_Help.c_str(), 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM);
|
|
if( m_HelpBar->m_Help.size()>0 )
|
|
AppendHelpString(&(m_HelpBar->m_VarRoot), m_HelpBar->m_Help.c_str(), 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM);
|
|
AppendHelpString(&(m_HelpBar->m_VarRoot), "", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_HEADER);
|
|
|
|
for( size_t ib=0; ib<m_Bars.size(); ++ib )
|
|
if( m_Bars[ib]!=NULL && !(m_Bars[ib]->m_IsHelpBar) && m_Bars[ib]!=m_PopupBar && m_Bars[ib]->m_Visible )
|
|
{
|
|
// Create a group
|
|
CTwVarGroup *Grp = new CTwVarGroup;
|
|
Grp->m_SummaryCallback = NULL;
|
|
Grp->m_SummaryClientData = NULL;
|
|
Grp->m_StructValuePtr = NULL;
|
|
if( m_Bars[ib]->m_Label.size()<=0 )
|
|
Grp->m_Name = m_Bars[ib]->m_Name;
|
|
else
|
|
Grp->m_Name = m_Bars[ib]->m_Label;
|
|
Grp->m_Open = true;
|
|
Grp->m_Color = m_HelpBar->m_ColGrpText;
|
|
m_HelpBar->m_VarRoot.m_Vars.push_back(Grp);
|
|
if( m_Bars[ib]->m_Help.size()>0 )
|
|
AppendHelpString(Grp, m_Bars[ib]->m_Help.c_str(), 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_GRP);
|
|
|
|
// Append variables (recursive)
|
|
AppendHelp(Grp, &(m_Bars[ib]->m_VarRoot), 1, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0);
|
|
|
|
// Append structures
|
|
StructSet UsedStructs;
|
|
InsertUsedStructs(UsedStructs, &(m_Bars[ib]->m_VarRoot));
|
|
CTwVarGroup *StructGrp = NULL;
|
|
for( StructSet::iterator it=UsedStructs.begin(); it!=UsedStructs.end(); ++it )
|
|
{
|
|
int idx = (*it) - TW_TYPE_STRUCT_BASE;
|
|
if( idx>=0 && idx<(int)g_TwMgr->m_Structs.size() && g_TwMgr->m_Structs[idx].m_Name.length()>0 )
|
|
{
|
|
if( StructGrp==NULL )
|
|
{
|
|
StructGrp = new CTwVarGroup;
|
|
StructGrp->m_StructType = TW_TYPE_HELP_STRUCT; // a special line background color will be used
|
|
StructGrp->m_Name = "Structures";
|
|
StructGrp->m_Open = false;
|
|
StructGrp->m_Color = m_HelpBar->m_ColStructText;
|
|
Grp->m_Vars.push_back(StructGrp);
|
|
}
|
|
CTwVarAtom *Var = new CTwVarAtom;
|
|
Var->m_Ptr = NULL;
|
|
Var->m_Type = TW_TYPE_HELP_GRP;
|
|
Var->m_DontClip = true;
|
|
Var->m_LeftMargin = (signed short)(2*g_TwMgr->m_HelpBar->m_Font->m_CharWidth[(int)' ']);
|
|
Var->m_TopMargin = 2;
|
|
Var->m_ReadOnly = true;
|
|
Var->m_NoSlider = true;
|
|
Var->m_Name = '{'+g_TwMgr->m_Structs[idx].m_Name+'}';
|
|
StructGrp->m_Vars.push_back(Var);
|
|
if( g_TwMgr->m_Structs[idx].m_Help.size()>0 )
|
|
AppendHelpString(StructGrp, g_TwMgr->m_Structs[idx].m_Help.c_str(), 2, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0-2*Var->m_LeftMargin, TW_TYPE_HELP_GRP);
|
|
|
|
// Append struct members
|
|
for( size_t im=0; im<g_TwMgr->m_Structs[idx].m_Members.size(); ++im )
|
|
{
|
|
CTwVarAtom *Var = new CTwVarAtom;
|
|
Var->m_Ptr = NULL;
|
|
Var->m_Type = TW_TYPE_SHORTCUT;
|
|
Var->m_Val.m_Shortcut.m_Incr[0] = 0;
|
|
Var->m_Val.m_Shortcut.m_Incr[1] = 0;
|
|
Var->m_Val.m_Shortcut.m_Decr[0] = 0;
|
|
Var->m_Val.m_Shortcut.m_Decr[1] = 0;
|
|
Var->m_ReadOnly = false;
|
|
Var->m_NoSlider = true;
|
|
if( g_TwMgr->m_Structs[idx].m_Members[im].m_Label.length()>0 )
|
|
Var->m_Name = " "+g_TwMgr->m_Structs[idx].m_Members[im].m_Label;
|
|
else
|
|
Var->m_Name = " "+g_TwMgr->m_Structs[idx].m_Members[im].m_Name;
|
|
StructGrp->m_Vars.push_back(Var);
|
|
if( g_TwMgr->m_Structs[idx].m_Members[im].m_Help.size()>0 )
|
|
AppendHelpString(StructGrp, g_TwMgr->m_Structs[idx].m_Members[im].m_Help.c_str(), 3, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0-4*Var->m_LeftMargin, TW_TYPE_HELP_ATOM);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Append RotoSlider
|
|
CTwVarGroup *RotoGrp = new CTwVarGroup;
|
|
RotoGrp->m_SummaryCallback = NULL;
|
|
RotoGrp->m_SummaryClientData = NULL;
|
|
RotoGrp->m_StructValuePtr = NULL;
|
|
RotoGrp->m_Name = "RotoSlider";
|
|
RotoGrp->m_Open = false;
|
|
RotoGrp->m_Color = m_HelpBar->m_ColGrpText;
|
|
m_HelpBar->m_VarRoot.m_Vars.push_back(RotoGrp);
|
|
AppendHelpString(RotoGrp, "The RotoSlider allows rapid editing of numerical values.", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM);
|
|
AppendHelpString(RotoGrp, "To modify a numerical value, click on it, then move the mouse outside of the grey circle while keeping the mouse button pressed, and turn around the circle to increase or decrease the numerical value.", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM);
|
|
AppendHelpString(RotoGrp, "The two grey lines depict the min and max bounds.", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM);
|
|
AppendHelpString(RotoGrp, "Moving the mouse far form the circle allows precise increase or decrease, while moving near the circle allows fast increase or decrease.", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM);
|
|
|
|
SynchroHierarchy(&m_HelpBar->m_VarRoot, &prevHierarchy);
|
|
|
|
m_HelpBarNotUpToDate = false;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
#if defined(ANT_WINDOWS)
|
|
|
|
void CTwMgr::CreateCursors()
|
|
{
|
|
if( m_CursorsCreated )
|
|
return;
|
|
m_CursorArrow = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_ARROW));
|
|
m_CursorMove = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZEALL));
|
|
m_CursorWE = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZEWE));
|
|
m_CursorNS = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENS));
|
|
m_CursorTopRight = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENESW));
|
|
m_CursorTopLeft = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENWSE));
|
|
m_CursorBottomLeft = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENESW));
|
|
m_CursorBottomRight = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENWSE));
|
|
m_CursorHelp = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_HELP));
|
|
m_CursorCross = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_CROSS));
|
|
m_CursorUpArrow = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_UPARROW));
|
|
m_CursorNo = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_NO));
|
|
#ifdef IDC_HAND
|
|
m_CursorHand = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_HAND));
|
|
#else
|
|
m_CursorHand = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_UPARROW));
|
|
#endif
|
|
int cur;
|
|
HMODULE hdll = GetModuleHandle(ANT_TWEAK_BAR_DLL);
|
|
m_CursorCenter = ::LoadCursor(hdll, MAKEINTRESOURCE(IDC_CURSOR1+0));
|
|
if( m_CursorCenter==NULL )
|
|
m_CursorCenter = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_CROSS));
|
|
m_CursorPoint = ::LoadCursor(hdll, MAKEINTRESOURCE(IDC_CURSOR1+1));
|
|
if( m_CursorPoint==NULL )
|
|
m_CursorPoint = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_CROSS));
|
|
|
|
for( cur=0; cur<NB_ROTO_CURSORS; ++cur )
|
|
{
|
|
m_RotoCursors[cur] = ::LoadCursor(hdll, MAKEINTRESOURCE(IDC_CURSOR1+2+cur));
|
|
if( m_RotoCursors[cur]==NULL )
|
|
m_RotoCursors[cur] = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_CROSS));
|
|
}
|
|
|
|
m_CursorsCreated = true;
|
|
}
|
|
|
|
void CTwMgr::FreeCursors()
|
|
{
|
|
m_CursorsCreated = false;
|
|
}
|
|
|
|
void CTwMgr::SetCursor(CTwMgr::CCursor _Cursor)
|
|
{
|
|
if( m_CursorsCreated )
|
|
::SetCursor(_Cursor);
|
|
}
|
|
|
|
|
|
#elif defined(ANT_UNIX)
|
|
|
|
|
|
#include "res/TwXCursors.h"
|
|
|
|
static XErrorHandler s_PrevErrorHandler = NULL;
|
|
|
|
static int InactiveErrorHandler(Display *display, XErrorEvent *err)
|
|
{
|
|
fprintf(stderr, "Ignoring Xlib error: error code %d request code %d\n", err->error_code, err->request_code);
|
|
// No exit!
|
|
return 0 ;
|
|
}
|
|
|
|
static void IgnoreXErrors()
|
|
{
|
|
if( g_TwMgr!=NULL && g_TwMgr->m_CurrentXDisplay==glXGetCurrentDisplay() )
|
|
{
|
|
XFlush(g_TwMgr->m_CurrentXDisplay);
|
|
XSync(g_TwMgr->m_CurrentXDisplay, False);
|
|
}
|
|
s_PrevErrorHandler = XSetErrorHandler(InactiveErrorHandler);
|
|
}
|
|
|
|
static void RestoreXErrors()
|
|
{
|
|
if( g_TwMgr!=NULL && g_TwMgr->m_CurrentXDisplay==glXGetCurrentDisplay() )
|
|
{
|
|
XFlush(g_TwMgr->m_CurrentXDisplay);
|
|
XSync(g_TwMgr->m_CurrentXDisplay, False);
|
|
}
|
|
XSetErrorHandler(s_PrevErrorHandler);
|
|
}
|
|
|
|
CTwMgr::CCursor CTwMgr::PixmapCursor(int _CurIdx)
|
|
{
|
|
if( !m_CurrentXDisplay || !m_CurrentXWindow )
|
|
return XC_left_ptr;
|
|
|
|
IgnoreXErrors();
|
|
|
|
XColor black, white, exact;
|
|
Colormap colmap = DefaultColormap(m_CurrentXDisplay, DefaultScreen(m_CurrentXDisplay));
|
|
Status s1 = XAllocNamedColor(m_CurrentXDisplay, colmap, "black", &black, &exact);
|
|
Status s2 = XAllocNamedColor(m_CurrentXDisplay, colmap, "white", &white, &exact);
|
|
if( s1==0 || s2==0 )
|
|
return XC_left_ptr; // cannot allocate colors!
|
|
int x, y;
|
|
unsigned int mask[32];
|
|
unsigned int pict[32];
|
|
for( y=0; y<32; ++y )
|
|
{
|
|
mask[y] = pict[y] = 0;
|
|
for( x=0; x<32; ++x )
|
|
{
|
|
mask[y] |= (((unsigned int)(g_CurMask[_CurIdx][x+y*32]))<<x);
|
|
pict[y] |= (((unsigned int)(g_CurPict[_CurIdx][x+y*32]))<<x);
|
|
}
|
|
}
|
|
Pixmap maskPix = XCreateBitmapFromData(m_CurrentXDisplay, m_CurrentXWindow, (char*)mask, 32, 32);
|
|
Pixmap pictPix = XCreateBitmapFromData(m_CurrentXDisplay, m_CurrentXWindow, (char*)pict, 32, 32);
|
|
Cursor cursor = XCreatePixmapCursor(m_CurrentXDisplay, pictPix, maskPix, &white, &black, g_CurHot[_CurIdx][0], g_CurHot[_CurIdx][1]);
|
|
XFreePixmap(m_CurrentXDisplay, maskPix);
|
|
XFreePixmap(m_CurrentXDisplay, pictPix);
|
|
|
|
RestoreXErrors();
|
|
|
|
if( cursor!=0 )
|
|
return cursor;
|
|
else
|
|
return XC_left_ptr;
|
|
}
|
|
|
|
void CTwMgr::CreateCursors()
|
|
{
|
|
if( m_CursorsCreated || !m_CurrentXDisplay || !m_CurrentXWindow )
|
|
return;
|
|
|
|
IgnoreXErrors();
|
|
m_CursorArrow = XCreateFontCursor(m_CurrentXDisplay, XC_left_ptr);
|
|
m_CursorMove = XCreateFontCursor(m_CurrentXDisplay, XC_plus);
|
|
m_CursorWE = XCreateFontCursor(m_CurrentXDisplay, XC_left_side);
|
|
m_CursorNS = XCreateFontCursor(m_CurrentXDisplay, XC_top_side);
|
|
m_CursorTopRight= XCreateFontCursor(m_CurrentXDisplay, XC_top_right_corner);
|
|
m_CursorTopLeft = XCreateFontCursor(m_CurrentXDisplay, XC_top_left_corner);
|
|
m_CursorBottomRight = XCreateFontCursor(m_CurrentXDisplay, XC_bottom_right_corner);
|
|
m_CursorBottomLeft = XCreateFontCursor(m_CurrentXDisplay, XC_bottom_left_corner);
|
|
m_CursorHelp = XCreateFontCursor(m_CurrentXDisplay, XC_question_arrow);
|
|
m_CursorHand = XCreateFontCursor(m_CurrentXDisplay, XC_hand1);
|
|
m_CursorCross = XCreateFontCursor(m_CurrentXDisplay, XC_X_cursor);
|
|
m_CursorUpArrow = XCreateFontCursor(m_CurrentXDisplay, XC_center_ptr);
|
|
m_CursorNo = XCreateFontCursor(m_CurrentXDisplay, XC_left_ptr);
|
|
for( int i=0; i<NB_ROTO_CURSORS; ++i )
|
|
{
|
|
m_RotoCursors[i] = PixmapCursor(i+2);
|
|
}
|
|
m_CursorCenter = PixmapCursor(0);
|
|
m_CursorPoint = PixmapCursor(1);
|
|
m_CursorsCreated = true;
|
|
|
|
RestoreXErrors();
|
|
}
|
|
|
|
void CTwMgr::FreeCursors()
|
|
{
|
|
IgnoreXErrors();
|
|
|
|
XFreeCursor(m_CurrentXDisplay, m_CursorArrow);
|
|
XFreeCursor(m_CurrentXDisplay, m_CursorMove);
|
|
XFreeCursor(m_CurrentXDisplay, m_CursorWE);
|
|
XFreeCursor(m_CurrentXDisplay, m_CursorNS);
|
|
XFreeCursor(m_CurrentXDisplay, m_CursorTopRight);
|
|
XFreeCursor(m_CurrentXDisplay, m_CursorTopLeft);
|
|
XFreeCursor(m_CurrentXDisplay, m_CursorBottomRight);
|
|
XFreeCursor(m_CurrentXDisplay, m_CursorBottomLeft);
|
|
XFreeCursor(m_CurrentXDisplay, m_CursorHelp);
|
|
XFreeCursor(m_CurrentXDisplay, m_CursorHand);
|
|
XFreeCursor(m_CurrentXDisplay, m_CursorCross);
|
|
XFreeCursor(m_CurrentXDisplay, m_CursorUpArrow);
|
|
XFreeCursor(m_CurrentXDisplay, m_CursorNo);
|
|
for( int i=0; i<NB_ROTO_CURSORS; ++i )
|
|
XFreeCursor(m_CurrentXDisplay, m_RotoCursors[i]);
|
|
XFreeCursor(m_CurrentXDisplay, m_CursorCenter);
|
|
XFreeCursor(m_CurrentXDisplay, m_CursorPoint);
|
|
|
|
m_CursorsCreated = false;
|
|
|
|
RestoreXErrors();
|
|
}
|
|
|
|
void CTwMgr::SetCursor(CTwMgr::CCursor _Cursor)
|
|
{
|
|
if( m_CursorsCreated && m_CurrentXDisplay && m_CurrentXWindow )
|
|
{
|
|
Display *dpy = glXGetCurrentDisplay();
|
|
if( dpy==g_TwMgr->m_CurrentXDisplay )
|
|
{
|
|
Window wnd = glXGetCurrentDrawable();
|
|
if( wnd!=g_TwMgr->m_CurrentXWindow )
|
|
{
|
|
FreeCursors();
|
|
g_TwMgr->m_CurrentXWindow = wnd;
|
|
CreateCursors();
|
|
// now _Cursor is not a valid cursor ID.
|
|
}
|
|
else
|
|
{
|
|
IgnoreXErrors();
|
|
XDefineCursor(m_CurrentXDisplay, m_CurrentXWindow, _Cursor);
|
|
RestoreXErrors();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif //defined(ANT_UNIX)
|
|
|
|
// ---------------------------------------------------------------------------
|