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