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