1 //  ---------------------------------------------------------------------------
2 //
3 //  @file       TwMgr.cpp
4 //  @author     Philippe Decaudin
5 //  @license    This file is part of the AntTweakBar library.
6 //              For conditions of distribution and use, see License.txt
7 //
8 //  ---------------------------------------------------------------------------
9 
10 
11 #include "TwPrecomp.h"
12 #include <AntTweakBar.h>
13 #include "TwMgr.h"
14 #include "TwBar.h"
15 #include "TwFonts.h"
16 #include "TwOpenGL.h"
17 #include "TwOpenGLCore.h"
18 #ifdef ANT_WINDOWS
19 #   include "TwDirect3D9.h"
20 #   include "TwDirect3D10.h"
21 #   include "TwDirect3D11.h"
22 #   include "resource.h"
23 #   ifdef _DEBUG
24 #       include <crtdbg.h>
25 #   endif // _DEBUG
26 #endif // ANT_WINDOWS
27 
28 #if !defined(ANT_WINDOWS)
29 #   define _snprintf snprintf
30 #endif  // defined(ANT_WINDOWS)
31 
32 
33 using namespace std;
34 
35 CTwMgr *g_TwMgr = NULL; // current TwMgr
36 bool g_BreakOnError = false;
37 TwErrorHandler g_ErrorHandler = NULL;
38 int g_TabLength = 4;
39 CTwBar * const TW_GLOBAL_BAR = (CTwBar *)(-1);
40 int g_InitWndWidth = -1;
41 int g_InitWndHeight = -1;
42 TwCopyCDStringToClient  g_InitCopyCDStringToClient = NULL;
43 TwCopyStdStringToClient g_InitCopyStdStringToClient = NULL;
44 float g_FontScaling = 1.0f;
45 
46 // multi-windows
47 const int TW_MASTER_WINDOW_ID = 0;
48 typedef map<int, CTwMgr *> CTwWndMap;
49 CTwWndMap g_Wnds;
50 CTwMgr *g_TwMasterMgr = NULL;
51 
52 // error messages
53 extern const char *g_ErrUnknownAttrib;
54 extern const char *g_ErrNoValue;
55 extern const char *g_ErrBadValue;
56 const char *g_ErrInit       = "Already initialized";
57 const char *g_ErrShut       = "Already shutdown";
58 const char *g_ErrNotInit    = "Not initialized";
59 const char *g_ErrUnknownAPI = "Unsupported graph API";
60 const char *g_ErrBadDevice  = "Invalid graph device";
61 const char *g_ErrBadParam   = "Invalid parameter";
62 const char *g_ErrExist      = "Exists already";
63 const char *g_ErrNotFound   = "Not found";
64 const char *g_ErrNthToDo    = "Nothing to do";
65 const char *g_ErrBadSize    = "Bad size";
66 const char *g_ErrIsDrawing  = "Asynchronous drawing detected";
67 const char *g_ErrIsProcessing="Asynchronous processing detected";
68 const char *g_ErrOffset     = "Offset larger than StructSize";
69 const char *g_ErrDelStruct  = "Cannot delete a struct member";
70 const char *g_ErrNoBackQuote= "Name cannot include back-quote";
71 const char *g_ErrStdString  = "Debug/Release std::string mismatch";
72 const char *g_ErrCStrParam  = "Value count for TW_PARAM_CSTRING must be 1";
73 const char *g_ErrOutOfRange = "Index out of range";
74 const char *g_ErrHasNoValue = "Has no value";
75 const char *g_ErrBadType    = "Incompatible type";
76 const char *g_ErrDelHelp    = "Cannot delete help bar";
77 char g_ErrParse[512];
78 
79 void ANT_CALL TwGlobalError(const char *_ErrorMessage);
80 
81 #if defined(ANT_UNIX) || defined(ANT_OSX)
82 #define _stricmp strcasecmp
83 #define _strdup strdup
84 #endif
85 
86 #ifdef ANT_WINDOWS
87     bool g_UseCurRsc = true;    // use dll resources for rotoslider cursors
88 #endif
89 
90 //  ---------------------------------------------------------------------------
91 
92 const float  FLOAT_EPS     = 1.0e-7f;
93 const float  FLOAT_EPS_SQ  = 1.0e-14f;
94 const float  FLOAT_PI      = 3.14159265358979323846f;
95 const double DOUBLE_EPS    = 1.0e-14;
96 const double DOUBLE_EPS_SQ = 1.0e-28;
97 const double DOUBLE_PI     = 3.14159265358979323846;
98 
DegToRad(double degree)99 inline double DegToRad(double degree) { return degree * (DOUBLE_PI/180.0); }
RadToDeg(double radian)100 inline double RadToDeg(double radian) { return radian * (180.0/DOUBLE_PI); }
101 
102 //  ---------------------------------------------------------------------------
103 
104 //  a static global object to verify that Tweakbar module has been properly terminated (in debug mode only)
105 #ifdef _DEBUG
106 static struct CTwVerif
107 {
~CTwVerifCTwVerif108     ~CTwVerif()
109     {
110         if( g_TwMgr!=NULL )
111             g_TwMgr->SetLastError("Tweak bar module has not been terminated properly: call TwTerminate()\n");
112     }
113 } s_Verif;
114 #endif // _DEBUG
115 
116 //  ---------------------------------------------------------------------------
117 //  Color ext type
118 //  ---------------------------------------------------------------------------
119 
RGB2HLS()120 void CColorExt::RGB2HLS()
121 {
122     float fH = 0, fL = 0, fS = 0;
123     ColorRGBToHLSf((float)R/255.0f, (float)G/255.0f, (float)B/255.0f, &fH, &fL, &fS);
124     H = (int)fH;
125     if( H>=360 )
126         H -= 360;
127     else if( H<0 )
128         H += 360;
129     L = (int)(255.0f*fL + 0.5f);
130     if( L<0 )
131         L = 0;
132     else if( L>255 )
133         L = 255;
134     S = (int)(255.0f*fS + 0.5f);
135     if( S<0 )
136         S = 0;
137     else if( S>255 )
138         S = 255;
139 }
140 
HLS2RGB()141 void CColorExt::HLS2RGB()
142 {
143     float fR = 0, fG = 0, fB = 0;
144     ColorHLSToRGBf((float)H, (float)L/255.0f, (float)S/255.0f, &fR, &fG, &fB);
145     R = (int)(255.0f*fR + 0.5f);
146     if( R<0 )
147         R = 0;
148     else if( R>255 )
149         R = 255;
150     G = (int)(255.0f*fG + 0.5f);
151     if( G<0 )
152         G = 0;
153     else if( G>255 )
154         G = 255;
155     B = (int)(255.0f*fB + 0.5f);
156     if( B<0 )
157         B = 0;
158     else if( B>255 )
159         B = 255;
160 }
161 
InitColor32CB(void * _ExtValue,void * _ClientData)162 void ANT_CALL CColorExt::InitColor32CB(void *_ExtValue, void *_ClientData)
163 {
164     CColorExt *ext = static_cast<CColorExt *>(_ExtValue);
165     if( ext )
166     {
167         ext->m_IsColorF = false;
168         ext->R = 0;
169         ext->G = 0;
170         ext->B = 0;
171         ext->H = 0;
172         ext->L = 0;
173         ext->S = 0;
174         ext->A = 255;
175         ext->m_HLS = false;
176         ext->m_HasAlpha = false;
177         ext->m_CanHaveAlpha = true;
178         if( g_TwMgr && g_TwMgr->m_GraphAPI==TW_DIRECT3D9 ) // D3D10 now use OGL rgba order!
179             ext->m_OGL = false;
180         else
181             ext->m_OGL = true;
182         ext->m_PrevConvertedColor = Color32FromARGBi(ext->A, ext->R, ext->G, ext->B);
183         ext->m_StructProxy = (CTwMgr::CStructProxy *)_ClientData;
184     }
185 }
186 
InitColor3FCB(void * _ExtValue,void * _ClientData)187 void ANT_CALL CColorExt::InitColor3FCB(void *_ExtValue, void *_ClientData)
188 {
189     InitColor32CB(_ExtValue, _ClientData);
190     CColorExt *ext = static_cast<CColorExt *>(_ExtValue);
191     if( ext )
192     {
193         ext->m_IsColorF = true;
194         ext->m_HasAlpha = false;
195         ext->m_CanHaveAlpha = false;
196     }
197 }
198 
InitColor4FCB(void * _ExtValue,void * _ClientData)199 void ANT_CALL CColorExt::InitColor4FCB(void *_ExtValue, void *_ClientData)
200 {
201     InitColor32CB(_ExtValue, _ClientData);
202     CColorExt *ext = static_cast<CColorExt *>(_ExtValue);
203     if( ext )
204     {
205         ext->m_IsColorF = true;
206         ext->m_HasAlpha = true;
207         ext->m_CanHaveAlpha = true;
208     }
209 }
210 
CopyVarFromExtCB(void * _VarValue,const void * _ExtValue,unsigned int _ExtMemberIndex,void * _ClientData)211 void ANT_CALL CColorExt::CopyVarFromExtCB(void *_VarValue, const void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData)
212 {
213     unsigned int *var32 = static_cast<unsigned int *>(_VarValue);
214     float *varF = static_cast<float *>(_VarValue);
215     CColorExt *ext = (CColorExt *)(_ExtValue);
216     CTwMgr::CMemberProxy *mProxy = static_cast<CTwMgr::CMemberProxy *>(_ClientData);
217     if( _VarValue && ext )
218     {
219         if( ext->m_HasAlpha && mProxy && mProxy->m_StructProxy && mProxy->m_StructProxy->m_Type==g_TwMgr->m_TypeColor3F )
220             ext->m_HasAlpha = false;
221 
222         // Synchronize HLS and RGB
223         if( _ExtMemberIndex>=0 && _ExtMemberIndex<=2 )
224             ext->RGB2HLS();
225         else if( _ExtMemberIndex>=3 && _ExtMemberIndex<=5 )
226             ext->HLS2RGB();
227         else if( mProxy && _ExtMemberIndex==7 && mProxy->m_VarParent )
228         {
229             assert( mProxy->m_VarParent->m_Vars.size()==8 );
230             if(    mProxy->m_VarParent->m_Vars[0]->m_Visible != !ext->m_HLS
231                 || mProxy->m_VarParent->m_Vars[1]->m_Visible != !ext->m_HLS
232                 || mProxy->m_VarParent->m_Vars[2]->m_Visible != !ext->m_HLS
233                 || mProxy->m_VarParent->m_Vars[3]->m_Visible != ext->m_HLS
234                 || mProxy->m_VarParent->m_Vars[4]->m_Visible != ext->m_HLS
235                 || mProxy->m_VarParent->m_Vars[5]->m_Visible != ext->m_HLS )
236             {
237                 mProxy->m_VarParent->m_Vars[0]->m_Visible = !ext->m_HLS;
238                 mProxy->m_VarParent->m_Vars[1]->m_Visible = !ext->m_HLS;
239                 mProxy->m_VarParent->m_Vars[2]->m_Visible = !ext->m_HLS;
240                 mProxy->m_VarParent->m_Vars[3]->m_Visible = ext->m_HLS;
241                 mProxy->m_VarParent->m_Vars[4]->m_Visible = ext->m_HLS;
242                 mProxy->m_VarParent->m_Vars[5]->m_Visible = ext->m_HLS;
243                 mProxy->m_Bar->NotUpToDate();
244             }
245             if( mProxy->m_VarParent->m_Vars[6]->m_Visible != ext->m_HasAlpha )
246             {
247                 mProxy->m_VarParent->m_Vars[6]->m_Visible = ext->m_HasAlpha;
248                 mProxy->m_Bar->NotUpToDate();
249             }
250             if( static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[7])->m_ReadOnly )
251             {
252                 static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[7])->m_ReadOnly = false;
253                 mProxy->m_Bar->NotUpToDate();
254             }
255         }
256         // Convert to color32
257         color32 col = Color32FromARGBi((ext->m_HasAlpha ? ext->A : 255), ext->R, ext->G, ext->B);
258         if( ext->m_OGL && !ext->m_IsColorF )
259             col = (col&0xff00ff00) | (unsigned char)(col>>16) | (((unsigned char)(col))<<16);
260         if( ext->m_IsColorF )
261             Color32ToARGBf(col, (ext->m_HasAlpha ? varF+3 : NULL), varF+0, varF+1, varF+2);
262         else
263         {
264             if( ext->m_HasAlpha )
265                 *var32 = col;
266             else
267                 *var32 = ((*var32)&0xff000000) | (col&0x00ffffff);
268         }
269         ext->m_PrevConvertedColor = col;
270     }
271 }
272 
CopyVarToExtCB(const void * _VarValue,void * _ExtValue,unsigned int _ExtMemberIndex,void * _ClientData)273 void ANT_CALL CColorExt::CopyVarToExtCB(const void *_VarValue, void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData)
274 {
275     const unsigned int *var32 = static_cast<const unsigned int *>(_VarValue);
276     const float *varF = static_cast<const float *>(_VarValue);
277     CColorExt *ext = static_cast<CColorExt *>(_ExtValue);
278     CTwMgr::CMemberProxy *mProxy = static_cast<CTwMgr::CMemberProxy *>(_ClientData);
279     if( _VarValue && ext )
280     {
281         if( ext->m_HasAlpha && mProxy && mProxy->m_StructProxy && mProxy->m_StructProxy->m_Type==g_TwMgr->m_TypeColor3F )
282             ext->m_HasAlpha = false;
283 
284         if( mProxy && _ExtMemberIndex==7 && mProxy->m_VarParent )
285         {
286             assert( mProxy->m_VarParent->m_Vars.size()==8 );
287             if(    mProxy->m_VarParent->m_Vars[0]->m_Visible != !ext->m_HLS
288                 || mProxy->m_VarParent->m_Vars[1]->m_Visible != !ext->m_HLS
289                 || mProxy->m_VarParent->m_Vars[2]->m_Visible != !ext->m_HLS
290                 || mProxy->m_VarParent->m_Vars[3]->m_Visible != ext->m_HLS
291                 || mProxy->m_VarParent->m_Vars[4]->m_Visible != ext->m_HLS
292                 || mProxy->m_VarParent->m_Vars[5]->m_Visible != ext->m_HLS )
293             {
294                 mProxy->m_VarParent->m_Vars[0]->m_Visible = !ext->m_HLS;
295                 mProxy->m_VarParent->m_Vars[1]->m_Visible = !ext->m_HLS;
296                 mProxy->m_VarParent->m_Vars[2]->m_Visible = !ext->m_HLS;
297                 mProxy->m_VarParent->m_Vars[3]->m_Visible = ext->m_HLS;
298                 mProxy->m_VarParent->m_Vars[4]->m_Visible = ext->m_HLS;
299                 mProxy->m_VarParent->m_Vars[5]->m_Visible = ext->m_HLS;
300                 mProxy->m_Bar->NotUpToDate();
301             }
302             if( mProxy->m_VarParent->m_Vars[6]->m_Visible != ext->m_HasAlpha )
303             {
304                 mProxy->m_VarParent->m_Vars[6]->m_Visible = ext->m_HasAlpha;
305                 mProxy->m_Bar->NotUpToDate();
306             }
307             if( static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[7])->m_ReadOnly )
308             {
309                 static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[7])->m_ReadOnly = false;
310                 mProxy->m_Bar->NotUpToDate();
311             }
312         }
313         color32 col;
314         if( ext->m_IsColorF )
315             col = Color32FromARGBf((ext->m_HasAlpha ? varF[3] : 1), varF[0], varF[1], varF[2]);
316         else
317             col = *var32;
318         if( ext->m_OGL && !ext->m_IsColorF )
319             col = (col&0xff00ff00) | (unsigned char)(col>>16) | (((unsigned char)(col))<<16);
320         Color32ToARGBi(col, (ext->m_HasAlpha ? &ext->A : NULL), &ext->R, &ext->G, &ext->B);
321         if( (col & 0x00ffffff)!=(ext->m_PrevConvertedColor & 0x00ffffff) )
322             ext->RGB2HLS();
323         ext->m_PrevConvertedColor = col;
324     }
325 }
326 
SummaryCB(char * _SummaryString,size_t,const void * _ExtValue,void *)327 void ANT_CALL CColorExt::SummaryCB(char *_SummaryString, size_t /*_SummaryMaxLength*/, const void *_ExtValue, void * /*_ClientData*/)
328 {
329     // copy var
330     CColorExt *ext = (CColorExt *)(_ExtValue);
331     if( ext && ext->m_StructProxy && ext->m_StructProxy->m_StructData )
332     {
333         if( ext->m_StructProxy->m_StructGetCallback )
334             ext->m_StructProxy->m_StructGetCallback(ext->m_StructProxy->m_StructData, ext->m_StructProxy->m_StructClientData);
335         //if( *(unsigned int *)(ext->m_StructProxy->m_StructData)!=ext->m_PrevConvertedColor )
336         CopyVarToExtCB(ext->m_StructProxy->m_StructData, ext, 99, NULL);
337     }
338 
339     //unsigned int col = 0;
340     //CopyVar32FromExtCB(&col, _ExtValue, 99, _ClientData);
341     //_snprintf(_SummaryString, _SummaryMaxLength, "0x%.8X", col);
342     //(void) _SummaryMaxLength, _ExtValue, _ClientData;
343     _SummaryString[0] = ' ';    // required to force background color for this value
344     _SummaryString[1] = '\0';
345 }
346 
CreateTypes()347 void CColorExt::CreateTypes()
348 {
349     if( g_TwMgr==NULL )
350         return;
351     TwStructMember ColorExtMembers[] = { { "Red", TW_TYPE_INT32, offsetof(CColorExt, R), "min=0 max=255" },
352                                          { "Green", TW_TYPE_INT32, offsetof(CColorExt, G), "min=0 max=255" },
353                                          { "Blue", TW_TYPE_INT32, offsetof(CColorExt, B), "min=0 max=255" },
354                                          { "Hue", TW_TYPE_INT32, offsetof(CColorExt, H), "hide min=0 max=359" },
355                                          { "Lightness", TW_TYPE_INT32, offsetof(CColorExt, L), "hide min=0 max=255" },
356                                          { "Saturation", TW_TYPE_INT32, offsetof(CColorExt, S), "hide min=0 max=255" },
357                                          { "Alpha", TW_TYPE_INT32, offsetof(CColorExt, A), "hide min=0 max=255" },
358                                          { "Mode", TW_TYPE_BOOLCPP, offsetof(CColorExt, m_HLS), "true='HLS' false='RGB' readwrite" } };
359     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, "A 32-bit-encoded color.");
360     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, "A 3-floats-encoded RGB color.");
361     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, "A 4-floats-encoded RGBA color.");
362     // Do not name them "TW_COLOR*" because the name is displayed in the help bar.
363 }
364 
365 //  ---------------------------------------------------------------------------
366 //  Quaternion ext type
367 //  ---------------------------------------------------------------------------
368 
InitQuat4FCB(void * _ExtValue,void * _ClientData)369 void ANT_CALL CQuaternionExt::InitQuat4FCB(void *_ExtValue, void *_ClientData)
370 {
371     CQuaternionExt *ext = static_cast<CQuaternionExt *>(_ExtValue);
372     if( ext )
373     {
374         ext->Qx = ext->Qy = ext->Qz = 0;
375         ext->Qs = 1;
376         ext->Vx = 1;
377         ext->Vy = ext->Vz = 0;
378         ext->Angle = 0;
379         ext->Dx = ext->Dy = ext->Dz = 0;
380         ext->m_AAMode = false; // Axis & angle mode hidden
381         ext->m_ShowVal = false;
382         ext->m_IsFloat = true;
383         ext->m_IsDir = false;
384         ext->m_Dir[0] = ext->m_Dir[1] = ext->m_Dir[2] = 0;
385         ext->m_DirColor = 0xffffff00;
386         int i, j;
387         for(i=0; i<3; ++i)
388             for(j=0; j<3; ++j)
389                 ext->m_Permute[i][j] = (i==j) ? 1.0f : 0.0f;
390         ext->m_StructProxy = (CTwMgr::CStructProxy *)_ClientData;
391         ext->ConvertToAxisAngle();
392         ext->m_Highlighted = false;
393         ext->m_Rotating = false;
394         if( ext->m_StructProxy!=NULL )
395         {
396             ext->m_StructProxy->m_CustomDrawCallback = CQuaternionExt::DrawCB;
397             ext->m_StructProxy->m_CustomMouseButtonCallback = CQuaternionExt::MouseButtonCB;
398             ext->m_StructProxy->m_CustomMouseMotionCallback = CQuaternionExt::MouseMotionCB;
399             ext->m_StructProxy->m_CustomMouseLeaveCallback = CQuaternionExt::MouseLeaveCB;
400         }
401     }
402 }
403 
InitQuat4DCB(void * _ExtValue,void * _ClientData)404 void ANT_CALL CQuaternionExt::InitQuat4DCB(void *_ExtValue, void *_ClientData)
405 {
406     CQuaternionExt *ext = static_cast<CQuaternionExt *>(_ExtValue);
407     if( ext )
408     {
409         ext->Qx = ext->Qy = ext->Qz = 0;
410         ext->Qs = 1;
411         ext->Vx = 1;
412         ext->Vy = ext->Vz = 0;
413         ext->Angle = 0;
414         ext->Dx = ext->Dy = ext->Dz = 0;
415         ext->m_AAMode = false; // Axis & angle mode hidden
416         ext->m_ShowVal = false;
417         ext->m_IsFloat = false;
418         ext->m_IsDir = false;
419         ext->m_Dir[0] = ext->m_Dir[1] = ext->m_Dir[2] = 0;
420         ext->m_DirColor = 0xffffff00;
421         int i, j;
422         for(i=0; i<3; ++i)
423             for(j=0; j<3; ++j)
424                 ext->m_Permute[i][j] = (i==j) ? 1.0f : 0.0f;
425         ext->m_StructProxy = (CTwMgr::CStructProxy *)_ClientData;
426         ext->ConvertToAxisAngle();
427         ext->m_Highlighted = false;
428         ext->m_Rotating = false;
429         if( ext->m_StructProxy!=NULL )
430         {
431             ext->m_StructProxy->m_CustomDrawCallback = CQuaternionExt::DrawCB;
432             ext->m_StructProxy->m_CustomMouseButtonCallback = CQuaternionExt::MouseButtonCB;
433             ext->m_StructProxy->m_CustomMouseMotionCallback = CQuaternionExt::MouseMotionCB;
434             ext->m_StructProxy->m_CustomMouseLeaveCallback = CQuaternionExt::MouseLeaveCB;
435         }
436     }
437 }
438 
InitDir3FCB(void * _ExtValue,void * _ClientData)439 void ANT_CALL CQuaternionExt::InitDir3FCB(void *_ExtValue, void *_ClientData)
440 {
441     CQuaternionExt *ext = static_cast<CQuaternionExt *>(_ExtValue);
442     if( ext )
443     {
444         ext->Qx = ext->Qy = ext->Qz = 0;
445         ext->Qs = 1;
446         ext->Vx = 1;
447         ext->Vy = ext->Vz = 0;
448         ext->Angle = 0;
449         ext->Dx = 1;
450         ext->Dy = ext->Dz = 0;
451         ext->m_AAMode = false; // Axis & angle mode hidden
452         ext->m_ShowVal = true;
453         ext->m_IsFloat = true;
454         ext->m_IsDir = true;
455         ext->m_Dir[0] = ext->m_Dir[1] = ext->m_Dir[2] = 0;
456         ext->m_DirColor = 0xffffff00;
457         int i, j;
458         for(i=0; i<3; ++i)
459             for(j=0; j<3; ++j)
460                 ext->m_Permute[i][j] = (i==j) ? 1.0f : 0.0f;
461         ext->m_StructProxy = (CTwMgr::CStructProxy *)_ClientData;
462         ext->ConvertToAxisAngle();
463         ext->m_Highlighted = false;
464         ext->m_Rotating = false;
465         if( ext->m_StructProxy!=NULL )
466         {
467             ext->m_StructProxy->m_CustomDrawCallback = CQuaternionExt::DrawCB;
468             ext->m_StructProxy->m_CustomMouseButtonCallback = CQuaternionExt::MouseButtonCB;
469             ext->m_StructProxy->m_CustomMouseMotionCallback = CQuaternionExt::MouseMotionCB;
470             ext->m_StructProxy->m_CustomMouseLeaveCallback = CQuaternionExt::MouseLeaveCB;
471         }
472     }
473 }
474 
InitDir3DCB(void * _ExtValue,void * _ClientData)475 void ANT_CALL CQuaternionExt::InitDir3DCB(void *_ExtValue, void *_ClientData)
476 {
477     CQuaternionExt *ext = static_cast<CQuaternionExt *>(_ExtValue);
478     if( ext )
479     {
480         ext->Qx = ext->Qy = ext->Qz = 0;
481         ext->Qs = 1;
482         ext->Vx = 1;
483         ext->Vy = ext->Vz = 0;
484         ext->Angle = 0;
485         ext->Dx = 1;
486         ext->Dy = ext->Dz = 0;
487         ext->m_AAMode = false; // Axis & angle mode hidden
488         ext->m_ShowVal = true;
489         ext->m_IsFloat = false;
490         ext->m_IsDir = true;
491         ext->m_Dir[0] = ext->m_Dir[1] = ext->m_Dir[2] = 0;
492         ext->m_DirColor = 0xffffff00;
493         int i, j;
494         for(i=0; i<3; ++i)
495             for(j=0; j<3; ++j)
496                 ext->m_Permute[i][j] = (i==j) ? 1.0f : 0.0f;
497         ext->m_StructProxy = (CTwMgr::CStructProxy *)_ClientData;
498         ext->ConvertToAxisAngle();
499         ext->m_Highlighted = false;
500         ext->m_Rotating = false;
501         if( ext->m_StructProxy!=NULL )
502         {
503             ext->m_StructProxy->m_CustomDrawCallback = CQuaternionExt::DrawCB;
504             ext->m_StructProxy->m_CustomMouseButtonCallback = CQuaternionExt::MouseButtonCB;
505             ext->m_StructProxy->m_CustomMouseMotionCallback = CQuaternionExt::MouseMotionCB;
506             ext->m_StructProxy->m_CustomMouseLeaveCallback = CQuaternionExt::MouseLeaveCB;
507         }
508     }
509 }
510 
CopyVarFromExtCB(void * _VarValue,const void * _ExtValue,unsigned int _ExtMemberIndex,void * _ClientData)511 void ANT_CALL CQuaternionExt::CopyVarFromExtCB(void *_VarValue, const void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData)
512 {
513     CQuaternionExt *ext = (CQuaternionExt *)(_ExtValue);
514     CTwMgr::CMemberProxy *mProxy = static_cast<CTwMgr::CMemberProxy *>(_ClientData);
515     if( _VarValue && ext )
516     {
517         // Synchronize Quat and AxisAngle
518         if( _ExtMemberIndex>=4 && _ExtMemberIndex<=7 )
519         {
520             ext->ConvertToAxisAngle();
521             // show/hide quat values
522             if( _ExtMemberIndex==4 && mProxy && mProxy->m_VarParent )
523             {
524                 assert( mProxy->m_VarParent->m_Vars.size()==16 );
525                 bool visible = ext->m_ShowVal;
526                 if( ext->m_IsDir )
527                 {
528                     if(    mProxy->m_VarParent->m_Vars[13]->m_Visible != visible
529                         || mProxy->m_VarParent->m_Vars[14]->m_Visible != visible
530                         || mProxy->m_VarParent->m_Vars[15]->m_Visible != visible )
531                     {
532                         mProxy->m_VarParent->m_Vars[13]->m_Visible = visible;
533                         mProxy->m_VarParent->m_Vars[14]->m_Visible = visible;
534                         mProxy->m_VarParent->m_Vars[15]->m_Visible = visible;
535                         mProxy->m_Bar->NotUpToDate();
536                     }
537                 }
538                 else
539                 {
540                     if(    mProxy->m_VarParent->m_Vars[4]->m_Visible != visible
541                         || mProxy->m_VarParent->m_Vars[5]->m_Visible != visible
542                         || mProxy->m_VarParent->m_Vars[6]->m_Visible != visible
543                         || mProxy->m_VarParent->m_Vars[7]->m_Visible != visible )
544                     {
545                         mProxy->m_VarParent->m_Vars[4]->m_Visible = visible;
546                         mProxy->m_VarParent->m_Vars[5]->m_Visible = visible;
547                         mProxy->m_VarParent->m_Vars[6]->m_Visible = visible;
548                         mProxy->m_VarParent->m_Vars[7]->m_Visible = visible;
549                         mProxy->m_Bar->NotUpToDate();
550                     }
551                 }
552             }
553         }
554         else if( _ExtMemberIndex>=8 && _ExtMemberIndex<=11 )
555             ext->ConvertFromAxisAngle();
556         else if( mProxy && _ExtMemberIndex==12 && mProxy->m_VarParent && !ext->m_IsDir )
557         {
558             assert( mProxy->m_VarParent->m_Vars.size()==16 );
559             bool aa = ext->m_AAMode;
560             if(    mProxy->m_VarParent->m_Vars[4]->m_Visible != !aa
561                 || mProxy->m_VarParent->m_Vars[5]->m_Visible != !aa
562                 || mProxy->m_VarParent->m_Vars[6]->m_Visible != !aa
563                 || mProxy->m_VarParent->m_Vars[7]->m_Visible != !aa
564                 || mProxy->m_VarParent->m_Vars[8 ]->m_Visible != aa
565                 || mProxy->m_VarParent->m_Vars[9 ]->m_Visible != aa
566                 || mProxy->m_VarParent->m_Vars[10]->m_Visible != aa
567                 || mProxy->m_VarParent->m_Vars[11]->m_Visible != aa )
568             {
569                 mProxy->m_VarParent->m_Vars[4]->m_Visible = !aa;
570                 mProxy->m_VarParent->m_Vars[5]->m_Visible = !aa;
571                 mProxy->m_VarParent->m_Vars[6]->m_Visible = !aa;
572                 mProxy->m_VarParent->m_Vars[7]->m_Visible = !aa;
573                 mProxy->m_VarParent->m_Vars[8 ]->m_Visible = aa;
574                 mProxy->m_VarParent->m_Vars[9 ]->m_Visible = aa;
575                 mProxy->m_VarParent->m_Vars[10]->m_Visible = aa;
576                 mProxy->m_VarParent->m_Vars[11]->m_Visible = aa;
577                 mProxy->m_Bar->NotUpToDate();
578             }
579             if( static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[12])->m_ReadOnly )
580             {
581                 static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[12])->m_ReadOnly = false;
582                 mProxy->m_Bar->NotUpToDate();
583             }
584         }
585 
586         if( ext->m_IsFloat )
587         {
588             float *var = static_cast<float *>(_VarValue);
589             if( ext->m_IsDir )
590             {
591                 var[0] = (float)ext->Dx;
592                 var[1] = (float)ext->Dy;
593                 var[2] = (float)ext->Dz;
594             }
595             else // quat
596             {
597                 var[0] = (float)ext->Qx;
598                 var[1] = (float)ext->Qy;
599                 var[2] = (float)ext->Qz;
600                 var[3] = (float)ext->Qs;
601             }
602         }
603         else
604         {
605             double *var = static_cast<double *>(_VarValue);
606             if( ext->m_IsDir )
607             {
608                 var[0] = ext->Dx;
609                 var[1] = ext->Dy;
610                 var[2] = ext->Dz;
611             }
612             else // quat
613             {
614                 var[0] = ext->Qx;
615                 var[1] = ext->Qy;
616                 var[2] = ext->Qz;
617                 var[3] = ext->Qs;
618             }
619         }
620     }
621 }
622 
CopyVarToExtCB(const void * _VarValue,void * _ExtValue,unsigned int _ExtMemberIndex,void * _ClientData)623 void ANT_CALL CQuaternionExt::CopyVarToExtCB(const void *_VarValue, void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData)
624 {
625     CQuaternionExt *ext = static_cast<CQuaternionExt *>(_ExtValue);
626     CTwMgr::CMemberProxy *mProxy = static_cast<CTwMgr::CMemberProxy *>(_ClientData);
627     (void)mProxy;
628     if( _VarValue && ext )
629     {
630         if( mProxy && _ExtMemberIndex==12 && mProxy->m_VarParent && !ext->m_IsDir )
631         {
632             assert( mProxy->m_VarParent->m_Vars.size()==16 );
633             bool aa = ext->m_AAMode;
634             if(    mProxy->m_VarParent->m_Vars[4]->m_Visible != !aa
635                 || mProxy->m_VarParent->m_Vars[5]->m_Visible != !aa
636                 || mProxy->m_VarParent->m_Vars[6]->m_Visible != !aa
637                 || mProxy->m_VarParent->m_Vars[7]->m_Visible != !aa
638                 || mProxy->m_VarParent->m_Vars[8 ]->m_Visible != aa
639                 || mProxy->m_VarParent->m_Vars[9 ]->m_Visible != aa
640                 || mProxy->m_VarParent->m_Vars[10]->m_Visible != aa
641                 || mProxy->m_VarParent->m_Vars[11]->m_Visible != aa )
642             {
643                 mProxy->m_VarParent->m_Vars[4]->m_Visible = !aa;
644                 mProxy->m_VarParent->m_Vars[5]->m_Visible = !aa;
645                 mProxy->m_VarParent->m_Vars[6]->m_Visible = !aa;
646                 mProxy->m_VarParent->m_Vars[7]->m_Visible = !aa;
647                 mProxy->m_VarParent->m_Vars[8 ]->m_Visible = aa;
648                 mProxy->m_VarParent->m_Vars[9 ]->m_Visible = aa;
649                 mProxy->m_VarParent->m_Vars[10]->m_Visible = aa;
650                 mProxy->m_VarParent->m_Vars[11]->m_Visible = aa;
651                 mProxy->m_Bar->NotUpToDate();
652             }
653             if( static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[12])->m_ReadOnly )
654             {
655                 static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[12])->m_ReadOnly = false;
656                 mProxy->m_Bar->NotUpToDate();
657             }
658         }
659         else if( mProxy && _ExtMemberIndex==4 && mProxy->m_VarParent )
660         {
661             assert( mProxy->m_VarParent->m_Vars.size()==16 );
662             bool visible = ext->m_ShowVal;
663             if( ext->m_IsDir )
664             {
665                 if(    mProxy->m_VarParent->m_Vars[13]->m_Visible != visible
666                     || mProxy->m_VarParent->m_Vars[14]->m_Visible != visible
667                     || mProxy->m_VarParent->m_Vars[15]->m_Visible != visible )
668                 {
669                     mProxy->m_VarParent->m_Vars[13]->m_Visible = visible;
670                     mProxy->m_VarParent->m_Vars[14]->m_Visible = visible;
671                     mProxy->m_VarParent->m_Vars[15]->m_Visible = visible;
672                     mProxy->m_Bar->NotUpToDate();
673                 }
674             }
675             else
676             {
677                 if(    mProxy->m_VarParent->m_Vars[4]->m_Visible != visible
678                     || mProxy->m_VarParent->m_Vars[5]->m_Visible != visible
679                     || mProxy->m_VarParent->m_Vars[6]->m_Visible != visible
680                     || mProxy->m_VarParent->m_Vars[7]->m_Visible != visible )
681                 {
682                     mProxy->m_VarParent->m_Vars[4]->m_Visible = visible;
683                     mProxy->m_VarParent->m_Vars[5]->m_Visible = visible;
684                     mProxy->m_VarParent->m_Vars[6]->m_Visible = visible;
685                     mProxy->m_VarParent->m_Vars[7]->m_Visible = visible;
686                     mProxy->m_Bar->NotUpToDate();
687                 }
688             }
689         }
690 
691         if( ext->m_IsFloat )
692         {
693             const float *var = static_cast<const float *>(_VarValue);
694             if( ext->m_IsDir )
695             {
696                 ext->Dx = var[0];
697                 ext->Dy = var[1];
698                 ext->Dz = var[2];
699                 QuatFromDir(&ext->Qx, &ext->Qy, &ext->Qz, &ext->Qs, var[0], var[1], var[2]);
700             }
701             else
702             {
703                 ext->Qx = var[0];
704                 ext->Qy = var[1];
705                 ext->Qz = var[2];
706                 ext->Qs = var[3];
707             }
708 
709         }
710         else
711         {
712             const double *var = static_cast<const double *>(_VarValue);
713             if( ext->m_IsDir )
714             {
715                 ext->Dx = var[0];
716                 ext->Dy = var[1];
717                 ext->Dz = var[2];
718                 QuatFromDir(&ext->Qx, &ext->Qy, &ext->Qz, &ext->Qs, var[0], var[1], var[2]);
719             }
720             else
721             {
722                 ext->Qx = var[0];
723                 ext->Qy = var[1];
724                 ext->Qz = var[2];
725                 ext->Qs = var[3];
726             }
727         }
728         ext->ConvertToAxisAngle();
729     }
730 }
731 
SummaryCB(char * _SummaryString,size_t _SummaryMaxLength,const void * _ExtValue,void *)732 void ANT_CALL CQuaternionExt::SummaryCB(char *_SummaryString, size_t _SummaryMaxLength, const void *_ExtValue, void * /*_ClientData*/)
733 {
734     const CQuaternionExt *ext = static_cast<const CQuaternionExt *>(_ExtValue);
735     if( ext )
736     {
737         if( ext->m_AAMode )
738             _snprintf(_SummaryString, _SummaryMaxLength, "V={%.2f,%.2f,%.2f} A=%.0f%c", ext->Vx, ext->Vy, ext->Vz, ext->Angle, 176);
739         else if( ext->m_IsDir )
740         {
741             //float d[] = {1, 0, 0};
742             //ApplyQuat(d+0, d+1, d+2, 1, 0, 0, (float)ext->Qx, (float)ext->Qy, (float)ext->Qz, (float)ext->Qs);
743             _snprintf(_SummaryString, _SummaryMaxLength, "V={%.2f,%.2f,%.2f}", ext->Dx, ext->Dy, ext->Dz);
744         }
745         else
746             _snprintf(_SummaryString, _SummaryMaxLength, "Q={x:%.2f,y:%.2f,z:%.2f,s:%.2f}", ext->Qx, ext->Qy, ext->Qz, ext->Qs);
747     }
748     else
749     {
750         _SummaryString[0] = ' ';    // required to force background color for this value
751         _SummaryString[1] = '\0';
752     }
753 }
754 
755 TwType CQuaternionExt::s_CustomType = TW_TYPE_UNDEF;
756 vector<float>   CQuaternionExt::s_SphTri;
757 vector<color32> CQuaternionExt::s_SphCol;
758 vector<int>     CQuaternionExt::s_SphTriProj;
759 vector<color32> CQuaternionExt::s_SphColLight;
760 vector<float>   CQuaternionExt::s_ArrowTri[4];
761 vector<float>   CQuaternionExt::s_ArrowNorm[4];
762 vector<int>     CQuaternionExt::s_ArrowTriProj[4];
763 vector<color32> CQuaternionExt::s_ArrowColLight[4];
764 
CreateTypes()765 void CQuaternionExt::CreateTypes()
766 {
767     if( g_TwMgr==NULL )
768         return;
769     s_CustomType = (TwType)(TW_TYPE_CUSTOM_BASE + (int)g_TwMgr->m_Customs.size());
770     g_TwMgr->m_Customs.push_back(NULL); // increment custom type number
771 
772     for(int pass=0; pass<2; pass++) // pass 0: create quat types; pass 1: create dir types
773     {
774         const char *quatDefPass0 = "step=0.01 hide";
775         const char *quatDefPass1 = "step=0.01 hide";
776         const char *quatSDefPass0 = "step=0.01 min=-1 max=1 hide";
777         const char *quatSDefPass1 = "step=0.01 min=-1 max=1 hide";
778         const char *dirDefPass0 = "step=0.01 hide";
779         const char *dirDefPass1 = "step=0.01";
780         const char *quatDef = (pass==0) ? quatDefPass0 : quatDefPass1;
781         const char *quatSDef = (pass==0) ? quatSDefPass0 : quatSDefPass1;
782         const char *dirDef = (pass==0) ? dirDefPass0 : dirDefPass1;
783 
784         TwStructMember QuatExtMembers[] = { { "0", s_CustomType, 0, "" },
785                                             { "1", s_CustomType, 0, "" },
786                                             { "2", s_CustomType, 0, "" },
787                                             { "3", s_CustomType, 0, "" },
788                                             { "Quat X", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Qx), quatDef }, // copy of the source quaternion
789                                             { "Quat Y", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Qy), quatDef },
790                                             { "Quat Z", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Qz), quatDef },
791                                             { "Quat S", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Qs), quatSDef },
792                                             { "Axis X", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Vx), "step=0.01 hide" }, // axis and angle conversion -> Mode hidden because it is not equivalent to a quat (would have required vector renormalization)
793                                             { "Axis Y", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Vy), "step=0.01 hide" },
794                                             { "Axis Z", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Vz), "step=0.01 hide" },
795                                             { "Angle (degree)",  TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Angle), "step=1 min=-360 max=360 hide" },
796                                             { "Mode", TW_TYPE_BOOLCPP, offsetof(CQuaternionExt, m_AAMode), "true='Axis Angle' false='Quaternion' readwrite hide" },
797                                             { "Dir X", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Dx), dirDef },      // copy of the source direction
798                                             { "Dir Y", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Dy), dirDef },
799                                             { "Dir Z", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Dz), dirDef } };
800         if( pass==0 )
801         {
802             g_TwMgr->m_TypeQuat4F = TwDefineStructExt("QUAT4F", QuatExtMembers, sizeof(QuatExtMembers)/sizeof(QuatExtMembers[0]), 4*sizeof(float), sizeof(CQuaternionExt), CQuaternionExt::InitQuat4FCB, CQuaternionExt::CopyVarFromExtCB, CQuaternionExt::CopyVarToExtCB, CQuaternionExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 4-floats-encoded quaternion");
803             g_TwMgr->m_TypeQuat4D = TwDefineStructExt("QUAT4D", QuatExtMembers, sizeof(QuatExtMembers)/sizeof(QuatExtMembers[0]), 4*sizeof(double), sizeof(CQuaternionExt), CQuaternionExt::InitQuat4DCB, CQuaternionExt::CopyVarFromExtCB, CQuaternionExt::CopyVarToExtCB, CQuaternionExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 4-doubles-encoded quaternion");
804         }
805         else if( pass==1 )
806         {
807             g_TwMgr->m_TypeDir3F = TwDefineStructExt("DIR4F", QuatExtMembers, sizeof(QuatExtMembers)/sizeof(QuatExtMembers[0]), 3*sizeof(float), sizeof(CQuaternionExt), CQuaternionExt::InitDir3FCB, CQuaternionExt::CopyVarFromExtCB, CQuaternionExt::CopyVarToExtCB, CQuaternionExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 3-floats-encoded direction");
808             g_TwMgr->m_TypeDir3D = TwDefineStructExt("DIR4D", QuatExtMembers, sizeof(QuatExtMembers)/sizeof(QuatExtMembers[0]), 3*sizeof(double), sizeof(CQuaternionExt), CQuaternionExt::InitDir3DCB, CQuaternionExt::CopyVarFromExtCB, CQuaternionExt::CopyVarToExtCB, CQuaternionExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 3-doubles-encoded direction");
809         }
810     }
811 
812     CreateSphere();
813     CreateArrow();
814 }
815 
ConvertToAxisAngle()816 void CQuaternionExt::ConvertToAxisAngle()
817 {
818     if( fabs(Qs)>(1.0 + FLOAT_EPS) )
819     {
820         //Vx = Vy = Vz = 0; // no, keep the previous value
821         Angle = 0;
822     }
823     else
824     {
825         double a;
826         if( Qs>=1.0f )
827             a = 0; // and keep V
828         else if( Qs<=-1.0f )
829             a = DOUBLE_PI; // and keep V
830         else if( fabs(Qx*Qx+Qy*Qy+Qz*Qz+Qs*Qs)<FLOAT_EPS_SQ )
831             a = 0;
832         else
833         {
834             a = acos(Qs);
835             if( a*Angle<0 ) // Preserve the sign of Angle
836                 a = -a;
837             double f = 1.0f / sin(a);
838             Vx = Qx * f;
839             Vy = Qy * f;
840             Vz = Qz * f;
841         }
842         Angle = 2.0*a;
843     }
844 
845     //  if( Angle>FLOAT_PI )
846     //      Angle -= 2.0f*FLOAT_PI;
847     //  else if( Angle<-FLOAT_PI )
848     //      Angle += 2.0f*FLOAT_PI;
849     Angle = RadToDeg(Angle);
850 
851     if( fabs(Angle)<FLOAT_EPS && fabs(Vx*Vx+Vy*Vy+Vz*Vz)<FLOAT_EPS_SQ )
852         Vx = 1.0e-7;    // all components cannot be null
853 }
854 
ConvertFromAxisAngle()855 void CQuaternionExt::ConvertFromAxisAngle()
856 {
857     double n = Vx*Vx + Vy*Vy + Vz*Vz;
858     if( fabs(n)>FLOAT_EPS_SQ )
859     {
860         double f = 0.5*DegToRad(Angle);
861         Qs = cos(f);
862         //do not normalize
863         //if( fabs(n - 1.0)>FLOAT_EPS_SQ )
864         //  f = sin(f) * (1.0/sqrt(n)) ;
865         //else
866         //  f = sin(f);
867         f = sin(f);
868 
869         Qx = Vx * f;
870         Qy = Vy * f;
871         Qz = Vz * f;
872     }
873     else
874     {
875         Qs = 1.0;
876         Qx = Qy = Qz = 0.0;
877     }
878 }
879 
CopyToVar()880 void CQuaternionExt::CopyToVar()
881 {
882     if( m_StructProxy!=NULL )
883     {
884         if( m_StructProxy->m_StructSetCallback!=NULL )
885         {
886             if( m_IsFloat )
887             {
888                 if( m_IsDir )
889                 {
890                     float d[] = {1, 0, 0};
891                     ApplyQuat(d+0, d+1, d+2, 1, 0, 0, (float)Qx, (float)Qy, (float)Qz, (float)Qs);
892                     float l = (float)sqrt(Dx*Dx + Dy*Dy + Dz*Dz);
893                     d[0] *= l; d[1] *= l; d[2] *= l;
894                     Dx = d[0]; Dy = d[1]; Dz = d[2]; // update also Dx,Dy,Dz
895                     m_StructProxy->m_StructSetCallback(d, m_StructProxy->m_StructClientData);
896                 }
897                 else
898                 {
899                     float q[] = { (float)Qx, (float)Qy, (float)Qz, (float)Qs };
900                     m_StructProxy->m_StructSetCallback(q, m_StructProxy->m_StructClientData);
901                 }
902             }
903             else
904             {
905                 if( m_IsDir )
906                 {
907                     float d[] = {1, 0, 0};
908                     ApplyQuat(d+0, d+1, d+2, 1, 0, 0, (float)Qx, (float)Qy, (float)Qz, (float)Qs);
909                     double l = sqrt(Dx*Dx + Dy*Dy + Dz*Dz);
910                     double dd[] = {l*d[0], l*d[1], l*d[2]};
911                     Dx = dd[0]; Dy = dd[1]; Dz = dd[2]; // update also Dx,Dy,Dz
912                     m_StructProxy->m_StructSetCallback(dd, m_StructProxy->m_StructClientData);
913                 }
914                 else
915                 {
916                     double q[] = { Qx, Qy, Qz, Qs };
917                     m_StructProxy->m_StructSetCallback(q, m_StructProxy->m_StructClientData);
918                 }
919             }
920         }
921         else if( m_StructProxy->m_StructData!=NULL )
922         {
923             if( m_IsFloat )
924             {
925                 if( m_IsDir )
926                 {
927                     float *d = static_cast<float *>(m_StructProxy->m_StructData);
928                     ApplyQuat(d+0, d+1, d+2, 1, 0, 0, (float)Qx, (float)Qy, (float)Qz, (float)Qs);
929                     float l = (float)sqrt(Dx*Dx + Dy*Dy + Dz*Dz);
930                     d[0] *= l; d[1] *= l; d[2] *= l;
931                     Dx = d[0]; Dy = d[1]; Dz = d[2]; // update also Dx,Dy,Dz
932                 }
933                 else
934                 {
935                     float *q = static_cast<float *>(m_StructProxy->m_StructData);
936                     q[0] = (float)Qx; q[1] = (float)Qy; q[2] = (float)Qz; q[3] = (float)Qs;
937                 }
938             }
939             else
940             {
941                 if( m_IsDir )
942                 {
943                     double *dd = static_cast<double *>(m_StructProxy->m_StructData);
944                     float d[] = {1, 0, 0};
945                     ApplyQuat(d+0, d+1, d+2, 1, 0, 0, (float)Qx, (float)Qy, (float)Qz, (float)Qs);
946                     double l = sqrt(Dx*Dx + Dy*Dy + Dz*Dz);
947                     dd[0] = l*d[0]; dd[1] = l*d[1]; dd[2] = l*d[2];
948                     Dx = dd[0]; Dy = dd[1]; Dz = dd[2]; // update also Dx,Dy,Dz
949                 }
950                 else
951                 {
952                     double *q = static_cast<double *>(m_StructProxy->m_StructData);
953                     q[0] = Qx; q[1] = Qy; q[2] = Qz; q[3] = Qs;
954                 }
955             }
956         }
957     }
958 }
959 
CreateSphere()960 void CQuaternionExt::CreateSphere()
961 {
962     const int SUBDIV = 7;
963     s_SphTri.clear();
964     s_SphCol.clear();
965 
966     const float A[8*3] = { 1,0,0, 0,0,-1, -1,0,0, 0,0,1,   0,0,1,  1,0,0,  0,0,-1, -1,0,0 };
967     const float B[8*3] = { 0,1,0, 0,1,0,  0,1,0,  0,1,0,   0,-1,0, 0,-1,0, 0,-1,0, 0,-1,0 };
968     const float C[8*3] = { 0,0,1, 1,0,0,  0,0,-1, -1,0,0,  1,0,0,  0,0,-1, -1,0,0, 0,0,1  };
969     //const color32 COL_A[8] = { 0xffff8080, 0xff000080, 0xff800000, 0xff8080ff,  0xff8080ff, 0xffff8080, 0xff000080, 0xff800000 };
970     //const color32 COL_B[8] = { 0xff80ff80, 0xff80ff80, 0xff80ff80, 0xff80ff80,  0xff008000, 0xff008000, 0xff008000, 0xff008000 };
971     //const color32 COL_C[8] = { 0xff8080ff, 0xffff8080, 0xff000080, 0xff800000,  0xffff8080, 0xff000080, 0xff800000, 0xff8080ff };
972     const color32 COL_A[8] = { 0xffffffff, 0xffffff40, 0xff40ff40, 0xff40ffff,  0xffff40ff, 0xffff4040, 0xff404040, 0xff4040ff };
973     const color32 COL_B[8] = { 0xffffffff, 0xffffff40, 0xff40ff40, 0xff40ffff,  0xffff40ff, 0xffff4040, 0xff404040, 0xff4040ff };
974     const color32 COL_C[8] = { 0xffffffff, 0xffffff40, 0xff40ff40, 0xff40ffff,  0xffff40ff, 0xffff4040, 0xff404040, 0xff4040ff };
975 
976     int i, j, k, l;
977     float xa, ya, za, xb, yb, zb, xc, yc, zc, x, y, z, norm, u[3], v[3];
978     color32 col;
979     for( i=0; i<8; ++i )
980     {
981         xa = A[3*i+0]; ya = A[3*i+1]; za = A[3*i+2];
982         xb = B[3*i+0]; yb = B[3*i+1]; zb = B[3*i+2];
983         xc = C[3*i+0]; yc = C[3*i+1]; zc = C[3*i+2];
984         for( j=0; j<=SUBDIV; ++j )
985             for( k=0; k<=2*(SUBDIV-j); ++k )
986             {
987                 if( k%2==0 )
988                 {
989                     u[0] = ((float)j)/(SUBDIV+1);
990                     v[0] = ((float)(k/2))/(SUBDIV+1);
991                     u[1] = ((float)(j+1))/(SUBDIV+1);
992                     v[1] = ((float)(k/2))/(SUBDIV+1);
993                     u[2] = ((float)j)/(SUBDIV+1);
994                     v[2] = ((float)(k/2+1))/(SUBDIV+1);
995                 }
996                 else
997                 {
998                     u[0] = ((float)j)/(SUBDIV+1);
999                     v[0] = ((float)(k/2+1))/(SUBDIV+1);
1000                     u[1] = ((float)(j+1))/(SUBDIV+1);
1001                     v[1] = ((float)(k/2))/(SUBDIV+1);
1002                     u[2] = ((float)(j+1))/(SUBDIV+1);
1003                     v[2] = ((float)(k/2+1))/(SUBDIV+1);
1004                 }
1005 
1006                 for( l=0; l<3; ++l )
1007                 {
1008                     x = (1.0f-u[l]-v[l])*xa + u[l]*xb + v[l]*xc;
1009                     y = (1.0f-u[l]-v[l])*ya + u[l]*yb + v[l]*yc;
1010                     z = (1.0f-u[l]-v[l])*za + u[l]*zb + v[l]*zc;
1011                     norm = sqrtf(x*x+y*y+z*z);
1012                     x /= norm; y /= norm; z /= norm;
1013                     s_SphTri.push_back(x); s_SphTri.push_back(y); s_SphTri.push_back(z);
1014                     if( u[l]+v[l]>FLOAT_EPS )
1015                         col = ColorBlend(COL_A[i], ColorBlend(COL_B[i], COL_C[i], v[l]/(u[l]+v[l])), u[l]+v[l]);
1016                     else
1017                         col = COL_A[i];
1018                     //if( (j==0 && k==0) || (j==0 && k==2*SUBDIV) || (j==SUBDIV && k==0) )
1019                     //  col = 0xffff0000;
1020                     s_SphCol.push_back(col);
1021                 }
1022             }
1023     }
1024     s_SphTriProj.clear();
1025     s_SphTriProj.resize(2*s_SphCol.size(), 0);
1026     s_SphColLight.clear();
1027     s_SphColLight.resize(s_SphCol.size(), 0);
1028 }
1029 
CreateArrow()1030 void CQuaternionExt::CreateArrow()
1031 {
1032     const int   SUBDIV  = 15;
1033     const float CYL_RADIUS  = 0.08f;
1034     const float CONE_RADIUS = 0.16f;
1035     const float CONE_LENGTH = 0.25f;
1036     const float ARROW_BGN = -1.1f;
1037     const float ARROW_END = 1.15f;
1038     int i;
1039     for(i=0; i<4; ++i)
1040     {
1041         s_ArrowTri[i].clear();
1042         s_ArrowNorm[i].clear();
1043     }
1044 
1045     float x0, x1, y0, y1, z0, z1, a0, a1, nx, nn;
1046     for(i=0; i<SUBDIV; ++i)
1047     {
1048         a0 = 2.0f*FLOAT_PI*(float(i))/SUBDIV;
1049         a1 = 2.0f*FLOAT_PI*(float(i+1))/SUBDIV;
1050         x0 = ARROW_BGN;
1051         x1 = ARROW_END-CONE_LENGTH;
1052         y0 = cosf(a0);
1053         z0 = sinf(a0);
1054         y1 = cosf(a1);
1055         z1 = sinf(a1);
1056         s_ArrowTri[ARROW_CYL].push_back(x1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z0);
1057         s_ArrowTri[ARROW_CYL].push_back(x0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z0);
1058         s_ArrowTri[ARROW_CYL].push_back(x0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z1);
1059         s_ArrowTri[ARROW_CYL].push_back(x1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z0);
1060         s_ArrowTri[ARROW_CYL].push_back(x0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z1);
1061         s_ArrowTri[ARROW_CYL].push_back(x1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z1);
1062         s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y0); s_ArrowNorm[ARROW_CYL].push_back(z0);
1063         s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y0); s_ArrowNorm[ARROW_CYL].push_back(z0);
1064         s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y1); s_ArrowNorm[ARROW_CYL].push_back(z1);
1065         s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y0); s_ArrowNorm[ARROW_CYL].push_back(z0);
1066         s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y1); s_ArrowNorm[ARROW_CYL].push_back(z1);
1067         s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y1); s_ArrowNorm[ARROW_CYL].push_back(z1);
1068         s_ArrowTri[ARROW_CYL_CAP].push_back(x0); s_ArrowTri[ARROW_CYL_CAP].push_back(0); s_ArrowTri[ARROW_CYL_CAP].push_back(0);
1069         s_ArrowTri[ARROW_CYL_CAP].push_back(x0); s_ArrowTri[ARROW_CYL_CAP].push_back(CYL_RADIUS*y1); s_ArrowTri[ARROW_CYL_CAP].push_back(CYL_RADIUS*z1);
1070         s_ArrowTri[ARROW_CYL_CAP].push_back(x0); s_ArrowTri[ARROW_CYL_CAP].push_back(CYL_RADIUS*y0); s_ArrowTri[ARROW_CYL_CAP].push_back(CYL_RADIUS*z0);
1071         s_ArrowNorm[ARROW_CYL_CAP].push_back(-1); s_ArrowNorm[ARROW_CYL_CAP].push_back(0); s_ArrowNorm[ARROW_CYL_CAP].push_back(0);
1072         s_ArrowNorm[ARROW_CYL_CAP].push_back(-1); s_ArrowNorm[ARROW_CYL_CAP].push_back(0); s_ArrowNorm[ARROW_CYL_CAP].push_back(0);
1073         s_ArrowNorm[ARROW_CYL_CAP].push_back(-1); s_ArrowNorm[ARROW_CYL_CAP].push_back(0); s_ArrowNorm[ARROW_CYL_CAP].push_back(0);
1074         x0 = ARROW_END-CONE_LENGTH;
1075         x1 = ARROW_END;
1076         nx = CONE_RADIUS/(x1-x0);
1077         nn = 1.0f/sqrtf(nx*nx+1);
1078         s_ArrowTri[ARROW_CONE].push_back(x1); s_ArrowTri[ARROW_CONE].push_back(0); s_ArrowTri[ARROW_CONE].push_back(0);
1079         s_ArrowTri[ARROW_CONE].push_back(x0); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*y0); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*z0);
1080         s_ArrowTri[ARROW_CONE].push_back(x0); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*y1); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*z1);
1081         s_ArrowTri[ARROW_CONE].push_back(x1); s_ArrowTri[ARROW_CONE].push_back(0); s_ArrowTri[ARROW_CONE].push_back(0);
1082         s_ArrowTri[ARROW_CONE].push_back(x0); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*y1); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*z1);
1083         s_ArrowTri[ARROW_CONE].push_back(x1); s_ArrowTri[ARROW_CONE].push_back(0); s_ArrowTri[ARROW_CONE].push_back(0);
1084         s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y0); s_ArrowNorm[ARROW_CONE].push_back(nn*z0);
1085         s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y0); s_ArrowNorm[ARROW_CONE].push_back(nn*z0);
1086         s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y1); s_ArrowNorm[ARROW_CONE].push_back(nn*z1);
1087         s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y0); s_ArrowNorm[ARROW_CONE].push_back(nn*z0);
1088         s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y1); s_ArrowNorm[ARROW_CONE].push_back(nn*z1);
1089         s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y1); s_ArrowNorm[ARROW_CONE].push_back(nn*z1);
1090         s_ArrowTri[ARROW_CONE_CAP].push_back(x0); s_ArrowTri[ARROW_CONE_CAP].push_back(0); s_ArrowTri[ARROW_CONE_CAP].push_back(0);
1091         s_ArrowTri[ARROW_CONE_CAP].push_back(x0); s_ArrowTri[ARROW_CONE_CAP].push_back(CONE_RADIUS*y1); s_ArrowTri[ARROW_CONE_CAP].push_back(CONE_RADIUS*z1);
1092         s_ArrowTri[ARROW_CONE_CAP].push_back(x0); s_ArrowTri[ARROW_CONE_CAP].push_back(CONE_RADIUS*y0); s_ArrowTri[ARROW_CONE_CAP].push_back(CONE_RADIUS*z0);
1093         s_ArrowNorm[ARROW_CONE_CAP].push_back(-1); s_ArrowNorm[ARROW_CONE_CAP].push_back(0); s_ArrowNorm[ARROW_CONE_CAP].push_back(0);
1094         s_ArrowNorm[ARROW_CONE_CAP].push_back(-1); s_ArrowNorm[ARROW_CONE_CAP].push_back(0); s_ArrowNorm[ARROW_CONE_CAP].push_back(0);
1095         s_ArrowNorm[ARROW_CONE_CAP].push_back(-1); s_ArrowNorm[ARROW_CONE_CAP].push_back(0); s_ArrowNorm[ARROW_CONE_CAP].push_back(0);
1096     }
1097 
1098     for(i=0; i<4; ++i)
1099     {
1100         s_ArrowTriProj[i].clear();
1101         s_ArrowTriProj[i].resize(2*(s_ArrowTri[i].size()/3), 0);
1102         s_ArrowColLight[i].clear();
1103         s_ArrowColLight[i].resize(s_ArrowTri[i].size()/3, 0);
1104     }
1105 }
1106 
QuatMult(double * out,const double * q1,const double * q2)1107 static inline void QuatMult(double *out, const double *q1, const double *q2)
1108 {
1109     out[0] = q1[3]*q2[0] + q1[0]*q2[3] + q1[1]*q2[2] - q1[2]*q2[1];
1110     out[1] = q1[3]*q2[1] + q1[1]*q2[3] + q1[2]*q2[0] - q1[0]*q2[2];
1111     out[2] = q1[3]*q2[2] + q1[2]*q2[3] + q1[0]*q2[1] - q1[1]*q2[0];
1112     out[3] = q1[3]*q2[3] - (q1[0]*q2[0] + q1[1]*q2[1] + q1[2]*q2[2]);
1113 }
1114 
QuatFromAxisAngle(double * out,const double * axis,double angle)1115 static inline void QuatFromAxisAngle(double *out, const double *axis, double angle)
1116 {
1117     double n = axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2];
1118     if( fabs(n)>DOUBLE_EPS )
1119     {
1120         double f = 0.5*angle;
1121         out[3] = cos(f);
1122         f = sin(f)/sqrt(n);
1123         out[0] = axis[0]*f;
1124         out[1] = axis[1]*f;
1125         out[2] = axis[2]*f;
1126     }
1127     else
1128     {
1129         out[3] = 1.0;
1130         out[0] = out[1] = out[2] = 0.0;
1131     }
1132 }
1133 
Vec3Cross(double * out,const double * a,const double * b)1134 static inline void Vec3Cross(double *out, const double *a, const double *b)
1135 {
1136     out[0] = a[1]*b[2]-a[2]*b[1];
1137     out[1] = a[2]*b[0]-a[0]*b[2];
1138     out[2] = a[0]*b[1]-a[1]*b[0];
1139 }
1140 
Vec3Dot(const double * a,const double * b)1141 static inline double Vec3Dot(const double *a, const double *b)
1142 {
1143     return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
1144 }
1145 
Vec3RotY(float * x,float * y,float * z)1146 static inline void Vec3RotY(float *x, float *y, float *z)
1147 {
1148     (void)y;
1149     float tmp = *x;
1150     *x = - *z;
1151     *z = tmp;
1152 }
1153 
Vec3RotZ(float * x,float * y,float * z)1154 static inline void Vec3RotZ(float *x, float *y, float *z)
1155 {
1156     (void)z;
1157     float tmp = *x;
1158     *x = - *y;
1159     *y = tmp;
1160 }
1161 
ApplyQuat(float * outX,float * outY,float * outZ,float x,float y,float z,float qx,float qy,float qz,float qs)1162 void CQuaternionExt::ApplyQuat(float *outX, float *outY, float *outZ, float x, float y, float z, float qx, float qy, float qz, float qs)
1163 {
1164     float ps = - qx * x - qy * y - qz * z;
1165     float px =   qs * x + qy * z - qz * y;
1166     float py =   qs * y + qz * x - qx * z;
1167     float pz =   qs * z + qx * y - qy * x;
1168     *outX = - ps * qx + px * qs - py * qz + pz * qy;
1169     *outY = - ps * qy + py * qs - pz * qx + px * qz;
1170     *outZ = - ps * qz + pz * qs - px * qy + py * qx;
1171 }
1172 
QuatFromDir(double * outQx,double * outQy,double * outQz,double * outQs,double dx,double dy,double dz)1173 void CQuaternionExt::QuatFromDir(double *outQx, double *outQy, double *outQz, double *outQs, double dx, double dy, double dz)
1174 {
1175     // compute a quaternion that rotates (1,0,0) to (dx,dy,dz)
1176 
1177     double dn = sqrt(dx*dx + dy*dy + dz*dz);
1178     if( dn<DOUBLE_EPS_SQ )
1179     {
1180         *outQx = *outQy = *outQz = 0;
1181         *outQs = 1;
1182     }
1183     else
1184     {
1185         double rotAxis[3] = { 0, -dz, dy };
1186         if( rotAxis[0]*rotAxis[0] + rotAxis[1]*rotAxis[1] + rotAxis[2]*rotAxis[2]<DOUBLE_EPS_SQ )
1187         {
1188             rotAxis[0] = rotAxis[1] = 0;
1189             rotAxis[2] = 1;
1190         }
1191         double rotAngle = acos(dx/dn);
1192         double rotQuat[4];
1193         QuatFromAxisAngle(rotQuat, rotAxis, rotAngle);
1194         *outQx = rotQuat[0];
1195         *outQy = rotQuat[1];
1196         *outQz = rotQuat[2];
1197         *outQs = rotQuat[3];
1198     }
1199 }
1200 
Permute(float * outX,float * outY,float * outZ,float x,float y,float z)1201 void CQuaternionExt::Permute(float *outX, float *outY, float *outZ, float x, float y, float z)
1202 {
1203     float px = x, py = y, pz = z;
1204     *outX = m_Permute[0][0]*px + m_Permute[1][0]*py + m_Permute[2][0]*pz;
1205     *outY = m_Permute[0][1]*px + m_Permute[1][1]*py + m_Permute[2][1]*pz;
1206     *outZ = m_Permute[0][2]*px + m_Permute[1][2]*py + m_Permute[2][2]*pz;
1207 }
1208 
PermuteInv(float * outX,float * outY,float * outZ,float x,float y,float z)1209 void CQuaternionExt::PermuteInv(float *outX, float *outY, float *outZ, float x, float y, float z)
1210 {
1211     float px = x, py = y, pz = z;
1212     *outX = m_Permute[0][0]*px + m_Permute[0][1]*py + m_Permute[0][2]*pz;
1213     *outY = m_Permute[1][0]*px + m_Permute[1][1]*py + m_Permute[1][2]*pz;
1214     *outZ = m_Permute[2][0]*px + m_Permute[2][1]*py + m_Permute[2][2]*pz;
1215 }
1216 
Permute(double * outX,double * outY,double * outZ,double x,double y,double z)1217 void CQuaternionExt::Permute(double *outX, double *outY, double *outZ, double x, double y, double z)
1218 {
1219     double px = x, py = y, pz = z;
1220     *outX = m_Permute[0][0]*px + m_Permute[1][0]*py + m_Permute[2][0]*pz;
1221     *outY = m_Permute[0][1]*px + m_Permute[1][1]*py + m_Permute[2][1]*pz;
1222     *outZ = m_Permute[0][2]*px + m_Permute[1][2]*py + m_Permute[2][2]*pz;
1223 }
1224 
PermuteInv(double * outX,double * outY,double * outZ,double x,double y,double z)1225 void CQuaternionExt::PermuteInv(double *outX, double *outY, double *outZ, double x, double y, double z)
1226 {
1227     double px = x, py = y, pz = z;
1228     *outX = m_Permute[0][0]*px + m_Permute[0][1]*py + m_Permute[0][2]*pz;
1229     *outY = m_Permute[1][0]*px + m_Permute[1][1]*py + m_Permute[1][2]*pz;
1230     *outZ = m_Permute[2][0]*px + m_Permute[2][1]*py + m_Permute[2][2]*pz;
1231 }
1232 
QuatD(int w,int h)1233 static inline float QuatD(int w, int h)
1234 {
1235     return (float)min(abs(w), abs(h)) - 4;
1236 }
1237 
QuatPX(float x,int w,int h)1238 static inline int QuatPX(float x, int w, int h)
1239 {
1240     return (int)(x*0.5f*QuatD(w, h) + (float)w*0.5f + 0.5f);
1241 }
1242 
QuatPY(float y,int w,int h)1243 static inline int QuatPY(float y, int w, int h)
1244 {
1245     return (int)(-y*0.5f*QuatD(w, h) + (float)h*0.5f - 0.5f);
1246 }
1247 
QuatIX(int x,int w,int h)1248 static inline float QuatIX(int x, int w, int h)
1249 {
1250     return (2.0f*(float)x - (float)w - 1.0f)/QuatD(w, h);
1251 }
1252 
QuatIY(int y,int w,int h)1253 static inline float QuatIY(int y, int w, int h)
1254 {
1255     return (-2.0f*(float)y + (float)h - 1.0f)/QuatD(w, h);
1256 }
1257 
DrawCB(int w,int h,void * _ExtValue,void * _ClientData,TwBar * _Bar,CTwVarGroup * varGrp)1258 void CQuaternionExt::DrawCB(int w, int h, void *_ExtValue, void *_ClientData, TwBar *_Bar, CTwVarGroup *varGrp)
1259 {
1260     if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
1261         return;
1262     assert( g_TwMgr->m_Graph->IsDrawing() );
1263     CQuaternionExt *ext = static_cast<CQuaternionExt *>(_ExtValue);
1264     assert( ext!=NULL );
1265     (void)_ClientData; (void)_Bar;
1266 
1267     // show/hide quat values
1268     assert( varGrp->m_Vars.size()==16 );
1269     bool visible = ext->m_ShowVal;
1270     if( ext->m_IsDir )
1271     {
1272         if(    varGrp->m_Vars[13]->m_Visible != visible
1273             || varGrp->m_Vars[14]->m_Visible != visible
1274             || varGrp->m_Vars[15]->m_Visible != visible )
1275         {
1276             varGrp->m_Vars[13]->m_Visible = visible;
1277             varGrp->m_Vars[14]->m_Visible = visible;
1278             varGrp->m_Vars[15]->m_Visible = visible;
1279             _Bar->NotUpToDate();
1280         }
1281     }
1282     else
1283     {
1284         if(    varGrp->m_Vars[4]->m_Visible != visible
1285             || varGrp->m_Vars[5]->m_Visible != visible
1286             || varGrp->m_Vars[6]->m_Visible != visible
1287             || varGrp->m_Vars[7]->m_Visible != visible )
1288         {
1289             varGrp->m_Vars[4]->m_Visible = visible;
1290             varGrp->m_Vars[5]->m_Visible = visible;
1291             varGrp->m_Vars[6]->m_Visible = visible;
1292             varGrp->m_Vars[7]->m_Visible = visible;
1293             _Bar->NotUpToDate();
1294         }
1295     }
1296 
1297     // force ext update
1298     static_cast<CTwVarAtom *>(varGrp->m_Vars[4])->ValueToDouble();
1299 
1300     assert( s_SphTri.size()>0 );
1301     assert( s_SphTri.size()==3*s_SphCol.size() );
1302     assert( s_SphTriProj.size()==2*s_SphCol.size() );
1303     assert( s_SphColLight.size()==s_SphCol.size() );
1304 
1305     if( QuatD(w, h)<=2 )
1306         return;
1307     float x, y, z, nx, ny, nz, kx, ky, kz, qx, qy, qz, qs;
1308     int i, j, k, l, m;
1309 
1310     // normalize quaternion
1311     float qn = (float)sqrt(ext->Qs*ext->Qs+ext->Qx*ext->Qx+ext->Qy*ext->Qy+ext->Qz*ext->Qz);
1312     if( qn>FLOAT_EPS )
1313     {
1314         qx = (float)ext->Qx/qn;
1315         qy = (float)ext->Qy/qn;
1316         qz = (float)ext->Qz/qn;
1317         qs = (float)ext->Qs/qn;
1318     }
1319     else
1320     {
1321         qx = qy = qz = 0;
1322         qs = 1;
1323     }
1324 
1325     double normDir = sqrt(ext->m_Dir[0]*ext->m_Dir[0] + ext->m_Dir[1]*ext->m_Dir[1] + ext->m_Dir[2]*ext->m_Dir[2]);
1326     bool drawDir = ext->m_IsDir || (normDir>DOUBLE_EPS);
1327     color32 alpha = ext->m_Highlighted ? 0xffffffff : 0xb0ffffff;
1328 
1329     // check if frame is right-handed
1330     ext->Permute(&kx, &ky, &kz, 1, 0, 0);
1331     double px[3] = { (double)kx, (double)ky, (double)kz };
1332     ext->Permute(&kx, &ky, &kz, 0, 1, 0);
1333     double py[3] = { (double)kx, (double)ky, (double)kz };
1334     ext->Permute(&kx, &ky, &kz, 0, 0, 1);
1335     double pz[3] = { (double)kx, (double)ky, (double)kz };
1336     double ez[3];
1337     Vec3Cross(ez, px, py);
1338     bool frameRightHanded = (ez[0]*pz[0]+ez[1]*pz[1]+ez[2]*pz[2] >= 0);
1339     ITwGraph::Cull cull = frameRightHanded ? ITwGraph::CULL_CW : ITwGraph::CULL_CCW;
1340 
1341     if( drawDir )
1342     {
1343         float dir[] = {(float)ext->m_Dir[0], (float)ext->m_Dir[1], (float)ext->m_Dir[2]};
1344         if( normDir<DOUBLE_EPS )
1345         {
1346             normDir = 1;
1347             dir[0] = 1;
1348         }
1349         kx = dir[0]; ky = dir[1]; kz = dir[2];
1350         double rotDirAxis[3] = { 0, -kz, ky };
1351         if( rotDirAxis[0]*rotDirAxis[0] + rotDirAxis[1]*rotDirAxis[1] + rotDirAxis[2]*rotDirAxis[2]<DOUBLE_EPS_SQ )
1352         {
1353             rotDirAxis[0] = rotDirAxis[1] = 0;
1354             rotDirAxis[2] = 1;
1355         }
1356         double rotDirAngle = acos(kx/normDir);
1357         double rotDirQuat[4];
1358         QuatFromAxisAngle(rotDirQuat, rotDirAxis, rotDirAngle);
1359 
1360         kx = 1; ky = 0; kz = 0;
1361         ApplyQuat(&kx, &ky, &kz, kx, ky, kz, (float)rotDirQuat[0], (float)rotDirQuat[1], (float)rotDirQuat[2], (float)rotDirQuat[3]);
1362         ApplyQuat(&kx, &ky, &kz, kx, ky, kz, qx, qy, qz, qs);
1363         for(k=0; k<4; ++k) // 4 parts of the arrow
1364         {
1365             // draw order
1366             ext->Permute(&x, &y, &z, kx, ky, kz);
1367             j = (z>0) ? 3-k : k;
1368 
1369             assert( s_ArrowTriProj[j].size()==2*(s_ArrowTri[j].size()/3) && s_ArrowColLight[j].size()==s_ArrowTri[j].size()/3 && s_ArrowNorm[j].size()==s_ArrowTri[j].size() );
1370             const int ntri = (int)s_ArrowTri[j].size()/3;
1371             const float *tri = &(s_ArrowTri[j][0]);
1372             const float *norm = &(s_ArrowNorm[j][0]);
1373             int *triProj = &(s_ArrowTriProj[j][0]);
1374             color32 *colLight = &(s_ArrowColLight[j][0]);
1375             for(i=0; i<ntri; ++i)
1376             {
1377                 x = tri[3*i+0]; y = tri[3*i+1]; z = tri[3*i+2];
1378                 nx = norm[3*i+0]; ny = norm[3*i+1]; nz = norm[3*i+2];
1379                 if( x>0 )
1380                     x = 2.5f*x - 2.0f;
1381                 else
1382                     x += 0.2f;
1383                 y *= 1.5f;
1384                 z *= 1.5f;
1385                 ApplyQuat(&x, &y, &z, x, y, z, (float)rotDirQuat[0], (float)rotDirQuat[1], (float)rotDirQuat[2], (float)rotDirQuat[3]);
1386                 ApplyQuat(&x, &y, &z, x, y, z, qx, qy, qz, qs);
1387                 ext->Permute(&x, &y, &z, x, y, z);
1388                 ApplyQuat(&nx, &ny, &nz, nx, ny, nz, (float)rotDirQuat[0], (float)rotDirQuat[1], (float)rotDirQuat[2], (float)rotDirQuat[3]);
1389                 ApplyQuat(&nx, &ny, &nz, nx, ny, nz, qx, qy, qz, qs);
1390                 ext->Permute(&nx, &ny, &nz, nx, ny, nz);
1391                 triProj[2*i+0] = QuatPX(x, w, h);
1392                 triProj[2*i+1] = QuatPY(y, w, h);
1393                 color32 col = (ext->m_DirColor|0xff000000) & alpha;
1394                 colLight[i] = ColorBlend(0xff000000, col, fabsf(TClamp(nz, -1.0f, 1.0f)));
1395             }
1396             if( s_ArrowTri[j].size()>=9 ) // 1 tri = 9 floats
1397                 g_TwMgr->m_Graph->DrawTriangles((int)s_ArrowTri[j].size()/9, triProj, colLight, cull);
1398         }
1399     }
1400     else
1401     {
1402         /*
1403         int px0 = QuatPX(0, w, h)-1, py0 = QuatPY(0, w, h), r0 = (int)(0.5f*QuatD(w, h)-0.5f);
1404         color32 col0 = 0x80000000;
1405         DrawArc(px0-1, py0, r0, 0, 360, col0);
1406         DrawArc(px0+1, py0, r0, 0, 360, col0);
1407         DrawArc(px0, py0-1, r0, 0, 360, col0);
1408         DrawArc(px0, py0+1, r0, 0, 360, col0);
1409         */
1410         // draw arrows & sphere
1411         const float SPH_RADIUS = 0.75f;
1412         for(m=0; m<2; ++m)  // m=0: back, m=1: front
1413         {
1414             for(l=0; l<3; ++l)  // draw 3 arrows
1415             {
1416                 kx = 1; ky = 0; kz = 0;
1417                 if( l==1 )
1418                     Vec3RotZ(&kx, &ky, &kz);
1419                 else if( l==2 )
1420                     Vec3RotY(&kx, &ky, &kz);
1421                 ApplyQuat(&kx, &ky, &kz, kx, ky, kz, qx, qy, qz, qs);
1422                 for(k=0; k<4; ++k) // 4 parts of the arrow
1423                 {
1424                     // draw order
1425                     ext->Permute(&x, &y, &z, kx, ky, kz);
1426                     j = (z>0) ? 3-k : k;
1427 
1428                     bool cone = true;
1429                     if( (m==0 && z>0) || (m==1 && z<=0) )
1430                     {
1431                         if( j==ARROW_CONE || j==ARROW_CONE_CAP ) // do not draw cone
1432                             continue;
1433                         else
1434                             cone = false;
1435                     }
1436                     assert( s_ArrowTriProj[j].size()==2*(s_ArrowTri[j].size()/3) && s_ArrowColLight[j].size()==s_ArrowTri[j].size()/3 && s_ArrowNorm[j].size()==s_ArrowTri[j].size() );
1437                     const int ntri = (int)s_ArrowTri[j].size()/3;
1438                     const float *tri = &(s_ArrowTri[j][0]);
1439                     const float *norm = &(s_ArrowNorm[j][0]);
1440                     int *triProj = &(s_ArrowTriProj[j][0]);
1441                     color32 *colLight = &(s_ArrowColLight[j][0]);
1442                     for(i=0; i<ntri; ++i)
1443                     {
1444                         x = tri[3*i+0]; y = tri[3*i+1]; z = tri[3*i+2];
1445                         if( cone && x<=0 )
1446                             x = SPH_RADIUS;
1447                         else if( !cone && x>0 )
1448                             x = -SPH_RADIUS;
1449                         nx = norm[3*i+0]; ny = norm[3*i+1]; nz = norm[3*i+2];
1450                         if( l==1 )
1451                         {
1452                             Vec3RotZ(&x, &y, &z);
1453                             Vec3RotZ(&nx, &ny, &nz);
1454                         }
1455                         else if( l==2 )
1456                         {
1457                             Vec3RotY(&x, &y, &z);
1458                             Vec3RotY(&nx, &ny, &nz);
1459                         }
1460                         ApplyQuat(&x, &y, &z, x, y, z, qx, qy, qz, qs);
1461                         ext->Permute(&x, &y, &z, x, y, z);
1462                         ApplyQuat(&nx, &ny, &nz, nx, ny, nz, qx, qy, qz, qs);
1463                         ext->Permute(&nx, &ny, &nz, nx, ny, nz);
1464                         triProj[2*i+0] = QuatPX(x, w, h);
1465                         triProj[2*i+1] = QuatPY(y, w, h);
1466                         float fade = ( m==0 && z<0 ) ? TClamp(2.0f*z*z, 0.0f, 1.0f) : 0;
1467                         float alphaFade = 1.0f;
1468                         Color32ToARGBf(alpha, &alphaFade, NULL, NULL, NULL);
1469                         alphaFade *= (1.0f-fade);
1470                         color32 alphaFadeCol = Color32FromARGBf(alphaFade, 1, 1, 1);
1471                         color32 col = (l==0) ? 0xffff0000 : ( (l==1) ? 0xff00ff00 : 0xff0000ff );
1472                         colLight[i] = ColorBlend(0xff000000, col, fabsf(TClamp(nz, -1.0f, 1.0f))) & alphaFadeCol;
1473                     }
1474                     if( s_ArrowTri[j].size()>=9 ) // 1 tri = 9 floats
1475                         g_TwMgr->m_Graph->DrawTriangles((int)s_ArrowTri[j].size()/9, triProj, colLight, cull);
1476                 }
1477             }
1478 
1479             if( m==0 )
1480             {
1481                 const float *tri = &(s_SphTri[0]);
1482                 int *triProj = &(s_SphTriProj[0]);
1483                 const color32 *col = &(s_SphCol[0]);
1484                 color32 *colLight = &(s_SphColLight[0]);
1485                 const int ntri = (int)s_SphTri.size()/3;
1486                 for(i=0; i<ntri; ++i)   // draw sphere
1487                 {
1488                     x = SPH_RADIUS*tri[3*i+0]; y = SPH_RADIUS*tri[3*i+1]; z = SPH_RADIUS*tri[3*i+2];
1489                     ApplyQuat(&x, &y, &z, x, y, z, qx, qy, qz, qs);
1490                     ext->Permute(&x, &y, &z, x, y, z);
1491                     triProj[2*i+0] = QuatPX(x, w, h);
1492                     triProj[2*i+1] = QuatPY(y, w, h);
1493                     colLight[i] = ColorBlend(0xff000000, col[i], fabsf(TClamp(z/SPH_RADIUS, -1.0f, 1.0f))) & alpha;
1494                 }
1495                 g_TwMgr->m_Graph->DrawTriangles((int)s_SphTri.size()/9, triProj, colLight, cull);
1496             }
1497         }
1498 
1499         // draw x
1500         g_TwMgr->m_Graph->DrawLine(w-12, h-36, w-12+5, h-36+5, 0xffc00000, true);
1501         g_TwMgr->m_Graph->DrawLine(w-12+5, h-36, w-12, h-36+5, 0xffc00000, true);
1502         // draw y
1503         g_TwMgr->m_Graph->DrawLine(w-12, h-25, w-12+3, h-25+4, 0xff00c000, true);
1504         g_TwMgr->m_Graph->DrawLine(w-12+5, h-25, w-12, h-25+7, 0xff00c000, true);
1505         // draw z
1506         g_TwMgr->m_Graph->DrawLine(w-12, h-12, w-12+5, h-12, 0xff0000c0, true);
1507         g_TwMgr->m_Graph->DrawLine(w-12, h-12+5, w-12+5, h-12+5, 0xff0000c0, true);
1508         g_TwMgr->m_Graph->DrawLine(w-12, h-12+5, w-12+5, h-12, 0xff0000c0, true);
1509     }
1510 
1511     // draw borders
1512     g_TwMgr->m_Graph->DrawLine(1, 0, w-1, 0, 0x40000000);
1513     g_TwMgr->m_Graph->DrawLine(w-1, 0, w-1, h-1, 0x40000000);
1514     g_TwMgr->m_Graph->DrawLine(w-1, h-1, 1, h-1, 0x40000000);
1515     g_TwMgr->m_Graph->DrawLine(1, h-1, 1, 0, 0x40000000);
1516 }
1517 
MouseMotionCB(int mouseX,int mouseY,int w,int h,void * structExtValue,void * clientData,TwBar * bar,CTwVarGroup * varGrp)1518 bool CQuaternionExt::MouseMotionCB(int mouseX, int mouseY, int w, int h, void *structExtValue, void *clientData, TwBar *bar, CTwVarGroup *varGrp)
1519 {
1520     CQuaternionExt *ext = static_cast<CQuaternionExt *>(structExtValue);
1521     if( ext==NULL )
1522         return false;
1523     (void)clientData, (void)varGrp;
1524 
1525     if( mouseX>0 && mouseX<w && mouseY>0 && mouseY<h )
1526         ext->m_Highlighted = true;
1527 
1528     if( ext->m_Rotating )
1529     {
1530         double x = QuatIX(mouseX, w, h);
1531         double y = QuatIY(mouseY, w, h);
1532         double z = 1;
1533         double px, py, pz, ox, oy, oz;
1534         ext->PermuteInv(&px, &py, &pz, x, y, z);
1535         ext->PermuteInv(&ox, &oy, &oz, ext->m_OrigX, ext->m_OrigY, 1);
1536         double n0 = sqrt(ox*ox + oy*oy + oz*oz);
1537         double n1 = sqrt(px*px + py*py + pz*pz);
1538         if( n0>DOUBLE_EPS && n1>DOUBLE_EPS )
1539         {
1540             double v0[] = { ox/n0, oy/n0, oz/n0 };
1541             double v1[] = { px/n1, py/n1, pz/n1 };
1542             double axis[3];
1543             Vec3Cross(axis, v0, v1);
1544             double sa = sqrt(Vec3Dot(axis, axis));
1545             double ca = Vec3Dot(v0, v1);
1546             double angle = atan2(sa, ca);
1547             if( x*x+y*y>1.0 )
1548                 angle *= 1.0 + 0.2f*(sqrt(x*x+y*y)-1.0);
1549             double qrot[4], qres[4], qorig[4];
1550             QuatFromAxisAngle(qrot, axis, angle);
1551             double nqorig = sqrt(ext->m_OrigQuat[0]*ext->m_OrigQuat[0]+ext->m_OrigQuat[1]*ext->m_OrigQuat[1]+ext->m_OrigQuat[2]*ext->m_OrigQuat[2]+ext->m_OrigQuat[3]*ext->m_OrigQuat[3]);
1552             if( fabs(nqorig)>DOUBLE_EPS_SQ )
1553             {
1554                 qorig[0] = ext->m_OrigQuat[0]/nqorig;
1555                 qorig[1] = ext->m_OrigQuat[1]/nqorig;
1556                 qorig[2] = ext->m_OrigQuat[2]/nqorig;
1557                 qorig[3] = ext->m_OrigQuat[3]/nqorig;
1558                 QuatMult(qres, qrot, qorig);
1559                 ext->Qx = qres[0];
1560                 ext->Qy = qres[1];
1561                 ext->Qz = qres[2];
1562                 ext->Qs = qres[3];
1563             }
1564             else
1565             {
1566                 ext->Qx = qrot[0];
1567                 ext->Qy = qrot[1];
1568                 ext->Qz = qrot[2];
1569                 ext->Qs = qrot[3];
1570             }
1571             ext->CopyToVar();
1572             if( bar!=NULL )
1573                 bar->NotUpToDate();
1574 
1575             ext->m_PrevX = x;
1576             ext->m_PrevY = y;
1577         }
1578     }
1579 
1580     return true;
1581 }
1582 
MouseButtonCB(TwMouseButtonID button,bool pressed,int mouseX,int mouseY,int w,int h,void * structExtValue,void * clientData,TwBar * bar,CTwVarGroup * varGrp)1583 bool CQuaternionExt::MouseButtonCB(TwMouseButtonID button, bool pressed, int mouseX, int mouseY, int w, int h, void *structExtValue, void *clientData, TwBar *bar, CTwVarGroup *varGrp)
1584 {
1585     CQuaternionExt *ext = static_cast<CQuaternionExt *>(structExtValue);
1586     if( ext==NULL )
1587         return false;
1588     (void)clientData; (void)bar, (void)varGrp;
1589 
1590     if( button==TW_MOUSE_LEFT )
1591     {
1592         if( pressed )
1593         {
1594             ext->m_OrigQuat[0] = ext->Qx;
1595             ext->m_OrigQuat[1] = ext->Qy;
1596             ext->m_OrigQuat[2] = ext->Qz;
1597             ext->m_OrigQuat[3] = ext->Qs;
1598             ext->m_OrigX = QuatIX(mouseX, w, h);
1599             ext->m_OrigY = QuatIY(mouseY, w, h);
1600             ext->m_PrevX = ext->m_OrigX;
1601             ext->m_PrevY = ext->m_OrigY;
1602             ext->m_Rotating = true;
1603         }
1604         else
1605             ext->m_Rotating = false;
1606     }
1607 
1608     //printf("Click %x\n", structExtValue);
1609     return true;
1610 }
1611 
MouseLeaveCB(void * structExtValue,void * clientData,TwBar * bar)1612 void CQuaternionExt::MouseLeaveCB(void *structExtValue, void *clientData, TwBar *bar)
1613 {
1614     CQuaternionExt *ext = static_cast<CQuaternionExt *>(structExtValue);
1615     if( ext==NULL )
1616         return;
1617     (void)clientData; (void)bar;
1618 
1619     //printf("Leave %x\n", structExtValue);
1620     ext->m_Highlighted = false;
1621     ext->m_Rotating = false;
1622 }
1623 
1624 
1625 //  ---------------------------------------------------------------------------
1626 //  Convertion between VC++ Debug/Release std::string
1627 //  (Needed because VC++ adds some extra info to std::string in Debug mode!)
1628 //  And resolve binary std::string incompatibility between VS2010 and other VS versions
1629 //  ---------------------------------------------------------------------------
1630 
1631 #ifdef _MSC_VER
1632 // VS2010 store the string allocator pointer at the end
1633 // VS2008 VS2012 and others store the string allocator pointer at the beginning
FixVS2010StdStringLibToClient(void * strPtr)1634 static void FixVS2010StdStringLibToClient(void *strPtr)
1635 {
1636     char *ptr = (char *)strPtr;
1637     const size_t SizeOfUndecoratedString = 16 + 2*sizeof(size_t) + sizeof(void *); // size of a VS std::string without extra debug iterator and info.
1638     assert(SizeOfUndecoratedString <= sizeof(std::string));
1639     TwType LibStdStringBaseType = (TwType)(TW_TYPE_STDSTRING&0xffff0000);
1640     void **allocAddress2008 = (void **)(ptr + sizeof(std::string) - SizeOfUndecoratedString);
1641     void **allocAddress2010 = (void **)(ptr + sizeof(std::string) - sizeof(void *));
1642     if (LibStdStringBaseType == TW_TYPE_STDSTRING_VS2008 && g_TwMgr->m_ClientStdStringBaseType == TW_TYPE_STDSTRING_VS2010)
1643     {
1644         void *allocator = *allocAddress2008;
1645         memmove(allocAddress2008, allocAddress2008 + 1, SizeOfUndecoratedString - sizeof(void *));
1646         *allocAddress2010 = allocator;
1647     }
1648     else if (LibStdStringBaseType == TW_TYPE_STDSTRING_VS2010 && g_TwMgr->m_ClientStdStringBaseType == TW_TYPE_STDSTRING_VS2008)
1649     {
1650         void *allocator = *allocAddress2010;
1651         memmove(allocAddress2008 + 1, allocAddress2008, SizeOfUndecoratedString - sizeof(void *));
1652         *allocAddress2008 = allocator;
1653     }
1654 }
1655 
FixVS2010StdStringClientToLib(void * strPtr)1656 static void FixVS2010StdStringClientToLib(void *strPtr)
1657 {
1658     char *ptr = (char *)strPtr;
1659     const size_t SizeOfUndecoratedString = 16 + 2*sizeof(size_t) + sizeof(void *); // size of a VS std::string without extra debug iterator and info.
1660     assert(SizeOfUndecoratedString <= sizeof(std::string));
1661     TwType LibStdStringBaseType = (TwType)(TW_TYPE_STDSTRING&0xffff0000);
1662     void **allocAddress2008 = (void **)(ptr + sizeof(std::string) - SizeOfUndecoratedString);
1663     void **allocAddress2010 = (void **)(ptr + sizeof(std::string) - sizeof(void *));
1664     if (LibStdStringBaseType == TW_TYPE_STDSTRING_VS2008 && g_TwMgr->m_ClientStdStringBaseType == TW_TYPE_STDSTRING_VS2010)
1665     {
1666         void *allocator = *allocAddress2010;
1667         memmove(allocAddress2008 + 1, allocAddress2008, SizeOfUndecoratedString - sizeof(void *));
1668         *allocAddress2008 = allocator;
1669     }
1670     else if (LibStdStringBaseType == TW_TYPE_STDSTRING_VS2010 && g_TwMgr->m_ClientStdStringBaseType == TW_TYPE_STDSTRING_VS2008)
1671     {
1672         void *allocator = *allocAddress2008;
1673         memmove(allocAddress2008, allocAddress2008 + 1, SizeOfUndecoratedString - sizeof(void *));
1674         *allocAddress2010 = allocator;
1675     }
1676 }
1677 #endif // _MSC_VER
1678 
CClientStdString()1679 CTwMgr::CClientStdString::CClientStdString()
1680 {
1681     memset(m_Data, 0, sizeof(m_Data));
1682 }
1683 
FromLib(const char * libStr)1684 void CTwMgr::CClientStdString::FromLib(const char *libStr)
1685 {
1686     m_LibStr = libStr; // it is ok to have a local copy here
1687     memcpy(m_Data + sizeof(void *), &m_LibStr, sizeof(std::string));
1688 #ifdef _MSC_VER
1689     FixVS2010StdStringLibToClient(m_Data + sizeof(void *));
1690 #endif
1691 }
1692 
ToClient()1693 std::string& CTwMgr::CClientStdString::ToClient()
1694 {
1695     assert( g_TwMgr!=NULL );
1696     if( g_TwMgr->m_ClientStdStringStructSize==sizeof(std::string)+sizeof(void *) )
1697         return *(std::string *)(m_Data);
1698     else if( g_TwMgr->m_ClientStdStringStructSize+sizeof(void *)==sizeof(std::string) )
1699         return *(std::string *)(m_Data + 2*sizeof(void *));
1700     else
1701     {
1702         assert( g_TwMgr->m_ClientStdStringStructSize==sizeof(std::string) );
1703         return *(std::string *)(m_Data + sizeof(void *));
1704     }
1705 }
1706 
1707 
CLibStdString()1708 CTwMgr::CLibStdString::CLibStdString()
1709 {
1710     memset(m_Data, 0, sizeof(m_Data));
1711 }
1712 
FromClient(const std::string & clientStr)1713 void CTwMgr::CLibStdString::FromClient(const std::string& clientStr)
1714 {
1715     assert( g_TwMgr!=NULL );
1716     memcpy(m_Data + sizeof(void *), &clientStr, g_TwMgr->m_ClientStdStringStructSize);
1717 #ifdef _MSC_VER
1718     FixVS2010StdStringClientToLib(m_Data + sizeof(void *));
1719 #endif
1720 }
1721 
ToLib()1722 std::string& CTwMgr::CLibStdString::ToLib()
1723 {
1724     assert( g_TwMgr!=NULL );
1725     if( g_TwMgr->m_ClientStdStringStructSize==sizeof(std::string)+sizeof(void *) )
1726         return *(std::string *)(m_Data + 2*sizeof(void *));
1727     else if( g_TwMgr->m_ClientStdStringStructSize+sizeof(void *)==sizeof(std::string) )
1728         return *(std::string *)(m_Data);
1729     else
1730     {
1731         assert( g_TwMgr->m_ClientStdStringStructSize==sizeof(std::string) );
1732         return *(std::string *)(m_Data + sizeof(void *));
1733     }
1734 }
1735 
1736 
1737 //  ---------------------------------------------------------------------------
1738 //  Management functions
1739 //  ---------------------------------------------------------------------------
1740 
1741 
TwCreateGraph(ETwGraphAPI _GraphAPI)1742 static int TwCreateGraph(ETwGraphAPI _GraphAPI)
1743 {
1744     assert( g_TwMgr!=NULL && g_TwMgr->m_Graph==NULL );
1745 
1746     switch( _GraphAPI )
1747     {
1748     case TW_OPENGL:
1749         g_TwMgr->m_Graph = new CTwGraphOpenGL;
1750         break;
1751     case TW_OPENGL_CORE:
1752         g_TwMgr->m_Graph = new CTwGraphOpenGLCore;
1753         break;
1754     case TW_DIRECT3D9:
1755         #ifdef ANT_WINDOWS
1756             if( g_TwMgr->m_Device!=NULL )
1757                 g_TwMgr->m_Graph = new CTwGraphDirect3D9;
1758             else
1759             {
1760                 g_TwMgr->SetLastError(g_ErrBadDevice);
1761                 return 0;
1762             }
1763         #endif // ANT_WINDOWS
1764         break;
1765     case TW_DIRECT3D10:
1766         #ifdef ANT_WINDOWS
1767             if( g_TwMgr->m_Device!=NULL )
1768                 g_TwMgr->m_Graph = new CTwGraphDirect3D10;
1769             else
1770             {
1771                 g_TwMgr->SetLastError(g_ErrBadDevice);
1772                 return 0;
1773             }
1774         #endif // ANT_WINDOWS
1775         break;
1776     case TW_DIRECT3D11:
1777         #ifdef ANT_WINDOWS
1778             if( g_TwMgr->m_Device!=NULL )
1779                 g_TwMgr->m_Graph = new CTwGraphDirect3D11;
1780             else
1781             {
1782                 g_TwMgr->SetLastError(g_ErrBadDevice);
1783                 return 0;
1784             }
1785         #endif // ANT_WINDOWS
1786         break;
1787     }
1788 
1789     if( g_TwMgr->m_Graph==NULL )
1790     {
1791         g_TwMgr->SetLastError(g_ErrUnknownAPI);
1792         return 0;
1793     }
1794     else
1795         return g_TwMgr->m_Graph->Init();
1796 }
1797 
1798 //  ---------------------------------------------------------------------------
1799 
TwFreeAsyncDrawing()1800 static inline int TwFreeAsyncDrawing()
1801 {
1802     if( g_TwMgr && g_TwMgr->m_Graph && g_TwMgr->m_Graph->IsDrawing() )
1803     {
1804         const double SLEEP_MAX = 0.25; // wait at most 1/4 second
1805         PerfTimer timer;
1806         while( g_TwMgr->m_Graph->IsDrawing() && timer.GetTime()<SLEEP_MAX )
1807         {
1808             #if defined(ANT_WINDOWS)
1809                 Sleep(1); // milliseconds
1810             #elif defined(ANT_UNIX) || defined(ANT_OSX)
1811                 usleep(1000); // microseconds
1812             #endif
1813         }
1814         if( g_TwMgr->m_Graph->IsDrawing() )
1815         {
1816             g_TwMgr->SetLastError(g_ErrIsDrawing);
1817             return 0;
1818         }
1819     }
1820     return 1;
1821 }
1822 
1823 //  ---------------------------------------------------------------------------
1824 
1825 /*
1826 static inline int TwFreeAsyncProcessing()
1827 {
1828     if( g_TwMgr && g_TwMgr->IsProcessing() )
1829     {
1830         const double SLEEP_MAX = 0.25; // wait at most 1/4 second
1831         PerfTimer timer;
1832         while( g_TwMgr->IsProcessing() && timer.GetTime()<SLEEP_MAX )
1833         {
1834             #if defined(ANT_WINDOWS)
1835                 Sleep(1); // milliseconds
1836             #elif defined(ANT_UNIX)
1837                 usleep(1000); // microseconds
1838             #endif
1839         }
1840         if( g_TwMgr->IsProcessing() )
1841         {
1842             g_TwMgr->SetLastError(g_ErrIsProcessing);
1843             return 0;
1844         }
1845     }
1846     return 1;
1847 }
1848 
1849 static inline int TwBeginProcessing()
1850 {
1851     if( !TwFreeAsyncProcessing() )
1852         return 0;
1853     if( g_TwMgr )
1854         g_TwMgr->SetProcessing(true);
1855 }
1856 
1857 static inline int TwEndProcessing()
1858 {
1859     if( g_TwMgr )
1860         g_TwMgr->SetProcessing(false);
1861 }
1862 */
1863 
1864 //  ---------------------------------------------------------------------------
1865 
TwInitMgr()1866 static int TwInitMgr()
1867 {
1868     assert( g_TwMasterMgr!=NULL );
1869     assert( g_TwMgr!=NULL );
1870 
1871     g_TwMgr->m_CurrentFont = g_DefaultNormalFont;
1872     g_TwMgr->m_Graph = g_TwMasterMgr->m_Graph;
1873 
1874     g_TwMgr->m_KeyPressedTextObj = g_TwMgr->m_Graph->NewTextObj();
1875     g_TwMgr->m_InfoTextObj = g_TwMgr->m_Graph->NewTextObj();
1876 
1877     g_TwMgr->m_HelpBar = TwNewBar("TW_HELP");
1878     if( g_TwMgr->m_HelpBar )
1879     {
1880         g_TwMgr->m_HelpBar->m_Label = "~ Help & Shortcuts ~";
1881         g_TwMgr->m_HelpBar->m_PosX = 32;
1882         g_TwMgr->m_HelpBar->m_PosY = 32;
1883         g_TwMgr->m_HelpBar->m_Width = 400;
1884         g_TwMgr->m_HelpBar->m_Height = 200;
1885         g_TwMgr->m_HelpBar->m_ValuesWidth = 12*(g_TwMgr->m_HelpBar->m_Font->m_CharHeight/2);
1886         g_TwMgr->m_HelpBar->m_Color = 0xa05f5f5f; //0xd75f5f5f;
1887         g_TwMgr->m_HelpBar->m_DarkText = false;
1888         g_TwMgr->m_HelpBar->m_IsHelpBar = true;
1889         g_TwMgr->Minimize(g_TwMgr->m_HelpBar);
1890     }
1891     else
1892         return 0;
1893 
1894     CColorExt::CreateTypes();
1895     CQuaternionExt::CreateTypes();
1896 
1897     return 1;
1898 }
1899 
1900 
TwInit(ETwGraphAPI _GraphAPI,void * _Device)1901 int ANT_CALL TwInit(ETwGraphAPI _GraphAPI, void *_Device)
1902 {
1903 #if defined(_DEBUG) && defined(ANT_WINDOWS)
1904     _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF));
1905 #endif
1906 
1907     if( g_TwMasterMgr!=NULL )
1908     {
1909         g_TwMasterMgr->SetLastError(g_ErrInit);
1910         return 0;
1911     }
1912     assert( g_TwMgr==0 );
1913     assert( g_Wnds.empty() );
1914 
1915     g_TwMasterMgr = new CTwMgr(_GraphAPI, _Device, TW_MASTER_WINDOW_ID);
1916     g_Wnds[TW_MASTER_WINDOW_ID] = g_TwMasterMgr;
1917     g_TwMgr = g_TwMasterMgr;
1918 
1919     TwGenerateDefaultFonts(g_FontScaling);
1920     g_TwMgr->m_CurrentFont = g_DefaultNormalFont;
1921 
1922     int Res = TwCreateGraph(_GraphAPI);
1923     if( Res )
1924         Res = TwInitMgr();
1925 
1926     if( !Res )
1927         TwTerminate();
1928 
1929     return Res;
1930 }
1931 
1932 //  ---------------------------------------------------------------------------
1933 
TwSetLastError(const char * _StaticErrorMessage)1934 int ANT_CALL TwSetLastError(const char *_StaticErrorMessage)
1935 {
1936     if( g_TwMasterMgr!=0 )
1937     {
1938         g_TwMasterMgr->SetLastError(_StaticErrorMessage);
1939         return 1;
1940     }
1941     else
1942         return 0;
1943 }
1944 
1945 //  ---------------------------------------------------------------------------
1946 
TwTerminate()1947 int ANT_CALL TwTerminate()
1948 {
1949     if( g_TwMgr==NULL )
1950     {
1951         //TwGlobalError(g_ErrShut); -> not an error
1952         return 0;  // already shutdown
1953     }
1954 
1955     // For multi-thread safety
1956     if( !TwFreeAsyncDrawing() )
1957         return 0;
1958 
1959     CTwWndMap::iterator it;
1960     for( it=g_Wnds.begin(); it!=g_Wnds.end(); it++ )
1961     {
1962         g_TwMgr = it->second;
1963 
1964         g_TwMgr->m_Terminating = true;
1965         TwDeleteAllBars();
1966         if( g_TwMgr->m_CursorsCreated )
1967             g_TwMgr->FreeCursors();
1968 
1969         if( g_TwMgr->m_Graph )
1970         {
1971             if( g_TwMgr->m_KeyPressedTextObj )
1972             {
1973                 g_TwMgr->m_Graph->DeleteTextObj(g_TwMgr->m_KeyPressedTextObj);
1974                 g_TwMgr->m_KeyPressedTextObj = NULL;
1975             }
1976             if( g_TwMgr->m_InfoTextObj )
1977             {
1978                 g_TwMgr->m_Graph->DeleteTextObj(g_TwMgr->m_InfoTextObj);
1979                 g_TwMgr->m_InfoTextObj = NULL;
1980             }
1981             if (g_TwMgr != g_TwMasterMgr)
1982                 g_TwMgr->m_Graph = NULL;
1983         }
1984 
1985         if (g_TwMgr != g_TwMasterMgr)
1986         {
1987             delete g_TwMgr;
1988             g_TwMgr = NULL;
1989         }
1990     }
1991 
1992     // delete g_TwMasterMgr
1993     int Res = 1;
1994     g_TwMgr = g_TwMasterMgr;
1995     if( g_TwMasterMgr->m_Graph )
1996     {
1997         Res = g_TwMasterMgr->m_Graph->Shut();
1998         delete g_TwMasterMgr->m_Graph;
1999         g_TwMasterMgr->m_Graph = NULL;
2000     }
2001     TwDeleteDefaultFonts();
2002     delete g_TwMasterMgr;
2003     g_TwMasterMgr = NULL;
2004     g_TwMgr = NULL;
2005     g_Wnds.clear();
2006 
2007     return Res;
2008 }
2009 
2010 //  ---------------------------------------------------------------------------
2011 
TwGetCurrentWindow()2012 int ANT_CALL TwGetCurrentWindow()
2013 {
2014     if( g_TwMgr==NULL )
2015     {
2016         TwGlobalError(g_ErrNotInit);
2017         return 0; // not initialized
2018     }
2019 
2020     return g_TwMgr->m_WndID;
2021 }
2022 
TwSetCurrentWindow(int wndID)2023 int ANT_CALL TwSetCurrentWindow(int wndID)
2024 {
2025     if( g_TwMgr==NULL )
2026     {
2027         TwGlobalError(g_ErrNotInit);
2028         return 0; // not initialized
2029     }
2030 
2031     if (wndID != g_TwMgr->m_WndID)
2032     {
2033         CTwWndMap::iterator foundWnd = g_Wnds.find(wndID);
2034         if (foundWnd == g_Wnds.end())
2035         {
2036             // create a new CTwMgr
2037             g_TwMgr = new CTwMgr(g_TwMasterMgr->m_GraphAPI, g_TwMasterMgr->m_Device, wndID);
2038             g_Wnds[wndID] = g_TwMgr;
2039             return TwInitMgr();
2040         }
2041         else
2042         {
2043             g_TwMgr = foundWnd->second;
2044             return 1;
2045         }
2046     }
2047     else
2048         return 1;
2049 }
2050 
TwWindowExists(int wndID)2051 int ANT_CALL TwWindowExists(int wndID)
2052 {
2053     CTwWndMap::iterator foundWnd = g_Wnds.find(wndID);
2054     if (foundWnd == g_Wnds.end())
2055         return 0;
2056     else
2057         return 1;
2058 }
2059 
2060 //  ---------------------------------------------------------------------------
2061 
TwDraw()2062 int ANT_CALL TwDraw()
2063 {
2064     PERF( PerfTimer Timer; double DT; )
2065     //CTwFPU fpu;   // fpu precision only forced in update (do not modif dx draw calls)
2066 
2067     if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
2068     {
2069         TwGlobalError(g_ErrNotInit);
2070         return 0; // not initialized
2071     }
2072 
2073     assert(g_TwMgr->m_Bars.size()==g_TwMgr->m_Order.size());
2074 
2075     // For multi-thread savety
2076     if( !TwFreeAsyncDrawing() )
2077         return 0;
2078 
2079     // Create cursors
2080     #if defined(ANT_WINDOWS) || defined(ANT_OSX)
2081         if( !g_TwMgr->m_CursorsCreated )
2082             g_TwMgr->CreateCursors();
2083     #elif defined(ANT_UNIX)
2084         if( !g_TwMgr->m_CurrentXDisplay )
2085             g_TwMgr->m_CurrentXDisplay = glXGetCurrentDisplay();
2086         if( !g_TwMgr->m_CurrentXWindow )
2087             g_TwMgr->m_CurrentXWindow = glXGetCurrentDrawable();
2088         if( g_TwMgr->m_CurrentXDisplay && !g_TwMgr->m_CursorsCreated )
2089             g_TwMgr->CreateCursors();
2090     #endif
2091 
2092     // Autorepeat TW_MOUSE_PRESSED
2093     double CurrTime = g_TwMgr->m_Timer.GetTime();
2094     double RepeatDT = CurrTime - g_TwMgr->m_LastMousePressedTime;
2095     double DrawDT = CurrTime - g_TwMgr->m_LastDrawTime;
2096     if(    RepeatDT>2.0*g_TwMgr->m_RepeatMousePressedDelay
2097         || DrawDT>2.0*g_TwMgr->m_RepeatMousePressedDelay
2098         || abs(g_TwMgr->m_LastMousePressedPosition[0]-g_TwMgr->m_LastMouseX)>4
2099         || abs(g_TwMgr->m_LastMousePressedPosition[1]-g_TwMgr->m_LastMouseY)>4 )
2100     {
2101         g_TwMgr->m_CanRepeatMousePressed = false;
2102         g_TwMgr->m_IsRepeatingMousePressed = false;
2103     }
2104     if( g_TwMgr->m_CanRepeatMousePressed )
2105     {
2106         if(    (!g_TwMgr->m_IsRepeatingMousePressed && RepeatDT>g_TwMgr->m_RepeatMousePressedDelay)
2107             || (g_TwMgr->m_IsRepeatingMousePressed && RepeatDT>g_TwMgr->m_RepeatMousePressedPeriod) )
2108         {
2109             g_TwMgr->m_IsRepeatingMousePressed = true;
2110             g_TwMgr->m_LastMousePressedTime = g_TwMgr->m_Timer.GetTime();
2111             TwMouseMotion(g_TwMgr->m_LastMouseX,g_TwMgr->m_LastMouseY);
2112             TwMouseButton(TW_MOUSE_PRESSED, g_TwMgr->m_LastMousePressedButtonID);
2113         }
2114     }
2115     g_TwMgr->m_LastDrawTime = CurrTime;
2116 
2117     if( g_TwMgr->m_WndWidth<0 || g_TwMgr->m_WndHeight<0 )
2118     {
2119         g_TwMgr->SetLastError(g_ErrBadSize);
2120         return 0;
2121     }
2122     else if( g_TwMgr->m_WndWidth==0 || g_TwMgr->m_WndHeight==0 )    // probably iconified
2123         return 1;   // nothing to do
2124 
2125     // count number of bars to draw
2126     size_t i, j;
2127     int Nb = 0;
2128     for( i=0; i<g_TwMgr->m_Bars.size(); ++i )
2129         if( g_TwMgr->m_Bars[i]!=NULL && g_TwMgr->m_Bars[i]->m_Visible )
2130             ++Nb;
2131 
2132     if( Nb>0 )
2133     {
2134         PERF( Timer.Reset(); )
2135         g_TwMgr->m_Graph->BeginDraw(g_TwMgr->m_WndWidth, g_TwMgr->m_WndHeight);
2136         PERF( DT = Timer.GetTime(); printf("\nBegin=%.4fms ", 1000.0*DT); )
2137 
2138         PERF( Timer.Reset(); )
2139         vector<CRect> TopBarsRects, ClippedBarRects;
2140         for( i=0; i<g_TwMgr->m_Bars.size(); ++i )
2141         {
2142             CTwBar *Bar = g_TwMgr->m_Bars[ g_TwMgr->m_Order[i] ];
2143             if( Bar->m_Visible )
2144             {
2145                 if( g_TwMgr->m_OverlapContent || Bar->IsMinimized() )
2146                     Bar->Draw();
2147                 else
2148                 {
2149                     // Clip overlapped transparent bars to make them more readable
2150                     const int Margin = 4;
2151                     CRect BarRect(Bar->m_PosX - Margin, Bar->m_PosY - Margin, Bar->m_Width + 2*Margin, Bar->m_Height + 2*Margin);
2152                     TopBarsRects.clear();
2153                     for( j=i+1; j<g_TwMgr->m_Bars.size(); ++j )
2154                     {
2155                         CTwBar *TopBar = g_TwMgr->m_Bars[g_TwMgr->m_Order[j]];
2156                         if( TopBar->m_Visible && !TopBar->IsMinimized() )
2157                             TopBarsRects.push_back(CRect(TopBar->m_PosX, TopBar->m_PosY, TopBar->m_Width, TopBar->m_Height));
2158                     }
2159                     ClippedBarRects.clear();
2160                     BarRect.Subtract(TopBarsRects, ClippedBarRects);
2161 
2162                     if( ClippedBarRects.size()==1 && ClippedBarRects[0]==BarRect )
2163                         //g_TwMgr->m_Graph->DrawRect(Bar->m_PosX, Bar->m_PosY, Bar->m_PosX+Bar->m_Width-1, Bar->m_PosY+Bar->m_Height-1, 0x70ffffff); // Clipping test
2164                         Bar->Draw(); // unclipped
2165                     else
2166                     {
2167                         Bar->Draw(CTwBar::DRAW_BG); // draw background only
2168 
2169                         // draw content for each clipped rectangle
2170                         for( j=0; j<ClippedBarRects.size(); j++ )
2171                             if (ClippedBarRects[j].W>1 && ClippedBarRects[j].H>1)
2172                             {
2173                                 g_TwMgr->m_Graph->SetScissor(ClippedBarRects[j].X+1, ClippedBarRects[j].Y, ClippedBarRects[j].W, ClippedBarRects[j].H-1);
2174                                 //g_TwMgr->m_Graph->DrawRect(0, 0, 1000, 1000, 0x70ffffff); // Clipping test
2175                                 Bar->Draw(CTwBar::DRAW_CONTENT);
2176                             }
2177                         g_TwMgr->m_Graph->SetScissor(0, 0, 0, 0);
2178                     }
2179                 }
2180             }
2181         }
2182         PERF( DT = Timer.GetTime(); printf("Draw=%.4fms ", 1000.0*DT); )
2183 
2184         PERF( Timer.Reset(); )
2185         g_TwMgr->m_Graph->EndDraw();
2186         PERF( DT = Timer.GetTime(); printf("End=%.4fms\n", 1000.0*DT); )
2187     }
2188 
2189     return 1;
2190 }
2191 
2192 //  ---------------------------------------------------------------------------
2193 
TwWindowSize(int _Width,int _Height)2194 int ANT_CALL TwWindowSize(int _Width, int _Height)
2195 {
2196     g_InitWndWidth = _Width;
2197     g_InitWndHeight = _Height;
2198 
2199     if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
2200     {
2201         //TwGlobalError(g_ErrNotInit);  -> not an error here
2202         return 0;  // not initialized
2203     }
2204 
2205     if( _Width<0 || _Height<0 )
2206     {
2207         g_TwMgr->SetLastError(g_ErrBadSize);
2208         return 0;
2209     }
2210 
2211     // For multi-thread savety
2212     if( !TwFreeAsyncDrawing() )
2213         return 0;
2214 
2215     // Delete the extra text objects
2216     if( g_TwMgr->m_KeyPressedTextObj )
2217     {
2218         g_TwMgr->m_Graph->DeleteTextObj(g_TwMgr->m_KeyPressedTextObj);
2219         g_TwMgr->m_KeyPressedTextObj = NULL;
2220     }
2221     if( g_TwMgr->m_InfoTextObj )
2222     {
2223         g_TwMgr->m_Graph->DeleteTextObj(g_TwMgr->m_InfoTextObj);
2224         g_TwMgr->m_InfoTextObj = NULL;
2225     }
2226 
2227     g_TwMgr->m_WndWidth = _Width;
2228     g_TwMgr->m_WndHeight = _Height;
2229     g_TwMgr->m_Graph->Restore();
2230 
2231     // Recreate extra text objects
2232     if( g_TwMgr->m_WndWidth!=0 && g_TwMgr->m_WndHeight!=0 )
2233     {
2234         if( g_TwMgr->m_KeyPressedTextObj==NULL )
2235         {
2236             g_TwMgr->m_KeyPressedTextObj = g_TwMgr->m_Graph->NewTextObj();
2237             g_TwMgr->m_KeyPressedBuildText = true;
2238         }
2239         if( g_TwMgr->m_InfoTextObj==NULL )
2240         {
2241             g_TwMgr->m_InfoTextObj = g_TwMgr->m_Graph->NewTextObj();
2242             g_TwMgr->m_InfoBuildText = true;
2243         }
2244     }
2245 
2246     for( std::vector<TwBar*>::iterator it=g_TwMgr->m_Bars.begin(); it!=g_TwMgr->m_Bars.end(); ++it )
2247         (*it)->NotUpToDate();
2248 
2249     return 1;
2250 }
2251 
2252 //  ---------------------------------------------------------------------------
2253 
CTwMgr(ETwGraphAPI _GraphAPI,void * _Device,int _WndID)2254 CTwMgr::CTwMgr(ETwGraphAPI _GraphAPI, void *_Device, int _WndID)
2255 {
2256     m_GraphAPI = _GraphAPI;
2257     m_Device = _Device;
2258     m_WndID = _WndID;
2259     m_LastError = NULL;
2260     m_CurrentDbgFile = "";
2261     m_CurrentDbgLine = 0;
2262     //m_Processing = false;
2263     m_Graph = NULL;
2264     m_WndWidth = g_InitWndWidth;
2265     m_WndHeight = g_InitWndHeight;
2266     m_CurrentFont = NULL;   // set after by TwIntialize
2267     m_NbMinimizedBars = 0;
2268     m_HelpBar = NULL;
2269     m_HelpBarNotUpToDate = true;
2270     m_HelpBarUpdateNow = false;
2271     m_LastHelpUpdateTime = 0;
2272     m_LastMouseX = -1;
2273     m_LastMouseY = -1;
2274     m_LastMouseWheelPos = 0;
2275     m_IconPos = 0;
2276     m_IconAlign = 0;
2277     m_IconMarginX = m_IconMarginY = 8;
2278     m_FontResizable = true;
2279     m_KeyPressedTextObj = NULL;
2280     m_KeyPressedBuildText = false;
2281     m_KeyPressedTime = 0;
2282     m_InfoTextObj = NULL;
2283     m_InfoBuildText = true;
2284     m_BarInitColorHue = 155;
2285     m_PopupBar = NULL;
2286     m_TypeColor32 = TW_TYPE_UNDEF;
2287     m_TypeColor3F = TW_TYPE_UNDEF;
2288     m_TypeColor4F = TW_TYPE_UNDEF;
2289     m_LastMousePressedTime = 0;
2290     m_LastMousePressedButtonID = TW_MOUSE_MIDDLE;
2291     m_LastMousePressedPosition[0] = -1000;
2292     m_LastMousePressedPosition[1] = -1000;
2293     m_RepeatMousePressedDelay = 0.5;
2294     m_RepeatMousePressedPeriod = 0.1;
2295     m_CanRepeatMousePressed = false;
2296     m_IsRepeatingMousePressed = false;
2297     m_LastDrawTime = 0;
2298     m_UseOldColorScheme = false;
2299     m_Contained = false;
2300     m_ButtonAlign = BUTTON_ALIGN_RIGHT;
2301     m_OverlapContent = false;
2302     m_Terminating = false;
2303 
2304     m_CursorsCreated = false;
2305     #if defined(ANT_UNIX)
2306         m_CurrentXDisplay = NULL;
2307         m_CurrentXWindow = 0;
2308     #endif  // defined(ANT_UNIX)
2309 
2310     m_CopyCDStringToClient = g_InitCopyCDStringToClient;
2311     m_CopyStdStringToClient = g_InitCopyStdStringToClient;
2312     m_ClientStdStringStructSize = 0;
2313     m_ClientStdStringBaseType = (TwType)0;
2314 }
2315 
2316 //  ---------------------------------------------------------------------------
2317 
~CTwMgr()2318 CTwMgr::~CTwMgr()
2319 {
2320 }
2321 
2322 //  ---------------------------------------------------------------------------
2323 
FindBar(const char * _Name) const2324 int CTwMgr::FindBar(const char *_Name) const
2325 {
2326     if( _Name==NULL || strlen(_Name)<=0 )
2327         return -1;
2328     int i;
2329     for( i=0; i<(int)m_Bars.size(); ++i )
2330         if( m_Bars[i]!=NULL && strcmp(_Name, m_Bars[i]->m_Name.c_str())==0 )
2331             return i;
2332     return -1;
2333 }
2334 
2335 
2336 //  ---------------------------------------------------------------------------
2337 
HasAttrib(const char * _Attrib,bool * _HasValue) const2338 int CTwMgr::HasAttrib(const char *_Attrib, bool *_HasValue) const
2339 {
2340     *_HasValue = true;
2341     if( _stricmp(_Attrib, "help")==0 )
2342         return MGR_HELP;
2343     else if( _stricmp(_Attrib, "fontsize")==0 )
2344         return MGR_FONT_SIZE;
2345     else if( _stricmp(_Attrib, "fontstyle")==0 )
2346         return MGR_FONT_STYLE;
2347     else if( _stricmp(_Attrib, "iconpos")==0 )
2348         return MGR_ICON_POS;
2349     else if( _stricmp(_Attrib, "iconalign")==0 )
2350         return MGR_ICON_ALIGN;
2351     else if( _stricmp(_Attrib, "iconmargin")==0 )
2352         return MGR_ICON_MARGIN;
2353     else if( _stricmp(_Attrib, "fontresizable")==0 )
2354         return MGR_FONT_RESIZABLE;
2355     else if( _stricmp(_Attrib, "colorscheme")==0 )
2356         return MGR_COLOR_SCHEME;
2357     else if( _stricmp(_Attrib, "contained")==0 )
2358         return MGR_CONTAINED;
2359     else if( _stricmp(_Attrib, "buttonalign")==0 )
2360         return MGR_BUTTON_ALIGN;
2361     else if( _stricmp(_Attrib, "overlap")==0 )
2362         return MGR_OVERLAP;
2363 
2364     *_HasValue = false;
2365     return 0; // not found
2366 }
2367 
SetAttrib(int _AttribID,const char * _Value)2368 int CTwMgr::SetAttrib(int _AttribID, const char *_Value)
2369 {
2370     switch( _AttribID )
2371     {
2372     case MGR_HELP:
2373         if( _Value && strlen(_Value)>0 )
2374         {
2375             m_Help = _Value;
2376             m_HelpBarNotUpToDate = true;
2377             return 1;
2378         }
2379         else
2380         {
2381             SetLastError(g_ErrNoValue);
2382             return 0;
2383         }
2384     case MGR_FONT_SIZE:
2385         if( _Value && strlen(_Value)>0 )
2386         {
2387             int s;
2388             int n = sscanf(_Value, "%d", &s);
2389             if( n==1 && s>=1 && s<=3 )
2390             {
2391                 if( s==1 )
2392                     SetFont(g_DefaultSmallFont, true);
2393                 else if( s==2 )
2394                     SetFont(g_DefaultNormalFont, true);
2395                 else if( s==3 )
2396                     SetFont(g_DefaultLargeFont, true);
2397                 return 1;
2398             }
2399             else
2400             {
2401                 SetLastError(g_ErrBadValue);
2402                 return 0;
2403             }
2404         }
2405         else
2406         {
2407             SetLastError(g_ErrNoValue);
2408             return 0;
2409         }
2410     case MGR_FONT_STYLE:
2411         if( _Value && strlen(_Value)>0 )
2412         {
2413             if( _stricmp(_Value, "fixed")==0 )
2414             {
2415                 if( m_CurrentFont!=g_DefaultFixed1Font )
2416                 {
2417                     SetFont(g_DefaultFixed1Font, true);
2418                     m_FontResizable = false; // for now fixed font is not resizable
2419                 }
2420                 return 1;
2421             }
2422             else if( _stricmp(_Value, "default")==0 )
2423             {
2424                 if( m_CurrentFont!=g_DefaultSmallFont && m_CurrentFont!=g_DefaultNormalFont && m_CurrentFont!=g_DefaultLargeFont )
2425                 {
2426                     if( m_CurrentFont == g_DefaultFixed1Font )
2427                         m_FontResizable = true;
2428                     SetFont(g_DefaultNormalFont, true);
2429                 }
2430                 return 1;
2431             }
2432             else
2433             {
2434                 SetLastError(g_ErrBadValue);
2435                 return 0;
2436             }
2437         }
2438         else
2439         {
2440             SetLastError(g_ErrNoValue);
2441             return 0;
2442         }
2443     case MGR_ICON_POS:
2444         if( _Value && strlen(_Value)>0 )
2445         {
2446             if( _stricmp(_Value, "bl")==0 || _stricmp(_Value, "lb")==0 || _stricmp(_Value, "bottomleft")==0 || _stricmp(_Value, "leftbottom")==0 )
2447             {
2448                 m_IconPos = 0;
2449                 return 1;
2450             }
2451             else if( _stricmp(_Value, "br")==0 || _stricmp(_Value, "rb")==0 || _stricmp(_Value, "bottomright")==0 || _stricmp(_Value, "rightbottom")==0 )
2452             {
2453                 m_IconPos = 1;
2454                 return 1;
2455             }
2456             else if( _stricmp(_Value, "tl")==0 || _stricmp(_Value, "lt")==0 || _stricmp(_Value, "topleft")==0 || _stricmp(_Value, "lefttop")==0 )
2457             {
2458                 m_IconPos = 2;
2459                 return 1;
2460             }
2461             else if( _stricmp(_Value, "tr")==0 || _stricmp(_Value, "rt")==0 || _stricmp(_Value, "topright")==0 || _stricmp(_Value, "righttop")==0 )
2462             {
2463                 m_IconPos = 3;
2464                 return 1;
2465             }
2466             else
2467             {
2468                 SetLastError(g_ErrBadValue);
2469                 return 0;
2470             }
2471         }
2472         else
2473         {
2474             SetLastError(g_ErrNoValue);
2475             return 0;
2476         }
2477     case MGR_ICON_ALIGN:
2478         if( _Value && strlen(_Value)>0 )
2479         {
2480             if( _stricmp(_Value, "vert")==0 || _stricmp(_Value, "vertical")==0  )
2481             {
2482                 m_IconAlign = 0;
2483                 return 1;
2484             }
2485             else if( _stricmp(_Value, "horiz")==0 || _stricmp(_Value, "horizontal")==0  )
2486             {
2487                 m_IconAlign = 1;
2488                 return 1;
2489             }
2490             else
2491             {
2492                 SetLastError(g_ErrBadValue);
2493                 return 0;
2494             }
2495         }
2496         else
2497         {
2498             SetLastError(g_ErrNoValue);
2499             return 0;
2500         }
2501     case MGR_ICON_MARGIN:
2502         if( _Value && strlen(_Value)>0 )
2503         {
2504             int x, y;
2505             int n = sscanf(_Value, "%d%d", &x, &y);
2506             if( n==2 && x>=0 && y>=0 )
2507             {
2508                 m_IconMarginX = x;
2509                 m_IconMarginY = y;
2510                 return 1;
2511             }
2512             else
2513             {
2514                 SetLastError(g_ErrBadValue);
2515                 return 0;
2516             }
2517         }
2518         else
2519         {
2520             SetLastError(g_ErrNoValue);
2521             return 0;
2522         }
2523     case MGR_FONT_RESIZABLE:
2524         if( _Value && strlen(_Value)>0 )
2525         {
2526             if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 )
2527             {
2528                 m_FontResizable = true;
2529                 return 1;
2530             }
2531             else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 )
2532             {
2533                 m_FontResizable = false;
2534                 return 1;
2535             }
2536             else
2537             {
2538                 g_TwMgr->SetLastError(g_ErrBadValue);
2539                 return 0;
2540             }
2541         }
2542         else
2543         {
2544             g_TwMgr->SetLastError(g_ErrNoValue);
2545             return 0;
2546         }
2547     case MGR_COLOR_SCHEME:
2548         if( _Value && strlen(_Value)>0 )
2549         {
2550             int s;
2551             int n = sscanf(_Value, "%d", &s);
2552             if( n==1 && s>=0 && s<=1 )
2553             {
2554                 if( s==0 )
2555                     m_UseOldColorScheme = true;
2556                 else
2557                     m_UseOldColorScheme = false;
2558                 return 1;
2559             }
2560             else
2561             {
2562                 SetLastError(g_ErrBadValue);
2563                 return 0;
2564             }
2565         }
2566         else
2567         {
2568             g_TwMgr->SetLastError(g_ErrNoValue);
2569             return 0;
2570         }
2571     case MGR_CONTAINED:
2572         if( _Value && strlen(_Value)>0 )
2573         {
2574             if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 )
2575                 m_Contained = true;
2576             else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 )
2577                 m_Contained = false;
2578             else
2579             {
2580                 g_TwMgr->SetLastError(g_ErrBadValue);
2581                 return 0;
2582             }
2583             vector<TwBar*>::iterator barIt;
2584             for( barIt=g_TwMgr->m_Bars.begin(); barIt!=g_TwMgr->m_Bars.end(); ++barIt )
2585                 if( (*barIt)!=NULL )
2586                     (*barIt)->m_Contained = m_Contained;
2587             return 1;
2588         }
2589         else
2590         {
2591             g_TwMgr->SetLastError(g_ErrNoValue);
2592             return 0;
2593         }
2594     case MGR_BUTTON_ALIGN:
2595         if( _Value && strlen(_Value)>0 )
2596         {
2597             if( _stricmp(_Value, "left")==0 )
2598                 m_ButtonAlign = BUTTON_ALIGN_LEFT;
2599             else if( _stricmp(_Value, "center")==0 )
2600                 m_ButtonAlign = BUTTON_ALIGN_CENTER;
2601             else if( _stricmp(_Value, "right")==0 )
2602                 m_ButtonAlign = BUTTON_ALIGN_RIGHT;
2603             else
2604             {
2605                 g_TwMgr->SetLastError(g_ErrBadValue);
2606                 return 0;
2607             }
2608             vector<TwBar*>::iterator barIt;
2609             for( barIt=g_TwMgr->m_Bars.begin(); barIt!=g_TwMgr->m_Bars.end(); ++barIt )
2610                 if( (*barIt)!=NULL )
2611                     (*barIt)->m_ButtonAlign = m_ButtonAlign;
2612             return 1;
2613         }
2614         else
2615         {
2616             g_TwMgr->SetLastError(g_ErrNoValue);
2617             return 0;
2618         }
2619     case MGR_OVERLAP:
2620         if( _Value && strlen(_Value)>0 )
2621         {
2622             if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 )
2623             {
2624                 m_OverlapContent = true;
2625                 return 1;
2626             }
2627             else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 )
2628             {
2629                 m_OverlapContent = false;
2630                 return 1;
2631             }
2632             else
2633             {
2634                 g_TwMgr->SetLastError(g_ErrBadValue);
2635                 return 0;
2636             }
2637         }
2638         else
2639         {
2640             g_TwMgr->SetLastError(g_ErrNoValue);
2641             return 0;
2642         }
2643     default:
2644         g_TwMgr->SetLastError(g_ErrUnknownAttrib);
2645         return 0;
2646     }
2647 }
2648 
GetAttrib(int _AttribID,std::vector<double> & outDoubles,std::ostringstream & outString) const2649 ERetType CTwMgr::GetAttrib(int _AttribID, std::vector<double>& outDoubles, std::ostringstream& outString) const
2650 {
2651     outDoubles.clear();
2652     outString.clear();
2653 
2654     switch( _AttribID )
2655     {
2656     case MGR_HELP:
2657         outString << m_Help;
2658         return RET_STRING;
2659     case MGR_FONT_SIZE:
2660         if( m_CurrentFont==g_DefaultSmallFont )
2661             outDoubles.push_back(1);
2662         else if( m_CurrentFont==g_DefaultNormalFont )
2663             outDoubles.push_back(2);
2664         else if( m_CurrentFont==g_DefaultLargeFont )
2665             outDoubles.push_back(3);
2666         else
2667             outDoubles.push_back(0); // should not happened
2668         return RET_DOUBLE;
2669     case MGR_FONT_STYLE:
2670         if( m_CurrentFont==g_DefaultFixed1Font )
2671             outString << "fixed";
2672         else
2673             outString << "default";
2674         return RET_STRING;
2675     case MGR_ICON_POS:
2676         if( m_IconPos==0 )
2677             outString << "bottomleft";
2678         else if( m_IconPos==1 )
2679             outString << "bottomright";
2680         else if( m_IconPos==2 )
2681             outString << "topleft";
2682         else if( m_IconPos==3 )
2683             outString << "topright";
2684         else
2685             outString << "undefined"; // should not happened
2686         return RET_STRING;
2687     case MGR_ICON_ALIGN:
2688         if( m_IconAlign==0 )
2689             outString << "vertical";
2690         else if( m_IconAlign==1 )
2691             outString << "horizontal";
2692         else
2693             outString << "undefined"; // should not happened
2694         return RET_STRING;
2695     case MGR_ICON_MARGIN:
2696         outDoubles.push_back(m_IconMarginX);
2697         outDoubles.push_back(m_IconMarginY);
2698         return RET_DOUBLE;
2699     case MGR_FONT_RESIZABLE:
2700         outDoubles.push_back(m_FontResizable);
2701         return RET_DOUBLE;
2702     case MGR_COLOR_SCHEME:
2703         outDoubles.push_back(m_UseOldColorScheme ? 0 : 1);
2704         return RET_DOUBLE;
2705     case MGR_CONTAINED:
2706         {
2707             bool contained = m_Contained;
2708             /*
2709             if( contained )
2710             {
2711                 vector<TwBar*>::iterator barIt;
2712                 for( barIt=g_TwMgr->m_Bars.begin(); barIt!=g_TwMgr->m_Bars.end(); ++barIt )
2713                     if( (*barIt)!=NULL && !(*barIt)->m_Contained )
2714                     {
2715                         contained = false;
2716                         break;
2717                     }
2718             }
2719             */
2720             outDoubles.push_back(contained);
2721             return RET_DOUBLE;
2722         }
2723     case MGR_BUTTON_ALIGN:
2724         if( m_ButtonAlign==BUTTON_ALIGN_LEFT )
2725             outString << "left";
2726         else if( m_ButtonAlign==BUTTON_ALIGN_CENTER )
2727             outString << "center";
2728         else
2729             outString << "right";
2730         return RET_STRING;
2731     case MGR_OVERLAP:
2732         outDoubles.push_back(m_OverlapContent);
2733         return RET_DOUBLE;
2734     default:
2735         g_TwMgr->SetLastError(g_ErrUnknownAttrib);
2736         return RET_ERROR;
2737     }
2738 }
2739 
2740 //  ---------------------------------------------------------------------------
2741 
Minimize(TwBar * _Bar)2742 void CTwMgr::Minimize(TwBar *_Bar)
2743 {
2744     assert(m_Graph!=NULL && _Bar!=NULL);
2745     assert(m_Bars.size()==m_MinOccupied.size());
2746     if( _Bar->m_IsMinimized )
2747         return;
2748     if( _Bar->m_Visible )
2749     {
2750         size_t i = m_NbMinimizedBars;
2751         m_NbMinimizedBars++;
2752         for( i=0; i<m_MinOccupied.size(); ++i )
2753             if( !m_MinOccupied[i] )
2754                 break;
2755         if( i<m_MinOccupied.size() )
2756             m_MinOccupied[i] = true;
2757         _Bar->m_MinNumber = (int)i;
2758     }
2759     else
2760         _Bar->m_MinNumber = -1;
2761     _Bar->m_IsMinimized = true;
2762     _Bar->NotUpToDate();
2763 }
2764 
2765 //  ---------------------------------------------------------------------------
2766 
Maximize(TwBar * _Bar)2767 void CTwMgr::Maximize(TwBar *_Bar)
2768 {
2769     assert(m_Graph!=NULL && _Bar!=NULL);
2770     assert(m_Bars.size()==m_MinOccupied.size());
2771     if( !_Bar->m_IsMinimized )
2772         return;
2773     if( _Bar->m_Visible )
2774     {
2775         --m_NbMinimizedBars;
2776         if( m_NbMinimizedBars<0 )
2777             m_NbMinimizedBars = 0;
2778         if( _Bar->m_MinNumber>=0 && _Bar->m_MinNumber<(int)m_MinOccupied.size() )
2779             m_MinOccupied[_Bar->m_MinNumber] = false;
2780     }
2781     _Bar->m_IsMinimized = false;
2782     _Bar->NotUpToDate();
2783     if( _Bar->m_IsHelpBar )
2784         m_HelpBarNotUpToDate = true;
2785 }
2786 
2787 //  ---------------------------------------------------------------------------
2788 
Hide(TwBar * _Bar)2789 void CTwMgr::Hide(TwBar *_Bar)
2790 {
2791     assert(m_Graph!=NULL && _Bar!=NULL);
2792     if( !_Bar->m_Visible )
2793         return;
2794     if( _Bar->IsMinimized() )
2795     {
2796         Maximize(_Bar);
2797         _Bar->m_Visible = false;
2798         Minimize(_Bar);
2799     }
2800     else
2801         _Bar->m_Visible = false;
2802     if( !_Bar->m_IsHelpBar )
2803         m_HelpBarNotUpToDate = true;
2804 }
2805 
2806 //  ---------------------------------------------------------------------------
2807 
Unhide(TwBar * _Bar)2808 void CTwMgr::Unhide(TwBar *_Bar)
2809 {
2810     assert(m_Graph!=NULL && _Bar!=NULL);
2811     if( _Bar->m_Visible )
2812         return;
2813     if( _Bar->IsMinimized() )
2814     {
2815         Maximize(_Bar);
2816         _Bar->m_Visible = true;
2817         Minimize(_Bar);
2818     }
2819     else
2820         _Bar->m_Visible = true;
2821     _Bar->NotUpToDate();
2822     if( !_Bar->m_IsHelpBar )
2823         m_HelpBarNotUpToDate = true;
2824 }
2825 
2826 //  ---------------------------------------------------------------------------
2827 
SetFont(const CTexFont * _Font,bool _ResizeBars)2828 void CTwMgr::SetFont(const CTexFont *_Font, bool _ResizeBars)
2829 {
2830     assert(m_Graph!=NULL);
2831     assert(_Font!=NULL);
2832 
2833     m_CurrentFont = _Font;
2834 
2835     for( int i=0; i<(int)m_Bars.size(); ++i )
2836         if( m_Bars[i]!=NULL )
2837         {
2838             int fh = m_Bars[i]->m_Font->m_CharHeight;
2839             m_Bars[i]->m_Font = _Font;
2840             if( _ResizeBars )
2841             {
2842                 if( m_Bars[i]->m_Movable )
2843                 {
2844                     m_Bars[i]->m_PosX += (3*(fh-_Font->m_CharHeight))/2;
2845                     m_Bars[i]->m_PosY += (fh-_Font->m_CharHeight)/2;
2846                 }
2847                 if( m_Bars[i]->m_Resizable )
2848                 {
2849                     m_Bars[i]->m_Width = (m_Bars[i]->m_Width*_Font->m_CharHeight)/fh;
2850                     m_Bars[i]->m_Height = (m_Bars[i]->m_Height*_Font->m_CharHeight)/fh;
2851                     m_Bars[i]->m_ValuesWidth = (m_Bars[i]->m_ValuesWidth*_Font->m_CharHeight)/fh;
2852                 }
2853             }
2854             m_Bars[i]->NotUpToDate();
2855         }
2856 
2857     if( g_TwMgr->m_HelpBar!=NULL )
2858         g_TwMgr->m_HelpBar->Update();
2859     g_TwMgr->m_InfoBuildText = true;
2860     g_TwMgr->m_KeyPressedBuildText = true;
2861     m_HelpBarNotUpToDate = true;
2862 }
2863 
2864 //  ---------------------------------------------------------------------------
2865 
TwGlobalError(const char * _ErrorMessage)2866 void ANT_CALL TwGlobalError(const char *_ErrorMessage)  // to be called when g_TwMasterMgr is not created
2867 {
2868     if( g_ErrorHandler==NULL )
2869     {
2870         fprintf(stderr, "ERROR(AntTweakBar) >> %s\n", _ErrorMessage);
2871     #ifdef ANT_WINDOWS
2872         OutputDebugString("ERROR(AntTweakBar) >> ");
2873         OutputDebugString(_ErrorMessage);
2874         OutputDebugString("\n");
2875     #endif // ANT_WINDOWS
2876     }
2877     else
2878         g_ErrorHandler(_ErrorMessage);
2879 
2880     if( g_BreakOnError )
2881         abort();
2882 }
2883 
2884 //  ---------------------------------------------------------------------------
2885 
SetLastError(const char * _ErrorMessage)2886 void CTwMgr::SetLastError(const char *_ErrorMessage)    // _ErrorMessage must be a static string
2887 {
2888     if (this != g_TwMasterMgr)
2889     {
2890         // route to master
2891         g_TwMasterMgr->SetLastError(_ErrorMessage);
2892         return;
2893     }
2894 
2895     m_LastError = _ErrorMessage;
2896 
2897     if( g_ErrorHandler==NULL )
2898     {
2899         if( m_CurrentDbgFile!=NULL && strlen(m_CurrentDbgFile)>0 && m_CurrentDbgLine>0 )
2900             fprintf(stderr, "%s(%d): ", m_CurrentDbgFile, m_CurrentDbgLine);
2901         fprintf(stderr, "ERROR(AntTweakBar) >> %s\n", m_LastError);
2902     #ifdef ANT_WINDOWS
2903         if( m_CurrentDbgFile!=NULL && strlen(m_CurrentDbgFile)>0 && m_CurrentDbgLine>0 )
2904         {
2905             OutputDebugString(m_CurrentDbgFile);
2906             char sl[32];
2907             sprintf(sl, "(%d): ", m_CurrentDbgLine);
2908             OutputDebugString(sl);
2909         }
2910         OutputDebugString("ERROR(AntTweakBar) >> ");
2911         OutputDebugString(m_LastError);
2912         OutputDebugString("\n");
2913     #endif // ANT_WINDOWS
2914     }
2915     else
2916         g_ErrorHandler(_ErrorMessage);
2917 
2918     if( g_BreakOnError )
2919         abort();
2920 }
2921 
2922 //  ---------------------------------------------------------------------------
2923 
GetLastError()2924 const char *CTwMgr::GetLastError()
2925 {
2926     if (this != g_TwMasterMgr)
2927     {
2928         // route to master
2929         return g_TwMasterMgr->GetLastError();
2930     }
2931 
2932     const char *Err = m_LastError;
2933     m_LastError = NULL;
2934     return Err;
2935 }
2936 
2937 //  ---------------------------------------------------------------------------
2938 
CheckLastError() const2939 const char *CTwMgr::CheckLastError() const
2940 {
2941     return m_LastError;
2942 }
2943 
2944 //  ---------------------------------------------------------------------------
2945 
SetCurrentDbgParams(const char * dbgFile,int dbgLine)2946 void CTwMgr::SetCurrentDbgParams(const char *dbgFile, int dbgLine)
2947 {
2948     m_CurrentDbgFile = dbgFile;
2949     m_CurrentDbgLine = dbgLine;
2950 }
2951 
2952 //  ---------------------------------------------------------------------------
2953 
__TwDbg(const char * dbgFile,int dbgLine)2954 int ANT_CALL __TwDbg(const char *dbgFile, int dbgLine)
2955 {
2956     if( g_TwMgr!=NULL )
2957         g_TwMgr->SetCurrentDbgParams(dbgFile, dbgLine);
2958     return 0;   // always returns zero
2959 }
2960 
2961 //  ---------------------------------------------------------------------------
2962 
TwHandleErrors(TwErrorHandler _ErrorHandler,int _BreakOnError)2963 void ANT_CALL TwHandleErrors(TwErrorHandler _ErrorHandler, int _BreakOnError)
2964 {
2965     g_ErrorHandler = _ErrorHandler;
2966     g_BreakOnError = (_BreakOnError) ? true : false;
2967 }
2968 
TwHandleErrors(TwErrorHandler _ErrorHandler)2969 void ANT_CALL TwHandleErrors(TwErrorHandler _ErrorHandler)
2970 {
2971     TwHandleErrors(_ErrorHandler, false);
2972 }
2973 
2974 //  ---------------------------------------------------------------------------
2975 
TwGetLastError()2976 const char *ANT_CALL TwGetLastError()
2977 {
2978     if( g_TwMasterMgr==NULL )
2979     {
2980         TwGlobalError(g_ErrNotInit);
2981         return g_ErrNotInit;
2982     }
2983     else
2984         return g_TwMasterMgr->GetLastError();
2985 }
2986 
2987 //  ---------------------------------------------------------------------------
2988 
TwNewBar(const char * _Name)2989 TwBar *ANT_CALL TwNewBar(const char *_Name)
2990 {
2991     if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
2992     {
2993         TwGlobalError(g_ErrNotInit);
2994         return NULL; // not initialized
2995     }
2996 
2997     TwFreeAsyncDrawing(); // For multi-thread savety
2998 
2999     if( _Name==NULL || strlen(_Name)<=0 )
3000     {
3001         g_TwMgr->SetLastError(g_ErrBadParam);
3002         return NULL;
3003     }
3004     if( g_TwMgr->FindBar(_Name)>=0 )
3005     {
3006         g_TwMgr->SetLastError(g_ErrExist);
3007         return NULL;
3008     }
3009 
3010     if( strstr(_Name, "`")!=NULL )
3011     {
3012         g_TwMgr->SetLastError(g_ErrNoBackQuote);
3013         return NULL;
3014     }
3015 
3016     if( g_TwMgr->m_PopupBar!=NULL ) // delete popup bar if it exists
3017     {
3018         TwDeleteBar(g_TwMgr->m_PopupBar);
3019         g_TwMgr->m_PopupBar = NULL;
3020     }
3021 
3022     TwBar *Bar = new CTwBar(_Name);
3023     g_TwMgr->m_Bars.push_back(Bar);
3024     g_TwMgr->m_Order.push_back((int)g_TwMgr->m_Bars.size()-1);
3025     g_TwMgr->m_MinOccupied.push_back(false);
3026     g_TwMgr->m_HelpBarNotUpToDate = true;
3027 
3028     return Bar;
3029 }
3030 
3031 //  ---------------------------------------------------------------------------
3032 
TwDeleteBar(TwBar * _Bar)3033 int ANT_CALL TwDeleteBar(TwBar *_Bar)
3034 {
3035     if( g_TwMgr==NULL )
3036     {
3037         TwGlobalError(g_ErrNotInit);
3038         return 0; // not initialized
3039     }
3040     if( _Bar==NULL )
3041     {
3042         g_TwMgr->SetLastError(g_ErrBadParam);
3043         return 0;
3044     }
3045     if( _Bar==g_TwMgr->m_HelpBar )
3046     {
3047         g_TwMgr->SetLastError(g_ErrDelHelp);
3048         return 0;
3049     }
3050 
3051     TwFreeAsyncDrawing(); // For multi-thread savety
3052 
3053     vector<TwBar*>::iterator BarIt;
3054     int i = 0;
3055     for( BarIt=g_TwMgr->m_Bars.begin(); BarIt!=g_TwMgr->m_Bars.end(); ++BarIt, ++i )
3056         if( (*BarIt)==_Bar )
3057             break;
3058     if( BarIt==g_TwMgr->m_Bars.end() )
3059     {
3060         g_TwMgr->SetLastError(g_ErrNotFound);
3061         return 0;
3062     }
3063 
3064     if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar )    // delete popup bar first if it exists
3065     {
3066         TwDeleteBar(g_TwMgr->m_PopupBar);
3067         g_TwMgr->m_PopupBar = NULL;
3068     }
3069 
3070     // force bar to un-minimize
3071     g_TwMgr->Maximize(_Bar);
3072     // find an empty MinOccupied
3073     vector<bool>::iterator itm;
3074     int j = 0;
3075     for( itm=g_TwMgr->m_MinOccupied.begin(); itm!=g_TwMgr->m_MinOccupied.end(); ++itm, ++j)
3076         if( (*itm)==false )
3077             break;
3078     assert( itm!=g_TwMgr->m_MinOccupied.end() );
3079     // shift MinNumbers and erase the empty MinOccupied
3080     for( size_t k=0; k<g_TwMgr->m_Bars.size(); ++k )
3081         if( g_TwMgr->m_Bars[k]!=NULL && g_TwMgr->m_Bars[k]->m_MinNumber>j )
3082             g_TwMgr->m_Bars[k]->m_MinNumber -= 1;
3083     g_TwMgr->m_MinOccupied.erase(itm);
3084     // erase _Bar order
3085     vector<int>::iterator BarOrderIt = g_TwMgr->m_Order.end();
3086     for(vector<int>::iterator it=g_TwMgr->m_Order.begin(); it!=g_TwMgr->m_Order.end(); ++it )
3087         if( (*it)==i )
3088             BarOrderIt = it;
3089         else if( (*it)>i )
3090             (*it) -= 1;
3091     assert( BarOrderIt!=g_TwMgr->m_Order.end() );
3092     g_TwMgr->m_Order.erase(BarOrderIt);
3093 
3094     // erase & delete _Bar
3095     g_TwMgr->m_Bars.erase(BarIt);
3096     delete _Bar;
3097 
3098     g_TwMgr->m_HelpBarNotUpToDate = true;
3099     return 1;
3100 }
3101 
3102 //  ---------------------------------------------------------------------------
3103 
TwDeleteAllBars()3104 int ANT_CALL TwDeleteAllBars()
3105 {
3106     if( g_TwMgr==NULL )
3107     {
3108         TwGlobalError(g_ErrNotInit);
3109         return 0; // not initialized
3110     }
3111 
3112     TwFreeAsyncDrawing(); // For multi-thread savety
3113 
3114     int n = 0;
3115     if( g_TwMgr->m_Terminating || g_TwMgr->m_HelpBar==NULL )
3116     {
3117         for( size_t i=0; i<g_TwMgr->m_Bars.size(); ++i )
3118             if( g_TwMgr->m_Bars[i]!=NULL )
3119             {
3120                 ++n;
3121                 delete g_TwMgr->m_Bars[i];
3122                 g_TwMgr->m_Bars[i] = NULL;
3123             }
3124         g_TwMgr->m_Bars.clear();
3125         g_TwMgr->m_Order.clear();
3126         g_TwMgr->m_MinOccupied.clear();
3127         g_TwMgr->m_HelpBarNotUpToDate = true;
3128     }
3129     else
3130     {
3131         vector<CTwBar *> bars = g_TwMgr->m_Bars;
3132         for( size_t i = 0; i < bars.size(); ++i )
3133             if( bars[i]!=0 && bars[i]!=g_TwMgr->m_HelpBar)
3134             {
3135                 ++n;
3136                 TwDeleteBar(bars[i]);
3137             }
3138         g_TwMgr->m_HelpBarNotUpToDate = true;
3139     }
3140 
3141     if( n==0 )
3142     {
3143         //g_TwMgr->SetLastError(g_ErrNthToDo);
3144         return 0;
3145     }
3146     else
3147         return 1;
3148 }
3149 
3150 //  ---------------------------------------------------------------------------
3151 
TwSetTopBar(const TwBar * _Bar)3152 int ANT_CALL TwSetTopBar(const TwBar *_Bar)
3153 {
3154     if( g_TwMgr==NULL )
3155     {
3156         TwGlobalError(g_ErrNotInit);
3157         return 0; // not initialized
3158     }
3159     if( _Bar==NULL )
3160     {
3161         g_TwMgr->SetLastError(g_ErrBadParam);
3162         return 0;
3163     }
3164 
3165     TwFreeAsyncDrawing(); // For multi-thread savety
3166 
3167     if( _Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_BarAlwaysOnBottom.length()>0 )
3168     {
3169         if( strcmp(_Bar->m_Name.c_str(), g_TwMgr->m_BarAlwaysOnBottom.c_str())==0 )
3170             return TwSetBottomBar(_Bar);
3171     }
3172 
3173     int i = -1, iOrder;
3174     for( iOrder=0; iOrder<(int)g_TwMgr->m_Bars.size(); ++iOrder )
3175     {
3176         i = g_TwMgr->m_Order[iOrder];
3177         assert( i>=0 && i<(int)g_TwMgr->m_Bars.size() );
3178         if( g_TwMgr->m_Bars[i]==_Bar )
3179             break;
3180     }
3181     if( i<0 || iOrder>=(int)g_TwMgr->m_Bars.size() )    // bar not found
3182     {
3183         g_TwMgr->SetLastError(g_ErrNotFound);
3184         return 0;
3185     }
3186 
3187     for( int j=iOrder; j<(int)g_TwMgr->m_Bars.size()-1; ++j )
3188         g_TwMgr->m_Order[j] = g_TwMgr->m_Order[j+1];
3189     g_TwMgr->m_Order[(int)g_TwMgr->m_Bars.size()-1] = i;
3190 
3191     if( _Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_BarAlwaysOnTop.length()>0 )
3192     {
3193         int topIdx = g_TwMgr->FindBar(g_TwMgr->m_BarAlwaysOnTop.c_str());
3194         TwBar *top = (topIdx>=0 && topIdx<(int)g_TwMgr->m_Bars.size()) ? g_TwMgr->m_Bars[topIdx] : NULL;
3195         if( top!=NULL && top!=_Bar )
3196             TwSetTopBar(top);
3197     }
3198 
3199     if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar )
3200         TwSetTopBar(g_TwMgr->m_PopupBar);
3201 
3202     return 1;
3203 }
3204 
3205 //  ---------------------------------------------------------------------------
3206 
TwGetTopBar()3207 TwBar * ANT_CALL TwGetTopBar()
3208 {
3209     if( g_TwMgr==NULL )
3210     {
3211         TwGlobalError(g_ErrNotInit);
3212         return NULL; // not initialized
3213     }
3214 
3215     if( g_TwMgr->m_Bars.size()>0 && g_TwMgr->m_PopupBar==NULL )
3216         return g_TwMgr->m_Bars[g_TwMgr->m_Order[ g_TwMgr->m_Bars.size()-1 ]];
3217     else if( g_TwMgr->m_Bars.size()>1 && g_TwMgr->m_PopupBar!=NULL )
3218         return g_TwMgr->m_Bars[g_TwMgr->m_Order[ g_TwMgr->m_Bars.size()-2 ]];
3219     else
3220         return NULL;
3221 }
3222 
3223 //  ---------------------------------------------------------------------------
3224 
TwSetBottomBar(const TwBar * _Bar)3225 int ANT_CALL TwSetBottomBar(const TwBar *_Bar)
3226 {
3227     if( g_TwMgr==NULL )
3228     {
3229         TwGlobalError(g_ErrNotInit);
3230         return 0; // not initialized
3231     }
3232     if( _Bar==NULL )
3233     {
3234         g_TwMgr->SetLastError(g_ErrBadParam);
3235         return 0;
3236     }
3237 
3238     TwFreeAsyncDrawing(); // For multi-thread savety
3239 
3240     if( _Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_BarAlwaysOnTop.length()>0 )
3241     {
3242         if( strcmp(_Bar->m_Name.c_str(), g_TwMgr->m_BarAlwaysOnTop.c_str())==0 )
3243             return TwSetTopBar(_Bar);
3244     }
3245 
3246     int i = -1, iOrder;
3247     for( iOrder=0; iOrder<(int)g_TwMgr->m_Bars.size(); ++iOrder )
3248     {
3249         i = g_TwMgr->m_Order[iOrder];
3250         assert( i>=0 && i<(int)g_TwMgr->m_Bars.size() );
3251         if( g_TwMgr->m_Bars[i]==_Bar )
3252             break;
3253     }
3254     if( i<0 || iOrder>=(int)g_TwMgr->m_Bars.size() )    // bar not found
3255     {
3256         g_TwMgr->SetLastError(g_ErrNotFound);
3257         return 0;
3258     }
3259 
3260     if( iOrder>0 )
3261         for( int j=iOrder-1; j>=0; --j )
3262             g_TwMgr->m_Order[j+1] = g_TwMgr->m_Order[j];
3263     g_TwMgr->m_Order[0] = i;
3264 
3265     if( _Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_BarAlwaysOnBottom.length()>0 )
3266     {
3267         int btmIdx = g_TwMgr->FindBar(g_TwMgr->m_BarAlwaysOnBottom.c_str());
3268         TwBar *btm = (btmIdx>=0 && btmIdx<(int)g_TwMgr->m_Bars.size()) ? g_TwMgr->m_Bars[btmIdx] : NULL;
3269         if( btm!=NULL && btm!=_Bar )
3270             TwSetBottomBar(btm);
3271     }
3272 
3273     return 1;
3274 }
3275 
3276 //  ---------------------------------------------------------------------------
3277 
TwGetBottomBar()3278 TwBar* ANT_CALL TwGetBottomBar()
3279 {
3280     if( g_TwMgr==NULL )
3281     {
3282         TwGlobalError(g_ErrNotInit);
3283         return NULL; // not initialized
3284     }
3285 
3286     if( g_TwMgr->m_Bars.size()>0 )
3287         return g_TwMgr->m_Bars[g_TwMgr->m_Order[0]];
3288     else
3289         return NULL;
3290 }
3291 
3292 //  ---------------------------------------------------------------------------
3293 
TwSetBarState(TwBar * _Bar,TwState _State)3294 int ANT_CALL TwSetBarState(TwBar *_Bar, TwState _State)
3295 {
3296     if( g_TwMgr==NULL )
3297     {
3298         TwGlobalError(g_ErrNotInit);
3299         return 0;  // not initialized
3300     }
3301     if( _Bar==NULL )
3302     {
3303         g_TwMgr->SetLastError(g_ErrBadParam);
3304         return 0;
3305     }
3306 
3307     TwFreeAsyncDrawing(); // For multi-thread savety
3308 
3309     switch( _State )
3310     {
3311     case TW_STATE_SHOWN:
3312         g_TwMgr->Unhide(_Bar);
3313         return 1;
3314     case TW_STATE_ICONIFIED:
3315         //g_TwMgr->Unhide(_Bar);
3316         g_TwMgr->Minimize(_Bar);
3317         return 1;
3318     case TW_STATE_HIDDEN:
3319         //g_TwMgr->Maximize(_Bar);
3320         g_TwMgr->Hide(_Bar);
3321         return 1;
3322     case TW_STATE_UNICONIFIED:
3323         //g_TwMgr->Unhide(_Bar);
3324         g_TwMgr->Maximize(_Bar);
3325         return 1;
3326     default:
3327         g_TwMgr->SetLastError(g_ErrBadParam);
3328         return 0;
3329     }
3330 }
3331 
3332 //  ---------------------------------------------------------------------------
3333 
3334 /*
3335 TwState ANT_CALL TwGetBarState(const TwBar *_Bar)
3336 {
3337     if( g_TwMgr==NULL )
3338     {
3339         TwGlobalError(g_ErrNotInit);
3340         return TW_STATE_ERROR;  // not initialized
3341     }
3342     if( _Bar==NULL )
3343     {
3344         g_TwMgr->SetLastError(g_ErrBadParam);
3345         return TW_STATE_ERROR;
3346     }
3347 
3348     if( !_Bar->m_Visible )
3349         return TW_STATE_HIDDEN;
3350     else if( _Bar->IsMinimized() )
3351         return TW_STATE_ICONIFIED;
3352     else
3353         return TW_STATE_SHOWN;
3354 }
3355 */
3356 
3357 //  ---------------------------------------------------------------------------
3358 
TwGetBarName(const TwBar * _Bar)3359 const char * ANT_CALL TwGetBarName(const TwBar *_Bar)
3360 {
3361     if( g_TwMgr==NULL )
3362     {
3363         TwGlobalError(g_ErrNotInit);
3364         return NULL;  // not initialized
3365     }
3366     if( _Bar==NULL )
3367     {
3368         g_TwMgr->SetLastError(g_ErrBadParam);
3369         return NULL;
3370     }
3371     vector<TwBar*>::iterator BarIt;
3372     int i = 0;
3373     for( BarIt=g_TwMgr->m_Bars.begin(); BarIt!=g_TwMgr->m_Bars.end(); ++BarIt, ++i )
3374         if( (*BarIt)==_Bar )
3375             break;
3376     if( BarIt==g_TwMgr->m_Bars.end() )
3377     {
3378         g_TwMgr->SetLastError(g_ErrNotFound);
3379         return NULL;
3380     }
3381 
3382     return _Bar->m_Name.c_str();
3383 }
3384 
3385 //  ---------------------------------------------------------------------------
3386 
TwGetBarCount()3387 int ANT_CALL TwGetBarCount()
3388 {
3389     if( g_TwMgr==NULL )
3390     {
3391         TwGlobalError(g_ErrNotInit);
3392         return 0;  // not initialized
3393     }
3394 
3395     return (int)g_TwMgr->m_Bars.size();
3396 }
3397 
3398 
3399 //  ---------------------------------------------------------------------------
3400 
TwGetBarByIndex(int index)3401 TwBar * ANT_CALL TwGetBarByIndex(int index)
3402 {
3403     if( g_TwMgr==NULL )
3404     {
3405         TwGlobalError(g_ErrNotInit);
3406         return NULL;  // not initialized
3407     }
3408 
3409     if( index>=0 && index<(int)g_TwMgr->m_Bars.size() )
3410         return g_TwMgr->m_Bars[index];
3411     else
3412     {
3413         g_TwMgr->SetLastError(g_ErrOutOfRange);
3414         return NULL;
3415     }
3416 }
3417 
3418 //  ---------------------------------------------------------------------------
3419 
TwGetBarByName(const char * name)3420 TwBar * ANT_CALL TwGetBarByName(const char *name)
3421 {
3422     if( g_TwMgr==NULL )
3423     {
3424         TwGlobalError(g_ErrNotInit);
3425         return NULL; // not initialized
3426     }
3427 
3428     int idx = g_TwMgr->FindBar(name);
3429     if ( idx>=0 && idx<(int)g_TwMgr->m_Bars.size() )
3430         return g_TwMgr->m_Bars[idx];
3431     else
3432         return NULL;
3433 }
3434 
3435 //  ---------------------------------------------------------------------------
3436 
TwRefreshBar(TwBar * bar)3437 int ANT_CALL TwRefreshBar(TwBar *bar)
3438 {
3439     if( g_TwMgr==NULL )
3440     {
3441         TwGlobalError(g_ErrNotInit);
3442         return 0;  // not initialized
3443     }
3444     if( bar==NULL )
3445     {
3446         vector<TwBar*>::iterator BarIt;
3447         for( BarIt=g_TwMgr->m_Bars.begin(); BarIt!=g_TwMgr->m_Bars.end(); ++BarIt )
3448             if( *BarIt!=NULL )
3449                 (*BarIt)->NotUpToDate();
3450     }
3451     else
3452     {
3453         vector<TwBar*>::iterator BarIt;
3454         int i = 0;
3455         for( BarIt=g_TwMgr->m_Bars.begin(); BarIt!=g_TwMgr->m_Bars.end(); ++BarIt, ++i )
3456             if( (*BarIt)==bar )
3457                 break;
3458         if( BarIt==g_TwMgr->m_Bars.end() )
3459         {
3460             g_TwMgr->SetLastError(g_ErrNotFound);
3461             return 0;
3462         }
3463 
3464         bar->NotUpToDate();
3465     }
3466     return 1;
3467 }
3468 
3469 //  ---------------------------------------------------------------------------
3470 
3471 int BarVarHasAttrib(CTwBar *_Bar, CTwVar *_Var, const char *_Attrib, bool *_HasValue);
3472 int BarVarSetAttrib(CTwBar *_Bar, CTwVar *_Var, CTwVarGroup *_VarParent, int _VarIndex, int _AttribID, const char *_Value);
3473 ERetType BarVarGetAttrib(CTwBar *_Bar, CTwVar *_Var, CTwVarGroup *_VarParent, int _VarIndex, int _AttribID, std::vector<double>& outDouble, std::ostringstream& outString);
3474 
3475 
TwGetParam(TwBar * bar,const char * varName,const char * paramName,TwParamValueType paramValueType,unsigned int outValueMaxCount,void * outValues)3476 int ANT_CALL TwGetParam(TwBar *bar, const char *varName, const char *paramName, TwParamValueType paramValueType, unsigned int outValueMaxCount, void *outValues)
3477 {
3478     CTwFPU fpu; // force fpu precision
3479 
3480     if( g_TwMgr==NULL )
3481     {
3482         TwGlobalError(g_ErrNotInit);
3483         return 0; // not initialized
3484     }
3485     if( paramName==NULL || strlen(paramName)<=0 )
3486     {
3487         g_TwMgr->SetLastError(g_ErrBadParam);
3488         return 0;
3489     }
3490     if( outValueMaxCount<=0 || outValues==NULL )
3491     {
3492         g_TwMgr->SetLastError(g_ErrBadParam);
3493         return 0;
3494     }
3495 
3496     if( bar==NULL )
3497         bar = TW_GLOBAL_BAR;
3498     else
3499     {
3500         vector<TwBar*>::iterator barIt;
3501         int i = 0;
3502         for( barIt=g_TwMgr->m_Bars.begin(); barIt!=g_TwMgr->m_Bars.end(); ++barIt, ++i )
3503             if( (*barIt)==bar )
3504                 break;
3505         if( barIt==g_TwMgr->m_Bars.end() )
3506         {
3507             g_TwMgr->SetLastError(g_ErrNotFound);
3508             return 0;
3509         }
3510     }
3511     CTwVarGroup *varParent = NULL;
3512     int varIndex = -1;
3513     CTwVar *var = NULL;
3514     if( varName!=NULL && strlen(varName)>0 )
3515     {
3516         var = bar->Find(varName, &varParent, &varIndex);
3517         if( var==NULL )
3518         {
3519             _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unknown var '%s/%s'",
3520                       (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(), varName);
3521             g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
3522             g_TwMgr->SetLastError(g_ErrParse);
3523             return 0;
3524         }
3525     }
3526 
3527     bool hasValue = false;
3528     int paramID = BarVarHasAttrib(bar, var, paramName, &hasValue);
3529     if( paramID>0 )
3530     {
3531         std::ostringstream valStr;
3532         std::vector<double> valDbl;
3533         const char *PrevLastErrorPtr = g_TwMgr->CheckLastError();
3534 
3535         ERetType retType = BarVarGetAttrib(bar, var, varParent, varIndex, paramID, valDbl, valStr);
3536         unsigned int i, valDblCount = (unsigned int)valDbl.size();
3537         if( valDblCount > outValueMaxCount )
3538             valDblCount = outValueMaxCount;
3539         if( retType==RET_DOUBLE && valDblCount==0 )
3540         {
3541             g_TwMgr->SetLastError(g_ErrHasNoValue);
3542             retType = RET_ERROR;
3543         }
3544 
3545         if( retType==RET_DOUBLE )
3546         {
3547             switch( paramValueType )
3548             {
3549             case TW_PARAM_INT32:
3550                 for( i=0; i<valDblCount; i++ )
3551                     (static_cast<int *>(outValues))[i] = (int)valDbl[i];
3552                 return valDblCount;
3553             case TW_PARAM_FLOAT:
3554                 for( i=0; i<valDblCount; i++ )
3555                     (static_cast<float *>(outValues))[i] = (float)valDbl[i];
3556                 return valDblCount;
3557             case TW_PARAM_DOUBLE:
3558                 for( i=0; i<valDblCount; i++ )
3559                     (static_cast<double *>(outValues))[i] = valDbl[i];
3560                 return valDblCount;
3561             case TW_PARAM_CSTRING:
3562                 valStr.clear();
3563                 for( i=0; i<(unsigned int)valDbl.size(); i++ ) // not valDblCount here
3564                     valStr << ((i>0) ? " " : "") << valDbl[i];
3565                 strncpy(static_cast<char *>(outValues), valStr.str().c_str(), outValueMaxCount);
3566                 i = (unsigned int)valStr.str().size();
3567                 if( i>outValueMaxCount-1 )
3568                     i = outValueMaxCount-1;
3569                 (static_cast<char *>(outValues))[i] = '\0';
3570                 return 1; // always returns 1 for CSTRING
3571             default:
3572                 g_TwMgr->SetLastError(g_ErrBadParam); // Unknown param value type
3573                 retType = RET_ERROR;
3574             }
3575         }
3576         else if( retType==RET_STRING )
3577         {
3578             if( paramValueType == TW_PARAM_CSTRING )
3579             {
3580                 strncpy(static_cast<char *>(outValues), valStr.str().c_str(), outValueMaxCount);
3581                 i = (unsigned int)valStr.str().size();
3582                 if( i>outValueMaxCount-1 )
3583                     i = outValueMaxCount-1;
3584                 (static_cast<char *>(outValues))[i] = '\0';
3585                 return 1; // always returns 1 for CSTRING
3586             }
3587             else
3588             {
3589                 g_TwMgr->SetLastError(g_ErrBadType); // string cannot be converted to int or double
3590                 retType = RET_ERROR;
3591             }
3592         }
3593 
3594         if( retType==RET_ERROR )
3595         {
3596             bool errMsg = (g_TwMgr->CheckLastError()!=NULL && strlen(g_TwMgr->CheckLastError())>0 && PrevLastErrorPtr!=g_TwMgr->CheckLastError());
3597             _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unable to get param '%s%s%s %s' %s%s",
3598                       (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(), (var!=NULL) ? "/" : "",
3599                       (var!=NULL) ? varName : "", paramName, errMsg ? " : " : "",
3600                       errMsg ? g_TwMgr->CheckLastError() : "");
3601             g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
3602             g_TwMgr->SetLastError(g_ErrParse);
3603         }
3604         return retType;
3605     }
3606     else
3607     {
3608         _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unknown param '%s%s%s %s'",
3609                   (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(),
3610                   (var!=NULL) ? "/" : "", (var!=NULL) ? varName : "", paramName);
3611         g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
3612         g_TwMgr->SetLastError(g_ErrParse);
3613         return 0;
3614     }
3615 }
3616 
3617 
TwSetParam(TwBar * bar,const char * varName,const char * paramName,TwParamValueType paramValueType,unsigned int inValueCount,const void * inValues)3618 int ANT_CALL TwSetParam(TwBar *bar, const char *varName, const char *paramName, TwParamValueType paramValueType, unsigned int inValueCount, const void *inValues)
3619 {
3620     CTwFPU fpu; // force fpu precision
3621 
3622     if( g_TwMgr==NULL )
3623     {
3624         TwGlobalError(g_ErrNotInit);
3625         return 0; // not initialized
3626     }
3627     if( paramName==NULL || strlen(paramName)<=0 )
3628     {
3629         g_TwMgr->SetLastError(g_ErrBadParam);
3630         return 0;
3631     }
3632     if( inValueCount>0 && inValues==NULL )
3633     {
3634         g_TwMgr->SetLastError(g_ErrBadParam);
3635         return 0;
3636     }
3637 
3638     TwFreeAsyncDrawing(); // For multi-thread savety
3639 
3640     if( bar==NULL )
3641         bar = TW_GLOBAL_BAR;
3642     else
3643     {
3644         vector<TwBar*>::iterator barIt;
3645         int i = 0;
3646         for( barIt=g_TwMgr->m_Bars.begin(); barIt!=g_TwMgr->m_Bars.end(); ++barIt, ++i )
3647             if( (*barIt)==bar )
3648                 break;
3649         if( barIt==g_TwMgr->m_Bars.end() )
3650         {
3651             g_TwMgr->SetLastError(g_ErrNotFound);
3652             return 0;
3653         }
3654     }
3655     CTwVarGroup *varParent = NULL;
3656     int varIndex = -1;
3657     CTwVar *var = NULL;
3658     if( varName!=NULL && strlen(varName)>0 )
3659     {
3660         var = bar->Find(varName, &varParent, &varIndex);
3661         if( var==NULL )
3662         {
3663             _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unknown var '%s/%s'",
3664                       (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(), varName);
3665             g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
3666             g_TwMgr->SetLastError(g_ErrParse);
3667             return 0;
3668         }
3669     }
3670 
3671     bool hasValue = false;
3672     int paramID = BarVarHasAttrib(bar, var, paramName, &hasValue);
3673     if( paramID>0 )
3674     {
3675         int ret = 0;
3676         const char *PrevLastErrorPtr = g_TwMgr->CheckLastError();
3677         if( hasValue )
3678         {
3679             std::ostringstream valuesStr;
3680             unsigned int i;
3681             switch( paramValueType )
3682             {
3683             case TW_PARAM_INT32:
3684                 for( i=0; i<inValueCount; i++ )
3685                     valuesStr << (static_cast<const int *>(inValues))[i] << ((i<inValueCount-1) ? " " : "");
3686                 break;
3687             case TW_PARAM_FLOAT:
3688                 for( i=0; i<inValueCount; i++ )
3689                     valuesStr << (static_cast<const float *>(inValues))[i] << ((i<inValueCount-1) ? " " : "");
3690                 break;
3691             case TW_PARAM_DOUBLE:
3692                 for( i=0; i<inValueCount; i++ )
3693                     valuesStr << (static_cast<const double *>(inValues))[i] << ((i<inValueCount-1) ? " " : "");
3694                 break;
3695             case TW_PARAM_CSTRING:
3696                 /*
3697                 for( i=0; i<inValueCount; i++ )
3698                 {
3699                     valuesStr << '`';
3700                     const char *str = (static_cast<char * const *>(inValues))[i];
3701                     for( const char *ch = str; *ch!=0; ch++ )
3702                         if( *ch=='`' )
3703                             valuesStr << "`'`'`";
3704                         else
3705                             valuesStr << *ch;
3706                     valuesStr << "` ";
3707                 }
3708                 */
3709                 if( inValueCount!=1 )
3710                 {
3711                     g_TwMgr->SetLastError(g_ErrCStrParam); // count for CString param must be 1
3712                     return 0;
3713                 }
3714                 else
3715                     valuesStr << static_cast<const char *>(inValues);
3716                 break;
3717             default:
3718                 g_TwMgr->SetLastError(g_ErrBadParam); // Unknown param value type
3719                 return 0;
3720             }
3721             ret = BarVarSetAttrib(bar, var, varParent, varIndex, paramID, valuesStr.str().c_str());
3722         }
3723         else
3724             ret = BarVarSetAttrib(bar, var, varParent, varIndex, paramID, NULL);
3725         if( ret==0 )
3726         {
3727             bool errMsg = (g_TwMgr->CheckLastError()!=NULL && strlen(g_TwMgr->CheckLastError())>0 && PrevLastErrorPtr!=g_TwMgr->CheckLastError());
3728             _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unable to set param '%s%s%s %s' %s%s",
3729                       (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(), (var!=NULL) ? "/" : "",
3730                       (var!=NULL) ? varName : "", paramName, errMsg ? " : " : "",
3731                       errMsg ? g_TwMgr->CheckLastError() : "");
3732             g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
3733             g_TwMgr->SetLastError(g_ErrParse);
3734         }
3735         return ret;
3736     }
3737     else
3738     {
3739         _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unknown param '%s%s%s %s'",
3740                   (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(),
3741                   (var!=NULL) ? "/" : "", (var!=NULL) ? varName : "", paramName);
3742         g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
3743         g_TwMgr->SetLastError(g_ErrParse);
3744         return 0;
3745     }
3746 }
3747 
3748 //  ---------------------------------------------------------------------------
3749 
3750 static int s_PassProxy = 0;
3751 void *CTwMgr::CStruct::s_PassProxyAsClientData = &s_PassProxy;  // special tag
3752 
CStructProxy()3753 CTwMgr::CStructProxy::CStructProxy()
3754 {
3755     memset(this, 0, sizeof(*this));
3756 }
3757 
~CStructProxy()3758 CTwMgr::CStructProxy::~CStructProxy()
3759 {
3760     if( m_StructData!=NULL && m_DeleteStructData )
3761     {
3762         //if( m_StructExtData==NULL && g_TwMgr!=NULL && m_Type>=TW_TYPE_STRUCT_BASE && m_Type<TW_TYPE_STRUCT_BASE+(int)g_TwMgr->m_Structs.size() )
3763         //  g_TwMgr->UninitVarData(m_Type, m_StructData, g_TwMgr->m_Structs[m_Type-TW_TYPE_STRUCT_BASE].m_Size);
3764         delete[] (char*)m_StructData;
3765     }
3766     if( m_StructExtData!=NULL )
3767     {
3768         //if( g_TwMgr!=NULL && m_Type>=TW_TYPE_STRUCT_BASE && m_Type<TW_TYPE_STRUCT_BASE+(int)g_TwMgr->m_Structs.size() )
3769         //  g_TwMgr->UninitVarData(m_Type, m_StructExtData, g_TwMgr->m_Structs[m_Type-TW_TYPE_STRUCT_BASE].m_Size);
3770         delete[] (char*)m_StructExtData;
3771     }
3772     memset(this, 0, sizeof(*this));
3773 }
3774 
3775 /*
3776 void CTwMgr::InitVarData(TwType _Type, void *_Data, size_t _Size)
3777 {
3778     if( _Data!=NULL )
3779     {
3780         if( _Type>=TW_TYPE_STRUCT_BASE && _Type<TW_TYPE_STRUCT_BASE+(int)m_Structs.size() )
3781         {
3782             CTwMgr::CStruct& s = m_Structs[_Type-TW_TYPE_STRUCT_BASE];
3783             for( size_t i=0; i<s.m_Members.size(); ++i )
3784             {
3785                 CTwMgr::CStructMember& sm = s.m_Members[i];
3786                 assert( sm.m_Offset+sm.m_Size<=_Size );
3787                 InitVarData(sm.m_Type, (char *)_Data + sm.m_Offset, sm.m_Size);
3788             }
3789         }
3790         else if( _Type==TW_TYPE_STDSTRING )
3791             ::new(_Data) std::string;
3792         else
3793             memset(_Data, 0, _Size);
3794     }
3795 }
3796 
3797 void CTwMgr::UninitVarData(TwType _Type, void *_Data, size_t _Size)
3798 {
3799     if( _Data!=NULL )
3800     {
3801         if( _Type>=TW_TYPE_STRUCT_BASE && _Type<TW_TYPE_STRUCT_BASE+(int)m_Structs.size() )
3802         {
3803             CTwMgr::CStruct& s = m_Structs[_Type-TW_TYPE_STRUCT_BASE];
3804             for( size_t i=0; i<s.m_Members.size(); ++i )
3805             {
3806                 CTwMgr::CStructMember& sm = s.m_Members[i];
3807                 assert( sm.m_Offset+sm.m_Size<=_Size );
3808                 UninitVarData(sm.m_Type, (char *)_Data + sm.m_Offset, sm.m_Size);
3809             }
3810         }
3811         else if( _Type==TW_TYPE_STDSTRING )
3812         {
3813             std::string *Str = (std::string *)_Data;
3814             Str->~string();
3815             memset(_Data, 0, _Size);
3816         }
3817         else
3818             memset(_Data, 0, _Size);
3819     }
3820 }
3821 */
3822 
UnrollCDStdString(std::vector<CCDStdStringRecord> & _Records,TwType _Type,void * _Data)3823 void CTwMgr::UnrollCDStdString(std::vector<CCDStdStringRecord>& _Records, TwType _Type, void *_Data)
3824 {
3825     if( _Data!=NULL )
3826     {
3827         if( _Type>=TW_TYPE_STRUCT_BASE && _Type<TW_TYPE_STRUCT_BASE+(int)m_Structs.size() )
3828         {
3829             CTwMgr::CStruct& s = m_Structs[_Type-TW_TYPE_STRUCT_BASE];
3830             if( !s.m_IsExt )
3831                 for( size_t i=0; i<s.m_Members.size(); ++i )
3832                 {
3833                     CTwMgr::CStructMember& sm = s.m_Members[i];
3834                     UnrollCDStdString(_Records, sm.m_Type, (char *)_Data + sm.m_Offset);
3835                 }
3836             else
3837             {
3838                 // nothing:
3839                 // Ext struct cannot have var of type TW_TYPE_CDSTDSTRING (converted from TW_TYPE_STDSTRING)
3840             }
3841         }
3842         else if( _Type==TW_TYPE_STDSTRING || _Type==TW_TYPE_CDSTDSTRING )
3843         {
3844             _Records.push_back(CCDStdStringRecord());
3845             CCDStdStringRecord& Rec = _Records.back();
3846             Rec.m_DataPtr = _Data;
3847             memcpy(Rec.m_PrevValue, _Data, m_ClientStdStringStructSize);
3848             const char *Str = *(const char **)_Data;
3849             if( Str!=NULL )
3850                 // Rec.m_StdString = Str;
3851                 Rec.m_ClientStdString.FromLib(Str);
3852             memcpy(Rec.m_DataPtr, &(Rec.m_ClientStdString.ToClient()), sizeof(std::string));
3853         }
3854     }
3855 }
3856 
RestoreCDStdString(const std::vector<CCDStdStringRecord> & _Records)3857 void CTwMgr::RestoreCDStdString(const std::vector<CCDStdStringRecord>& _Records)
3858 {
3859     for( size_t i=0; i<_Records.size(); ++i )
3860         memcpy(_Records[i].m_DataPtr, _Records[i].m_PrevValue, m_ClientStdStringStructSize);
3861 }
3862 
CMemberProxy()3863 CTwMgr::CMemberProxy::CMemberProxy()
3864 {
3865     memset(this, 0, sizeof(*this));
3866 }
3867 
~CMemberProxy()3868 CTwMgr::CMemberProxy::~CMemberProxy()
3869 {
3870     memset(this, 0, sizeof(*this));
3871 }
3872 
SetCB(const void * _Value,void * _ClientData)3873 void ANT_CALL CTwMgr::CMemberProxy::SetCB(const void *_Value, void *_ClientData)
3874 {
3875     if( _ClientData && _Value )
3876     {
3877         const CMemberProxy *mProxy = static_cast<const CMemberProxy *>(_ClientData);
3878         if( g_TwMgr && mProxy )
3879         {
3880             const CStructProxy *sProxy = mProxy->m_StructProxy;
3881             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() )
3882             {
3883                 CTwMgr::CStruct& s = g_TwMgr->m_Structs[sProxy->m_Type-TW_TYPE_STRUCT_BASE];
3884                 if( mProxy->m_MemberIndex>=0 && mProxy->m_MemberIndex<(int)s.m_Members.size() )
3885                 {
3886                     CTwMgr::CStructMember& m = s.m_Members[mProxy->m_MemberIndex];
3887                     if( m.m_Size>0 && m.m_Type!=TW_TYPE_BUTTON )
3888                     {
3889                         if( s.m_IsExt )
3890                         {
3891                             memcpy((char *)sProxy->m_StructExtData + m.m_Offset, _Value, m.m_Size);
3892                             if( s.m_CopyVarFromExtCallback && sProxy->m_StructExtData )
3893                                 s.m_CopyVarFromExtCallback(sProxy->m_StructData, sProxy->m_StructExtData, mProxy->m_MemberIndex, (s.m_ExtClientData==s.s_PassProxyAsClientData) ? _ClientData : s.m_ExtClientData);
3894                         }
3895                         else
3896                             memcpy((char *)sProxy->m_StructData + m.m_Offset, _Value, m.m_Size);
3897                         if( sProxy->m_StructSetCallback )
3898                         {
3899                             g_TwMgr->m_CDStdStringRecords.resize(0);
3900                             g_TwMgr->UnrollCDStdString(g_TwMgr->m_CDStdStringRecords, sProxy->m_Type, sProxy->m_StructData);
3901                             sProxy->m_StructSetCallback(sProxy->m_StructData, sProxy->m_StructClientData);
3902                             g_TwMgr->RestoreCDStdString(g_TwMgr->m_CDStdStringRecords);
3903                         }
3904                     }
3905                 }
3906             }
3907         }
3908     }
3909 }
3910 
GetCB(void * _Value,void * _ClientData)3911 void ANT_CALL CTwMgr::CMemberProxy::GetCB(void *_Value, void *_ClientData)
3912 {
3913     if( _ClientData && _Value )
3914     {
3915         const CMemberProxy *mProxy = static_cast<const CMemberProxy *>(_ClientData);
3916         if( g_TwMgr && mProxy )
3917         {
3918             const CStructProxy *sProxy = mProxy->m_StructProxy;
3919             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() )
3920             {
3921                 CTwMgr::CStruct& s = g_TwMgr->m_Structs[sProxy->m_Type-TW_TYPE_STRUCT_BASE];
3922                 if( mProxy->m_MemberIndex>=0 && mProxy->m_MemberIndex<(int)s.m_Members.size() )
3923                 {
3924                     CTwMgr::CStructMember& m = s.m_Members[mProxy->m_MemberIndex];
3925                     if( m.m_Size>0 && m.m_Type!=TW_TYPE_BUTTON )
3926                     {
3927                         if( sProxy->m_StructGetCallback )
3928                             sProxy->m_StructGetCallback(sProxy->m_StructData, sProxy->m_StructClientData);
3929                         if( s.m_IsExt )
3930                         {
3931                             if( s.m_CopyVarToExtCallback && sProxy->m_StructExtData )
3932                                 s.m_CopyVarToExtCallback(sProxy->m_StructData, sProxy->m_StructExtData, mProxy->m_MemberIndex,  (s.m_ExtClientData==s.s_PassProxyAsClientData) ? _ClientData : s.m_ExtClientData);
3933                             memcpy(_Value, (char *)sProxy->m_StructExtData + m.m_Offset, m.m_Size);
3934                         }
3935                         else
3936                             memcpy(_Value, (char *)sProxy->m_StructData + m.m_Offset, m.m_Size);
3937                     }
3938                 }
3939             }
3940         }
3941     }
3942 }
3943 
3944 //  ---------------------------------------------------------------------------
3945 
SetCB(const void * _Value,void * _ClientData)3946 void ANT_CALL CTwMgr::CCDStdString::SetCB(const void *_Value, void *_ClientData)
3947 {
3948     if( _Value==NULL || _ClientData==NULL || g_TwMgr==NULL )
3949         return;
3950     CTwMgr::CCDStdString *CDStdString = (CTwMgr::CCDStdString *)_ClientData;
3951     const char *SrcStr = *(const char **)_Value;
3952     if( SrcStr==NULL )
3953     {
3954         static char s_EmptyString[] = "";
3955         SrcStr = s_EmptyString;
3956     }
3957     if( CDStdString->m_ClientSetCallback==NULL )
3958     {
3959         if( g_TwMgr->m_CopyStdStringToClient && CDStdString->m_ClientStdStringPtr!=NULL )
3960         {
3961             CTwMgr::CClientStdString clientSrcStr; // convert VC++ Release/Debug std::string
3962             clientSrcStr.FromLib(SrcStr);
3963             g_TwMgr->m_CopyStdStringToClient(*(CDStdString->m_ClientStdStringPtr), clientSrcStr.ToClient());
3964         }
3965     }
3966     else
3967     {
3968         if( CDStdString->m_ClientSetCallback==CMemberProxy::SetCB )
3969             CDStdString->m_ClientSetCallback(&SrcStr, CDStdString->m_ClientData);
3970         else
3971         {
3972             CTwMgr::CClientStdString clientSrcStr; // convert VC++ Release/Debug std::string
3973             clientSrcStr.FromLib(SrcStr);
3974             std::string& ValStr = clientSrcStr.ToClient();
3975             CDStdString->m_ClientSetCallback(&ValStr, CDStdString->m_ClientData);
3976         }
3977     }
3978 }
3979 
GetCB(void * _Value,void * _ClientData)3980 void ANT_CALL CTwMgr::CCDStdString::GetCB(void *_Value, void *_ClientData)
3981 {
3982     if( _Value==NULL || _ClientData==NULL || g_TwMgr==NULL )
3983         return;
3984     CTwMgr::CCDStdString *CDStdString = (CTwMgr::CCDStdString *)_ClientData;
3985     char **DstStrPtr = (char **)_Value;
3986     if( CDStdString->m_ClientGetCallback==NULL )
3987     {
3988         if( CDStdString->m_ClientStdStringPtr!=NULL )
3989         {
3990             //*DstStrPtr = const_cast<char *>(CDStdString->m_ClientStdStringPtr->c_str());
3991             static CTwMgr::CLibStdString s_LibStr; // static because it will be used as a returned value
3992             s_LibStr.FromClient(*CDStdString->m_ClientStdStringPtr);
3993             *DstStrPtr = const_cast<char *>(s_LibStr.ToLib().c_str());
3994         }
3995         else
3996         {
3997             static char s_EmptyString[] = "";
3998             *DstStrPtr = s_EmptyString;
3999         }
4000     }
4001     else
4002     {
4003         // m_ClientGetCallback uses TwCopyStdStringToLibrary to copy string
4004         // and TwCopyStdStringToLibrary does the VC++ Debug/Release std::string conversion.
4005         CDStdString->m_ClientGetCallback(&(CDStdString->m_LocalString[0]), CDStdString->m_ClientData);
4006         //*DstStrPtr = const_cast<char *>(CDStdString->m_LocalString.c_str());
4007         char **StrPtr = (char **)&(CDStdString->m_LocalString[0]);
4008         *DstStrPtr = *StrPtr;
4009     }
4010 }
4011 
4012 //  ---------------------------------------------------------------------------
4013 
4014 static int s_SeparatorTag = 0;
4015 
4016 //  ---------------------------------------------------------------------------
4017 
AddVar(TwBar * _Bar,const char * _Name,ETwType _Type,void * _VarPtr,bool _ReadOnly,TwSetVarCallback _SetCallback,TwGetVarCallback _GetCallback,TwButtonCallback _ButtonCallback,void * _ClientData,const char * _Def)4018 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)
4019 {
4020     CTwFPU fpu; // force fpu precision
4021 
4022     if( g_TwMgr==NULL )
4023     {
4024         TwGlobalError(g_ErrNotInit);
4025         return 0; // not initialized
4026     }
4027 
4028     char unnamedVarName[64];
4029     if( _Name==NULL || strlen(_Name)==0 ) // create a name automatically
4030     {
4031         static unsigned int s_UnnamedVarCount = 0;
4032         _snprintf(unnamedVarName, sizeof(unnamedVarName), "TW_UNNAMED_%04X", s_UnnamedVarCount);
4033         _Name = unnamedVarName;
4034         ++s_UnnamedVarCount;
4035     }
4036 
4037     if( _Bar==NULL || _Name==NULL || strlen(_Name)==0 || (_VarPtr==NULL && _GetCallback==NULL && _Type!=TW_TYPE_BUTTON) )
4038     {
4039         g_TwMgr->SetLastError(g_ErrBadParam);
4040         return 0;
4041     }
4042     if( _Bar->Find(_Name)!=NULL )
4043     {
4044         g_TwMgr->SetLastError(g_ErrExist);
4045         return 0;
4046     }
4047 
4048     if( strstr(_Name, "`")!=NULL )
4049     {
4050         g_TwMgr->SetLastError(g_ErrNoBackQuote);
4051         return 0;
4052     }
4053 
4054     if( _VarPtr==NULL && _Type!=TW_TYPE_BUTTON && _GetCallback!=NULL && _SetCallback==NULL )
4055         _ReadOnly = true;   // force readonly in this case
4056 
4057     // Convert color types
4058     if( _Type==TW_TYPE_COLOR32 )
4059         _Type = g_TwMgr->m_TypeColor32;
4060     else if( _Type==TW_TYPE_COLOR3F )
4061         _Type = g_TwMgr->m_TypeColor3F;
4062     else if( _Type==TW_TYPE_COLOR4F )
4063         _Type = g_TwMgr->m_TypeColor4F;
4064 
4065     // Convert rotation types
4066     if( _Type==TW_TYPE_QUAT4F )
4067         _Type = g_TwMgr->m_TypeQuat4F;
4068     else if( _Type==TW_TYPE_QUAT4D )
4069         _Type = g_TwMgr->m_TypeQuat4D;
4070     else if( _Type==TW_TYPE_DIR3F )
4071         _Type = g_TwMgr->m_TypeDir3F;
4072     else if( _Type==TW_TYPE_DIR3D )
4073         _Type = g_TwMgr->m_TypeDir3D;
4074 
4075     // VC++ uses a different definition of std::string in Debug and Release modes.
4076     // sizeof(std::string) is encoded in TW_TYPE_STDSTRING to overcome this issue.
4077     // With VS2010 the binary representation of std::string has changed too. This is
4078     // also detected here.
4079     if( (_Type&0xffff0000)==(TW_TYPE_STDSTRING&0xffff0000) || (_Type&0xffff0000)==TW_TYPE_STDSTRING_VS2010 || (_Type&0xffff0000)==TW_TYPE_STDSTRING_VS2008 )
4080     {
4081         if( g_TwMgr->m_ClientStdStringBaseType==0 )
4082             g_TwMgr->m_ClientStdStringBaseType = (TwType)(_Type&0xffff0000);
4083 
4084         size_t clientStdStringStructSize = (_Type&0xffff);
4085         if( g_TwMgr->m_ClientStdStringStructSize==0 )
4086             g_TwMgr->m_ClientStdStringStructSize = clientStdStringStructSize;
4087         int diff = abs((int)g_TwMgr->m_ClientStdStringStructSize - (int)sizeof(std::string));
4088         if( g_TwMgr->m_ClientStdStringStructSize!=clientStdStringStructSize || g_TwMgr->m_ClientStdStringStructSize==0
4089             || (diff!=0 && diff!=sizeof(void*)))
4090         {
4091             g_TwMgr->SetLastError(g_ErrStdString);
4092             return 0;
4093         }
4094 
4095         _Type = TW_TYPE_STDSTRING; // force type to be our TW_TYPE_STDSTRING
4096     }
4097 
4098     if( _Type==TW_TYPE_STDSTRING )
4099     {
4100         g_TwMgr->m_CDStdStrings.push_back(CTwMgr::CCDStdString());
4101         CTwMgr::CCDStdString& CDStdString = g_TwMgr->m_CDStdStrings.back();
4102         CDStdString.m_ClientStdStringPtr = (std::string *)_VarPtr;
4103         CDStdString.m_ClientSetCallback = _SetCallback;
4104         CDStdString.m_ClientGetCallback = _GetCallback;
4105         CDStdString.m_ClientData = _ClientData;
4106         //CDStdString.m_This = g_TwMgr->m_CDStdStrings.end();
4107         //--CDStdString.m_This;
4108         TwGetVarCallback GetCB = CTwMgr::CCDStdString::GetCB;
4109         TwSetVarCallback SetCB = CTwMgr::CCDStdString::SetCB;
4110         if( _VarPtr==NULL && _SetCallback==NULL )
4111             SetCB = NULL;
4112         if( _VarPtr==NULL && _GetCallback==NULL )
4113             GetCB = NULL;
4114         return AddVar(_Bar, _Name, TW_TYPE_CDSTDSTRING, NULL, _ReadOnly, SetCB, GetCB, NULL, &CDStdString, _Def);
4115     }
4116     else if(    (_Type>TW_TYPE_UNDEF && _Type<TW_TYPE_STRUCT_BASE)
4117              || (_Type>=TW_TYPE_ENUM_BASE && _Type<TW_TYPE_ENUM_BASE+(int)g_TwMgr->m_Enums.size())
4118              || (_Type>TW_TYPE_CSSTRING_BASE && _Type<=TW_TYPE_CSSTRING_MAX)
4119              || _Type==TW_TYPE_CDSTDSTRING
4120              || IsCustomType(_Type) ) // (_Type>=TW_TYPE_CUSTOM_BASE && _Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size()) )
4121     {
4122         CTwVarAtom *Var = new CTwVarAtom;
4123         Var->m_Name = _Name;
4124         Var->m_Ptr = _VarPtr;
4125         Var->m_Type = _Type;
4126         Var->m_ColorPtr = &(_Bar->m_ColLabelText);
4127         if( _VarPtr!=NULL )
4128         {
4129             assert( _GetCallback==NULL && _SetCallback==NULL && _ButtonCallback==NULL );
4130 
4131             Var->m_ReadOnly = _ReadOnly;
4132             Var->m_GetCallback = NULL;
4133             Var->m_SetCallback = NULL;
4134             Var->m_ClientData = NULL;
4135         }
4136         else
4137         {
4138             assert( _GetCallback!=NULL || _Type==TW_TYPE_BUTTON );
4139 
4140             Var->m_GetCallback = _GetCallback;
4141             Var->m_SetCallback = _SetCallback;
4142             Var->m_ClientData = _ClientData;
4143             if( _Type==TW_TYPE_BUTTON )
4144             {
4145                 Var->m_Val.m_Button.m_Callback = _ButtonCallback;
4146                 if( _ButtonCallback==NULL && _ClientData==&s_SeparatorTag )
4147                 {
4148                     Var->m_Val.m_Button.m_Separator = 1;
4149                     Var->m_Label = " ";
4150                 }
4151                 else if( _ButtonCallback==NULL )
4152                     Var->m_ColorPtr = &(_Bar->m_ColStaticText);
4153             }
4154             if( _Type!=TW_TYPE_BUTTON )
4155                 Var->m_ReadOnly = (_SetCallback==NULL || _ReadOnly);
4156             else
4157                 Var->m_ReadOnly = (_ButtonCallback==NULL);
4158         }
4159         Var->SetDefaults();
4160 
4161         if( IsCustomType(_Type) ) // _Type>=TW_TYPE_CUSTOM_BASE && _Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size() )
4162         {
4163             if( Var->m_GetCallback==CTwMgr::CMemberProxy::GetCB && Var->m_SetCallback==CTwMgr::CMemberProxy::SetCB )
4164                 Var->m_Val.m_Custom.m_MemberProxy = static_cast<CTwMgr::CMemberProxy *>(Var->m_ClientData);
4165             else
4166                 Var->m_Val.m_Custom.m_MemberProxy = NULL;
4167         }
4168 
4169         _Bar->m_VarRoot.m_Vars.push_back(Var);
4170         _Bar->NotUpToDate();
4171         g_TwMgr->m_HelpBarNotUpToDate = true;
4172 
4173         if( _Def!=NULL && strlen(_Def)>0 )
4174         {
4175             string d = '`' + _Bar->m_Name + "`/`" + _Name + "` " + _Def;
4176             return TwDefine(d.c_str());
4177         }
4178         else
4179             return 1;
4180     }
4181     else if(_Type>=TW_TYPE_STRUCT_BASE && _Type<TW_TYPE_STRUCT_BASE+(TwType)g_TwMgr->m_Structs.size())
4182     {
4183         CTwMgr::CStruct& s = g_TwMgr->m_Structs[_Type-TW_TYPE_STRUCT_BASE];
4184         CTwMgr::CStructProxy *sProxy = NULL;
4185         void *vPtr;
4186         if( !s.m_IsExt )
4187         {
4188             if( _VarPtr!=NULL )
4189                 vPtr = _VarPtr;
4190             else
4191             {
4192                 assert( _GetCallback!=NULL || _SetCallback!=NULL );
4193                 assert( s.m_Size>0 );
4194                 vPtr = new char[s.m_Size];
4195                 memset(vPtr, 0, s.m_Size);
4196                 // create a new StructProxy
4197                 g_TwMgr->m_StructProxies.push_back(CTwMgr::CStructProxy());
4198                 sProxy = &(g_TwMgr->m_StructProxies.back());
4199                 sProxy->m_Type = _Type;
4200                 sProxy->m_StructData = vPtr;
4201                 sProxy->m_DeleteStructData = true;
4202                 sProxy->m_StructSetCallback = _SetCallback;
4203                 sProxy->m_StructGetCallback = _GetCallback;
4204                 sProxy->m_StructClientData = _ClientData;
4205                 sProxy->m_CustomDrawCallback = NULL;
4206                 sProxy->m_CustomMouseButtonCallback = NULL;
4207                 sProxy->m_CustomMouseMotionCallback = NULL;
4208                 sProxy->m_CustomMouseLeaveCallback = NULL;
4209                 sProxy->m_CustomCaptureFocus = false;
4210                 sProxy->m_CustomIndexFirst = -1;
4211                 sProxy->m_CustomIndexLast = -1;
4212                 //g_TwMgr->InitVarData(sProxy->m_Type, sProxy->m_StructData, s.m_Size);
4213             }
4214         }
4215         else // s.m_IsExt
4216         {
4217             assert( s.m_Size>0 && s.m_ClientStructSize>0 );
4218             vPtr = new char[s.m_Size];  // will be m_StructExtData
4219             memset(vPtr, 0, s.m_Size);
4220             // create a new StructProxy
4221             g_TwMgr->m_StructProxies.push_back(CTwMgr::CStructProxy());
4222             sProxy = &(g_TwMgr->m_StructProxies.back());
4223             sProxy->m_Type = _Type;
4224             sProxy->m_StructExtData = vPtr;
4225             sProxy->m_StructSetCallback = _SetCallback;
4226             sProxy->m_StructGetCallback = _GetCallback;
4227             sProxy->m_StructClientData = _ClientData;
4228             sProxy->m_CustomDrawCallback = NULL;
4229             sProxy->m_CustomMouseButtonCallback = NULL;
4230             sProxy->m_CustomMouseMotionCallback = NULL;
4231             sProxy->m_CustomMouseLeaveCallback = NULL;
4232             sProxy->m_CustomCaptureFocus = false;
4233             sProxy->m_CustomIndexFirst = -1;
4234             sProxy->m_CustomIndexLast = -1;
4235             //g_TwMgr->InitVarData(sProxy->m_Type, sProxy->m_StructExtData, s.m_Size);
4236             if( _VarPtr!=NULL )
4237             {
4238                 sProxy->m_StructData = _VarPtr;
4239                 sProxy->m_DeleteStructData = false;
4240             }
4241             else
4242             {
4243                 sProxy->m_StructData = new char[s.m_ClientStructSize];
4244                 memset(sProxy->m_StructData, 0, s.m_ClientStructSize);
4245                 sProxy->m_DeleteStructData = true;
4246                 //g_TwMgr->InitVarData(ClientStructType, sProxy->m_StructData, s.m_ClientStructSize); //ClientStructType is unknown
4247             }
4248             _VarPtr = NULL; // force use of TwAddVarCB for members
4249 
4250             // init m_StructExtdata
4251             if( s.m_ExtClientData==CTwMgr::CStruct::s_PassProxyAsClientData )
4252                 s.m_StructExtInitCallback(sProxy->m_StructExtData, sProxy);
4253             else
4254                 s.m_StructExtInitCallback(sProxy->m_StructExtData, s.m_ExtClientData);
4255         }
4256 
4257         for( int i=0; i<(int)s.m_Members.size(); ++i )
4258         {
4259             CTwMgr::CStructMember& m = s.m_Members[i];
4260             string name = string(_Name) + '.' + m.m_Name;
4261             const char *access = "";
4262             if( _ReadOnly )
4263                 access = "readonly ";
4264             string def  = "label=`" + m.m_Name + "` group=`" + _Name + "` " + access; // + m.m_DefString;  // member def must be done after group def
4265             if( _VarPtr!=NULL )
4266             {
4267                 if( TwAddVarRW(_Bar, name.c_str(), m.m_Type, (char*)vPtr+m.m_Offset, def.c_str())==0 )
4268                     return 0;
4269             }
4270             else
4271             {
4272                 assert( sProxy!=NULL );
4273                 // create a new MemberProxy
4274                 g_TwMgr->m_MemberProxies.push_back(CTwMgr::CMemberProxy());
4275                 CTwMgr::CMemberProxy& mProxy = g_TwMgr->m_MemberProxies.back();
4276                 mProxy.m_StructProxy = sProxy;
4277                 mProxy.m_MemberIndex = i;
4278                 assert( !(s.m_IsExt && (m.m_Type==TW_TYPE_STDSTRING || m.m_Type==TW_TYPE_CDSTDSTRING)) );   // forbidden because this case is not handled by UnrollCDStdString
4279                 if( TwAddVarCB(_Bar, name.c_str(), m.m_Type, CTwMgr::CMemberProxy::SetCB, CTwMgr::CMemberProxy::GetCB, &mProxy, def.c_str())==0 )
4280                     return 0;
4281                 mProxy.m_Var = _Bar->Find(name.c_str(), &mProxy.m_VarParent, NULL);
4282                 mProxy.m_Bar = _Bar;
4283             }
4284 
4285             if( sProxy!=NULL && IsCustomType(m.m_Type) ) // m.m_Type>=TW_TYPE_CUSTOM_BASE && m.m_Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size() )
4286             {
4287                 if( sProxy->m_CustomIndexFirst<0 )
4288                     sProxy->m_CustomIndexFirst = sProxy->m_CustomIndexLast = i;
4289                 else
4290                     sProxy->m_CustomIndexLast = i;
4291             }
4292         }
4293         char structInfo[64];
4294         sprintf(structInfo, "typeid=%d valptr=%p close ", _Type, vPtr);
4295         string grpDef = '`' + _Bar->m_Name + "`/`" + _Name + "` " + structInfo;
4296         if( _Def!=NULL && strlen(_Def)>0 )
4297             grpDef += _Def;
4298         int ret = TwDefine(grpDef.c_str());
4299         for( int i=0; i<(int)s.m_Members.size(); ++i ) // members must be defined even if grpDef has error
4300         {
4301             CTwMgr::CStructMember& m = s.m_Members[i];
4302             if( m.m_DefString.length()>0 )
4303             {
4304                 string memberDef = '`' + _Bar->m_Name + "`/`" + _Name + '.' + m.m_Name + "` " + m.m_DefString;
4305                 if( !TwDefine(memberDef.c_str()) ) // all members must be defined even if memberDef has error
4306                     ret = 0;
4307             }
4308         }
4309         return ret;
4310     }
4311     else
4312     {
4313         if( _Type==TW_TYPE_CSSTRING_BASE )
4314             g_TwMgr->SetLastError(g_ErrBadSize); // static string of size null
4315         else
4316             g_TwMgr->SetLastError(g_ErrNotFound);
4317         return 0;
4318     }
4319 }
4320 
4321 //  ---------------------------------------------------------------------------
4322 
TwAddVarRW(TwBar * _Bar,const char * _Name,ETwType _Type,void * _Var,const char * _Def)4323 int ANT_CALL TwAddVarRW(TwBar *_Bar, const char *_Name, ETwType _Type, void *_Var, const char *_Def)
4324 {
4325     return AddVar(_Bar, _Name, _Type, _Var, false, NULL, NULL, NULL, NULL, _Def);
4326 }
4327 
4328 //  ---------------------------------------------------------------------------
4329 
TwAddVarRO(TwBar * _Bar,const char * _Name,ETwType _Type,const void * _Var,const char * _Def)4330 int ANT_CALL TwAddVarRO(TwBar *_Bar, const char *_Name, ETwType _Type, const void *_Var, const char *_Def)
4331 {
4332     return AddVar(_Bar, _Name, _Type, const_cast<void *>(_Var), true, NULL, NULL, NULL, NULL, _Def);
4333 }
4334 
4335 //  ---------------------------------------------------------------------------
4336 
TwAddVarCB(TwBar * _Bar,const char * _Name,ETwType _Type,TwSetVarCallback _SetCallback,TwGetVarCallback _GetCallback,void * _ClientData,const char * _Def)4337 int ANT_CALL TwAddVarCB(TwBar *_Bar, const char *_Name, ETwType _Type, TwSetVarCallback _SetCallback, TwGetVarCallback _GetCallback, void *_ClientData, const char *_Def)
4338 {
4339     return AddVar(_Bar, _Name, _Type, NULL, false, _SetCallback, _GetCallback, NULL, _ClientData, _Def);
4340 }
4341 
4342 //  ---------------------------------------------------------------------------
4343 
TwAddButton(TwBar * _Bar,const char * _Name,TwButtonCallback _Callback,void * _ClientData,const char * _Def)4344 int ANT_CALL TwAddButton(TwBar *_Bar, const char *_Name, TwButtonCallback _Callback, void *_ClientData, const char *_Def)
4345 {
4346     return AddVar(_Bar, _Name, TW_TYPE_BUTTON, NULL, false, NULL, NULL, _Callback, _ClientData, _Def);
4347 }
4348 
4349 //  ---------------------------------------------------------------------------
4350 
TwAddSeparator(TwBar * _Bar,const char * _Name,const char * _Def)4351 int ANT_CALL TwAddSeparator(TwBar *_Bar, const char *_Name, const char *_Def)
4352 {
4353     return AddVar(_Bar, _Name, TW_TYPE_BUTTON, NULL, true, NULL, NULL, NULL, &s_SeparatorTag, _Def);
4354 }
4355 
4356 //  ---------------------------------------------------------------------------
4357 
TwRemoveVar(TwBar * _Bar,const char * _Name)4358 int ANT_CALL TwRemoveVar(TwBar *_Bar, const char *_Name)
4359 {
4360     if( g_TwMgr==NULL )
4361     {
4362         TwGlobalError(g_ErrNotInit);
4363         return 0; // not initialized
4364     }
4365     if( _Bar==NULL || _Name==NULL || strlen(_Name)==0 )
4366     {
4367         g_TwMgr->SetLastError(g_ErrBadParam);
4368         return 0;
4369     }
4370 
4371     if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar )    // delete popup bar first if it exists
4372     {
4373         TwDeleteBar(g_TwMgr->m_PopupBar);
4374         g_TwMgr->m_PopupBar = NULL;
4375     }
4376 
4377     _Bar->StopEditInPlace();    // desactivate EditInPlace
4378 
4379     CTwVarGroup *Parent = NULL;
4380     int Index = -1;
4381     CTwVar *Var = _Bar->Find(_Name, &Parent, &Index);
4382     if( Var!=NULL && Parent!=NULL && Index>=0 )
4383     {
4384         if( Parent->m_StructValuePtr!=NULL )
4385         {
4386             g_TwMgr->SetLastError(g_ErrDelStruct);
4387             return 0;
4388         }
4389 
4390         delete Var;
4391         Parent->m_Vars.erase(Parent->m_Vars.begin()+Index);
4392         if( Parent!=&(_Bar->m_VarRoot) && Parent->m_Vars.size()<=0 )
4393             TwRemoveVar(_Bar, Parent->m_Name.c_str());
4394         _Bar->NotUpToDate();
4395         if( _Bar!=g_TwMgr->m_HelpBar )
4396             g_TwMgr->m_HelpBarNotUpToDate = true;
4397         return 1;
4398     }
4399 
4400     g_TwMgr->SetLastError(g_ErrNotFound);
4401     return 0;
4402 }
4403 
4404 //  ---------------------------------------------------------------------------
4405 
TwRemoveAllVars(TwBar * _Bar)4406 int ANT_CALL TwRemoveAllVars(TwBar *_Bar)
4407 {
4408     if( g_TwMgr==NULL )
4409     {
4410         TwGlobalError(g_ErrNotInit);
4411         return 0; // not initialized
4412     }
4413     if( _Bar==NULL )
4414     {
4415         g_TwMgr->SetLastError(g_ErrBadParam);
4416         return 0;
4417     }
4418 
4419     if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar && _Bar!=g_TwMgr->m_HelpBar )    // delete popup bar first if it exists
4420     {
4421         TwDeleteBar(g_TwMgr->m_PopupBar);
4422         g_TwMgr->m_PopupBar = NULL;
4423     }
4424 
4425     _Bar->StopEditInPlace();    // desactivate EditInPlace
4426 
4427     for( vector<CTwVar*>::iterator it=_Bar->m_VarRoot.m_Vars.begin(); it!=_Bar->m_VarRoot.m_Vars.end(); ++it )
4428         if( *it != NULL )
4429         {
4430             delete *it;
4431             *it = NULL;
4432         }
4433     _Bar->m_VarRoot.m_Vars.resize(0);
4434     _Bar->NotUpToDate();
4435     g_TwMgr->m_HelpBarNotUpToDate = true;
4436     return 1;
4437 }
4438 
4439 //  ---------------------------------------------------------------------------
4440 
ParseToken(string & _Token,const char * _Def,int & Line,int & Column,bool _KeepQuotes,bool _EndCR,char _Sep1='\\0',char _Sep2='\\0')4441 int ParseToken(string& _Token, const char *_Def, int& Line, int& Column, bool _KeepQuotes, bool _EndCR, char _Sep1='\0', char _Sep2='\0')
4442 {
4443     const char *Cur = _Def;
4444     _Token = "";
4445     // skip spaces
4446     while( *Cur==' ' || *Cur=='\t' || *Cur=='\r' || *Cur=='\n' )
4447     {
4448         if( *Cur=='\n' && _EndCR )
4449             return (int)(Cur-_Def); // a CR has been found
4450         ++Cur;
4451         if( *Cur=='\n' )
4452         {
4453             ++Line;
4454             Column = 1;
4455         }
4456         else if( *Cur=='\t' )
4457             Column += g_TabLength;
4458         else if( *Cur!='\r' )
4459             ++Column;
4460     }
4461     // read token
4462     int QuoteLine=0, QuoteColumn=0;
4463     char Quote = 0;
4464     bool AddChar;
4465     bool LineJustIncremented = false;
4466     while(    (Quote==0 && (*Cur!='\0' && *Cur!=' ' && *Cur!='\t' && *Cur!='\r' && *Cur!='\n' && *Cur!=_Sep1 && *Cur!=_Sep2))
4467            || (Quote!=0 && (*Cur!='\0' /* && *Cur!='\r' && *Cur!='\n' */)) ) // allow multi-line strings
4468     {
4469         LineJustIncremented = false;
4470         AddChar = true;
4471         if( Quote==0 && (*Cur=='\'' || *Cur=='\"' || *Cur=='`') )
4472         {
4473             Quote = *Cur;
4474             QuoteLine = Line;
4475             QuoteColumn = Column;
4476             AddChar = _KeepQuotes;
4477         }
4478         else if ( Quote!=0 && *Cur==Quote )
4479         {
4480             Quote = 0;
4481             AddChar = _KeepQuotes;
4482         }
4483 
4484         if( AddChar )
4485             _Token += *Cur;
4486         ++Cur;
4487         if( *Cur=='\t' )
4488             Column += g_TabLength;
4489         else if( *Cur=='\n' )
4490         {
4491             ++Line;
4492             LineJustIncremented = true;
4493             Column = 1;
4494         }
4495         else
4496             ++Column;
4497     }
4498 
4499     if( Quote!=0 )
4500     {
4501         Line = QuoteLine;
4502         Column = QuoteColumn;
4503         return -(int)(Cur-_Def);    // unclosed quote
4504     }
4505     else
4506     {
4507         if( *Cur=='\n' )
4508         {
4509             if( !LineJustIncremented )
4510                 ++Line;
4511             Column = 1;
4512         }
4513         else if( *Cur=='\t' )
4514             Column += g_TabLength;
4515         else if( *Cur!='\r' && *Cur!='\0' )
4516             ++Column;
4517         return (int)(Cur-_Def);
4518     }
4519 }
4520 
4521 //  ---------------------------------------------------------------------------
4522 
GetBarVarFromString(CTwBar ** _Bar,CTwVar ** _Var,CTwVarGroup ** _VarParent,int * _VarIndex,const char * _Str)4523 int GetBarVarFromString(CTwBar **_Bar, CTwVar **_Var, CTwVarGroup **_VarParent, int *_VarIndex, const char *_Str)
4524 {
4525     *_Bar = NULL;
4526     *_Var = NULL;
4527     *_VarParent = NULL;
4528     *_VarIndex = -1;
4529     vector<string> Names;
4530     string Token;
4531     const char *Cur =_Str;
4532     int l=1, c=1, p=1;
4533     while( *Cur!='\0' && p>0 && Names.size()<=3 )
4534     {
4535         p = ParseToken(Token, Cur, l, c, false, true, '/', '\\');
4536         if( p>0 && Token.size()>0 )
4537         {
4538             Names.push_back(Token);
4539             Cur += p + ((Cur[p]!='\0')?1:0);
4540         }
4541     }
4542     if( p<=0 || (Names.size()!=1 && Names.size()!=2) )
4543         return 0;   // parse error
4544     int BarIdx = g_TwMgr->FindBar(Names[0].c_str());
4545     if( BarIdx<0 )
4546     {
4547         if( Names.size()==1 && strcmp(Names[0].c_str(), "GLOBAL")==0 )
4548         {
4549             *_Bar = TW_GLOBAL_BAR;
4550             return +3;  // 'GLOBAL' found
4551         }
4552         else
4553             return -1;  // bar not found
4554     }
4555     *_Bar = g_TwMgr->m_Bars[BarIdx];
4556     if( Names.size()==1 )
4557         return 1;   // bar found, no var name parsed
4558     *_Var = (*_Bar)->Find(Names[1].c_str(), _VarParent, _VarIndex);
4559     if( *_Var==NULL )
4560         return -2;  // var not found
4561     return 2;       // bar and var found
4562 }
4563 
4564 
BarVarHasAttrib(CTwBar * _Bar,CTwVar * _Var,const char * _Attrib,bool * _HasValue)4565 int BarVarHasAttrib(CTwBar *_Bar, CTwVar *_Var, const char *_Attrib, bool *_HasValue)
4566 {
4567     assert(_Bar!=NULL && _HasValue!=NULL && _Attrib!=NULL && strlen(_Attrib)>0);
4568     *_HasValue = false;
4569     if( _Bar==TW_GLOBAL_BAR )
4570     {
4571         assert( _Var==NULL );
4572         return g_TwMgr->HasAttrib(_Attrib, _HasValue);
4573     }
4574     else if( _Var==NULL )
4575         return _Bar->HasAttrib(_Attrib, _HasValue);
4576     else
4577         return _Var->HasAttrib(_Attrib, _HasValue);
4578 }
4579 
4580 
BarVarSetAttrib(CTwBar * _Bar,CTwVar * _Var,CTwVarGroup * _VarParent,int _VarIndex,int _AttribID,const char * _Value)4581 int BarVarSetAttrib(CTwBar *_Bar, CTwVar *_Var, CTwVarGroup *_VarParent, int _VarIndex, int _AttribID, const char *_Value)
4582 {
4583     assert(_Bar!=NULL && _AttribID>0);
4584 
4585     /* don't delete popupbar here: if any attrib is changed every frame by the app, popup will not work anymore.
4586     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
4587     {
4588         TwDeleteBar(g_TwMgr->m_PopupBar);
4589         g_TwMgr->m_PopupBar = NULL;
4590     }
4591     */
4592 
4593     if( _Bar==TW_GLOBAL_BAR )
4594     {
4595         assert( _Var==NULL );
4596         return g_TwMgr->SetAttrib(_AttribID, _Value);
4597     }
4598     else if( _Var==NULL )
4599         return _Bar->SetAttrib(_AttribID, _Value);
4600     else
4601         return _Var->SetAttrib(_AttribID, _Value, _Bar, _VarParent, _VarIndex);
4602     // don't make _Bar not-up-to-date here, should be done in SetAttrib if needed to avoid too frequent refreshs
4603 }
4604 
4605 
BarVarGetAttrib(CTwBar * _Bar,CTwVar * _Var,CTwVarGroup * _VarParent,int _VarIndex,int _AttribID,std::vector<double> & outDoubles,std::ostringstream & outString)4606 ERetType BarVarGetAttrib(CTwBar *_Bar, CTwVar *_Var, CTwVarGroup *_VarParent, int _VarIndex, int _AttribID, std::vector<double>& outDoubles, std::ostringstream& outString)
4607 {
4608     assert(_Bar!=NULL && _AttribID>0);
4609 
4610     if( _Bar==TW_GLOBAL_BAR )
4611     {
4612         assert( _Var==NULL );
4613         return g_TwMgr->GetAttrib(_AttribID, outDoubles, outString);
4614     }
4615     else if( _Var==NULL )
4616         return _Bar->GetAttrib(_AttribID, outDoubles, outString);
4617     else
4618         return _Var->GetAttrib(_AttribID, _Bar, _VarParent, _VarIndex, outDoubles, outString);
4619 }
4620 
4621 //  ---------------------------------------------------------------------------
4622 
ErrorPosition(bool _MultiLine,int _Line,int _Column)4623 static inline std::string ErrorPosition(bool _MultiLine, int _Line, int _Column)
4624 {
4625     if( !_MultiLine )
4626         return "";
4627     else
4628     {
4629         char pos[32];
4630         //_snprintf(pos, sizeof(pos)-1, " line %d column %d", _Line, _Column);
4631         _snprintf(pos, sizeof(pos)-1, " line %d", _Line); (void)_Column;
4632         pos[sizeof(pos)-1] = '\0';
4633         return pos;
4634     }
4635 }
4636 
4637 //  ---------------------------------------------------------------------------
4638 
TwDefine(const char * _Def)4639 int ANT_CALL TwDefine(const char *_Def)
4640 {
4641     CTwFPU fpu; // force fpu precision
4642 
4643     // hack to scale fonts artificially (for retina display for instance)
4644     if( g_TwMgr==NULL && _Def!=NULL )
4645     {
4646         size_t l = strlen(_Def);
4647         const char *eq = strchr(_Def, '=');
4648         if( eq!=NULL && eq!=_Def && l>0 && l<512 )
4649         {
4650             char *a = new char[l+1];
4651             char *b = new char[l+1];
4652             if( sscanf(_Def, "%s%s", a, b)==2 && strcmp(a, "GLOBAL")==0 )
4653             {
4654                 if( strchr(b, '=') != NULL )
4655                     *strchr(b, '=') = '\0';
4656                 double scal = 1.0;
4657                 if( _stricmp(b, "fontscaling")==0 && sscanf(eq+1, "%lf", &scal)==1 && scal>0 )
4658                 {
4659                     g_FontScaling = (float)scal;
4660                     delete[] a;
4661                     delete[] b;
4662                     return 1;
4663                 }
4664             }
4665             delete[] a;
4666             delete[] b;
4667         }
4668     }
4669 
4670     if( g_TwMgr==NULL )
4671     {
4672         TwGlobalError(g_ErrNotInit);
4673         return 0; // not initialized
4674     }
4675     if( _Def==NULL )
4676     {
4677         g_TwMgr->SetLastError(g_ErrBadParam);
4678         return 0;
4679     }
4680 
4681     bool MultiLine = false;
4682     const char *Cur = _Def;
4683     while( *Cur!='\0' )
4684     {
4685         if( *Cur=='\n' )
4686         {
4687             MultiLine = true;
4688             break;
4689         }
4690         ++Cur;
4691     }
4692 
4693     int Line = 1;
4694     int Column = 1;
4695     enum EState { PARSE_NAME, PARSE_ATTRIB };
4696     EState State = PARSE_NAME;
4697     string Token;
4698     string Value;
4699     CTwBar *Bar = NULL;
4700     CTwVar *Var = NULL;
4701     CTwVarGroup *VarParent = NULL;
4702     int VarIndex = -1;
4703     int p;
4704 
4705     Cur = _Def;
4706     while( *Cur!='\0' )
4707     {
4708         const char *PrevCur = Cur;
4709         p = ParseToken(Token, Cur, Line, Column, (State==PARSE_NAME), (State==PARSE_ATTRIB), (State==PARSE_ATTRIB)?'=':'\0');
4710         if( p<=0 || Token.size()<=0 )
4711         {
4712             if( p>0 && Cur[p]=='\0' )
4713             {
4714                 Cur += p;
4715                 continue;
4716             }
4717             _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), (p<0)?(Cur-p):PrevCur);
4718             g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
4719             g_TwMgr->SetLastError(g_ErrParse);
4720             return 0;
4721         }
4722         char CurSep = Cur[p];
4723         Cur += p + ((CurSep!='\0')?1:0);
4724 
4725         if( State==PARSE_NAME )
4726         {
4727             int Err = GetBarVarFromString(&Bar, &Var, &VarParent, &VarIndex, Token.c_str());
4728             if( Err<=0 )
4729             {
4730                 if( Err==-1 )
4731                     _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: Bar not found%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str());
4732                 else if( Err==-2 )
4733                     _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: Variable not found%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str());
4734                 else
4735                     _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str());
4736                 g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
4737                 g_TwMgr->SetLastError(g_ErrParse);
4738                 return 0;
4739             }
4740             State = PARSE_ATTRIB;
4741         }
4742         else // State==PARSE_ATTRIB
4743         {
4744             assert(State==PARSE_ATTRIB);
4745             assert(Bar!=NULL);
4746 
4747             bool HasValue = false;
4748             Value = "";
4749             int AttribID = BarVarHasAttrib(Bar, Var, Token.c_str(), &HasValue);
4750             if( AttribID<=0 )
4751             {
4752                 _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: Unknown attribute%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str());
4753                 g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
4754                 g_TwMgr->SetLastError(g_ErrParse);
4755                 return 0;
4756             }
4757 
4758             // special case for backward compatibility
4759             if( HasValue && ( _stricmp(Token.c_str(), "readonly")==0 || _stricmp(Token.c_str(), "hexa")==0 ) )
4760             {
4761                 if( CurSep==' ' || CurSep=='\t' )
4762                 {
4763                     const char *ch = Cur;
4764                     while( *ch==' ' || *ch=='\t' ) // find next non-space character
4765                         ++ch;
4766                     if( *ch!='=' ) // if this is not '=' the param has no value
4767                         HasValue = false;
4768                 }
4769             }
4770 
4771             if( HasValue )
4772             {
4773                 if( CurSep!='=' )
4774                 {
4775                     string EqualStr;
4776                     p = ParseToken(EqualStr, Cur, Line, Column, true, true, '=');
4777                     CurSep = Cur[p];
4778                     if( p<0 || EqualStr.size()>0 || CurSep!='=' )
4779                     {
4780                         _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: '=' not found while reading attribute value%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str());
4781                         g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
4782                         g_TwMgr->SetLastError(g_ErrParse);
4783                         return 0;
4784                     }
4785                     Cur += p + 1;
4786                 }
4787                 p = ParseToken(Value, Cur, Line, Column, false, true);
4788                 if( p<=0 )
4789                 {
4790                     _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: can't read attribute value%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str());
4791                     g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
4792                     g_TwMgr->SetLastError(g_ErrParse);
4793                     return 0;
4794                 }
4795                 CurSep = Cur[p];
4796                 Cur += p + ((CurSep!='\0')?1:0);
4797             }
4798             const char *PrevLastErrorPtr = g_TwMgr->CheckLastError();
4799             if( BarVarSetAttrib(Bar, Var, VarParent, VarIndex, AttribID, HasValue?Value.c_str():NULL)==0 )
4800             {
4801                 if( g_TwMgr->CheckLastError()==NULL || strlen(g_TwMgr->CheckLastError())<=0 || g_TwMgr->CheckLastError()==PrevLastErrorPtr )
4802                     _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: wrong attribute value%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str());
4803                 else
4804                     _snprintf(g_ErrParse, sizeof(g_ErrParse), "%s%s [%-16s...]", g_TwMgr->CheckLastError(), ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str());
4805                 g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
4806                 g_TwMgr->SetLastError(g_ErrParse);
4807                 return 0;
4808             }
4809             // sweep spaces to detect next attrib
4810             while( *Cur==' ' || *Cur=='\t' || *Cur=='\r' )
4811             {
4812                 ++Cur;
4813                 if( *Cur=='\t' )
4814                     Column += g_TabLength;
4815                 else if( *Cur!='\r' )
4816                     ++Column;
4817             }
4818             if( *Cur=='\n' )    // new line detected
4819             {
4820                 ++Line;
4821                 Column = 1;
4822                 State = PARSE_NAME;
4823             }
4824         }
4825     }
4826 
4827     g_TwMgr->m_HelpBarNotUpToDate = true;
4828     return 1;
4829 }
4830 
4831 //  ---------------------------------------------------------------------------
4832 
TwDefineEnum(const char * _Name,const TwEnumVal * _EnumValues,unsigned int _NbValues)4833 TwType ANT_CALL TwDefineEnum(const char *_Name, const TwEnumVal *_EnumValues, unsigned int _NbValues)
4834 {
4835     CTwFPU fpu; // force fpu precision
4836 
4837     if( g_TwMgr==NULL )
4838     {
4839         TwGlobalError(g_ErrNotInit);
4840         return TW_TYPE_UNDEF; // not initialized
4841     }
4842     if( _EnumValues==NULL && _NbValues!=0 )
4843     {
4844         g_TwMgr->SetLastError(g_ErrBadParam);
4845         return TW_TYPE_UNDEF;
4846     }
4847 
4848     if( g_TwMgr->m_PopupBar!=NULL ) // delete popup bar first if it exists
4849     {
4850         TwDeleteBar(g_TwMgr->m_PopupBar);
4851         g_TwMgr->m_PopupBar = NULL;
4852     }
4853 
4854     size_t enumIndex = g_TwMgr->m_Enums.size();
4855     if( _Name!=NULL && strlen(_Name)>0 )
4856         for( size_t j=0; j<g_TwMgr->m_Enums.size(); ++j )
4857             if( strcmp(_Name, g_TwMgr->m_Enums[j].m_Name.c_str())==0 )
4858             {
4859                 enumIndex = j;
4860                 break;
4861             }
4862     if( enumIndex==g_TwMgr->m_Enums.size() )
4863         g_TwMgr->m_Enums.push_back(CTwMgr::CEnum());
4864     assert( enumIndex>=0 && enumIndex<g_TwMgr->m_Enums.size() );
4865     CTwMgr::CEnum& e = g_TwMgr->m_Enums[enumIndex];
4866     if( _Name!=NULL && strlen(_Name)>0 )
4867         e.m_Name = _Name;
4868     else
4869         e.m_Name = "";
4870     e.m_Entries.clear();
4871     for(unsigned int i=0; i<_NbValues; ++i)
4872     {
4873         CTwMgr::CEnum::CEntries::value_type Entry(_EnumValues[i].Value, (_EnumValues[i].Label!=NULL)?_EnumValues[i].Label:"");
4874         pair<CTwMgr::CEnum::CEntries::iterator, bool> Result = e.m_Entries.insert(Entry);
4875         if( !Result.second )
4876             (Result.first)->second = Entry.second;
4877     }
4878 
4879     return TwType( TW_TYPE_ENUM_BASE + enumIndex );
4880 }
4881 
4882 //  ---------------------------------------------------------------------------
4883 
TwDefineEnumFromString(const char * _Name,const char * _EnumString)4884 TwType TW_CALL TwDefineEnumFromString(const char *_Name, const char *_EnumString)
4885 {
4886     if (_EnumString == NULL)
4887         return TwDefineEnum(_Name, NULL, 0);
4888 
4889     // split enumString
4890     stringstream EnumStream(_EnumString);
4891     string Label;
4892     vector<string> Labels;
4893     while( getline(EnumStream, Label, ',') ) {
4894         // trim Label
4895         size_t Start = Label.find_first_not_of(" \n\r\t");
4896         size_t End = Label.find_last_not_of(" \n\r\t");
4897         if( Start==string::npos || End==string::npos )
4898             Label = "";
4899         else
4900             Label = Label.substr(Start, (End-Start)+1);
4901         // store Label
4902         Labels.push_back(Label);
4903     }
4904     // create TwEnumVal array
4905     vector<TwEnumVal> Vals(Labels.size());
4906     for( int i=0; i<(int)Labels.size(); i++ )
4907     {
4908         Vals[i].Value = i;
4909         Vals[i].Label = Labels[i].c_str();
4910     }
4911 
4912     return TwDefineEnum(_Name, Vals.empty() ? NULL : &(Vals[0]), (unsigned int)Vals.size());
4913 }
4914 
4915 //  ---------------------------------------------------------------------------
4916 
DefaultSummary(char * _SummaryString,size_t _SummaryMaxLength,const void * _Value,void * _ClientData)4917 void ANT_CALL CTwMgr::CStruct::DefaultSummary(char *_SummaryString, size_t _SummaryMaxLength, const void *_Value, void *_ClientData)
4918 {
4919     const CTwVarGroup *varGroup = static_cast<const CTwVarGroup *>(_Value); // special case
4920     if( _SummaryString && _SummaryMaxLength>0 )
4921         _SummaryString[0] = '\0';
4922     size_t structIndex = (size_t)(_ClientData);
4923     if(    g_TwMgr && _SummaryString && _SummaryMaxLength>2
4924         && varGroup && static_cast<const CTwVar *>(varGroup)->IsGroup()
4925         && structIndex>=0 && structIndex<=g_TwMgr->m_Structs.size() )
4926     {
4927         // return g_TwMgr->m_Structs[structIndex].m_Name.c_str();
4928         CTwMgr::CStruct& s = g_TwMgr->m_Structs[structIndex];
4929         _SummaryString[0] = '{';
4930         _SummaryString[1] = '\0';
4931         bool separator = false;
4932         for( size_t i=0; i<s.m_Members.size(); ++i )
4933         {
4934             string varName = varGroup->m_Name + '.' + s.m_Members[i].m_Name;
4935             const CTwVar *var = varGroup->Find(varName.c_str(), NULL, NULL);
4936             if( var )
4937             {
4938                 if( var->IsGroup() )
4939                 {
4940                     const CTwVarGroup *grp = static_cast<const CTwVarGroup *>(var);
4941                     if( grp->m_SummaryCallback!=NULL )
4942                     {
4943                         size_t l = strlen(_SummaryString);
4944                         if( separator )
4945                         {
4946                             _SummaryString[l++] = ',';
4947                             _SummaryString[l++] = '\0';
4948                         }
4949                         if( grp->m_SummaryCallback==CTwMgr::CStruct::DefaultSummary )
4950                             grp->m_SummaryCallback(_SummaryString+l, _SummaryMaxLength-l, grp, grp->m_SummaryClientData);
4951                         else
4952                             grp->m_SummaryCallback(_SummaryString+l, _SummaryMaxLength-l, grp->m_StructValuePtr, grp->m_SummaryClientData);
4953                         separator = true;
4954                     }
4955                 }
4956                 else
4957                 {
4958                     size_t l = strlen(_SummaryString);
4959                     if( separator )
4960                     {
4961                         _SummaryString[l++] = ',';
4962                         _SummaryString[l++] = '\0';
4963                     }
4964                     string valString;
4965                     const CTwVarAtom *atom = static_cast<const CTwVarAtom *>(var);
4966                     atom->ValueToString(&valString);
4967                     if( atom->m_Type==TW_TYPE_BOOLCPP || atom->m_Type==TW_TYPE_BOOL8 || atom->m_Type==TW_TYPE_BOOL16 || atom->m_Type==TW_TYPE_BOOL32 )
4968                     {
4969                         if (valString == "0")
4970                             valString = "-";
4971                         else if (valString == "1")
4972                             valString = "\x7f"; // check sign
4973                     }
4974                     strncat(_SummaryString, valString.c_str(), _SummaryMaxLength-l);
4975                     separator = true;
4976                 }
4977                 if( strlen(_SummaryString)>_SummaryMaxLength-2 )
4978                     break;
4979             }
4980         }
4981         size_t l = strlen(_SummaryString);
4982         if( l>_SummaryMaxLength-2 )
4983         {
4984             _SummaryString[_SummaryMaxLength-2] = '.';
4985             _SummaryString[_SummaryMaxLength-1] = '.';
4986             _SummaryString[_SummaryMaxLength+0] = '\0';
4987         }
4988         else
4989         {
4990             _SummaryString[l+0] = '}';
4991             _SummaryString[l+1] = '\0';
4992         }
4993     }
4994 }
4995 
4996 //  ---------------------------------------------------------------------------
4997 
TwDefineStruct(const char * _StructName,const TwStructMember * _StructMembers,unsigned int _NbMembers,size_t _StructSize,TwSummaryCallback _SummaryCallback,void * _SummaryClientData)4998 TwType ANT_CALL TwDefineStruct(const char *_StructName, const TwStructMember *_StructMembers, unsigned int _NbMembers, size_t _StructSize, TwSummaryCallback _SummaryCallback, void *_SummaryClientData)
4999 {
5000     CTwFPU fpu; // force fpu precision
5001 
5002     if( g_TwMgr==NULL )
5003     {
5004         TwGlobalError(g_ErrNotInit);
5005         return TW_TYPE_UNDEF; // not initialized
5006     }
5007     if( _StructMembers==NULL || _NbMembers==0 || _StructSize==0 )
5008     {
5009         g_TwMgr->SetLastError(g_ErrBadParam);
5010         return TW_TYPE_UNDEF;
5011     }
5012 
5013     if( _StructName!=NULL && strlen(_StructName)>0 )
5014         for( size_t j=0; j<g_TwMgr->m_Structs.size(); ++j )
5015             if( strcmp(_StructName, g_TwMgr->m_Structs[j].m_Name.c_str())==0 )
5016             {
5017                 g_TwMgr->SetLastError(g_ErrExist);
5018                 return TW_TYPE_UNDEF;
5019             }
5020 
5021     size_t structIndex = g_TwMgr->m_Structs.size();
5022     CTwMgr::CStruct s;
5023     s.m_Size = _StructSize;
5024     if( _StructName!=NULL && strlen(_StructName)>0 )
5025         s.m_Name = _StructName;
5026     else
5027         s.m_Name = "";
5028     s.m_Members.resize(_NbMembers);
5029     if( _SummaryCallback!=NULL )
5030     {
5031         s.m_SummaryCallback = _SummaryCallback;
5032         s.m_SummaryClientData = _SummaryClientData;
5033     }
5034     else
5035     {
5036         s.m_SummaryCallback = CTwMgr::CStruct::DefaultSummary;
5037         s.m_SummaryClientData = (void *)(structIndex);
5038     }
5039     for( unsigned int i=0; i<_NbMembers; ++i )
5040     {
5041         CTwMgr::CStructMember& m = s.m_Members[i];
5042         if( _StructMembers[i].Name!=NULL )
5043             m.m_Name = _StructMembers[i].Name;
5044         else
5045         {
5046             char name[16];
5047             sprintf(name, "%u", i);
5048             m.m_Name = name;
5049         }
5050         m.m_Type = _StructMembers[i].Type;
5051         m.m_Size = 0;   // to avoid endless recursivity in GetDataSize
5052         m.m_Size = CTwVar::GetDataSize(m.m_Type);
5053         if( _StructMembers[i].Offset<_StructSize )
5054             m.m_Offset = _StructMembers[i].Offset;
5055         else
5056         {
5057             g_TwMgr->SetLastError(g_ErrOffset);
5058             return TW_TYPE_UNDEF;
5059         }
5060         if( _StructMembers[i].DefString!=NULL && strlen(_StructMembers[i].DefString)>0 )
5061             m.m_DefString = _StructMembers[i].DefString;
5062         else
5063             m.m_DefString = "";
5064     }
5065 
5066     g_TwMgr->m_Structs.push_back(s);
5067     assert( g_TwMgr->m_Structs.size()==structIndex+1 );
5068     return TwType( TW_TYPE_STRUCT_BASE + structIndex );
5069 }
5070 
5071 //  ---------------------------------------------------------------------------
5072 
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,const char * _Help)5073 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, const char *_Help)
5074 {
5075     CTwFPU fpu; // force fpu precision
5076 
5077     if( g_TwMgr==NULL )
5078     {
5079         TwGlobalError(g_ErrNotInit);
5080         return TW_TYPE_UNDEF; // not initialized
5081     }
5082     if( _StructSize==0 || _StructExtInitCallback==NULL || _CopyVarFromExtCallback==NULL || _CopyVarToExtCallback==NULL )
5083     {
5084         g_TwMgr->SetLastError(g_ErrBadParam);
5085         return TW_TYPE_UNDEF;
5086     }
5087     TwType type = TwDefineStruct(_StructName, _StructExtMembers, _NbExtMembers, _StructExtSize, _SummaryCallback, _ClientData);
5088     if( type>=TW_TYPE_STRUCT_BASE && type<TW_TYPE_STRUCT_BASE+(int)g_TwMgr->m_Structs.size() )
5089     {
5090         CTwMgr::CStruct& s = g_TwMgr->m_Structs[type-TW_TYPE_STRUCT_BASE];
5091         s.m_IsExt = true;
5092         s.m_ClientStructSize = _StructSize;
5093         s.m_StructExtInitCallback = _StructExtInitCallback;
5094         s.m_CopyVarFromExtCallback = _CopyVarFromExtCallback;
5095         s.m_CopyVarToExtCallback = _CopyVarToExtCallback;
5096         s.m_ExtClientData = _ClientData;
5097         if( _Help!=NULL )
5098             s.m_Help = _Help;
5099     }
5100     return type;
5101 }
5102 
5103 
5104 //  ---------------------------------------------------------------------------
5105 
TwGetKeyCode(int * _Code,int * _Modif,const char * _String)5106 bool TwGetKeyCode(int *_Code, int *_Modif, const char *_String)
5107 {
5108     assert(_Code!=NULL && _Modif!=NULL);
5109     bool Ok = true;
5110     *_Modif = TW_KMOD_NONE;
5111     *_Code = 0;
5112     size_t Start = strlen(_String)-1;
5113     if( Start<0 )
5114         return false;
5115     while( Start>0 && _String[Start-1]!='+' )
5116         --Start;
5117     while( _String[Start]==' ' || _String[Start]=='\t' )
5118         ++Start;
5119     char *CodeStr = _strdup(_String+Start);
5120     for( size_t i=strlen(CodeStr)-1; i>=0; ++i )
5121         if( CodeStr[i]==' ' || CodeStr[i]=='\t' )
5122             CodeStr[i] = '\0';
5123         else
5124             break;
5125 
5126     /*
5127     if( strstr(_String, "SHIFT")!=NULL || strstr(_String, "shift")!=NULL )
5128         *_Modif |= TW_KMOD_SHIFT;
5129     if( strstr(_String, "CTRL")!=NULL || strstr(_String, "ctrl")!=NULL )
5130         *_Modif |= TW_KMOD_CTRL;
5131     if( strstr(_String, "META")!=NULL || strstr(_String, "meta")!=NULL )
5132         *_Modif |= TW_KMOD_META;
5133 
5134     if( strstr(_String, "ALTGR")!=NULL || strstr(_String, "altgr")!=NULL )
5135         ((void)(0));    // *_Modif |= TW_KMOD_ALTGR;
5136     else // ALT and ALTGR are exclusive
5137         if( strstr(_String, "ALT")!=NULL || strstr(_String, "alt")!=NULL )
5138             *_Modif |= TW_KMOD_ALT;
5139     */
5140     char *up = _strdup(_String);
5141     // _strupr(up);
5142     for( char *upch=up; *upch!='\0'; ++upch )
5143         *upch = (char)toupper(*upch);
5144     if( strstr(up, "SHIFT")!=NULL )
5145         *_Modif |= TW_KMOD_SHIFT;
5146     if( strstr(up, "CTRL")!=NULL )
5147         *_Modif |= TW_KMOD_CTRL;
5148     if( strstr(up, "META")!=NULL )
5149         *_Modif |= TW_KMOD_META;
5150 
5151     if( strstr(up, "ALTGR")!=NULL )
5152         ((void)(0));    // *_Modif |= TW_KMOD_ALTGR;
5153     else // ALT and ALTGR are exclusive
5154         if( strstr(up, "ALT")!=NULL )
5155             *_Modif |= TW_KMOD_ALT;
5156     free(up);
5157 
5158     if( strlen(CodeStr)==1 )
5159         *_Code = (unsigned char)(CodeStr[0]);
5160     else if( _stricmp(CodeStr, "backspace")==0 || _stricmp(CodeStr, "bs")==0 )
5161         *_Code = TW_KEY_BACKSPACE;
5162     else if( _stricmp(CodeStr, "tab")==0 )
5163         *_Code = TW_KEY_TAB;
5164     else if( _stricmp(CodeStr, "clear")==0 || _stricmp(CodeStr, "clr")==0 )
5165         *_Code = TW_KEY_CLEAR;
5166     else if( _stricmp(CodeStr, "return")==0 || _stricmp(CodeStr, "ret")==0 )
5167         *_Code = TW_KEY_RETURN;
5168     else if( _stricmp(CodeStr, "pause")==0 )
5169         *_Code = TW_KEY_PAUSE;
5170     else if( _stricmp(CodeStr, "escape")==0 || _stricmp(CodeStr, "esc")==0 )
5171         *_Code = TW_KEY_ESCAPE;
5172     else if( _stricmp(CodeStr, "space")==0 )
5173         *_Code = TW_KEY_SPACE;
5174     else if( _stricmp(CodeStr, "delete")==0 || _stricmp(CodeStr, "del")==0 )
5175         *_Code = TW_KEY_DELETE;
5176     /*
5177     else if( strlen(CodeStr)==4 && CodeStr[3]>='0' && CodeStr[3]<='9' && (strstr(CodeStr, "pad")==CodeStr || strstr(CodeStr, "PAD")==CodeStr) )
5178         *_Code = TW_KEY_PAD_0 + CodeStr[3]-'0';
5179     else if( _stricmp(CodeStr, "pad.")==0 )
5180         *_Code = TW_KEY_PAD_PERIOD;
5181     else if( _stricmp(CodeStr, "pad/")==0 )
5182         *_Code = TW_KEY_PAD_DIVIDE;
5183     else if( _stricmp(CodeStr, "pad*")==0 )
5184         *_Code = TW_KEY_PAD_MULTIPLY;
5185     else if( _stricmp(CodeStr, "pad+")==0 )
5186         *_Code = TW_KEY_PAD_PLUS;
5187     else if( _stricmp(CodeStr, "pad-")==0 )
5188         *_Code = TW_KEY_PAD_MINUS;
5189     else if( _stricmp(CodeStr, "padenter")==0 )
5190         *_Code = TW_KEY_PAD_ENTER;
5191     else if( _stricmp(CodeStr, "pad=")==0 )
5192         *_Code = TW_KEY_PAD_EQUALS;
5193     */
5194     else if( _stricmp(CodeStr, "up")==0 )
5195         *_Code = TW_KEY_UP;
5196     else if( _stricmp(CodeStr, "down")==0 )
5197         *_Code = TW_KEY_DOWN;
5198     else if( _stricmp(CodeStr, "right")==0 )
5199         *_Code = TW_KEY_RIGHT;
5200     else if( _stricmp(CodeStr, "left")==0 )
5201         *_Code = TW_KEY_LEFT;
5202     else if( _stricmp(CodeStr, "insert")==0 || _stricmp(CodeStr, "ins")==0 )
5203         *_Code = TW_KEY_INSERT;
5204     else if( _stricmp(CodeStr, "home")==0 )
5205         *_Code = TW_KEY_HOME;
5206     else if( _stricmp(CodeStr, "end")==0 )
5207         *_Code = TW_KEY_END;
5208     else if( _stricmp(CodeStr, "pgup")==0 )
5209         *_Code = TW_KEY_PAGE_UP;
5210     else if( _stricmp(CodeStr, "pgdown")==0 )
5211         *_Code = TW_KEY_PAGE_DOWN;
5212     else if( (strlen(CodeStr)==2 || strlen(CodeStr)==3) && (CodeStr[0]=='f' || CodeStr[0]=='F') )
5213     {
5214         int n = 0;
5215         if( sscanf(CodeStr+1, "%d", &n)==1 && n>0 && n<16 )
5216             *_Code = TW_KEY_F1 + n-1;
5217         else
5218             Ok = false;
5219     }
5220 
5221     free(CodeStr);
5222     return Ok;
5223 }
5224 
TwGetKeyString(std::string * _String,int _Code,int _Modif)5225 bool TwGetKeyString(std::string *_String, int _Code, int _Modif)
5226 {
5227     assert(_String!=NULL);
5228     bool Ok = true;
5229     if( _Modif & TW_KMOD_SHIFT )
5230         *_String += "SHIFT+";
5231     if( _Modif & TW_KMOD_CTRL )
5232         *_String += "CTRL+";
5233     if ( _Modif & TW_KMOD_ALT )
5234         *_String += "ALT+";
5235     if ( _Modif & TW_KMOD_META )
5236         *_String += "META+";
5237     // if ( _Modif & TW_KMOD_ALTGR )
5238     //  *_String += "ALTGR+";
5239     switch( _Code )
5240     {
5241     case TW_KEY_BACKSPACE:
5242         *_String += "BackSpace";
5243         break;
5244     case TW_KEY_TAB:
5245         *_String += "Tab";
5246         break;
5247     case TW_KEY_CLEAR:
5248         *_String += "Clear";
5249         break;
5250     case TW_KEY_RETURN:
5251         *_String += "Return";
5252         break;
5253     case TW_KEY_PAUSE:
5254         *_String += "Pause";
5255         break;
5256     case TW_KEY_ESCAPE:
5257         *_String += "Esc";
5258         break;
5259     case TW_KEY_SPACE:
5260         *_String += "Space";
5261         break;
5262     case TW_KEY_DELETE:
5263         *_String += "Delete";
5264         break;
5265     /*
5266     case TW_KEY_PAD_0:
5267         *_String += "PAD0";
5268         break;
5269     case TW_KEY_PAD_1:
5270         *_String += "PAD1";
5271         break;
5272     case TW_KEY_PAD_2:
5273         *_String += "PAD2";
5274         break;
5275     case TW_KEY_PAD_3:
5276         *_String += "PAD3";
5277         break;
5278     case TW_KEY_PAD_4:
5279         *_String += "PAD4";
5280         break;
5281     case TW_KEY_PAD_5:
5282         *_String += "PAD5";
5283         break;
5284     case TW_KEY_PAD_6:
5285         *_String += "PAD6";
5286         break;
5287     case TW_KEY_PAD_7:
5288         *_String += "PAD7";
5289         break;
5290     case TW_KEY_PAD_8:
5291         *_String += "PAD8";
5292         break;
5293     case TW_KEY_PAD_9:
5294         *_String += "PAD9";
5295         break;
5296     case TW_KEY_PAD_PERIOD:
5297         *_String += "PAD.";
5298         break;
5299     case TW_KEY_PAD_DIVIDE:
5300         *_String += "PAD/";
5301         break;
5302     case TW_KEY_PAD_MULTIPLY:
5303         *_String += "PAD*";
5304         break;
5305     case TW_KEY_PAD_MINUS:
5306         *_String += "PAD-";
5307         break;
5308     case TW_KEY_PAD_PLUS:
5309         *_String += "PAD+";
5310         break;
5311     case TW_KEY_PAD_ENTER:
5312         *_String += "PADEnter";
5313         break;
5314     case TW_KEY_PAD_EQUALS:
5315         *_String += "PAD=";
5316         break;
5317     */
5318     case TW_KEY_UP:
5319         *_String += "Up";
5320         break;
5321     case TW_KEY_DOWN:
5322         *_String += "Down";
5323         break;
5324     case TW_KEY_RIGHT:
5325         *_String += "Right";
5326         break;
5327     case TW_KEY_LEFT:
5328         *_String += "Left";
5329         break;
5330     case TW_KEY_INSERT:
5331         *_String += "Insert";
5332         break;
5333     case TW_KEY_HOME:
5334         *_String += "Home";
5335         break;
5336     case TW_KEY_END:
5337         *_String += "End";
5338         break;
5339     case TW_KEY_PAGE_UP:
5340         *_String += "PgUp";
5341         break;
5342     case TW_KEY_PAGE_DOWN:
5343         *_String += "PgDown";
5344         break;
5345     case TW_KEY_F1:
5346         *_String += "F1";
5347         break;
5348     case TW_KEY_F2:
5349         *_String += "F2";
5350         break;
5351     case TW_KEY_F3:
5352         *_String += "F3";
5353         break;
5354     case TW_KEY_F4:
5355         *_String += "F4";
5356         break;
5357     case TW_KEY_F5:
5358         *_String += "F5";
5359         break;
5360     case TW_KEY_F6:
5361         *_String += "F6";
5362         break;
5363     case TW_KEY_F7:
5364         *_String += "F7";
5365         break;
5366     case TW_KEY_F8:
5367         *_String += "F8";
5368         break;
5369     case TW_KEY_F9:
5370         *_String += "F9";
5371         break;
5372     case TW_KEY_F10:
5373         *_String += "F10";
5374         break;
5375     case TW_KEY_F11:
5376         *_String += "F11";
5377         break;
5378     case TW_KEY_F12:
5379         *_String += "F12";
5380         break;
5381     case TW_KEY_F13:
5382         *_String += "F13";
5383         break;
5384     case TW_KEY_F14:
5385         *_String += "F14";
5386         break;
5387     case TW_KEY_F15:
5388         *_String += "F15";
5389         break;
5390     default:
5391         if( _Code>0 && _Code<256 )
5392             *_String += char(_Code);
5393         else
5394         {
5395             *_String += "Unknown";
5396             Ok = false;
5397         }
5398     }
5399     return Ok;
5400 }
5401 
5402 //  ---------------------------------------------------------------------------
5403 
5404 const int        TW_MOUSE_NOMOTION = -1;
5405 ETwMouseAction   TW_MOUSE_MOTION = (ETwMouseAction)(-2);
5406 ETwMouseAction   TW_MOUSE_WHEEL = (ETwMouseAction)(-3);
5407 ETwMouseButtonID TW_MOUSE_NA = (ETwMouseButtonID)(-1);
5408 
TwMouseEvent(ETwMouseAction _EventType,TwMouseButtonID _Button,int _MouseX,int _MouseY,int _WheelPos)5409 static int TwMouseEvent(ETwMouseAction _EventType, TwMouseButtonID _Button, int _MouseX, int _MouseY, int _WheelPos)
5410 {
5411     CTwFPU fpu; // force fpu precision
5412 
5413     if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
5414     {
5415         // TwGlobalError(g_ErrNotInit); -> not an error here
5416         return 0; // not initialized
5417     }
5418     if( g_TwMgr->m_WndHeight<=0 || g_TwMgr->m_WndWidth<=0 )
5419     {
5420         //g_TwMgr->SetLastError(g_ErrBadWndSize);   // not an error, windows not yet ready.
5421         return 0;
5422     }
5423 
5424     // For multi-thread safety
5425     if( !TwFreeAsyncDrawing() )
5426         return 0;
5427 
5428     if( _MouseX==TW_MOUSE_NOMOTION )
5429         _MouseX = g_TwMgr->m_LastMouseX;
5430     else
5431         g_TwMgr->m_LastMouseX = _MouseX;
5432     if( _MouseY==TW_MOUSE_NOMOTION )
5433         _MouseY = g_TwMgr->m_LastMouseY;
5434     else
5435         g_TwMgr->m_LastMouseY = _MouseY;
5436 
5437     // for autorepeat
5438     if( (!g_TwMgr->m_IsRepeatingMousePressed || !g_TwMgr->m_CanRepeatMousePressed) && _EventType==TW_MOUSE_PRESSED )
5439     {
5440         g_TwMgr->m_LastMousePressedTime = g_TwMgr->m_Timer.GetTime();
5441         g_TwMgr->m_LastMousePressedButtonID = _Button;
5442         g_TwMgr->m_LastMousePressedPosition[0] = _MouseX;
5443         g_TwMgr->m_LastMousePressedPosition[1] = _MouseY;
5444         g_TwMgr->m_CanRepeatMousePressed = true;
5445         g_TwMgr->m_IsRepeatingMousePressed = false;
5446     }
5447     else if( _EventType==TW_MOUSE_RELEASED || _EventType==TW_MOUSE_WHEEL )
5448     {
5449         g_TwMgr->m_CanRepeatMousePressed = false;
5450         g_TwMgr->m_IsRepeatingMousePressed = false;
5451     }
5452 
5453     bool Handled = false;
5454     bool wasPopup = (g_TwMgr->m_PopupBar!=NULL);
5455     CTwBar *Bar = NULL;
5456     int i;
5457 
5458     // search for a bar with mousedrag enabled
5459     CTwBar *BarDragging = NULL;
5460     for( i=((int)g_TwMgr->m_Bars.size())-1; i>=0; --i )
5461     {
5462         Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]];
5463         if( Bar!=NULL && Bar->m_Visible && Bar->IsDragging() )
5464         {
5465             BarDragging = Bar;
5466             break;
5467         }
5468     }
5469 
5470     for( i=(int)g_TwMgr->m_Bars.size(); i>=0; --i )
5471     {
5472         if( i==(int)g_TwMgr->m_Bars.size() )    // first try the bar with mousedrag enabled (this bar has the focus)
5473             Bar = BarDragging;
5474         else
5475         {
5476             Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]];
5477             if( Bar==BarDragging )
5478                 continue;
5479         }
5480         if( Bar!=NULL && Bar->m_Visible )
5481         {
5482             if( _EventType==TW_MOUSE_MOTION )
5483                 Handled = Bar->MouseMotion(_MouseX, _MouseY);
5484             else if( _EventType==TW_MOUSE_PRESSED || _EventType==TW_MOUSE_RELEASED )
5485                 Handled = Bar->MouseButton(_Button, (_EventType==TW_MOUSE_PRESSED), _MouseX, _MouseY);
5486             else if( _EventType==TW_MOUSE_WHEEL )
5487             {
5488                 if( abs(_WheelPos-g_TwMgr->m_LastMouseWheelPos)<4 ) // avoid crazy wheel positions
5489                     Handled = Bar->MouseWheel(_WheelPos, g_TwMgr->m_LastMouseWheelPos, _MouseX, _MouseY);
5490             }
5491             if( Handled )
5492                 break;
5493         }
5494     }
5495 
5496     if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call
5497         return 1;
5498 
5499     /*
5500     if( i>=0 && Bar!=NULL && Handled && (_EventType==TW_MOUSE_PRESSED || Bar->IsMinimized()) && i!=((int)g_TwMgr->m_Bars.size())-1 )
5501     {
5502         int iOrder = g_TwMgr->m_Order[i];
5503         for( int j=i; j<(int)g_TwMgr->m_Bars.size()-1; ++j )
5504             g_TwMgr->m_Order[j] = g_TwMgr->m_Order[j+1];
5505         g_TwMgr->m_Order[(int)g_TwMgr->m_Bars.size()-1] = iOrder;
5506     }
5507     */
5508     if( _EventType==TW_MOUSE_PRESSED || (Bar!=NULL && Bar->IsMinimized() && Handled) )
5509     {
5510         if( wasPopup && Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_PopupBar!=NULL ) // delete popup
5511         {
5512             TwDeleteBar(g_TwMgr->m_PopupBar);
5513             g_TwMgr->m_PopupBar = NULL;
5514         }
5515 
5516         if( i>=0 && Bar!=NULL && Handled && !wasPopup )
5517             TwSetTopBar(Bar);
5518     }
5519 
5520     if( _EventType==TW_MOUSE_WHEEL )
5521         g_TwMgr->m_LastMouseWheelPos = _WheelPos;
5522 
5523     return Handled ? 1 : 0;
5524 }
5525 
TwMouseButton(ETwMouseAction _EventType,TwMouseButtonID _Button)5526 int ANT_CALL TwMouseButton(ETwMouseAction _EventType, TwMouseButtonID _Button)
5527 {
5528     return TwMouseEvent(_EventType, _Button, TW_MOUSE_NOMOTION, TW_MOUSE_NOMOTION, 0);
5529 }
5530 
TwMouseMotion(int _MouseX,int _MouseY)5531 int ANT_CALL TwMouseMotion(int _MouseX, int _MouseY)
5532 {
5533     return TwMouseEvent(TW_MOUSE_MOTION, TW_MOUSE_NA, _MouseX, _MouseY, 0);
5534 }
5535 
TwMouseWheel(int _Pos)5536 int ANT_CALL TwMouseWheel(int _Pos)
5537 {
5538     return TwMouseEvent(TW_MOUSE_WHEEL, TW_MOUSE_NA, TW_MOUSE_NOMOTION, TW_MOUSE_NOMOTION, _Pos);
5539 }
5540 
5541 //  ---------------------------------------------------------------------------
5542 
TranslateKey(int _Key,int _Modifiers)5543 static int TranslateKey(int _Key, int _Modifiers)
5544 {
5545     // CTRL special cases
5546     //if( (_Modifiers&TW_KMOD_CTRL) && !(_Modifiers&TW_KMOD_ALT || _Modifiers&TW_KMOD_META) && _Key>0 && _Key<32 )
5547     //  _Key += 'a'-1;
5548     if( (_Modifiers&TW_KMOD_CTRL) )
5549     {
5550         if( _Key>='a' && _Key<='z' && ( ((_Modifiers&0x2000) && !(_Modifiers&TW_KMOD_SHIFT)) || (!(_Modifiers&0x2000) && (_Modifiers&TW_KMOD_SHIFT)) )) // 0x2000 is SDL's KMOD_CAPS
5551             _Key += 'A'-'a';
5552         else if ( _Key>='A' && _Key<='Z' && ( ((_Modifiers&0x2000) && (_Modifiers&TW_KMOD_SHIFT)) || (!(_Modifiers&0x2000) && !(_Modifiers&TW_KMOD_SHIFT)) )) // 0x2000 is SDL's KMOD_CAPS
5553             _Key += 'a'-'A';
5554     }
5555 
5556     // PAD translation (for SDL keysym)
5557     if( _Key>=256 && _Key<=272 ) // 256=SDLK_KP0 ... 272=SDLK_KP_EQUALS
5558     {
5559         //bool Num = ((_Modifiers&TW_KMOD_SHIFT) && !(_Modifiers&0x1000)) || (!(_Modifiers&TW_KMOD_SHIFT) && (_Modifiers&0x1000)); // 0x1000 is SDL's KMOD_NUM
5560         //_Modifiers &= ~TW_KMOD_SHIFT; // remove shift modifier
5561         bool Num = (!(_Modifiers&TW_KMOD_SHIFT) && (_Modifiers&0x1000)); // 0x1000 is SDL's KMOD_NUM
5562         if( _Key==266 )          // SDLK_KP_PERIOD
5563             _Key = Num ? '.' : TW_KEY_DELETE;
5564         else if( _Key==267 )     // SDLK_KP_DIVIDE
5565             _Key = '/';
5566         else if( _Key==268 )     // SDLK_KP_MULTIPLY
5567             _Key = '*';
5568         else if( _Key==269 )     // SDLK_KP_MINUS
5569             _Key = '-';
5570         else if( _Key==270 )     // SDLK_KP_PLUS
5571             _Key = '+';
5572         else if( _Key==271 )     // SDLK_KP_ENTER
5573             _Key = TW_KEY_RETURN;
5574         else if( _Key==272 )     // SDLK_KP_EQUALS
5575             _Key = '=';
5576         else if( Num )           // num SDLK_KP0..9
5577             _Key += '0' - 256;
5578         else if( _Key==256 )     // non-num SDLK_KP01
5579             _Key = TW_KEY_INSERT;
5580         else if( _Key==257 )     // non-num SDLK_KP1
5581             _Key = TW_KEY_END;
5582         else if( _Key==258 )     // non-num SDLK_KP2
5583             _Key = TW_KEY_DOWN;
5584         else if( _Key==259 )     // non-num SDLK_KP3
5585             _Key = TW_KEY_PAGE_DOWN;
5586         else if( _Key==260 )     // non-num SDLK_KP4
5587             _Key = TW_KEY_LEFT;
5588         else if( _Key==262 )     // non-num SDLK_KP6
5589             _Key = TW_KEY_RIGHT;
5590         else if( _Key==263 )     // non-num SDLK_KP7
5591             _Key = TW_KEY_HOME;
5592         else if( _Key==264 )     // non-num SDLK_KP8
5593             _Key = TW_KEY_UP;
5594         else if( _Key==265 )     // non-num SDLK_KP9
5595             _Key = TW_KEY_PAGE_UP;
5596     }
5597     return _Key;
5598 }
5599 
5600 //  ---------------------------------------------------------------------------
5601 
KeyPressed(int _Key,int _Modifiers,bool _TestOnly)5602 static int KeyPressed(int _Key, int _Modifiers, bool _TestOnly)
5603 {
5604     CTwFPU fpu; // force fpu precision
5605 
5606     if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
5607     {
5608         // TwGlobalError(g_ErrNotInit); -> not an error here
5609         return 0; // not initialized
5610     }
5611     if( g_TwMgr->m_WndHeight<=0 || g_TwMgr->m_WndWidth<=0 )
5612     {
5613         //g_TwMgr->SetLastError(g_ErrBadWndSize);   // not an error, windows not yet ready.
5614         return 0;
5615     }
5616 
5617     // For multi-thread savety
5618     if( !TwFreeAsyncDrawing() )
5619         return 0;
5620 
5621     /*
5622     // Test for TwDeleteBar
5623     if( _Key>='0' && _Key<='9' )
5624     {
5625         int n = _Key-'0';
5626         if( (int)g_TwMgr->m_Bars.size()>n && g_TwMgr->m_Bars[n]!=NULL )
5627         {
5628             printf("Delete %s\n", g_TwMgr->m_Bars[n]->m_Name.c_str());
5629             TwDeleteBar(g_TwMgr->m_Bars[n]);
5630         }
5631         else
5632             printf("can't delete %d\n", n);
5633         return 1;
5634     }
5635     */
5636 
5637     //char s[256];
5638     //sprintf(s, "twkeypressed k=%d m=%x\n", _Key, _Modifiers);
5639     //OutputDebugString(s);
5640 
5641     _Key = TranslateKey(_Key, _Modifiers);
5642     if( _Key>' ' && _Key<256 ) // don't test SHIFT if _Key is a common key
5643         _Modifiers &= ~TW_KMOD_SHIFT;
5644     // complete partial modifiers comming from SDL
5645     if( _Modifiers & TW_KMOD_SHIFT )
5646         _Modifiers |= TW_KMOD_SHIFT;
5647     if( _Modifiers & TW_KMOD_CTRL )
5648         _Modifiers |= TW_KMOD_CTRL;
5649     if( _Modifiers & TW_KMOD_ALT )
5650         _Modifiers |= TW_KMOD_ALT;
5651     if( _Modifiers & TW_KMOD_META )
5652         _Modifiers |= TW_KMOD_META;
5653 
5654     bool Handled = false;
5655     CTwBar *Bar = NULL;
5656     CTwBar *PopupBar = g_TwMgr->m_PopupBar;
5657     //int Order = 0;
5658     int i;
5659     if( _Key>0 && _Key<TW_KEY_LAST )
5660     {
5661         // First send it to bar which includes the mouse pointer
5662         int MouseX = g_TwMgr->m_LastMouseX;
5663         int MouseY = g_TwMgr->m_LastMouseY;
5664         for( i=((int)g_TwMgr->m_Bars.size())-1; i>=0 && !Handled; --i )
5665         {
5666             Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]];
5667             if( Bar!=NULL && Bar->m_Visible && !Bar->IsMinimized()
5668                 && ( (MouseX>=Bar->m_PosX && MouseX<Bar->m_PosX+Bar->m_Width && MouseY>=Bar->m_PosY && MouseY<Bar->m_PosY+Bar->m_Height)
5669                      || Bar==PopupBar) )
5670             {
5671                 if (_TestOnly)
5672                     Handled = Bar->KeyTest(_Key, _Modifiers);
5673                 else
5674                     Handled = Bar->KeyPressed(_Key, _Modifiers);
5675             }
5676         }
5677 
5678         // If not handled, send it to non-iconified bars in the right order
5679         for( i=((int)g_TwMgr->m_Bars.size())-1; i>=0 && !Handled; --i )
5680         {
5681             Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]];
5682             /*
5683             for( size_t j=0; j<g_TwMgr->m_Bars.size(); ++j )
5684                 if( g_TwMgr->m_Order[j]==i )
5685                 {
5686                     Bar = g_TwMgr->m_Bars[j];
5687                     break;
5688                 }
5689             Order = i;
5690             */
5691 
5692             if( Bar!=NULL && Bar->m_Visible && !Bar->IsMinimized() )
5693             {
5694                 if( _TestOnly )
5695                     Handled = Bar->KeyTest(_Key, _Modifiers);
5696                 else
5697                     Handled = Bar->KeyPressed(_Key, _Modifiers);
5698                 if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call
5699                     return 1;
5700             }
5701         }
5702 
5703         // If not handled, send it to iconified bars in the right order
5704         for( i=((int)g_TwMgr->m_Bars.size())-1; i>=0 && !Handled; --i )
5705         {
5706             Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]];
5707             if( Bar!=NULL && Bar->m_Visible && Bar->IsMinimized() )
5708             {
5709                 if( _TestOnly )
5710                     Handled = Bar->KeyTest(_Key, _Modifiers);
5711                 else
5712                     Handled = Bar->KeyPressed(_Key, _Modifiers);
5713             }
5714         }
5715 
5716         if( g_TwMgr->m_HelpBar!=NULL && g_TwMgr->m_Graph && !_TestOnly )
5717         {
5718             string Str;
5719             TwGetKeyString(&Str, _Key, _Modifiers);
5720             char Msg[256];
5721             sprintf(Msg, "Key pressed: %s", Str.c_str());
5722             g_TwMgr->m_KeyPressedStr = Msg;
5723             g_TwMgr->m_KeyPressedBuildText = true;
5724             // OutputDebugString(Msg);
5725         }
5726     }
5727 
5728     if( Handled && Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_PopupBar!=NULL && g_TwMgr->m_PopupBar==PopupBar )  // delete popup
5729     {
5730         TwDeleteBar(g_TwMgr->m_PopupBar);
5731         g_TwMgr->m_PopupBar = NULL;
5732     }
5733 
5734     if( Handled && Bar!=NULL && Bar!=g_TwMgr->m_PopupBar && Bar!=PopupBar ) // popup bar may have been destroyed
5735         TwSetTopBar(Bar);
5736 
5737     return Handled ? 1 : 0;
5738 }
5739 
TwKeyPressed(int _Key,int _Modifiers)5740 int ANT_CALL TwKeyPressed(int _Key, int _Modifiers)
5741 {
5742     return KeyPressed(_Key, _Modifiers, false);
5743 }
5744 
TwKeyTest(int _Key,int _Modifiers)5745 int ANT_CALL TwKeyTest(int _Key, int _Modifiers)
5746 {
5747     return KeyPressed(_Key, _Modifiers, true);
5748 }
5749 
5750 //  ---------------------------------------------------------------------------
5751 
5752 struct StructCompare : public binary_function<TwType, TwType, bool>
5753 {
operator ()StructCompare5754     bool operator()(const TwType& _Left, const TwType& _Right) const
5755     {
5756         assert( g_TwMgr!=NULL );
5757         int i0 = _Left-TW_TYPE_STRUCT_BASE;
5758         int i1 = _Right-TW_TYPE_STRUCT_BASE;
5759         if( i0>=0 && i0<(int)g_TwMgr->m_Structs.size() && i1>=0 && i1<(int)g_TwMgr->m_Structs.size() )
5760             return g_TwMgr->m_Structs[i0].m_Name < g_TwMgr->m_Structs[i1].m_Name;
5761         else
5762             return false;
5763     }
5764 };
5765 
5766 typedef set<TwType, StructCompare> StructSet;
5767 
InsertUsedStructs(StructSet & _Set,const CTwVarGroup * _Grp)5768 static void InsertUsedStructs(StructSet& _Set, const CTwVarGroup *_Grp)
5769 {
5770     assert( g_TwMgr!=NULL && _Grp!=NULL );
5771 
5772     for( size_t i=0; i<_Grp->m_Vars.size(); ++i )
5773         if( _Grp->m_Vars[i]!=NULL && _Grp->m_Vars[i]->m_Visible && _Grp->m_Vars[i]->IsGroup() )// && _Grp->m_Vars[i]->m_Help.length()>0 )
5774         {
5775             const CTwVarGroup *SubGrp = static_cast<const CTwVarGroup *>(_Grp->m_Vars[i]);
5776             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 )
5777             {
5778                 if( SubGrp->m_Help.length()>0 )
5779                     _Set.insert(SubGrp->m_StructType);
5780                 else
5781                 {
5782                     int idx = SubGrp->m_StructType - TW_TYPE_STRUCT_BASE;
5783                     if( idx>=0 && idx<(int)g_TwMgr->m_Structs.size() && g_TwMgr->m_Structs[idx].m_Name.length()>0 )
5784                     {
5785                         for( size_t j=0; j<g_TwMgr->m_Structs[idx].m_Members.size(); ++j )
5786                             if( g_TwMgr->m_Structs[idx].m_Members[j].m_Help.length()>0 )
5787                             {
5788                                 _Set.insert(SubGrp->m_StructType);
5789                                 break;
5790                             }
5791                     }
5792                 }
5793             }
5794             InsertUsedStructs(_Set, SubGrp);
5795         }
5796 }
5797 
SplitString(vector<string> & _OutSplits,const char * _String,int _Width,const CTexFont * _Font)5798 static void SplitString(vector<string>& _OutSplits, const char *_String, int _Width, const CTexFont *_Font)
5799 {
5800     assert( _Font!=NULL && _String!=NULL );
5801     _OutSplits.resize(0);
5802     int l = (int)strlen(_String);
5803     if( l==0 )
5804     {
5805         _String = " ";
5806         l = 1;
5807     }
5808 
5809     if( _String!=NULL && l>0 && _Width>0 )
5810     {
5811         int w = 0;
5812         int i = 0;
5813         int First = 0;
5814         int Last = 0;
5815         bool PrevNotBlank = true;
5816         unsigned char c;
5817         bool Tab = false, CR = false;
5818         string Split;
5819         const string TabString(g_TabLength, ' ');
5820 
5821         while( i<l )
5822         {
5823             c = _String[i];
5824             if( c=='\t' )
5825             {
5826                 w += g_TabLength * _Font->m_CharWidth[(int)' '];
5827                 Tab = true;
5828             }
5829             else if( c=='\n' )
5830             {
5831                 w += _Width+1; // force split
5832                 Last = i;
5833                 CR = true;
5834             }
5835             else
5836                 w += _Font->m_CharWidth[(int)c];
5837             if( w>_Width || i==l-1 )
5838             {
5839                 if( Last<=First || i==l-1 )
5840                     Last = i;
5841                 if( Tab )
5842                 {
5843                     Split.resize(0);
5844                     for(int k=0; k<Last-First+(CR?0:1); ++k)
5845                         if( _String[First+k]=='\t' )
5846                             Split += TabString;
5847                         else
5848                             Split += _String[First+k];
5849                     Tab = false;
5850                 }
5851                 else
5852                     Split.assign(_String+First, Last-First+(CR?0:1));
5853                 _OutSplits.push_back(Split);
5854                 First = Last+1;
5855                 if( !CR )
5856                     while( First<l && (_String[First]==' ' || _String[First]=='\t') )   // skip blanks
5857                         ++First;
5858                 Last = First;
5859                 w = 0;
5860                 PrevNotBlank = true;
5861                 i = First;
5862                 CR = false;
5863             }
5864             else if( c==' ' || c=='\t' )
5865             {
5866                 if( PrevNotBlank )
5867                     Last = i-1;
5868                 PrevNotBlank = false;
5869                 ++i;
5870             }
5871             else
5872             {
5873                 PrevNotBlank = true;
5874                 ++i;
5875             }
5876         }
5877     }
5878 }
5879 
AppendHelpString(CTwVarGroup * _Grp,const char * _String,int _Level,int _Width,ETwType _Type)5880 static int AppendHelpString(CTwVarGroup *_Grp, const char *_String, int _Level, int _Width, ETwType _Type)
5881 {
5882     assert( _Grp!=NULL && g_TwMgr!=NULL && g_TwMgr->m_HelpBar!=NULL);
5883     assert( _String!=NULL );
5884     int n = 0;
5885     const CTexFont *Font = g_TwMgr->m_HelpBar->m_Font;
5886     assert(Font!=NULL);
5887     string Decal;
5888     for( int s=0; s<_Level; ++s )
5889         Decal += ' ';
5890     int DecalWidth = (_Level+2)*Font->m_CharWidth[(int)' '];
5891 
5892     if( _Width>DecalWidth )
5893     {
5894         vector<string> Split;
5895         SplitString(Split, _String, _Width-DecalWidth, Font);
5896         for( int i=0; i<(int)Split.size(); ++i )
5897         {
5898             CTwVarAtom *Var = new CTwVarAtom;
5899             Var->m_Name = Decal + Split[i];
5900             Var->m_Ptr = NULL;
5901             if( _Type==TW_TYPE_HELP_HEADER )
5902                 Var->m_ReadOnly = false;
5903             else
5904                 Var->m_ReadOnly = true;
5905             Var->m_NoSlider = true;
5906             Var->m_DontClip = true;
5907             Var->m_Type = _Type;
5908             Var->m_LeftMargin = (signed short)((_Level+1)*Font->m_CharWidth[(int)' ']);
5909             Var->m_TopMargin  = (signed short)(-g_TwMgr->m_HelpBar->m_Sep);
5910             //Var->m_TopMargin  = 1;
5911             Var->m_ColorPtr = &(g_TwMgr->m_HelpBar->m_ColHelpText);
5912             Var->SetDefaults();
5913             _Grp->m_Vars.push_back(Var);
5914             ++n;
5915         }
5916     }
5917     return n;
5918 }
5919 
AppendHelp(CTwVarGroup * _Grp,const CTwVarGroup * _ToAppend,int _Level,int _Width)5920 static int AppendHelp(CTwVarGroup *_Grp, const CTwVarGroup *_ToAppend, int _Level, int _Width)
5921 {
5922     assert( _Grp!=NULL );
5923     assert( _ToAppend!=NULL );
5924     int n = 0;
5925     string Decal;
5926     for( int s=0; s<_Level; ++s )
5927         Decal += ' ';
5928 
5929     if( _ToAppend->m_Help.size()>0 )
5930         n += AppendHelpString(_Grp, _ToAppend->m_Help.c_str(), _Level, _Width, TW_TYPE_HELP_GRP);
5931 
5932     for( size_t i=0; i<_ToAppend->m_Vars.size(); ++i )
5933         if( _ToAppend->m_Vars[i]!=NULL && _ToAppend->m_Vars[i]->m_Visible )
5934         {
5935             bool append = true;
5936             if( !_ToAppend->m_Vars[i]->IsGroup() )
5937             {
5938                 const CTwVarAtom *a = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i]);
5939                 if( a->m_Type==TW_TYPE_BUTTON && a->m_Val.m_Button.m_Callback==NULL )
5940                     append = false;
5941                 else if( a->m_KeyIncr[0]==0 && a->m_KeyIncr[1]==0 && a->m_KeyDecr[0]==0 && a->m_KeyDecr[1]==0 && a->m_Help.length()<=0 )
5942                     append = false;
5943             }
5944             else if( _ToAppend->m_Vars[i]->IsGroup() && static_cast<const CTwVarGroup *>(_ToAppend->m_Vars[i])->m_StructValuePtr!=NULL // that's a struct var
5945                      && _ToAppend->m_Vars[i]->m_Help.length()<=0 )
5946                  append = false;
5947 
5948             if( append )
5949             {
5950                 CTwVarAtom *Var = new CTwVarAtom;
5951                 Var->m_Name = Decal;
5952                 if( _ToAppend->m_Vars[i]->m_Label.size()>0 )
5953                     Var->m_Name += _ToAppend->m_Vars[i]->m_Label;
5954                 else
5955                     Var->m_Name += _ToAppend->m_Vars[i]->m_Name;
5956                 Var->m_Ptr = NULL;
5957                 if( _ToAppend->m_Vars[i]->IsGroup() && static_cast<const CTwVarGroup *>(_ToAppend->m_Vars[i])->m_StructValuePtr!=NULL )
5958                 {   // That's a struct var
5959                     Var->m_Type = TW_TYPE_HELP_STRUCT;
5960                     Var->m_Val.m_HelpStruct.m_StructType = static_cast<const CTwVarGroup *>(_ToAppend->m_Vars[i])->m_StructType;
5961                     Var->m_ReadOnly = true;
5962                     Var->m_NoSlider = true;
5963                 }
5964                 else if( !_ToAppend->m_Vars[i]->IsGroup() )
5965                 {
5966                     Var->m_Type = TW_TYPE_SHORTCUT;
5967                     Var->m_Val.m_Shortcut.m_Incr[0] = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i])->m_KeyIncr[0];
5968                     Var->m_Val.m_Shortcut.m_Incr[1] = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i])->m_KeyIncr[1];
5969                     Var->m_Val.m_Shortcut.m_Decr[0] = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i])->m_KeyDecr[0];
5970                     Var->m_Val.m_Shortcut.m_Decr[1] = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i])->m_KeyDecr[1];
5971                     Var->m_ReadOnly = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i])->m_ReadOnly;
5972                     Var->m_NoSlider = true;
5973                 }
5974                 else
5975                 {
5976                     Var->m_Type = TW_TYPE_HELP_GRP;
5977                     Var->m_DontClip = true;
5978                     Var->m_LeftMargin = (signed short)((_Level+2)*g_TwMgr->m_HelpBar->m_Font->m_CharWidth[(int)' ']);
5979                     //Var->m_TopMargin  = (signed short)(g_TwMgr->m_HelpBar->m_Font->m_CharHeight/2-2+2*(_Level-1));
5980                     Var->m_TopMargin  = 2;
5981                     if( Var->m_TopMargin>g_TwMgr->m_HelpBar->m_Font->m_CharHeight-3 )
5982                         Var->m_TopMargin = (signed short)(g_TwMgr->m_HelpBar->m_Font->m_CharHeight-3);
5983                     Var->m_ReadOnly = true;
5984                 }
5985                 Var->SetDefaults();
5986                 _Grp->m_Vars.push_back(Var);
5987                 size_t VarIndex = _Grp->m_Vars.size()-1;
5988                 ++n;
5989                 if( _ToAppend->m_Vars[i]->IsGroup() && static_cast<const CTwVarGroup *>(_ToAppend->m_Vars[i])->m_StructValuePtr==NULL )
5990                 {
5991                     int nAppended = AppendHelp(_Grp, static_cast<const CTwVarGroup *>(_ToAppend->m_Vars[i]), _Level+1, _Width);
5992                     if( _Grp->m_Vars.size()==VarIndex+1 )
5993                     {
5994                         delete _Grp->m_Vars[VarIndex];
5995                         _Grp->m_Vars.resize(VarIndex);
5996                     }
5997                     else
5998                         n += nAppended;
5999                 }
6000                 else if( _ToAppend->m_Vars[i]->m_Help.length()>0 )
6001                     n += AppendHelpString(_Grp, _ToAppend->m_Vars[i]->m_Help.c_str(), _Level+1, _Width, TW_TYPE_HELP_ATOM);
6002             }
6003         }
6004     return n;
6005 }
6006 
6007 
CopyHierarchy(CTwVarGroup * dst,const CTwVarGroup * src)6008 static void CopyHierarchy(CTwVarGroup *dst, const CTwVarGroup *src)
6009 {
6010     if( dst==NULL || src==NULL )
6011         return;
6012 
6013     dst->m_Name = src->m_Name;
6014     dst->m_Open = src->m_Open;
6015     dst->m_Visible = src->m_Visible;
6016     dst->m_ColorPtr = src->m_ColorPtr;
6017     dst->m_DontClip = src->m_DontClip;
6018     dst->m_IsRoot = src->m_IsRoot;
6019     dst->m_LeftMargin = src->m_LeftMargin;
6020     dst->m_TopMargin = src->m_TopMargin;
6021 
6022     dst->m_Vars.resize(src->m_Vars.size());
6023     for(size_t i=0; i<src->m_Vars.size(); ++i)
6024         if( src->m_Vars[i]!=NULL && src->m_Vars[i]->IsGroup() )
6025         {
6026             CTwVarGroup *grp = new CTwVarGroup;
6027             CopyHierarchy(grp, static_cast<const CTwVarGroup *>(src->m_Vars[i]));
6028             dst->m_Vars[i] = grp;
6029         }
6030         else
6031             dst->m_Vars[i] = NULL;
6032 }
6033 
6034 // copy the 'open' flag from original hierarchy to current hierarchy
SynchroHierarchy(CTwVarGroup * cur,const CTwVarGroup * orig)6035 static void SynchroHierarchy(CTwVarGroup *cur, const CTwVarGroup *orig)
6036 {
6037     if( cur==NULL || orig==NULL )
6038         return;
6039 
6040     if( strcmp(cur->m_Name.c_str(), orig->m_Name.c_str())==0 )
6041         cur->m_Open = orig->m_Open;
6042 
6043     size_t j = 0;
6044     while( j<orig->m_Vars.size() && (orig->m_Vars[j]==NULL || !orig->m_Vars[j]->IsGroup()) )
6045         ++j;
6046 
6047     for(size_t i=0; i<cur->m_Vars.size(); ++i)
6048         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() )
6049         {
6050             CTwVarGroup *curGrp = static_cast<CTwVarGroup *>(cur->m_Vars[i]);
6051             const CTwVarGroup *origGrp = static_cast<const CTwVarGroup *>(orig->m_Vars[j]);
6052             if( strcmp(curGrp->m_Name.c_str(), origGrp->m_Name.c_str())==0 )
6053             {
6054                 curGrp->m_Open = origGrp->m_Open;
6055 
6056                 SynchroHierarchy(curGrp, origGrp);
6057 
6058                 ++j;
6059                 while( j<orig->m_Vars.size() && (orig->m_Vars[j]==NULL || !orig->m_Vars[j]->IsGroup()) )
6060                     ++j;
6061             }
6062         }
6063 }
6064 
6065 
UpdateHelpBar()6066 void CTwMgr::UpdateHelpBar()
6067 {
6068     if( m_HelpBar==NULL || m_HelpBar->IsMinimized() )
6069         return;
6070     if( !m_HelpBarUpdateNow && (float)m_Timer.GetTime()<m_LastHelpUpdateTime+2 )    // update at most every 2 seconds
6071         return;
6072     m_HelpBarUpdateNow = false;
6073     m_LastHelpUpdateTime = (float)m_Timer.GetTime();
6074     #ifdef _DEBUG
6075         //printf("UPDATE HELPBAR\n");
6076     #endif // _DEBUG
6077 
6078     CTwVarGroup prevHierarchy;
6079     CopyHierarchy(&prevHierarchy, &m_HelpBar->m_VarRoot);
6080 
6081     TwRemoveAllVars(m_HelpBar);
6082 
6083     if( m_HelpBar->m_UpToDate )
6084         m_HelpBar->Update();
6085 
6086     if( m_Help.size()>0 )
6087         AppendHelpString(&(m_HelpBar->m_VarRoot), m_Help.c_str(), 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM);
6088     if( m_HelpBar->m_Help.size()>0 )
6089         AppendHelpString(&(m_HelpBar->m_VarRoot), m_HelpBar->m_Help.c_str(), 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM);
6090     AppendHelpString(&(m_HelpBar->m_VarRoot), "", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_HEADER);
6091 
6092     for( size_t ib=0; ib<m_Bars.size(); ++ib )
6093         if( m_Bars[ib]!=NULL && !(m_Bars[ib]->m_IsHelpBar) && m_Bars[ib]!=m_PopupBar && m_Bars[ib]->m_Visible )
6094         {
6095             // Create a group
6096             CTwVarGroup *Grp = new CTwVarGroup;
6097             Grp->m_SummaryCallback = NULL;
6098             Grp->m_SummaryClientData = NULL;
6099             Grp->m_StructValuePtr = NULL;
6100             if( m_Bars[ib]->m_Label.size()<=0 )
6101                 Grp->m_Name = m_Bars[ib]->m_Name;
6102             else
6103                 Grp->m_Name = m_Bars[ib]->m_Label;
6104             Grp->m_Open = true;
6105             Grp->m_ColorPtr = &(m_HelpBar->m_ColGrpText);
6106             m_HelpBar->m_VarRoot.m_Vars.push_back(Grp);
6107             if( m_Bars[ib]->m_Help.size()>0 )
6108                 AppendHelpString(Grp, m_Bars[ib]->m_Help.c_str(), 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_GRP);
6109 
6110             // Append variables (recursive)
6111             AppendHelp(Grp, &(m_Bars[ib]->m_VarRoot), 1, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0);
6112 
6113             // Append structures
6114             StructSet UsedStructs;
6115             InsertUsedStructs(UsedStructs, &(m_Bars[ib]->m_VarRoot));
6116             CTwVarGroup *StructGrp = NULL;
6117             int MemberCount = 0;
6118             for( StructSet::iterator it=UsedStructs.begin(); it!=UsedStructs.end(); ++it )
6119             {
6120                 int idx = (*it) - TW_TYPE_STRUCT_BASE;
6121                 if( idx>=0 && idx<(int)g_TwMgr->m_Structs.size() && g_TwMgr->m_Structs[idx].m_Name.length()>0 )
6122                 {
6123                     if( StructGrp==NULL )
6124                     {
6125                         StructGrp = new CTwVarGroup;
6126                         StructGrp->m_StructType = TW_TYPE_HELP_STRUCT;  // a special line background color will be used
6127                         StructGrp->m_Name = "Structures";
6128                         StructGrp->m_Open = false;
6129                         StructGrp->m_ColorPtr = &(m_HelpBar->m_ColStructText);
6130                         //Grp->m_Vars.push_back(StructGrp);
6131                         MemberCount = 0;
6132                     }
6133                     CTwVarAtom *Var = new CTwVarAtom;
6134                     Var->m_Ptr = NULL;
6135                     Var->m_Type = TW_TYPE_HELP_GRP;
6136                     Var->m_DontClip = true;
6137                     Var->m_LeftMargin = (signed short)(3*g_TwMgr->m_HelpBar->m_Font->m_CharWidth[(int)' ']);
6138                     Var->m_TopMargin  = 2;
6139                     Var->m_ReadOnly = true;
6140                     Var->m_NoSlider = true;
6141                     Var->m_Name = '{'+g_TwMgr->m_Structs[idx].m_Name+'}';
6142                     StructGrp->m_Vars.push_back(Var);
6143                     size_t structIndex = StructGrp->m_Vars.size()-1;
6144                     if( g_TwMgr->m_Structs[idx].m_Help.size()>0 )
6145                         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_ATOM);
6146 
6147                     // Append struct members
6148                     for( size_t im=0; im<g_TwMgr->m_Structs[idx].m_Members.size(); ++im )
6149                     {
6150                         if( g_TwMgr->m_Structs[idx].m_Members[im].m_Help.size()>0 )
6151                         {
6152                             CTwVarAtom *Var = new CTwVarAtom;
6153                             Var->m_Ptr = NULL;
6154                             Var->m_Type = TW_TYPE_SHORTCUT;
6155                             Var->m_Val.m_Shortcut.m_Incr[0] = 0;
6156                             Var->m_Val.m_Shortcut.m_Incr[1] = 0;
6157                             Var->m_Val.m_Shortcut.m_Decr[0] = 0;
6158                             Var->m_Val.m_Shortcut.m_Decr[1] = 0;
6159                             Var->m_ReadOnly = false;
6160                             Var->m_NoSlider = true;
6161                             if( g_TwMgr->m_Structs[idx].m_Members[im].m_Label.length()>0 )
6162                                 Var->m_Name = "  "+g_TwMgr->m_Structs[idx].m_Members[im].m_Label;
6163                             else
6164                                 Var->m_Name = "  "+g_TwMgr->m_Structs[idx].m_Members[im].m_Name;
6165                             StructGrp->m_Vars.push_back(Var);
6166                             //if( g_TwMgr->m_Structs[idx].m_Members[im].m_Help.size()>0 )
6167                             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);
6168                         }
6169                     }
6170 
6171                     if( StructGrp->m_Vars.size()==structIndex+1 ) // remove struct from help
6172                     {
6173                         delete StructGrp->m_Vars[structIndex];
6174                         StructGrp->m_Vars.resize(structIndex);
6175                     }
6176                     else
6177                         ++MemberCount;
6178                 }
6179             }
6180             if( StructGrp!=NULL )
6181             {
6182                 if( MemberCount==1 )
6183                     StructGrp->m_Name = "Structure";
6184                 if( StructGrp->m_Vars.size()>0 )
6185                     Grp->m_Vars.push_back(StructGrp);
6186                 else
6187                 {
6188                     delete StructGrp;
6189                     StructGrp = NULL;
6190                 }
6191             }
6192         }
6193 
6194     // Append RotoSlider
6195     CTwVarGroup *RotoGrp = new CTwVarGroup;
6196     RotoGrp->m_SummaryCallback = NULL;
6197     RotoGrp->m_SummaryClientData = NULL;
6198     RotoGrp->m_StructValuePtr = NULL;
6199     RotoGrp->m_Name = "RotoSlider";
6200     RotoGrp->m_Open = false;
6201     RotoGrp->m_ColorPtr = &(m_HelpBar->m_ColGrpText);
6202     m_HelpBar->m_VarRoot.m_Vars.push_back(RotoGrp);
6203     AppendHelpString(RotoGrp, "The RotoSlider allows rapid editing of numerical values.", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM);
6204     AppendHelpString(RotoGrp, "To modify a numerical value, click on its label or on its roto [.] button, 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);
6205     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);
6206     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);
6207 
6208     SynchroHierarchy(&m_HelpBar->m_VarRoot, &prevHierarchy);
6209 
6210     m_HelpBarNotUpToDate = false;
6211 }
6212 
6213 //  ---------------------------------------------------------------------------
6214 
6215 #if defined(ANT_WINDOWS)
6216 
6217 #include "res/TwXCursors.h"
6218 
CreateCursors()6219 void CTwMgr::CreateCursors()
6220 {
6221     if( m_CursorsCreated )
6222         return;
6223     m_CursorArrow = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_ARROW));
6224     m_CursorMove = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZEALL));
6225     m_CursorWE = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZEWE));
6226     m_CursorNS = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENS));
6227     m_CursorTopRight = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENESW));
6228     m_CursorTopLeft = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENWSE));
6229     m_CursorBottomLeft = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENESW));
6230     m_CursorBottomRight = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENWSE));
6231     m_CursorHelp = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_HELP));
6232     m_CursorCross = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_CROSS));
6233     m_CursorUpArrow = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_UPARROW));
6234     m_CursorNo = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_NO));
6235     m_CursorIBeam = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_IBEAM));
6236     #ifdef IDC_HAND
6237         m_CursorHand = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_HAND));
6238     #else
6239         m_CursorHand = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_UPARROW));
6240     #endif
6241     int cur;
6242     HMODULE hdll = GetModuleHandle(ANT_TWEAK_BAR_DLL);
6243     if( hdll==NULL )
6244         g_UseCurRsc = false;    // force the use of built-in cursors (not using resources)
6245     if( g_UseCurRsc )
6246         m_CursorCenter = ::LoadCursor(hdll, MAKEINTRESOURCE(IDC_CURSOR1+0));
6247     else
6248         m_CursorCenter  = PixmapCursor(0);
6249     if( m_CursorCenter==NULL )
6250         m_CursorCenter = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_CROSS));
6251     if( g_UseCurRsc )
6252         m_CursorPoint = ::LoadCursor(hdll, MAKEINTRESOURCE(IDC_CURSOR1+1));
6253     else
6254         m_CursorPoint   = PixmapCursor(1);
6255     if( m_CursorPoint==NULL )
6256         m_CursorPoint = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_CROSS));
6257 
6258     for( cur=0; cur<NB_ROTO_CURSORS; ++cur )
6259     {
6260         if( g_UseCurRsc )
6261             m_RotoCursors[cur] = ::LoadCursor(hdll, MAKEINTRESOURCE(IDC_CURSOR1+2+cur));
6262         else
6263             m_RotoCursors[cur] = PixmapCursor(cur+2);
6264         if( m_RotoCursors[cur]==NULL )
6265             m_RotoCursors[cur] = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_CROSS));
6266     }
6267 
6268     m_CursorsCreated = true;
6269 }
6270 
6271 
PixmapCursor(int _CurIdx)6272 CTwMgr::CCursor CTwMgr::PixmapCursor(int _CurIdx)
6273 {
6274     int x, y;
6275     unsigned char mask[32*4];
6276     unsigned char pict[32*4];
6277     for( y=0; y<32; ++y )
6278     {
6279         mask[y*4+0] = pict[y*4+0] = 0;
6280         mask[y*4+1] = pict[y*4+1] = 0;
6281         mask[y*4+2] = pict[y*4+2] = 0;
6282         mask[y*4+3] = pict[y*4+3] = 0;
6283         for( x=0; x<32; ++x )
6284         {
6285             mask[y*4+x/8] |= (((unsigned int)(g_CurMask[_CurIdx][x+y*32]))<<(7-(x%8)));
6286             pict[y*4+x/8] |= (((unsigned int)(g_CurPict[_CurIdx][x+y*32]))<<(7-(x%8)));
6287         }
6288     }
6289 
6290     unsigned char ands[32*4];
6291     unsigned char xors[32*4];
6292     for( y=0; y<32*4; ++y )
6293     {
6294         ands[y] = ~mask[y];
6295         xors[y] = pict[y];
6296     }
6297 
6298     HMODULE hdll = GetModuleHandle(ANT_TWEAK_BAR_DLL);
6299     CCursor cursor = ::CreateCursor(hdll, g_CurHot[_CurIdx][0], g_CurHot[_CurIdx][1], 32, 32, ands, xors);
6300 
6301     return cursor;
6302 }
6303 
FreeCursors()6304 void CTwMgr::FreeCursors()
6305 {
6306     if( !g_UseCurRsc )
6307     {
6308         if( m_CursorCenter!=NULL )
6309         {
6310             ::DestroyCursor(m_CursorCenter);
6311             m_CursorCenter = NULL;
6312         }
6313         if( m_CursorPoint!=NULL )
6314         {
6315             ::DestroyCursor(m_CursorPoint);
6316             m_CursorPoint = NULL;
6317         }
6318         for( int cur=0; cur<NB_ROTO_CURSORS; ++cur )
6319             if( m_RotoCursors[cur]!=NULL )
6320             {
6321                 ::DestroyCursor(m_RotoCursors[cur]);
6322                 m_RotoCursors[cur] = NULL;
6323             }
6324     }
6325     m_CursorsCreated = false;
6326 }
6327 
SetCursor(CTwMgr::CCursor _Cursor)6328 void CTwMgr::SetCursor(CTwMgr::CCursor _Cursor)
6329 {
6330     if( m_CursorsCreated )
6331     {
6332         CURSORINFO ci;
6333         memset(&ci, 0, sizeof(ci));
6334         ci.cbSize = sizeof(ci);
6335         BOOL ok = ::GetCursorInfo(&ci);
6336         if( ok && (ci.flags & CURSOR_SHOWING) )
6337             ::SetCursor(_Cursor);
6338     }
6339 }
6340 
6341 
6342 #elif defined(ANT_OSX)
6343 
6344 #include "res/TwXCursors.h"
6345 
PixmapCursor(int _CurIdx)6346 CTwMgr::CCursor CTwMgr::PixmapCursor(int _CurIdx)
6347 {
6348     unsigned char *data;
6349     int x,y;
6350 
6351     NSBitmapImageRep *imgr = [[NSBitmapImageRep alloc]
6352                               initWithBitmapDataPlanes: NULL
6353                               pixelsWide: 32
6354                               pixelsHigh: 32
6355                               bitsPerSample: 1
6356                               samplesPerPixel: 2
6357                               hasAlpha: YES
6358                               isPlanar: NO
6359                               colorSpaceName: NSCalibratedWhiteColorSpace
6360                               bitmapFormat: NSAlphaNonpremultipliedBitmapFormat
6361                               bytesPerRow: 8
6362                               bitsPerPixel: 2
6363                               ];
6364     data = [imgr bitmapData];
6365     memset(data,0x0,32*8);
6366     for (y=0;y<32;y++) {
6367         for (x=0;x<32;x++) {
6368             //printf("%d",g_CurMask[_CurIdx][x+y*32]);
6369             data[(x>>2) + y*8] |= (unsigned char)(g_CurPict[_CurIdx][x+y*32] << 2*(3-(x&3))+1); //turn whiteon
6370             data[(x>>2) + y*8] |= (unsigned char)(g_CurMask[_CurIdx][x+y*32] << 2*(3-(x&3))); //turn the alpha all the way up
6371         }
6372         //printf("\n");
6373     }
6374     NSImage *img = [[NSImage alloc] initWithSize: [imgr size]];
6375     [img addRepresentation: imgr];
6376     NSCursor *cur = [[NSCursor alloc] initWithImage: img hotSpot: NSMakePoint(g_CurHot[_CurIdx][0],g_CurHot[_CurIdx][1])];
6377 
6378     [imgr autorelease];
6379     [img autorelease];
6380     if (cur)
6381         return cur;
6382     else
6383         return [NSCursor arrowCursor];
6384 }
6385 
CreateCursors()6386 void CTwMgr::CreateCursors()
6387 {
6388     if (m_CursorsCreated)
6389         return;
6390 
6391     m_CursorArrow        = [[NSCursor arrowCursor] retain];
6392     m_CursorMove         = [[NSCursor crosshairCursor] retain];
6393     m_CursorWE           = [[NSCursor resizeLeftRightCursor] retain];
6394     m_CursorNS           = [[NSCursor resizeUpDownCursor] retain];
6395     m_CursorTopRight     = [[NSCursor arrowCursor] retain]; //osx not have one
6396     m_CursorTopLeft      = [[NSCursor arrowCursor] retain]; //osx not have one
6397     m_CursorBottomRight  = [[NSCursor arrowCursor] retain]; //osx not have one
6398     m_CursorBottomLeft   = [[NSCursor arrowCursor] retain]; //osx not have one
6399     m_CursorHelp         = [[NSCursor arrowCursor] retain]; //osx not have one
6400     m_CursorHand         = [[NSCursor pointingHandCursor] retain];
6401     m_CursorCross        = [[NSCursor arrowCursor] retain];
6402     m_CursorUpArrow      = [[NSCursor arrowCursor] retain];
6403     m_CursorNo           = [[NSCursor arrowCursor] retain];
6404     m_CursorIBeam        = [[NSCursor IBeamCursor] retain];
6405     for (int i=0;i<NB_ROTO_CURSORS; i++)
6406     {
6407         m_RotoCursors[i] = [PixmapCursor(i+2) retain];
6408     }
6409     m_CursorCenter  = [PixmapCursor(0) retain];
6410     m_CursorPoint   = [PixmapCursor(1) retain];
6411     m_CursorsCreated = true;
6412 }
6413 
FreeCursors()6414 void CTwMgr::FreeCursors()
6415 {
6416     [m_CursorArrow release];
6417     [m_CursorMove release];
6418     [m_CursorWE release];
6419     [m_CursorNS release];
6420     [m_CursorTopRight release];
6421     [m_CursorTopLeft release];
6422     [m_CursorBottomRight release];
6423     [m_CursorBottomLeft release];
6424     [m_CursorHelp release];
6425     [m_CursorHand release];
6426     [m_CursorCross release];
6427     [m_CursorUpArrow release];
6428     [m_CursorNo release];
6429     [m_CursorIBeam release];
6430     for( int i=0; i<NB_ROTO_CURSORS; ++i )
6431         [m_RotoCursors[i] release];
6432     [m_CursorCenter release];
6433     [m_CursorPoint release];
6434     m_CursorsCreated = false;
6435 }
6436 
SetCursor(CTwMgr::CCursor _Cursor)6437 void CTwMgr::SetCursor(CTwMgr::CCursor _Cursor)
6438 {
6439     if (m_CursorsCreated && _Cursor) {
6440         [_Cursor set];
6441     }
6442 }
6443 
6444 
6445 #elif defined(ANT_UNIX)
6446 
6447 #include "res/TwXCursors.h"
6448 
6449 static XErrorHandler s_PrevErrorHandler = NULL;
6450 
InactiveErrorHandler(Display * display,XErrorEvent * err)6451 static int InactiveErrorHandler(Display *display, XErrorEvent *err)
6452 {
6453     fprintf(stderr, "Ignoring Xlib error: error code %d request code %d\n", err->error_code, err->request_code);
6454     // No exit!
6455     return 0 ;
6456 }
6457 
IgnoreXErrors()6458 static void IgnoreXErrors()
6459 {
6460     if( g_TwMgr!=NULL && g_TwMgr->m_CurrentXDisplay==glXGetCurrentDisplay() )
6461     {
6462         XFlush(g_TwMgr->m_CurrentXDisplay);
6463         XSync(g_TwMgr->m_CurrentXDisplay, False);
6464     }
6465     s_PrevErrorHandler = XSetErrorHandler(InactiveErrorHandler);
6466 }
6467 
RestoreXErrors()6468 static void RestoreXErrors()
6469 {
6470     if( g_TwMgr!=NULL && g_TwMgr->m_CurrentXDisplay==glXGetCurrentDisplay() )
6471     {
6472         XFlush(g_TwMgr->m_CurrentXDisplay);
6473         XSync(g_TwMgr->m_CurrentXDisplay, False);
6474     }
6475     XSetErrorHandler(s_PrevErrorHandler);
6476 }
6477 
PixmapCursor(int _CurIdx)6478 CTwMgr::CCursor CTwMgr::PixmapCursor(int _CurIdx)
6479 {
6480     if( !m_CurrentXDisplay || !m_CurrentXWindow )
6481         return XC_left_ptr;
6482 
6483     IgnoreXErrors();
6484 
6485     XColor black, white, exact;
6486     Colormap colmap = DefaultColormap(m_CurrentXDisplay, DefaultScreen(m_CurrentXDisplay));
6487     Status s1 = XAllocNamedColor(m_CurrentXDisplay, colmap, "black", &black, &exact);
6488     Status s2 = XAllocNamedColor(m_CurrentXDisplay, colmap, "white", &white, &exact);
6489     if( s1==0 || s2==0 )
6490         return XC_left_ptr; // cannot allocate colors!
6491     int x, y;
6492     unsigned int mask[32];
6493     unsigned int pict[32];
6494     for( y=0; y<32; ++y )
6495     {
6496         mask[y] = pict[y] = 0;
6497         for( x=0; x<32; ++x )
6498         {
6499             mask[y] |= (((unsigned int)(g_CurMask[_CurIdx][x+y*32]))<<x);
6500             pict[y] |= (((unsigned int)(g_CurPict[_CurIdx][x+y*32]))<<x);
6501         }
6502     }
6503     Pixmap maskPix = XCreateBitmapFromData(m_CurrentXDisplay, m_CurrentXWindow, (char*)mask, 32, 32);
6504     Pixmap pictPix = XCreateBitmapFromData(m_CurrentXDisplay, m_CurrentXWindow, (char*)pict, 32, 32);
6505     Cursor cursor = XCreatePixmapCursor(m_CurrentXDisplay, pictPix, maskPix, &white, &black, g_CurHot[_CurIdx][0], g_CurHot[_CurIdx][1]);
6506     XFreePixmap(m_CurrentXDisplay, maskPix);
6507     XFreePixmap(m_CurrentXDisplay, pictPix);
6508 
6509     RestoreXErrors();
6510 
6511     if( cursor!=0 )
6512         return cursor;
6513     else
6514         return XC_left_ptr;
6515 }
6516 
CreateCursors()6517 void CTwMgr::CreateCursors()
6518 {
6519     if( m_CursorsCreated || !m_CurrentXDisplay || !m_CurrentXWindow )
6520         return;
6521 
6522     IgnoreXErrors();
6523     m_CursorArrow   = XCreateFontCursor(m_CurrentXDisplay, XC_left_ptr);
6524     m_CursorMove    = XCreateFontCursor(m_CurrentXDisplay, XC_plus);
6525     m_CursorWE      = XCreateFontCursor(m_CurrentXDisplay, XC_left_side);
6526     m_CursorNS      = XCreateFontCursor(m_CurrentXDisplay, XC_top_side);
6527     m_CursorTopRight= XCreateFontCursor(m_CurrentXDisplay, XC_top_right_corner);
6528     m_CursorTopLeft = XCreateFontCursor(m_CurrentXDisplay, XC_top_left_corner);
6529     m_CursorBottomRight = XCreateFontCursor(m_CurrentXDisplay, XC_bottom_right_corner);
6530     m_CursorBottomLeft  = XCreateFontCursor(m_CurrentXDisplay, XC_bottom_left_corner);
6531     m_CursorHelp    = XCreateFontCursor(m_CurrentXDisplay, XC_question_arrow);
6532     m_CursorHand    = XCreateFontCursor(m_CurrentXDisplay, XC_hand1);
6533     m_CursorCross   = XCreateFontCursor(m_CurrentXDisplay, XC_X_cursor);
6534     m_CursorUpArrow = XCreateFontCursor(m_CurrentXDisplay, XC_center_ptr);
6535     m_CursorNo      = XCreateFontCursor(m_CurrentXDisplay, XC_left_ptr);
6536     m_CursorIBeam   = XCreateFontCursor(m_CurrentXDisplay, XC_xterm);
6537     for( int i=0; i<NB_ROTO_CURSORS; ++i )
6538     {
6539         m_RotoCursors[i] = PixmapCursor(i+2);
6540     }
6541     m_CursorCenter  = PixmapCursor(0);
6542     m_CursorPoint   = PixmapCursor(1);
6543     m_CursorsCreated = true;
6544 
6545     RestoreXErrors();
6546 }
6547 
FreeCursors()6548 void CTwMgr::FreeCursors()
6549 {
6550     IgnoreXErrors();
6551 
6552     XFreeCursor(m_CurrentXDisplay, m_CursorArrow);
6553     XFreeCursor(m_CurrentXDisplay, m_CursorMove);
6554     XFreeCursor(m_CurrentXDisplay, m_CursorWE);
6555     XFreeCursor(m_CurrentXDisplay, m_CursorNS);
6556     XFreeCursor(m_CurrentXDisplay, m_CursorTopRight);
6557     XFreeCursor(m_CurrentXDisplay, m_CursorTopLeft);
6558     XFreeCursor(m_CurrentXDisplay, m_CursorBottomRight);
6559     XFreeCursor(m_CurrentXDisplay, m_CursorBottomLeft);
6560     XFreeCursor(m_CurrentXDisplay, m_CursorHelp);
6561     XFreeCursor(m_CurrentXDisplay, m_CursorHand);
6562     XFreeCursor(m_CurrentXDisplay, m_CursorCross);
6563     XFreeCursor(m_CurrentXDisplay, m_CursorUpArrow);
6564     XFreeCursor(m_CurrentXDisplay, m_CursorNo);
6565     for( int i=0; i<NB_ROTO_CURSORS; ++i )
6566         XFreeCursor(m_CurrentXDisplay, m_RotoCursors[i]);
6567     XFreeCursor(m_CurrentXDisplay, m_CursorCenter);
6568     XFreeCursor(m_CurrentXDisplay, m_CursorPoint);
6569 
6570     m_CursorsCreated = false;
6571 
6572     RestoreXErrors();
6573 }
6574 
SetCursor(CTwMgr::CCursor _Cursor)6575 void CTwMgr::SetCursor(CTwMgr::CCursor _Cursor)
6576 {
6577     if( m_CursorsCreated && m_CurrentXDisplay && m_CurrentXWindow )
6578     {
6579         Display *dpy = glXGetCurrentDisplay();
6580         if( dpy==g_TwMgr->m_CurrentXDisplay )
6581         {
6582             Window wnd = glXGetCurrentDrawable();
6583             if( wnd!=g_TwMgr->m_CurrentXWindow )
6584             {
6585                 FreeCursors();
6586                 g_TwMgr->m_CurrentXWindow = wnd;
6587                 CreateCursors();
6588                 // now _Cursor is not a valid cursor ID.
6589             }
6590             else
6591             {
6592                 IgnoreXErrors();
6593                 XDefineCursor(m_CurrentXDisplay, m_CurrentXWindow, _Cursor);
6594                 RestoreXErrors();
6595             }
6596         }
6597     }
6598 }
6599 
6600 #endif //defined(ANT_UNIX)
6601 
6602 //  ---------------------------------------------------------------------------
6603 
TwCopyCDStringToClientFunc(TwCopyCDStringToClient copyCDStringToClientFunc)6604 void ANT_CALL TwCopyCDStringToClientFunc(TwCopyCDStringToClient copyCDStringToClientFunc)
6605 {
6606     g_InitCopyCDStringToClient = copyCDStringToClientFunc;
6607     if( g_TwMgr!=NULL )
6608         g_TwMgr->m_CopyCDStringToClient = copyCDStringToClientFunc;
6609 }
6610 
TwCopyCDStringToLibrary(char ** destinationLibraryStringPtr,const char * sourceClientString)6611 void ANT_CALL TwCopyCDStringToLibrary(char **destinationLibraryStringPtr, const char *sourceClientString)
6612 {
6613     if( g_TwMgr==NULL )
6614     {
6615         if( destinationLibraryStringPtr!=NULL )
6616             *destinationLibraryStringPtr = const_cast<char *>(sourceClientString);
6617         return;
6618     }
6619 
6620     // static buffer to store sourceClientString copy associated to sourceClientString pointer
6621     std::vector<char>& Buf = g_TwMgr->m_CDStdStringCopyBuffers[(void *)sourceClientString];
6622 
6623     size_t len = (sourceClientString!=NULL) ? strlen(sourceClientString) : 0;
6624     if( Buf.size()<len+1 )
6625         Buf.resize(len+128); // len + some margin
6626     char *SrcStrCopy = &(Buf[0]);
6627     SrcStrCopy[0] = '\0';
6628     if( sourceClientString!=NULL )
6629         memcpy(SrcStrCopy, sourceClientString, len+1);
6630     SrcStrCopy[len] = '\0';
6631     if( destinationLibraryStringPtr!=NULL )
6632         *destinationLibraryStringPtr = SrcStrCopy;
6633 }
6634 
TwCopyStdStringToClientFunc(TwCopyStdStringToClient copyStdStringToClientFunc)6635 void ANT_CALL TwCopyStdStringToClientFunc(TwCopyStdStringToClient copyStdStringToClientFunc)
6636 {
6637     g_InitCopyStdStringToClient = copyStdStringToClientFunc;
6638     if( g_TwMgr!=NULL )
6639         g_TwMgr->m_CopyStdStringToClient = copyStdStringToClientFunc;
6640 }
6641 
TwCopyStdStringToLibrary(std::string & destLibraryString,const std::string & srcClientString)6642 void ANT_CALL TwCopyStdStringToLibrary(std::string& destLibraryString, const std::string& srcClientString)
6643 {
6644     /*
6645     // check if destLibraryString should be initialized
6646     char *Mem = (char *)&destLibraryString;
6647     bool Init = true;
6648     for( int i=0; i<sizeof(std::string) && Init; ++i )
6649         if( Mem[i]!=0 )
6650             Init = false; // has already been initialized
6651     assert( !Init );
6652     //  ::new(&destLibraryString) std::string;
6653 
6654     // copy string
6655     destLibraryString = srcClientString;
6656     */
6657 
6658     if( g_TwMgr==NULL )
6659         return;
6660 
6661     CTwMgr::CLibStdString srcLibString; // Convert VC++ Debug/Release std::string
6662     srcLibString.FromClient(srcClientString);
6663     const char *SrcStr = srcLibString.ToLib().c_str();
6664     const char **DstStrPtr = (const char **)&destLibraryString;
6665 
6666     // SrcStr can be defined locally by the caller, so we need to copy it
6667     // ( *DstStrPtr = copy of SrcStr )
6668 
6669     // static buffer to store srcClientString copy associated to srcClientString pointer
6670     std::vector<char>& Buf = g_TwMgr->m_CDStdStringCopyBuffers[(void *)&srcClientString];
6671 
6672     size_t len = strlen(SrcStr);
6673     if( Buf.size()<len+1 )
6674         Buf.resize(len+128); // len + some margin
6675     char *SrcStrCopy = &(Buf[0]);
6676 
6677     memcpy(SrcStrCopy, SrcStr, len+1);
6678     SrcStrCopy[len] = '\0';
6679     *DstStrPtr = SrcStrCopy;
6680     //*(const char **)&destLibraryString = srcClientString.c_str();
6681 }
6682 
6683 //  ---------------------------------------------------------------------------
6684 
Subtract(const CRect & _Rect,vector<CRect> & _OutRects) const6685 bool CRect::Subtract(const CRect& _Rect, vector<CRect>& _OutRects) const
6686 {
6687     if( Empty() )
6688         return false;
6689     if( _Rect.Empty() || _Rect.Y>=Y+H || _Rect.Y+_Rect.H<=Y || _Rect.X>=X+W || _Rect.X+_Rect.W<=X )
6690     {
6691         _OutRects.push_back(*this);
6692         return true;
6693     }
6694 
6695     bool Ret = false;
6696     int Y0 = Y;
6697     int Y1 = Y+H-1;
6698     if( _Rect.Y>Y )
6699     {
6700         Y0 = _Rect.Y;
6701         _OutRects.push_back(CRect(X, Y, W, Y0-Y+1));
6702         Ret = true;
6703     }
6704     if( _Rect.Y+_Rect.H<Y+H )
6705     {
6706         Y1 = _Rect.Y+_Rect.H;
6707         _OutRects.push_back(CRect(X, Y1, W, Y+H-Y1));
6708         Ret = true;
6709     }
6710     int X0 = X;
6711     int X1 = X+W-1;
6712     if( _Rect.X>X )
6713     {
6714         X0 = _Rect.X; //-2;
6715         _OutRects.push_back(CRect(X, Y0, X0-X+1, Y1-Y0+1));
6716         Ret = true;
6717     }
6718     if( _Rect.X+_Rect.W<X+W )
6719     {
6720         X1 = _Rect.X+_Rect.W; //-1;
6721         _OutRects.push_back(CRect(X1, Y0, X+W-X1, Y1-Y0+1));
6722         Ret = true;
6723     }
6724     return Ret;
6725 }
6726 
Subtract(const vector<CRect> & _Rects,vector<CRect> & _OutRects) const6727 bool CRect::Subtract(const vector<CRect>& _Rects, vector<CRect>& _OutRects) const
6728 {
6729     _OutRects.clear();
6730     size_t i, j, NbRects = _Rects.size();
6731     if( NbRects==0 )
6732     {
6733         _OutRects.push_back(*this);
6734         return true;
6735     }
6736     else
6737     {
6738         vector<CRect> TmpRects;
6739         Subtract(_Rects[0], _OutRects);
6740 
6741         for( i=1; i<NbRects; i++)
6742         {
6743             for( j=0; j<_OutRects.size(); j++ )
6744                 _OutRects[j].Subtract(_Rects[i], TmpRects);
6745             _OutRects.swap(TmpRects);
6746             TmpRects.clear();
6747         }
6748         return _OutRects.empty();
6749     }
6750 }
6751 
6752 //  ---------------------------------------------------------------------------
6753 
6754